mirror of
https://github.com/django/django.git
synced 2025-10-31 09:41:08 +00:00
Fixed #26033 -- Added Argon2 password hasher.
This commit is contained in:
committed by
Tim Graham
parent
74670498e9
commit
b4250ea04a
@@ -25,6 +25,11 @@ try:
|
||||
except ImportError:
|
||||
bcrypt = None
|
||||
|
||||
try:
|
||||
import argon2
|
||||
except ImportError:
|
||||
argon2 = None
|
||||
|
||||
|
||||
class PBKDF2SingleIterationHasher(PBKDF2PasswordHasher):
|
||||
iterations = 1
|
||||
@@ -434,3 +439,58 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||
with six.assertRaisesRegex(self, ValueError,
|
||||
"Couldn't load 'PlainHasher' algorithm library: No module named '?plain'?"):
|
||||
PlainHasher()._load_library()
|
||||
|
||||
|
||||
@skipUnless(argon2, "argon2-cffi not installed")
|
||||
@override_settings(PASSWORD_HASHERS=PASSWORD_HASHERS)
|
||||
class TestUtilsHashPassArgon2(SimpleTestCase):
|
||||
|
||||
def test_argon2(self):
|
||||
encoded = make_password('lètmein', hasher='argon2')
|
||||
self.assertTrue(is_password_usable(encoded))
|
||||
self.assertTrue(encoded.startswith('argon2$'))
|
||||
self.assertTrue(check_password('lètmein', encoded))
|
||||
self.assertFalse(check_password('lètmeinz', encoded))
|
||||
self.assertEqual(identify_hasher(encoded).algorithm, 'argon2')
|
||||
# Blank passwords
|
||||
blank_encoded = make_password('', hasher='argon2')
|
||||
self.assertTrue(blank_encoded.startswith('argon2$'))
|
||||
self.assertTrue(is_password_usable(blank_encoded))
|
||||
self.assertTrue(check_password('', blank_encoded))
|
||||
self.assertFalse(check_password(' ', blank_encoded))
|
||||
|
||||
def test_argon2_upgrade(self):
|
||||
self._test_argon2_upgrade('time_cost', 'time cost', 1)
|
||||
self._test_argon2_upgrade('memory_cost', 'memory cost', 16)
|
||||
self._test_argon2_upgrade('parallelism', 'parallelism', 1)
|
||||
|
||||
def _test_argon2_upgrade(self, attr, summary_key, new_value):
|
||||
hasher = get_hasher('argon2')
|
||||
self.assertEqual('argon2', hasher.algorithm)
|
||||
self.assertNotEqual(getattr(hasher, attr), new_value)
|
||||
|
||||
old_value = getattr(hasher, attr)
|
||||
try:
|
||||
# Generate hash with attr set to 1
|
||||
setattr(hasher, attr, new_value)
|
||||
encoded = make_password('letmein', hasher='argon2')
|
||||
attr_value = hasher.safe_summary(encoded)[summary_key]
|
||||
self.assertEqual(attr_value, new_value)
|
||||
|
||||
state = {'upgraded': False}
|
||||
|
||||
def setter(password):
|
||||
state['upgraded'] = True
|
||||
|
||||
# Check that no upgrade is triggered.
|
||||
self.assertTrue(check_password('letmein', encoded, setter, 'argon2'))
|
||||
self.assertFalse(state['upgraded'])
|
||||
|
||||
# Revert to the old rounds count and ...
|
||||
setattr(hasher, attr, old_value)
|
||||
|
||||
# ... check if the password would get updated to the new count.
|
||||
self.assertTrue(check_password('letmein', encoded, setter, 'argon2'))
|
||||
self.assertTrue(state['upgraded'])
|
||||
finally:
|
||||
setattr(hasher, attr, old_value)
|
||||
|
||||
Reference in New Issue
Block a user