Преглед на файлове

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 години
родител
ревизия
74e5999c63
променени са 3 файла, в които са добавени 32 реда и са изтрити 9 реда
  1. 3 1
      docs/full-configuration.md
  2. 27 7
      internal/dataprovider/dataprovider.go
  3. 2 1
      internal/sftpd/sftpd_test.go

+ 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