Kaynağa Gözat

added support for verifying sha256/sha512 passwords hash

this simplifies the migration of users from some proprietary products

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
Nicola Murino 2 yıl önce
ebeveyn
işleme
74e5999c63

+ 3 - 1
docs/full-configuration.md

@@ -585,7 +585,9 @@ Supported hash algorithms:
 - MD5 crypt APR1, prefix `$apr1$`
 - SHA256 crypt, prefix `$5$`
 - SHA512 crypt, prefix `$6$`
-- LDAP MD5, prefix `{MD5}`
+- MD5 digest, prefix `{MD5}`
+- SHA256 digest, prefix `{SHA256}`
+- SHA512 digest, prefix `{SHA512}`
 
 If you set a password with one of these prefixes it will not be hashed.
 When users log in, if their passwords are stored with anything other than the preferred algorithm, SFTPGo will automatically upgrade the algorithm to the preferred one.

+ 27 - 7
internal/dataprovider/dataprovider.go

@@ -100,7 +100,9 @@ const (
 	sha256cryptPwdPrefix      = "$5$"
 	sha512cryptPwdPrefix      = "$6$"
 	yescryptPwdPrefix         = "$y$"
-	md5LDAPPwdPrefix          = "{MD5}"
+	md5DigestPwdPrefix        = "{MD5}"
+	sha256DigestPwdPrefix     = "{SHA256}"
+	sha512DigestPwdPrefix     = "{SHA512}"
 	trackQuotaDisabledError   = "please enable track_quota in your configuration to use this method"
 	operationAdd              = "add"
 	operationUpdate           = "update"
@@ -180,12 +182,13 @@ var (
 	sqlPlaceholders          []string
 	internalHashPwdPrefixes  = []string{argonPwdPrefix, bcryptPwdPrefix}
 	hashPwdPrefixes          = []string{argonPwdPrefix, bcryptPwdPrefix, pbkdf2SHA1Prefix, pbkdf2SHA256Prefix,
-		pbkdf2SHA512Prefix, pbkdf2SHA256B64SaltPrefix, md5cryptPwdPrefix, md5cryptApr1PwdPrefix, md5LDAPPwdPrefix,
-		sha256cryptPwdPrefix, sha512cryptPwdPrefix, yescryptPwdPrefix}
+		pbkdf2SHA512Prefix, pbkdf2SHA256B64SaltPrefix, md5cryptPwdPrefix, md5cryptApr1PwdPrefix, md5DigestPwdPrefix,
+		sha256DigestPwdPrefix, sha512DigestPwdPrefix, sha256cryptPwdPrefix, sha512cryptPwdPrefix, yescryptPwdPrefix}
 	pbkdfPwdPrefixes        = []string{pbkdf2SHA1Prefix, pbkdf2SHA256Prefix, pbkdf2SHA512Prefix, pbkdf2SHA256B64SaltPrefix}
 	pbkdfPwdB64SaltPrefixes = []string{pbkdf2SHA256B64SaltPrefix}
 	unixPwdPrefixes         = []string{md5cryptPwdPrefix, md5cryptApr1PwdPrefix, sha256cryptPwdPrefix, sha512cryptPwdPrefix,
 		yescryptPwdPrefix}
+	digestPwdPrefixes            = []string{md5DigestPwdPrefix, sha256DigestPwdPrefix, sha512DigestPwdPrefix}
 	sharedProviders              = []string{PGSQLDataProviderName, MySQLDataProviderName, CockroachDataProviderName}
 	logSender                    = "dataprovider"
 	sqlTableUsers                string
@@ -3211,10 +3214,8 @@ func isPasswordOK(user *User, password string) (bool, error) {
 		if err != nil {
 			return match, err
 		}
-	} else if strings.HasPrefix(user.Password, md5LDAPPwdPrefix) {
-		h := md5.New()
-		h.Write([]byte(password))
-		match = fmt.Sprintf("%s%x", md5LDAPPwdPrefix, h.Sum(nil)) == user.Password
+	} else if util.IsStringPrefixInSlice(user.Password, digestPwdPrefixes) {
+		match = compareDigestPasswordAndHash(user, password)
 	}
 	if err == nil && match {
 		cachedUserPasswords.Add(user.Username, password, user.Password)
@@ -3377,6 +3378,25 @@ func checkUserAndPubKey(user *User, pubKey []byte, isSSHCert bool) (User, string
 	return *user, "", ErrInvalidCredentials
 }
 
+func compareDigestPasswordAndHash(user *User, password string) bool {
+	if strings.HasPrefix(user.Password, md5DigestPwdPrefix) {
+		h := md5.New()
+		h.Write([]byte(password))
+		return fmt.Sprintf("%s%x", md5DigestPwdPrefix, h.Sum(nil)) == user.Password
+	}
+	if strings.HasPrefix(user.Password, sha256DigestPwdPrefix) {
+		h := sha256.New()
+		h.Write([]byte(password))
+		return fmt.Sprintf("%s%x", sha256DigestPwdPrefix, h.Sum(nil)) == user.Password
+	}
+	if strings.HasPrefix(user.Password, sha512DigestPwdPrefix) {
+		h := sha512.New()
+		h.Write([]byte(password))
+		return fmt.Sprintf("%s%x", sha512DigestPwdPrefix, h.Sum(nil)) == user.Password
+	}
+	return false
+}
+
 func compareUnixPasswordAndHash(user *User, password string) (bool, error) {
 	if strings.HasPrefix(user.Password, yescryptPwdPrefix) {
 		return compareYescryptPassword(user.Password, password)

+ 2 - 1
internal/sftpd/sftpd_test.go

@@ -7416,7 +7416,8 @@ func TestHashedPasswords(t *testing.T) {
 	pwdMapping["$5$h4Aalt0fJdGX8sgv$Rd2ew0fvgzUN.DzAVlKa9QL4q/DZWo4SsKpB9.3AyZ/"] = plainPwd
 	pwdMapping["$apr1$OBWLeSme$WoJbB736e7kKxMBIAqilb1"] = plainPwd
 	pwdMapping["{MD5}5f4dcc3b5aa765d61d8327deb882cf99"] = plainPwd
-
+	pwdMapping["{SHA256}5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"] = plainPwd
+	pwdMapping["{SHA512}b109f3bbbc244eb82441917ed06d618b9008dd09b3befd1b5e07394c706a8bb980b1d7785e5976ec049b46df5f1326af5a2ea6d103fd07c95385ffab0cacbc86"] = plainPwd
 	for pwd, clearPwd := range pwdMapping {
 		u := getTestUser(usePubKey)
 		u.Password = pwd