diff options
| author | ryowright <43687737+ryowright@users.noreply.github.com> | 2020-12-26 18:54:47 -0800 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2021-07-22 12:40:33 +0200 |
| commit | 1783b3cb24cdefd8e1e3d73acd1d1ef3011c96be (patch) | |
| tree | 3b71a9e0a089dd7c59275cd22b741013863f8f84 /tests/auth_tests/test_hashers.py | |
| parent | 65b880b7268dd8fe97fde5af77bede46305eb499 (diff) | |
Fixed #32275 -- Added scrypt password hasher.
Co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com>
Diffstat (limited to 'tests/auth_tests/test_hashers.py')
| -rw-r--r-- | tests/auth_tests/test_hashers.py | 81 |
1 files changed, 79 insertions, 2 deletions
diff --git a/tests/auth_tests/test_hashers.py b/tests/auth_tests/test_hashers.py index 46ac4062f3..81234a44f0 100644 --- a/tests/auth_tests/test_hashers.py +++ b/tests/auth_tests/test_hashers.py @@ -5,8 +5,8 @@ from django.contrib.auth.hashers import ( UNUSABLE_PASSWORD_PREFIX, UNUSABLE_PASSWORD_SUFFIX_LENGTH, BasePasswordHasher, BCryptPasswordHasher, BCryptSHA256PasswordHasher, MD5PasswordHasher, PBKDF2PasswordHasher, PBKDF2SHA1PasswordHasher, - SHA1PasswordHasher, check_password, get_hasher, identify_hasher, - is_password_usable, make_password, + ScryptPasswordHasher, SHA1PasswordHasher, check_password, get_hasher, + identify_hasher, is_password_usable, make_password, ) from django.test import SimpleTestCase from django.test.utils import override_settings @@ -480,6 +480,7 @@ class TestUtilsHashPass(SimpleTestCase): MD5PasswordHasher, PBKDF2PasswordHasher, PBKDF2SHA1PasswordHasher, + ScryptPasswordHasher, SHA1PasswordHasher, ] msg = 'salt must be provided and cannot contain $.' @@ -495,6 +496,7 @@ class TestUtilsHashPass(SimpleTestCase): MD5PasswordHasher, PBKDF2PasswordHasher, PBKDF2SHA1PasswordHasher, + ScryptPasswordHasher, SHA1PasswordHasher, ] msg = 'password must be provided.' @@ -662,3 +664,78 @@ class TestUtilsHashPassArgon2(SimpleTestCase): self.assertTrue(state['upgraded']) finally: setattr(hasher, attr, old_value) + + +@override_settings(PASSWORD_HASHERS=PASSWORD_HASHERS) +class TestUtilsHashPassScrypt(SimpleTestCase): + + def test_scrypt(self): + encoded = make_password('lètmein', 'seasalt', 'scrypt') + self.assertEqual( + encoded, + 'scrypt$16384$seasalt$8$1$Qj3+9PPyRjSJIebHnG81TMjsqtaIGxNQG/aEB/NY' + 'afTJ7tibgfYz71m0ldQESkXFRkdVCBhhY8mx7rQwite/Pw==' + ) + self.assertIs(is_password_usable(encoded), True) + self.assertIs(check_password('lètmein', encoded), True) + self.assertIs(check_password('lètmeinz', encoded), False) + self.assertEqual(identify_hasher(encoded).algorithm, "scrypt") + # Blank passwords. + blank_encoded = make_password('', 'seasalt', 'scrypt') + self.assertIs(blank_encoded.startswith('scrypt$'), True) + self.assertIs(is_password_usable(blank_encoded), True) + self.assertIs(check_password('', blank_encoded), True) + self.assertIs(check_password(' ', blank_encoded), False) + + def test_scrypt_decode(self): + encoded = make_password('lètmein', 'seasalt', 'scrypt') + hasher = get_hasher('scrypt') + decoded = hasher.decode(encoded) + tests = [ + ('block_size', hasher.block_size), + ('parallelism', hasher.parallelism), + ('salt', 'seasalt'), + ('work_factor', hasher.work_factor), + ] + for key, excepted in tests: + with self.subTest(key=key): + self.assertEqual(decoded[key], excepted) + + def _test_scrypt_upgrade(self, attr, summary_key, new_value): + hasher = get_hasher('scrypt') + self.assertEqual(hasher.algorithm, 'scrypt') + self.assertNotEqual(getattr(hasher, attr), new_value) + + old_value = getattr(hasher, attr) + try: + # Generate hash with attr set to the new value. + setattr(hasher, attr, new_value) + encoded = make_password('lètmein', 'seasalt', 'scrypt') + attr_value = hasher.safe_summary(encoded)[summary_key] + self.assertEqual(attr_value, new_value) + + state = {'upgraded': False} + + def setter(password): + state['upgraded'] = True + + # No update is triggered. + self.assertIs(check_password('lètmein', encoded, setter, 'scrypt'), True) + self.assertIs(state['upgraded'], False) + # Revert to the old value. + setattr(hasher, attr, old_value) + # Password is updated. + self.assertIs(check_password('lètmein', encoded, setter, 'scrypt'), True) + self.assertIs(state['upgraded'], True) + finally: + setattr(hasher, attr, old_value) + + def test_scrypt_upgrade(self): + tests = [ + ('work_factor', 'work factor', 2 ** 11), + ('block_size', 'block size', 10), + ('parallelism', 'parallelism', 2), + ] + for attr, summary_key, new_value in tests: + with self.subTest(attr=attr): + self._test_scrypt_upgrade(attr, summary_key, new_value) |
