Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixes #17777 and makes tests run again.

Adds a salted MD5 hasher for backwards compatibility.
Thanks gunnar@g10f.de for the report.

Also fixes a bug preventing the hasher tests from being run during
contrib tests.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@17604 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 413e37481d0b81d50b5826f660eeb79f360be9fc 1 parent ae640e5
@PaulMcMillan PaulMcMillan authored
View
1  django/conf/global_settings.py
@@ -507,6 +507,7 @@
'django.contrib.auth.hashers.BCryptPasswordHasher',
'django.contrib.auth.hashers.SHA1PasswordHasher',
'django.contrib.auth.hashers.MD5PasswordHasher',
+ 'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher',
'django.contrib.auth.hashers.CryptPasswordHasher',
)
View
38 django/contrib/auth/hashers.py
@@ -36,7 +36,7 @@ def check_password(password, encoded, setter=None, preferred='default'):
encoded = smart_str(encoded)
if len(encoded) == 32 and '$' not in encoded:
- hasher = get_hasher('md5')
+ hasher = get_hasher('unsalted_md5')
else:
algorithm = encoded.split('$', 1)[0]
hasher = get_hasher(algorithm)
@@ -69,11 +69,13 @@ def make_password(password, salt=None, hasher='default'):
return hasher.encode(password, salt)
-def load_hashers():
+def load_hashers(password_hashers=None):
global HASHERS
global PREFERRED_HASHER
hashers = []
- for backend in settings.PASSWORD_HASHERS:
+ if not password_hashers:
+ password_hashers = settings.PASSWORD_HASHERS
+ for backend in password_hashers:
try:
mod_path, cls_name = backend.rsplit('.', 1)
mod = importlib.import_module(mod_path)
@@ -301,6 +303,34 @@ def safe_summary(self, encoded):
class MD5PasswordHasher(BasePasswordHasher):
"""
+ The Salted MD5 password hashing algorithm (not recommended)
+ """
+ algorithm = "md5"
+
+ def encode(self, password, salt):
+ assert password
+ assert salt and '$' not in salt
+ hash = hashlib.md5(salt + password).hexdigest()
+ return "%s$%s$%s" % (self.algorithm, salt, hash)
+
+ def verify(self, password, encoded):
+ algorithm, salt, hash = encoded.split('$', 2)
+ assert algorithm == self.algorithm
+ encoded_2 = self.encode(password, salt)
+ return constant_time_compare(encoded, encoded_2)
+
+ def safe_summary(self, encoded):
+ algorithm, salt, hash = encoded.split('$', 2)
+ assert algorithm == self.algorithm
+ return SortedDict([
+ (_('algorithm'), algorithm),
+ (_('salt'), mask_hash(salt, show=2)),
+ (_('hash'), mask_hash(hash)),
+ ])
+
+
+class UnsaltedMD5PasswordHasher(BasePasswordHasher):
+ """
I am an incredibly insecure algorithm you should *never* use;
stores unsalted MD5 hashes without the algorithm prefix.
@@ -308,7 +338,7 @@ class MD5PasswordHasher(BasePasswordHasher):
this way. Some older Django installs still have these values
lingering around so we need to handle and upgrade them properly.
"""
- algorithm = "md5"
+ algorithm = "unsalted_md5"
def salt(self):
return ''
View
13 django/contrib/auth/tests/hashers.py
@@ -20,7 +20,7 @@
class TestUtilsHashPass(unittest.TestCase):
def setUp(self):
- load_hashers()
+ load_hashers(password_hashers=default_hashers)
def test_simple(self):
encoded = make_password('letmein')
@@ -47,6 +47,14 @@ def test_sha1(self):
def test_md5(self):
encoded = make_password('letmein', 'seasalt', 'md5')
+ self.assertEqual(encoded,
+ 'md5$seasalt$f5531bef9f3687d0ccf0f617f0e25573')
+ self.assertTrue(is_password_usable(encoded))
+ self.assertTrue(check_password(u'letmein', encoded))
+ self.assertFalse(check_password('letmeinz', encoded))
+
+ def test_unsalted_md5(self):
+ encoded = make_password('letmein', 'seasalt', 'unsalted_md5')
self.assertEqual(encoded, '0d107d09f5bbe40cade3de5c71e9e9b7')
self.assertTrue(is_password_usable(encoded))
self.assertTrue(check_password(u'letmein', encoded))
@@ -123,6 +131,3 @@ def setter():
state['upgraded'] = True
self.assertFalse(check_password('WRONG', encoded, setter))
self.assertFalse(state['upgraded'])
-
-
-TestUtilsHashPass = override_settings(PASSWORD_HASHERS=default_hashers)(TestUtilsHashPass)
Please sign in to comment.
Something went wrong with that request. Please try again.