From e77a1c5187ff9d800cbb3523851985a0f94fa8ff Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Tue, 14 Apr 2026 13:04:42 +0200 Subject: [PATCH] test/auth: add bcrypt max len test The maximum password length of bcrypt is 72 chars, any longer password will create the same hash. Some password/hashing lib combinations truncate for us, for others we might catch exceptions. So test all that to make sure we can handle all combinations. Related-to: #1896 Signed-off-by: Henning Schild --- radicale/tests/test_auth.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/radicale/tests/test_auth.py b/radicale/tests/test_auth.py index 90925f6d..ea3de970 100644 --- a/radicale/tests/test_auth.py +++ b/radicale/tests/test_auth.py @@ -42,6 +42,8 @@ class TestBaseAuthRequests(BaseTest): """ + BCRYPT_MAX_PWLEN = 72 + # test for available bcrypt module try: import bcrypt @@ -174,6 +176,21 @@ class TestBaseAuthRequests(BaseTest): def test_htpasswd_bcrypt_unicode(self) -> None: self._test_htpasswd("bcrypt", "😀:$2y$10$Oyz5aHV4MD9eQJbk6GPemOs4T6edK6U9Sqlzr.W1mMVCS8wJUftnW", "unicode") + @pytest.mark.skipif(has_bcrypt == 0, reason="No bcrypt module installed") + @pytest.mark.skipif(not utils.passlib_libpass_supports_bcrypt()[0], reason="bcrypt module incompatible with passlib(libpass) module") + def test_htpasswd_bcrypt_long(self) -> None: + import bcrypt + m = ( + # full available len + ("tmp", "a" * self.BCRYPT_MAX_PWLEN, True), + # longer than valid -> same password + ("tmp", "a" * (self.BCRYPT_MAX_PWLEN + 42), True), + # shorter that before -> some other password + ("tmp", "a" * (self.BCRYPT_MAX_PWLEN - 1), False), + ) + hash = bcrypt.hashpw(("a" * self.BCRYPT_MAX_PWLEN).encode(), bcrypt.gensalt()) + self._test_htpasswd("bcrypt", "tmp:" + hash.decode('utf-8'), m) + @pytest.mark.skipif(has_argon2 == 0, reason="No argon2 module installed") def test_htpasswd_argon2_i(self) -> None: self._test_htpasswd("argon2", "tmp:$argon2i$v=19$m=65536,t=3,p=4$NgZg7F1rzRkDoNSaMwag9A$qmsvMKEn5zOXHm8e3O5fKzzcRo0UESwaDr/cETe5YPI")