Refs #32508 -- Raised TypeError/ValueError instead of using "assert" in encode() methods of some password hashers.
This commit is contained in:
parent
c35b81b864
commit
83022d279c
|
@ -209,6 +209,12 @@ class BasePasswordHasher:
|
|||
"""Check if the given password is correct."""
|
||||
raise NotImplementedError('subclasses of BasePasswordHasher must provide a verify() method')
|
||||
|
||||
def _check_encode_args(self, password, salt):
|
||||
if password is None:
|
||||
raise TypeError('password must be provided.')
|
||||
if not salt or '$' in salt:
|
||||
raise ValueError('salt must be provided and cannot contain $.')
|
||||
|
||||
def encode(self, password, salt):
|
||||
"""
|
||||
Create an encoded database value.
|
||||
|
@ -269,8 +275,7 @@ class PBKDF2PasswordHasher(BasePasswordHasher):
|
|||
digest = hashlib.sha256
|
||||
|
||||
def encode(self, password, salt, iterations=None):
|
||||
assert password is not None
|
||||
assert salt and '$' not in salt
|
||||
self._check_encode_args(password, salt)
|
||||
iterations = iterations or self.iterations
|
||||
hash = pbkdf2(password, salt, iterations, digest=self.digest)
|
||||
hash = base64.b64encode(hash).decode('ascii').strip()
|
||||
|
@ -519,8 +524,7 @@ class SHA1PasswordHasher(BasePasswordHasher):
|
|||
algorithm = "sha1"
|
||||
|
||||
def encode(self, password, salt):
|
||||
assert password is not None
|
||||
assert salt and '$' not in salt
|
||||
self._check_encode_args(password, salt)
|
||||
hash = hashlib.sha1((salt + password).encode()).hexdigest()
|
||||
return "%s$%s$%s" % (self.algorithm, salt, hash)
|
||||
|
||||
|
@ -561,8 +565,7 @@ class MD5PasswordHasher(BasePasswordHasher):
|
|||
algorithm = "md5"
|
||||
|
||||
def encode(self, password, salt):
|
||||
assert password is not None
|
||||
assert salt and '$' not in salt
|
||||
self._check_encode_args(password, salt)
|
||||
hash = hashlib.md5((salt + password).encode()).hexdigest()
|
||||
return "%s$%s$%s" % (self.algorithm, salt, hash)
|
||||
|
||||
|
|
|
@ -4,8 +4,9 @@ from django.conf.global_settings import PASSWORD_HASHERS
|
|||
from django.contrib.auth.hashers import (
|
||||
UNUSABLE_PASSWORD_PREFIX, UNUSABLE_PASSWORD_SUFFIX_LENGTH,
|
||||
BasePasswordHasher, BCryptPasswordHasher, BCryptSHA256PasswordHasher,
|
||||
PBKDF2PasswordHasher, PBKDF2SHA1PasswordHasher, check_password, get_hasher,
|
||||
identify_hasher, is_password_usable, make_password,
|
||||
MD5PasswordHasher, PBKDF2PasswordHasher, PBKDF2SHA1PasswordHasher,
|
||||
SHA1PasswordHasher, check_password, get_hasher, identify_hasher,
|
||||
is_password_usable, make_password,
|
||||
)
|
||||
from django.test import SimpleTestCase
|
||||
from django.test.utils import override_settings
|
||||
|
@ -474,6 +475,35 @@ class TestUtilsHashPass(SimpleTestCase):
|
|||
check_password('wrong_password', encoded)
|
||||
self.assertEqual(hasher.harden_runtime.call_count, 1)
|
||||
|
||||
def test_encode_invalid_salt(self):
|
||||
hasher_classes = [
|
||||
MD5PasswordHasher,
|
||||
PBKDF2PasswordHasher,
|
||||
PBKDF2SHA1PasswordHasher,
|
||||
SHA1PasswordHasher,
|
||||
]
|
||||
msg = 'salt must be provided and cannot contain $.'
|
||||
for hasher_class in hasher_classes:
|
||||
hasher = hasher_class()
|
||||
for salt in [None, '', 'sea$salt']:
|
||||
with self.subTest(hasher_class.__name__, salt=salt):
|
||||
with self.assertRaisesMessage(ValueError, msg):
|
||||
hasher.encode('password', salt)
|
||||
|
||||
def test_encode_password_required(self):
|
||||
hasher_classes = [
|
||||
MD5PasswordHasher,
|
||||
PBKDF2PasswordHasher,
|
||||
PBKDF2SHA1PasswordHasher,
|
||||
SHA1PasswordHasher,
|
||||
]
|
||||
msg = 'password must be provided.'
|
||||
for hasher_class in hasher_classes:
|
||||
hasher = hasher_class()
|
||||
with self.subTest(hasher_class.__name__):
|
||||
with self.assertRaisesMessage(TypeError, msg):
|
||||
hasher.encode(None, 'seasalt')
|
||||
|
||||
|
||||
class BasePasswordHasherTests(SimpleTestCase):
|
||||
not_implemented_msg = 'subclasses of BasePasswordHasher must provide %s() method'
|
||||
|
|
Loading…
Reference in New Issue