Skip to content

Commit

Permalink
chore(connector): add logs to agent connector mode authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
henrybarreto authored and gustavosbarreto committed Oct 31, 2023
1 parent acce4f4 commit 0a6f2f7
Showing 1 changed file with 117 additions and 0 deletions.
117 changes: 117 additions & 0 deletions pkg/agent/server/modes/connector/authenticator.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/shellhub-io/shellhub/pkg/agent/server/modes"
"github.com/shellhub-io/shellhub/pkg/api/client"
"github.com/shellhub-io/shellhub/pkg/models"
log "github.com/sirupsen/logrus"
gossh "golang.org/x/crypto/ssh"
)

Expand Down Expand Up @@ -68,48 +69,111 @@ func getPasswd(ctx context.Context, cli dockerclient.APIClient, container string
func (a *Authenticator) Password(ctx gliderssh.Context, username string, password string) bool {
passwd, err := getPasswd(ctx, a.docker, *a.container)
if err != nil {
log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).WithError(err).Error("failed to get the passwd file from container")

return false
}

user, err := a.osauth.LookupUserFromPasswd(username, passwd)
if err != nil {
log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).WithError(err).Error("failed to lookup for the user on passwd file")

return false
}

if user.Password == "" {
log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).WithError(err).Error("user passwd is empty, so the authentication via password is blocked")

// NOTICE(r): when the user doesn't have password, we block the login.
return false
}

shadowTar, _, err := a.docker.CopyFromContainer(ctx, *a.container, "/etc/shadow")
if err != nil {
log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).WithError(err).Error("failed to get the shadow file from the container")

return false
}

shadow := tar.NewReader(shadowTar)
if _, err := shadow.Next(); err != nil {
log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).WithError(err).Error("failed to get the shadow file from the tar")

return false
}

if !a.osauth.AuthUserFromShadow(username, password, shadow) {
log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).WithError(err).Error("failed to authenticate the user on the device")

return false
}

// NOTICE: set the osauth.User to the context to be obtained later on.
ctx.SetValue("user", user)

log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).Error("using password authentication")

return true
}

// PublicKey handles the server's SSH public key authentication when server is running in connector mode.
func (a *Authenticator) PublicKey(ctx gliderssh.Context, username string, key gliderssh.PublicKey) bool {
passwd, err := getPasswd(ctx, a.docker, *a.container)
if err != nil {
log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).WithError(err).Error("failed to get the passwd file from container")

return false
}

user, err := a.osauth.LookupUserFromPasswd(username, passwd)
if err != nil {
log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).WithError(err).Error("failed to lookup for the user on passwd file")

return false
}

Expand All @@ -125,6 +189,13 @@ func (a *Authenticator) PublicKey(ctx gliderssh.Context, username string, key gl

sigBytes, err := json.Marshal(sig)
if err != nil {
log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).WithError(err).Error("failed to marshal signature")

return false
}

Expand All @@ -135,32 +206,78 @@ func (a *Authenticator) PublicKey(ctx gliderssh.Context, username string, key gl
Data: string(sigBytes),
}, a.authData.Token)
if err != nil {
log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).WithError(err).Error("failed to authenticate the user via public key")

return false
}

digest, err := base64.StdEncoding.DecodeString(res.Signature)
if err != nil {
if err != nil {
log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).WithError(err).Error("failed to decode the signature")

return false
}

return false
}

cryptoKey, ok := key.(gossh.CryptoPublicKey)
if !ok {
log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).WithError(err).Error("failed to get the crypto public key")

return false
}

pubCrypto := cryptoKey.CryptoPublicKey()

pubKey, ok := pubCrypto.(*rsa.PublicKey)
if !ok {
log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).WithError(err).Error("failed to get the crypto public key")

return false
}

if err = rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, sigHash[:], digest); err != nil {
log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).WithError(err).Error("failed to verify the signature")

return false
}

// NOTICE: set the osauth.User to the context to be obtained later on.
ctx.SetValue("user", user)

log.WithFields(
log.Fields{
"container": *a.container,
"username": username,
},
).Error("using public key authentication")

return true
}

0 comments on commit 0a6f2f7

Please sign in to comment.