1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Fixed #24115 -- Allowed bcrypt hashers to upgrade passwords on rounds change.

Thanks Florian Apolloner for the review.
This commit is contained in:
Tim Graham 2015-02-26 14:04:24 -05:00
parent e4cf8c8420
commit b86abbceb9
3 changed files with 39 additions and 0 deletions

View File

@ -337,6 +337,10 @@ class BCryptSHA256PasswordHasher(BasePasswordHasher):
(_('checksum'), mask_hash(checksum)),
])
def must_update(self, encoded):
algorithm, empty, algostr, rounds, data = encoded.split('$', 4)
return int(rounds) != self.rounds
class BCryptPasswordHasher(BCryptSHA256PasswordHasher):
"""

View File

@ -56,6 +56,9 @@ Minor features
subclassed ``django.contrib.auth.hashers.PBKDF2PasswordHasher`` to change the
default value.
* The ``BCryptSHA256PasswordHasher`` will now update passwords if its
``rounds`` attribute is changed.
:mod:`django.contrib.gis`
^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -177,6 +177,38 @@ class TestUtilsHashPass(SimpleTestCase):
self.assertTrue(check_password('', blank_encoded))
self.assertFalse(check_password(' ', blank_encoded))
@skipUnless(bcrypt, "bcrypt not installed")
def test_bcrypt_upgrade(self):
hasher = get_hasher('bcrypt')
self.assertEqual('bcrypt', hasher.algorithm)
self.assertNotEqual(hasher.rounds, 4)
old_rounds = hasher.rounds
try:
# Generate a password with 4 rounds.
hasher.rounds = 4
encoded = make_password('letmein', hasher='bcrypt')
rounds = hasher.safe_summary(encoded)['work factor']
self.assertEqual(rounds, '04')
state = {'upgraded': False}
def setter(password):
state['upgraded'] = True
# Check that no upgrade is triggered.
self.assertTrue(check_password('letmein', encoded, setter, 'bcrypt'))
self.assertFalse(state['upgraded'])
# Revert to the old rounds count and ...
hasher.rounds = old_rounds
# ... check if the password would get updated to the new count.
self.assertTrue(check_password('letmein', encoded, setter, 'bcrypt'))
self.assertTrue(state['upgraded'])
finally:
hasher.rounds = old_rounds
def test_unusable(self):
encoded = make_password(None)
self.assertEqual(len(encoded), len(UNUSABLE_PASSWORD_PREFIX) + UNUSABLE_PASSWORD_SUFFIX_LENGTH)