mirror of https://github.com/django/django.git
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
This commit is contained in:
parent
ae640e5ea0
commit
413e37481d
|
@ -507,6 +507,7 @@ PASSWORD_HASHERS = (
|
|||
'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',
|
||||
)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
@ -300,6 +302,34 @@ class SHA1PasswordHasher(BasePasswordHasher):
|
|||
|
||||
|
||||
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 ''
|
||||
|
|
|
@ -20,7 +20,7 @@ except ImportError:
|
|||
|
||||
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 @@ class TestUtilsHashPass(unittest.TestCase):
|
|||
|
||||
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 @@ class TestUtilsHashPass(unittest.TestCase):
|
|||
state['upgraded'] = True
|
||||
self.assertFalse(check_password('WRONG', encoded, setter))
|
||||
self.assertFalse(state['upgraded'])
|
||||
|
||||
|
||||
TestUtilsHashPass = override_settings(PASSWORD_HASHERS=default_hashers)(TestUtilsHashPass)
|
||||
|
|
Loading…
Reference in New Issue