99 lines
3.0 KiB
Go
99 lines
3.0 KiB
Go
// Copyright (C) MongoDB, Inc. 2017-present.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
// not use this file except in compliance with the License. You may obtain
|
|
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
package auth
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"go.mongodb.org/mongo-driver/mongo/description"
|
|
)
|
|
|
|
func newDefaultAuthenticator(cred *Cred) (Authenticator, error) {
|
|
scram, err := newScramSHA256Authenticator(cred)
|
|
if err != nil {
|
|
return nil, newAuthError("failed to create internal authenticator", err)
|
|
}
|
|
speculative, ok := scram.(SpeculativeAuthenticator)
|
|
if !ok {
|
|
typeErr := fmt.Errorf("expected SCRAM authenticator to be SpeculativeAuthenticator but got %T", scram)
|
|
return nil, newAuthError("failed to create internal authenticator", typeErr)
|
|
}
|
|
|
|
return &DefaultAuthenticator{
|
|
Cred: cred,
|
|
speculativeAuthenticator: speculative,
|
|
}, nil
|
|
}
|
|
|
|
// DefaultAuthenticator uses SCRAM-SHA-1 or MONGODB-CR depending
|
|
// on the server version.
|
|
type DefaultAuthenticator struct {
|
|
Cred *Cred
|
|
|
|
// The authenticator to use for speculative authentication. Because the correct auth mechanism is unknown when doing
|
|
// the initial hello, SCRAM-SHA-256 is used for the speculative attempt.
|
|
speculativeAuthenticator SpeculativeAuthenticator
|
|
}
|
|
|
|
var _ SpeculativeAuthenticator = (*DefaultAuthenticator)(nil)
|
|
|
|
// CreateSpeculativeConversation creates a speculative conversation for SCRAM authentication.
|
|
func (a *DefaultAuthenticator) CreateSpeculativeConversation() (SpeculativeConversation, error) {
|
|
return a.speculativeAuthenticator.CreateSpeculativeConversation()
|
|
}
|
|
|
|
// Auth authenticates the connection.
|
|
func (a *DefaultAuthenticator) Auth(ctx context.Context, cfg *Config) error {
|
|
var actual Authenticator
|
|
var err error
|
|
|
|
switch chooseAuthMechanism(cfg) {
|
|
case SCRAMSHA256:
|
|
actual, err = newScramSHA256Authenticator(a.Cred)
|
|
case SCRAMSHA1:
|
|
actual, err = newScramSHA1Authenticator(a.Cred)
|
|
default:
|
|
actual, err = newMongoDBCRAuthenticator(a.Cred)
|
|
}
|
|
|
|
if err != nil {
|
|
return newAuthError("error creating authenticator", err)
|
|
}
|
|
|
|
return actual.Auth(ctx, cfg)
|
|
}
|
|
|
|
// If a server provides a list of supported mechanisms, we choose
|
|
// SCRAM-SHA-256 if it exists or else MUST use SCRAM-SHA-1.
|
|
// Otherwise, we decide based on what is supported.
|
|
func chooseAuthMechanism(cfg *Config) string {
|
|
if saslSupportedMechs := cfg.HandshakeInfo.SaslSupportedMechs; saslSupportedMechs != nil {
|
|
for _, v := range saslSupportedMechs {
|
|
if v == SCRAMSHA256 {
|
|
return v
|
|
}
|
|
}
|
|
return SCRAMSHA1
|
|
}
|
|
|
|
if err := scramSHA1Supported(cfg.HandshakeInfo.Description.WireVersion); err == nil {
|
|
return SCRAMSHA1
|
|
}
|
|
|
|
return MONGODBCR
|
|
}
|
|
|
|
// scramSHA1Supported returns an error if the given server version does not support scram-sha-1.
|
|
func scramSHA1Supported(wireVersion *description.VersionRange) error {
|
|
if wireVersion != nil && wireVersion.Max < 3 {
|
|
return fmt.Errorf("SCRAM-SHA-1 is only supported for servers 3.0 or newer")
|
|
}
|
|
|
|
return nil
|
|
}
|