diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py index 87e4218a8f0..7656b504374 100644 --- a/django/contrib/auth/hashers.py +++ b/django/contrib/auth/hashers.py @@ -22,6 +22,7 @@ UNUSABLE_PASSWORD_SUFFIX_LENGTH = 40 # number of random chars to add after UNUS HASHERS = None # lazily loaded from PASSWORD_HASHERS PREFERRED_HASHER = None # defaults to first item in PASSWORD_HASHERS + @receiver(setting_changed) def reset_hashers(**kwargs): if kwargs['setting'] == 'PASSWORD_HASHERS': @@ -34,7 +35,7 @@ def is_password_usable(encoded): if encoded is None or encoded.startswith(UNUSABLE_PASSWORD_PREFIX): return False try: - hasher = identify_hasher(encoded) + identify_hasher(encoded) except ValueError: return False return True @@ -48,7 +49,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 is_password_usable(encoded): + if password is None or not is_password_usable(encoded): return False preferred = get_hasher(preferred) diff --git a/django/contrib/auth/tests/test_hashers.py b/django/contrib/auth/tests/test_hashers.py index 8e8119b7417..4b90127c377 100644 --- a/django/contrib/auth/tests/test_hashers.py +++ b/django/contrib/auth/tests/test_hashers.py @@ -187,6 +187,13 @@ class TestUtilsHashPass(unittest.TestCase): # This might fail one day due to a hash collision. self.assertNotEqual(encoded, make_password(None), "Random password collision?") + def test_unspecified_password(self): + """ + Makes sure specifying no plain password with a valid encoded password + returns `False`. + """ + self.assertFalse(check_password(None, make_password('lètmein'))) + def test_bad_algorithm(self): with self.assertRaises(ValueError): make_password('lètmein', hasher='lolcat')