github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/client/auth.go (about) 1 // Copyright 2020 DataStax 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package client 16 17 import ( 18 "bytes" 19 "fmt" 20 ) 21 22 // AuthCredentials encapsulates a username and a password to use with plain-text authenticators. 23 type AuthCredentials struct { 24 Username string 25 Password string 26 } 27 28 func (c *AuthCredentials) String() string { 29 return fmt.Sprintf("AuthCredentials{username: %v}", c.Username) 30 } 31 32 // Marshal serializes the current credentials to an authentication token with the expected format for 33 // PasswordAuthenticator. 34 func (c *AuthCredentials) Marshal() []byte { 35 token := bytes.NewBuffer(make([]byte, 0, len(c.Username)+len(c.Password)+2)) 36 token.WriteByte(0) 37 token.WriteString(c.Username) 38 token.WriteByte(0) 39 token.WriteString(c.Password) 40 return token.Bytes() 41 } 42 43 // Unmarshal deserializes an authentication token with the expected format for PasswordAuthenticator into the current 44 // AuthCredentials. 45 func (c *AuthCredentials) Unmarshal(token []byte) error { 46 token = append(token, 0) 47 source := bytes.NewBuffer(token) 48 if _, err := source.ReadByte(); err != nil { 49 return err 50 } else if username, err := source.ReadString(0); err != nil { 51 return err 52 } else if password, err := source.ReadString(0); err != nil { 53 return err 54 } else { 55 c.Username = username[:len(username)-1] 56 c.Password = password[:len(password)-1] 57 return nil 58 } 59 } 60 61 func (c AuthCredentials) Copy() *AuthCredentials { 62 return &c 63 } 64 65 // A simple authenticator to perform plain-text authentications for CQL clients. 66 type PlainTextAuthenticator struct { 67 Credentials *AuthCredentials 68 } 69 70 var ( 71 expectedChallenge = []byte("PLAIN-START") 72 mechanism = []byte("PLAIN") 73 ) 74 75 func (a *PlainTextAuthenticator) InitialResponse(authenticator string) ([]byte, error) { 76 switch authenticator { 77 case "com.datastax.bdp.cassandra.auth.DseAuthenticator": 78 return mechanism, nil 79 case "org.apache.cassandra.auth.PasswordAuthenticator": 80 return a.Credentials.Marshal(), nil 81 } 82 return nil, fmt.Errorf("unknown authenticator: %v", authenticator) 83 } 84 85 func (a *PlainTextAuthenticator) EvaluateChallenge(challenge []byte) ([]byte, error) { 86 if challenge == nil || bytes.Compare(challenge, expectedChallenge) != 0 { 87 return nil, fmt.Errorf("incorrect SASL challenge from server, expecting PLAIN-START, got: %v", string(challenge)) 88 } 89 return a.Credentials.Marshal(), nil 90 }