github.com/XiaoMi/Gaea@v1.2.5/parser/auth/auth.go (about) 1 // Copyright 2015 PingCAP, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package auth 15 16 import ( 17 "bytes" 18 "crypto/sha1" 19 "encoding/hex" 20 "fmt" 21 22 "github.com/pingcap/errors" 23 24 "github.com/XiaoMi/Gaea/parser/format" 25 "github.com/XiaoMi/Gaea/parser/terror" 26 ) 27 28 // UserIdentity represents username and hostname. 29 type UserIdentity struct { 30 Username string 31 Hostname string 32 CurrentUser bool 33 AuthUsername string // Username matched in privileges system 34 AuthHostname string // Match in privs system (i.e. could be a wildcard) 35 } 36 37 // RoleIdentity role identity 38 type RoleIdentity struct { 39 Username string 40 Hostname string 41 } 42 43 // Restore implements Node interface. 44 func (user *UserIdentity) Restore(ctx *format.RestoreCtx) error { 45 if user.CurrentUser { 46 ctx.WriteKeyWord("CURRENT_USER") 47 } else { 48 ctx.WriteName(user.Username) 49 if user.Hostname != "" { 50 ctx.WritePlain("@") 51 ctx.WriteName(user.Hostname) 52 } 53 } 54 return nil 55 } 56 57 // String converts UserIdentity to the format user@host. 58 func (user *UserIdentity) String() string { 59 // TODO: Escape username and hostname. 60 return fmt.Sprintf("%s@%s", user.Username, user.Hostname) 61 } 62 63 // AuthIdentityString returns matched identity in user@host format 64 func (user *UserIdentity) AuthIdentityString() string { 65 // TODO: Escape username and hostname. 66 return fmt.Sprintf("%s@%s", user.AuthUsername, user.AuthHostname) 67 } 68 69 // CheckScrambledPassword check scrambled password received from client. 70 // The new authentication is performed in following manner: 71 // SERVER: public_seed=create_random_string() 72 // send(public_seed) 73 // CLIENT: recv(public_seed) 74 // hash_stage1=sha1("password") 75 // hash_stage2=sha1(hash_stage1) 76 // reply=xor(hash_stage1, sha1(public_seed,hash_stage2) 77 // // this three steps are done in scramble() 78 // send(reply) 79 // SERVER: recv(reply) 80 // hash_stage1=xor(reply, sha1(public_seed,hash_stage2)) 81 // candidate_hash2=sha1(hash_stage1) 82 // check(candidate_hash2==hash_stage2) 83 // // this three steps are done in check_scramble() 84 func CheckScrambledPassword(salt, hpwd, auth []byte) bool { 85 crypt := sha1.New() 86 _, err := crypt.Write(salt) 87 terror.Log(errors.Trace(err)) 88 _, err = crypt.Write(hpwd) 89 terror.Log(errors.Trace(err)) 90 hash := crypt.Sum(nil) 91 // token = scrambleHash XOR stage1Hash 92 for i := range hash { 93 hash[i] ^= auth[i] 94 } 95 96 return bytes.Equal(hpwd, Sha1Hash(hash)) 97 } 98 99 // Sha1Hash is an util function to calculate sha1 hash. 100 func Sha1Hash(bs []byte) []byte { 101 crypt := sha1.New() 102 _, err := crypt.Write(bs) 103 terror.Log(errors.Trace(err)) 104 return crypt.Sum(nil) 105 } 106 107 // EncodePassword converts plaintext password to hashed hex string. 108 func EncodePassword(pwd string) string { 109 if len(pwd) == 0 { 110 return "" 111 } 112 hash1 := Sha1Hash([]byte(pwd)) 113 hash2 := Sha1Hash(hash1) 114 115 return fmt.Sprintf("*%X", hash2) 116 } 117 118 // DecodePassword converts hex string password without prefix '*' to byte array. 119 func DecodePassword(pwd string) ([]byte, error) { 120 x, err := hex.DecodeString(pwd[1:]) 121 if err != nil { 122 return nil, errors.Trace(err) 123 } 124 return x, nil 125 }