Loading django/contrib/auth/hashers.py +4 −0 Original line number Diff line number Diff line Loading @@ -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): """ Loading docs/releases/1.9.txt +3 −0 Original line number Diff line number Diff line Loading @@ -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` ^^^^^^^^^^^^^^^^^^^^^^^^^^ Loading tests/auth_tests/test_hashers.py +32 −0 Original line number Diff line number Diff line Loading @@ -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) Loading Loading
django/contrib/auth/hashers.py +4 −0 Original line number Diff line number Diff line Loading @@ -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): """ Loading
docs/releases/1.9.txt +3 −0 Original line number Diff line number Diff line Loading @@ -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` ^^^^^^^^^^^^^^^^^^^^^^^^^^ Loading
tests/auth_tests/test_hashers.py +32 −0 Original line number Diff line number Diff line Loading @@ -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) Loading