diff options
| author | Claude Paroz <claude@2xlibre.net> | 2013-02-02 11:57:25 +0100 |
|---|---|---|
| committer | Claude Paroz <claude@2xlibre.net> | 2013-02-02 12:03:08 +0100 |
| commit | c39be8b836282c1060e64dc17c6cb8184c14cf0b (patch) | |
| tree | 8a4f4243bc2e130b36501cbc69d9525e124db5d4 | |
| parent | fd61ce9c4f03ddc66139e4658933216fa630c208 (diff) | |
[1.5.x] Fixed #18144 -- Added backwards compatibility with old unsalted MD5 passwords
Thanks apreobrazhensky at gmail.com for the report.
Backport of 63d6a50dd from master.
| -rw-r--r-- | django/contrib/auth/hashers.py | 5 | ||||
| -rw-r--r-- | django/contrib/auth/tests/hashers.py | 5 |
2 files changed, 9 insertions, 1 deletions
diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py index b3631a6b8c..188886858b 100644 --- a/django/contrib/auth/hashers.py +++ b/django/contrib/auth/hashers.py @@ -132,7 +132,8 @@ def identify_hasher(encoded): get_hasher() to return hasher. Raises ValueError if algorithm cannot be identified, or if hasher is not loaded. """ - if len(encoded) == 32 and '$' not in encoded: + if ((len(encoded) == 32 and '$' not in encoded) or + len(encoded) == 37 and encoded.startswith('md5$$')): algorithm = 'unsalted_md5' else: algorithm = encoded.split('$', 1)[0] @@ -372,6 +373,8 @@ class UnsaltedMD5PasswordHasher(BasePasswordHasher): return hashlib.md5(force_bytes(password)).hexdigest() def verify(self, password, encoded): + if len(encoded) == 37 and encoded.startswith('md5$$'): + encoded = encoded[5:] encoded_2 = self.encode(password, '') return constant_time_compare(encoded, encoded_2) diff --git a/django/contrib/auth/tests/hashers.py b/django/contrib/auth/tests/hashers.py index e2a3537695..d53ec1c173 100644 --- a/django/contrib/auth/tests/hashers.py +++ b/django/contrib/auth/tests/hashers.py @@ -66,6 +66,11 @@ class TestUtilsHashPass(unittest.TestCase): self.assertTrue(check_password('lètmein', encoded)) self.assertFalse(check_password('lètmeinz', encoded)) self.assertEqual(identify_hasher(encoded).algorithm, "unsalted_md5") + # Alternate unsalted syntax + alt_encoded = "md5$$%s" % encoded + self.assertTrue(is_password_usable(alt_encoded)) + self.assertTrue(check_password('lètmein', alt_encoded)) + self.assertFalse(check_password('lètmeinz', alt_encoded)) @skipUnless(crypt, "no crypt module to generate password.") def test_crypt(self): |
