github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/go.mongodb.org/mongo-driver/x/mongo/driver/auth/scram.go (about) 1 // Copyright (C) MongoDB, Inc. 2017-present. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 // not use this file except in compliance with the License. You may obtain 5 // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 7 // Copyright (C) MongoDB, Inc. 2018-present. 8 // 9 // Licensed under the Apache License, Version 2.0 (the "License"); you may 10 // not use this file except in compliance with the License. You may obtain 11 // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 12 13 package auth 14 15 import ( 16 "context" 17 "fmt" 18 19 "github.com/xdg-go/scram" 20 "github.com/xdg-go/stringprep" 21 "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" 22 ) 23 24 const ( 25 // SCRAMSHA1 holds the mechanism name "SCRAM-SHA-1" 26 SCRAMSHA1 = "SCRAM-SHA-1" 27 28 // SCRAMSHA256 holds the mechanism name "SCRAM-SHA-256" 29 SCRAMSHA256 = "SCRAM-SHA-256" 30 ) 31 32 var ( 33 // Additional options for the saslStart command to enable a shorter SCRAM conversation 34 scramStartOptions bsoncore.Document = bsoncore.BuildDocumentFromElements(nil, 35 bsoncore.AppendBooleanElement(nil, "skipEmptyExchange", true), 36 ) 37 ) 38 39 func newScramSHA1Authenticator(cred *Cred) (Authenticator, error) { 40 passdigest := mongoPasswordDigest(cred.Username, cred.Password) 41 client, err := scram.SHA1.NewClientUnprepped(cred.Username, passdigest, "") 42 if err != nil { 43 return nil, newAuthError("error initializing SCRAM-SHA-1 client", err) 44 } 45 client.WithMinIterations(4096) 46 return &ScramAuthenticator{ 47 mechanism: SCRAMSHA1, 48 source: cred.Source, 49 client: client, 50 }, nil 51 } 52 53 func newScramSHA256Authenticator(cred *Cred) (Authenticator, error) { 54 passprep, err := stringprep.SASLprep.Prepare(cred.Password) 55 if err != nil { 56 return nil, newAuthError(fmt.Sprintf("error SASLprepping password '%s'", cred.Password), err) 57 } 58 client, err := scram.SHA256.NewClientUnprepped(cred.Username, passprep, "") 59 if err != nil { 60 return nil, newAuthError("error initializing SCRAM-SHA-256 client", err) 61 } 62 client.WithMinIterations(4096) 63 return &ScramAuthenticator{ 64 mechanism: SCRAMSHA256, 65 source: cred.Source, 66 client: client, 67 }, nil 68 } 69 70 // ScramAuthenticator uses the SCRAM algorithm over SASL to authenticate a connection. 71 type ScramAuthenticator struct { 72 mechanism string 73 source string 74 client *scram.Client 75 } 76 77 var _ SpeculativeAuthenticator = (*ScramAuthenticator)(nil) 78 79 // Auth authenticates the provided connection by conducting a full SASL conversation. 80 func (a *ScramAuthenticator) Auth(ctx context.Context, cfg *Config) error { 81 err := ConductSaslConversation(ctx, cfg, a.source, a.createSaslClient()) 82 if err != nil { 83 return newAuthError("sasl conversation error", err) 84 } 85 return nil 86 } 87 88 // CreateSpeculativeConversation creates a speculative conversation for SCRAM authentication. 89 func (a *ScramAuthenticator) CreateSpeculativeConversation() (SpeculativeConversation, error) { 90 return newSaslConversation(a.createSaslClient(), a.source, true), nil 91 } 92 93 func (a *ScramAuthenticator) createSaslClient() SaslClient { 94 return &scramSaslAdapter{ 95 conversation: a.client.NewConversation(), 96 mechanism: a.mechanism, 97 } 98 } 99 100 type scramSaslAdapter struct { 101 mechanism string 102 conversation *scram.ClientConversation 103 } 104 105 var _ SaslClient = (*scramSaslAdapter)(nil) 106 var _ ExtraOptionsSaslClient = (*scramSaslAdapter)(nil) 107 108 func (a *scramSaslAdapter) Start() (string, []byte, error) { 109 step, err := a.conversation.Step("") 110 if err != nil { 111 return a.mechanism, nil, err 112 } 113 return a.mechanism, []byte(step), nil 114 } 115 116 func (a *scramSaslAdapter) Next(challenge []byte) ([]byte, error) { 117 step, err := a.conversation.Step(string(challenge)) 118 if err != nil { 119 return nil, err 120 } 121 return []byte(step), nil 122 } 123 124 func (a *scramSaslAdapter) Completed() bool { 125 return a.conversation.Done() 126 } 127 128 func (*scramSaslAdapter) StartCommandOptions() bsoncore.Document { 129 return scramStartOptions 130 }