From f4503e07cda4a57a47f978ee651e6105673171e4 Mon Sep 17 00:00:00 2001 From: lennartzellmer <2241624+lennartzellmer@users.noreply.github.com> Date: Tue, 28 Oct 2025 17:26:48 +0100 Subject: [PATCH] feat(api): integrates drupal7 hash verifier from passwap (#10918) # Which Problems Are Solved - Integrates the Drupal 7 hash verifier from passwap # Additional Changes - The docs inform about the option to use the Drupal 7 hash verifier - Updates passwap to version v0.10.0 # Additional Context - Follow-up for PR [#passwap/pull/70](https://github.com/zitadel/passwap/pull/70) Co-authored-by: Marco A. --- docs/docs/concepts/architecture/secrets.md | 3 ++- internal/crypto/passwap.go | 8 +++++++- internal/crypto/passwap_test.go | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/docs/concepts/architecture/secrets.md b/docs/docs/concepts/architecture/secrets.md index 1f368027541..7c3fd911a22 100644 --- a/docs/docs/concepts/architecture/secrets.md +++ b/docs/docs/concepts/architecture/secrets.md @@ -72,12 +72,13 @@ The following hash algorithms are supported: - md5plain: md5 digest of a password without salt [^2] - md5salted: md5 digest of a salted password [^2] - phpass: md5 digest with PHPass algorithm (used in WordPress) [^2] +- drupal7: Custom hashing format used in Drupal 7 [^2] - sha2: implementation of crypt(3) SHA-256 & SHA-512 - scrypt - pbkdf2 [^1]: argon2 algorithms are currently disabled on ZITADEL Cloud due to its steep memory requirements. -[^2]: md5 is insecure and can only be used to import and verify users, not hash new passwords. +[^2]: md5 and drupal7 are insecure and can only be used to import and verify users, not hash new passwords. :::info ZITADEL updates stored hashes when the configured algorithm or its parameters are updated, diff --git a/internal/crypto/passwap.go b/internal/crypto/passwap.go index e4f3313342e..66b5441f757 100644 --- a/internal/crypto/passwap.go +++ b/internal/crypto/passwap.go @@ -10,6 +10,7 @@ import ( "github.com/zitadel/passwap" "github.com/zitadel/passwap/argon2" "github.com/zitadel/passwap/bcrypt" + "github.com/zitadel/passwap/drupal7" "github.com/zitadel/passwap/md5" "github.com/zitadel/passwap/md5plain" "github.com/zitadel/passwap/md5salted" @@ -57,6 +58,7 @@ const ( HashNameSha2 HashName = "sha2" // hash and verify HashNameScrypt HashName = "scrypt" // hash and verify HashNamePBKDF2 HashName = "pbkdf2" // hash and verify + HashNameDrupal7 HashName = "drupal7" // verify only, Drupal 7 legacy hashes ) type HashMode string @@ -137,6 +139,10 @@ var knowVerifiers = map[HashName]prefixVerifier{ prefixes: []string{phpass.IdentifierP, phpass.IdentifierH}, verifier: phpass.Verifier, }, + HashNameDrupal7: { + prefixes: []string{drupal7.Identifier}, + verifier: drupal7.Verifier, + }, } func (c *HashConfig) buildVerifiers() (verifiers []verifier.Verifier, prefixes []string, err error) { @@ -174,7 +180,7 @@ func (c *HasherConfig) buildHasher() (hasher passwap.Hasher, prefixes []string, return c.sha2() case "": return nil, nil, fmt.Errorf("missing hasher algorithm") - case HashNameArgon2, HashNameMd5, HashNameMd5Plain, HashNameMd5Salted, HashNamePHPass: + case HashNameArgon2, HashNameMd5, HashNameMd5Plain, HashNameMd5Salted, HashNamePHPass, HashNameDrupal7: fallthrough default: return nil, nil, fmt.Errorf("invalid algorithm %q", c.Algorithm) diff --git a/internal/crypto/passwap_test.go b/internal/crypto/passwap_test.go index dfcafd14064..5fcc2df5063 100644 --- a/internal/crypto/passwap_test.go +++ b/internal/crypto/passwap_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/zitadel/passwap/argon2" "github.com/zitadel/passwap/bcrypt" + "github.com/zitadel/passwap/drupal7" "github.com/zitadel/passwap/md5" "github.com/zitadel/passwap/md5salted" "github.com/zitadel/passwap/pbkdf2" @@ -249,6 +250,19 @@ func TestPasswordHashConfig_PasswordHasher(t *testing.T) { }, wantPrefixes: []string{bcrypt.Prefix, argon2.Prefix, md5.Prefix, scrypt.Prefix, scrypt.Prefix_Linux, md5salted.Prefix}, }, + { + name: "drupal7 verifier", + fields: fields{ + Hasher: HasherConfig{ + Algorithm: HashNameBcrypt, + Params: map[string]any{ + "cost": 3, + }, + }, + Verifiers: []HashName{HashNameDrupal7}, + }, + wantPrefixes: []string{bcrypt.Prefix, drupal7.Identifier}, + }, { name: "scrypt, error", fields: fields{