Skip to content

Commit

Permalink
Limit offered authentication methods
Browse files Browse the repository at this point in the history
Do not offer non-enabled authentication methods to the client. This
avoids unnecessary password prompts when password auth is disabled.

Fixes: ContainerSSH/ContainerSSH#579
  • Loading branch information
tsipinakis committed May 5, 2024
1 parent 1159c53 commit 3858d33
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 5 deletions.
10 changes: 10 additions & 0 deletions internal/authintegration/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,16 @@ func (h *handler) OnNetworkConnection(meta metadata.ConnectionMetadata) (
authorizationProvider: h.authorizationProvider,
}

if h.passwordAuthenticator != nil {
meta.AuthenticationMethods[metadata.AuthMethodPassword] = true
}
if h.publicKeyAuthenticator != nil {
meta.AuthenticationMethods[metadata.AuthMethodPubKey] = true
}
if h.keyboardInteractiveAuthenticator != nil {
meta.AuthenticationMethods[metadata.AuthMethodKeyboardInteractive] = true
}

if h.authorizationProvider != nil {
// We inject the authz handler before the normal authentication handler in the chain as we need the authenticated metadata the handler returns.
// Authentications request will first hit the authz handler which will pass it through to the authHandler, once it returns we can perform authorization.
Expand Down
26 changes: 21 additions & 5 deletions internal/sshserver/serverImpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,11 @@ func (s *serverImpl) createKeyboardInteractiveCallback(
handlerNetworkConnection *networkConnectionWrapper,
logger log.Logger,
) func(conn ssh.ConnMetadata, challenge ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
ok, val := connectionMetadata.AuthenticationMethods[metadata.AuthMethodKeyboardInteractive]
if !ok || !val {
return nil
}

keyboardInteractiveHandler := s.createKeyboardInteractiveHandler(
connectionMetadata,
handlerNetworkConnection,
Expand Down Expand Up @@ -474,6 +479,11 @@ func (s *serverImpl) createPubKeyCallback(
handlerNetworkConnection *networkConnectionWrapper,
logger log.Logger,
) func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
ok, val := meta.AuthenticationMethods[metadata.AuthMethodPubKey]
if !ok || !val {
return nil
}

pubKeyHandler := s.createPubKeyAuthenticator(meta, handlerNetworkConnection, logger)
pubkeyCallback := func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
permissions, authenticatedMetadata, err := pubKeyHandler(conn, key)
Expand Down Expand Up @@ -506,6 +516,11 @@ func (s *serverImpl) createPasswordCallback(
handlerNetworkConnection *networkConnectionWrapper,
logger log.Logger,
) func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
ok, val := meta.AuthenticationMethods[metadata.AuthMethodPassword]
if !ok || !val {
return nil
}

passwordHandler := s.createPasswordAuthenticator(meta, handlerNetworkConnection, logger)
passwordCallback := func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
permissions, authenticatedMetadata, err := passwordHandler(conn, password)
Expand Down Expand Up @@ -540,11 +555,12 @@ func (s *serverImpl) handleConnection(conn net.Conn) {
WithLabel("remoteAddr", addr.IP.String()).
WithLabel("connectionId", connectionID)
connectionMeta := metadata.ConnectionMetadata{
RemoteAddress: metadata.RemoteAddress(*addr),
ConnectionID: connectionID,
Metadata: map[string]metadata.Value{},
Environment: map[string]metadata.Value{},
Files: map[string]metadata.BinaryValue{},
RemoteAddress: metadata.RemoteAddress(*addr),
ConnectionID: connectionID,
AuthenticationMethods: map[metadata.AuthMethod]bool{},
Metadata: map[string]metadata.Value{},
Environment: map[string]metadata.Value{},
Files: map[string]metadata.BinaryValue{},
}

handlerNetworkConnection, connectionMeta, err := s.handler.OnNetworkConnection(connectionMeta)
Expand Down
12 changes: 12 additions & 0 deletions metadata/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ func (r *RemoteAddress) UnmarshalText(input []byte) error {
return nil
}

type AuthMethod string

const (
AuthMethodPassword AuthMethod = "password"
AuthMethodPubKey AuthMethod = "publickey"
AuthMethodKeyboardInteractive AuthMethod = "keyboard-interactive"
)

// ConnectionMetadata holds a metadata structure passed around with a metadata. Its main purpose is to allow an
// authentication or authorization module to configure data exposed to the configuration server or the backend.
//
Expand All @@ -96,6 +104,10 @@ type ConnectionMetadata struct {
// in: body
ConnectionID string `json:"connectionId"`

// AuthenticationMethods are the authentication methods that can be
// used to authenticate this connection
AuthenticationMethods map[AuthMethod]bool `json:"-"`

// Metadata is a set of key-value pairs that carry additional information from the authentication and configuration
// system to the backends. Backends can expose this information as container labels, environment variables, or
// other places.
Expand Down

0 comments on commit 3858d33

Please sign in to comment.