mirror of
https://github.com/zalando/postgres-operator.git
synced 2026-10-18 04:50:03 +02:00
Use scram-sha-256 hash if postgresql parameter password_encryption set to do so. (#995)
* Use scram-sha-256 hash if postgresql parameter password_encryption set to do so. * test fixed * Refactoring * code style
This commit is contained in:
+57
-4
@@ -1,8 +1,11 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/md5" // #nosec we need it to for PostgreSQL md5 passwords
|
||||
cryptoRand "crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
@@ -16,10 +19,14 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/zalando/postgres-operator/pkg/spec"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
const (
|
||||
md5prefix = "md5"
|
||||
md5prefix = "md5"
|
||||
scramsha256prefix = "SCRAM-SHA-256"
|
||||
saltlength = 16
|
||||
iterations = 4096
|
||||
)
|
||||
|
||||
var passwordChars = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
||||
@@ -61,16 +68,62 @@ func NameFromMeta(meta metav1.ObjectMeta) spec.NamespacedName {
|
||||
}
|
||||
}
|
||||
|
||||
// PGUserPassword is used to generate md5 password hash for a given user. It does nothing for already hashed passwords.
|
||||
func PGUserPassword(user spec.PgUser) string {
|
||||
if (len(user.Password) == md5.Size*2+len(md5prefix) && user.Password[:3] == md5prefix) || user.Password == "" {
|
||||
type Hasher func(user spec.PgUser) string
|
||||
type Random func(n int) string
|
||||
|
||||
type Encryptor struct {
|
||||
encrypt Hasher
|
||||
random Random
|
||||
}
|
||||
|
||||
func NewEncryptor(encryption string) *Encryptor {
|
||||
e := Encryptor{random: RandomPassword}
|
||||
m := map[string]Hasher{
|
||||
"md5": e.PGUserPasswordMD5,
|
||||
"scram-sha-256": e.PGUserPasswordScramSHA256,
|
||||
}
|
||||
hasher, ok := m[encryption]
|
||||
if !ok {
|
||||
hasher = e.PGUserPasswordMD5
|
||||
}
|
||||
e.encrypt = hasher
|
||||
return &e
|
||||
}
|
||||
|
||||
func (e *Encryptor) PGUserPassword(user spec.PgUser) string {
|
||||
if (len(user.Password) == md5.Size*2+len(md5prefix) && user.Password[:3] == md5prefix) ||
|
||||
(len(user.Password) > len(scramsha256prefix) && user.Password[:len(scramsha256prefix)] == scramsha256prefix) || user.Password == "" {
|
||||
// Avoid processing already encrypted or empty passwords
|
||||
return user.Password
|
||||
}
|
||||
return e.encrypt(user)
|
||||
}
|
||||
|
||||
func (e *Encryptor) PGUserPasswordMD5(user spec.PgUser) string {
|
||||
s := md5.Sum([]byte(user.Password + user.Name)) // #nosec, using md5 since PostgreSQL uses it for hashing passwords.
|
||||
return md5prefix + hex.EncodeToString(s[:])
|
||||
}
|
||||
|
||||
func (e *Encryptor) PGUserPasswordScramSHA256(user spec.PgUser) string {
|
||||
salt := []byte(e.random(saltlength))
|
||||
key := pbkdf2.Key([]byte(user.Password), salt, iterations, 32, sha256.New)
|
||||
mac := hmac.New(sha256.New, key)
|
||||
mac.Write([]byte("Server Key"))
|
||||
serverKey := mac.Sum(nil)
|
||||
mac = hmac.New(sha256.New, key)
|
||||
mac.Write([]byte("Client Key"))
|
||||
clientKey := mac.Sum(nil)
|
||||
storedKey := sha256.Sum256(clientKey)
|
||||
pass := fmt.Sprintf("%s$%v:%s$%s:%s",
|
||||
scramsha256prefix,
|
||||
iterations,
|
||||
base64.StdEncoding.EncodeToString(salt),
|
||||
base64.StdEncoding.EncodeToString(storedKey[:]),
|
||||
base64.StdEncoding.EncodeToString(serverKey),
|
||||
)
|
||||
return pass
|
||||
}
|
||||
|
||||
// Diff returns diffs between 2 objects
|
||||
func Diff(a, b interface{}) []string {
|
||||
return pretty.Diff(a, b)
|
||||
|
||||
Reference in New Issue
Block a user