diff options
| author | Erik Romijn <erik@erik.io> | 2013-06-17 18:06:26 +0200 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2013-06-18 13:32:54 -0400 |
| commit | 2c4fe761a0e2b28e2c5c3b4bc506ee06824a443d (patch) | |
| tree | 1c0ab164a4d507366916548256e9945888b06fd1 /django | |
| parent | 3128f3d38d1db0bc01da9a4bf4be81119079d73a (diff) | |
Fixed #20593 -- Allow blank passwords in check_password() and set_password()
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/auth/hashers.py | 12 | ||||
| -rw-r--r-- | django/contrib/auth/tests/test_hashers.py | 53 |
2 files changed, 59 insertions, 6 deletions
diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py index 36d247d71e..d8a04e1473 100644 --- a/django/contrib/auth/hashers.py +++ b/django/contrib/auth/hashers.py @@ -47,7 +47,7 @@ def check_password(password, encoded, setter=None, preferred='default'): If setter is specified, it'll be called when you need to regenerate the password. """ - if not password or not is_password_usable(encoded): + if not is_password_usable(encoded): return False preferred = get_hasher(preferred) @@ -65,10 +65,10 @@ def make_password(password, salt=None, hasher='default'): Turn a plain-text password into a hash for database storage Same as encode() but generates a new random salt. If - password is None or blank then UNUSABLE_PASSWORD will be + password is None then UNUSABLE_PASSWORD will be returned which disallows logins. """ - if not password: + if password is None: return UNUSABLE_PASSWORD hasher = get_hasher(hasher) @@ -222,7 +222,7 @@ class PBKDF2PasswordHasher(BasePasswordHasher): digest = hashlib.sha256 def encode(self, password, salt, iterations=None): - assert password + assert password is not None assert salt and '$' not in salt if not iterations: iterations = self.iterations @@ -350,7 +350,7 @@ class SHA1PasswordHasher(BasePasswordHasher): algorithm = "sha1" def encode(self, password, salt): - assert password + assert password is not None assert salt and '$' not in salt hash = hashlib.sha1(force_bytes(salt + password)).hexdigest() return "%s$%s$%s" % (self.algorithm, salt, hash) @@ -378,7 +378,7 @@ class MD5PasswordHasher(BasePasswordHasher): algorithm = "md5" def encode(self, password, salt): - assert password + assert password is not None assert salt and '$' not in salt hash = hashlib.md5(force_bytes(salt + password)).hexdigest() return "%s$%s$%s" % (self.algorithm, salt, hash) diff --git a/django/contrib/auth/tests/test_hashers.py b/django/contrib/auth/tests/test_hashers.py index 4becc2dffe..9df6bd8592 100644 --- a/django/contrib/auth/tests/test_hashers.py +++ b/django/contrib/auth/tests/test_hashers.py @@ -32,6 +32,12 @@ class TestUtilsHashPass(unittest.TestCase): self.assertTrue(is_password_usable(encoded)) self.assertTrue(check_password('lètmein', encoded)) self.assertFalse(check_password('lètmeinz', encoded)) + # Blank passwords + blank_encoded = make_password('') + self.assertTrue(blank_encoded.startswith('pbkdf2_sha256$')) + self.assertTrue(is_password_usable(blank_encoded)) + self.assertTrue(check_password('', blank_encoded)) + self.assertFalse(check_password(' ', blank_encoded)) def test_pkbdf2(self): encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256') @@ -41,6 +47,12 @@ class TestUtilsHashPass(unittest.TestCase): self.assertTrue(check_password('lètmein', encoded)) self.assertFalse(check_password('lètmeinz', encoded)) self.assertEqual(identify_hasher(encoded).algorithm, "pbkdf2_sha256") + # Blank passwords + blank_encoded = make_password('', 'seasalt', 'pbkdf2_sha256') + self.assertTrue(blank_encoded.startswith('pbkdf2_sha256$')) + self.assertTrue(is_password_usable(blank_encoded)) + self.assertTrue(check_password('', blank_encoded)) + self.assertFalse(check_password(' ', blank_encoded)) def test_sha1(self): encoded = make_password('lètmein', 'seasalt', 'sha1') @@ -50,6 +62,12 @@ class TestUtilsHashPass(unittest.TestCase): self.assertTrue(check_password('lètmein', encoded)) self.assertFalse(check_password('lètmeinz', encoded)) self.assertEqual(identify_hasher(encoded).algorithm, "sha1") + # Blank passwords + blank_encoded = make_password('', 'seasalt', 'sha1') + self.assertTrue(blank_encoded.startswith('sha1$')) + self.assertTrue(is_password_usable(blank_encoded)) + self.assertTrue(check_password('', blank_encoded)) + self.assertFalse(check_password(' ', blank_encoded)) def test_md5(self): encoded = make_password('lètmein', 'seasalt', 'md5') @@ -59,6 +77,12 @@ class TestUtilsHashPass(unittest.TestCase): self.assertTrue(check_password('lètmein', encoded)) self.assertFalse(check_password('lètmeinz', encoded)) self.assertEqual(identify_hasher(encoded).algorithm, "md5") + # Blank passwords + blank_encoded = make_password('', 'seasalt', 'md5') + self.assertTrue(blank_encoded.startswith('md5$')) + self.assertTrue(is_password_usable(blank_encoded)) + self.assertTrue(check_password('', blank_encoded)) + self.assertFalse(check_password(' ', blank_encoded)) def test_unsalted_md5(self): encoded = make_password('lètmein', '', 'unsalted_md5') @@ -72,6 +96,11 @@ class TestUtilsHashPass(unittest.TestCase): self.assertTrue(is_password_usable(alt_encoded)) self.assertTrue(check_password('lètmein', alt_encoded)) self.assertFalse(check_password('lètmeinz', alt_encoded)) + # Blank passwords + blank_encoded = make_password('', '', 'unsalted_md5') + self.assertTrue(is_password_usable(blank_encoded)) + self.assertTrue(check_password('', blank_encoded)) + self.assertFalse(check_password(' ', blank_encoded)) def test_unsalted_sha1(self): encoded = make_password('lètmein', '', 'unsalted_sha1') @@ -83,6 +112,12 @@ class TestUtilsHashPass(unittest.TestCase): # Raw SHA1 isn't acceptable alt_encoded = encoded[6:] self.assertFalse(check_password('lètmein', alt_encoded)) + # Blank passwords + blank_encoded = make_password('', '', 'unsalted_sha1') + self.assertTrue(blank_encoded.startswith('sha1$')) + self.assertTrue(is_password_usable(blank_encoded)) + self.assertTrue(check_password('', blank_encoded)) + self.assertFalse(check_password(' ', blank_encoded)) @skipUnless(crypt, "no crypt module to generate password.") def test_crypt(self): @@ -92,6 +127,12 @@ class TestUtilsHashPass(unittest.TestCase): self.assertTrue(check_password('lètmei', encoded)) self.assertFalse(check_password('lètmeiz', encoded)) self.assertEqual(identify_hasher(encoded).algorithm, "crypt") + # Blank passwords + blank_encoded = make_password('', 'ab', 'crypt') + self.assertTrue(blank_encoded.startswith('crypt$')) + self.assertTrue(is_password_usable(blank_encoded)) + self.assertTrue(check_password('', blank_encoded)) + self.assertFalse(check_password(' ', blank_encoded)) @skipUnless(bcrypt, "bcrypt not installed") def test_bcrypt_sha256(self): @@ -108,6 +149,12 @@ class TestUtilsHashPass(unittest.TestCase): encoded = make_password(password, hasher='bcrypt_sha256') self.assertTrue(check_password(password, encoded)) self.assertFalse(check_password(password[:72], encoded)) + # Blank passwords + blank_encoded = make_password('', hasher='bcrypt_sha256') + self.assertTrue(blank_encoded.startswith('bcrypt_sha256$')) + self.assertTrue(is_password_usable(blank_encoded)) + self.assertTrue(check_password('', blank_encoded)) + self.assertFalse(check_password(' ', blank_encoded)) @skipUnless(bcrypt, "bcrypt not installed") def test_bcrypt(self): @@ -117,6 +164,12 @@ class TestUtilsHashPass(unittest.TestCase): self.assertTrue(check_password('lètmein', encoded)) self.assertFalse(check_password('lètmeinz', encoded)) self.assertEqual(identify_hasher(encoded).algorithm, "bcrypt") + # Blank passwords + blank_encoded = make_password('', hasher='bcrypt') + self.assertTrue(blank_encoded.startswith('bcrypt$')) + self.assertTrue(is_password_usable(blank_encoded)) + self.assertTrue(check_password('', blank_encoded)) + self.assertFalse(check_password(' ', blank_encoded)) def test_unusable(self): encoded = make_password(None) |
