mirror of https://github.com/django/django.git
Refs #33691 -- Deprecated insecure password hashers.
SHA1PasswordHasher, UnsaltedSHA1PasswordHasher, and UnsaltedMD5PasswordHasher are now deprecated.
This commit is contained in:
parent
a46dfa87d0
commit
3b79dab19a
|
@ -17,7 +17,7 @@ from django.utils.crypto import (
|
||||||
md5,
|
md5,
|
||||||
pbkdf2,
|
pbkdf2,
|
||||||
)
|
)
|
||||||
from django.utils.deprecation import RemovedInDjango50Warning
|
from django.utils.deprecation import RemovedInDjango50Warning, RemovedInDjango51Warning
|
||||||
from django.utils.module_loading import import_string
|
from django.utils.module_loading import import_string
|
||||||
from django.utils.translation import gettext_noop as _
|
from django.utils.translation import gettext_noop as _
|
||||||
|
|
||||||
|
@ -624,6 +624,7 @@ class ScryptPasswordHasher(BasePasswordHasher):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# RemovedInDjango51Warning.
|
||||||
class SHA1PasswordHasher(BasePasswordHasher):
|
class SHA1PasswordHasher(BasePasswordHasher):
|
||||||
"""
|
"""
|
||||||
The SHA1 password hashing algorithm (not recommended)
|
The SHA1 password hashing algorithm (not recommended)
|
||||||
|
@ -631,6 +632,14 @@ class SHA1PasswordHasher(BasePasswordHasher):
|
||||||
|
|
||||||
algorithm = "sha1"
|
algorithm = "sha1"
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
warnings.warn(
|
||||||
|
"django.contrib.auth.hashers.SHA1PasswordHasher is deprecated.",
|
||||||
|
RemovedInDjango51Warning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def encode(self, password, salt):
|
def encode(self, password, salt):
|
||||||
self._check_encode_args(password, salt)
|
self._check_encode_args(password, salt)
|
||||||
hash = hashlib.sha1((salt + password).encode()).hexdigest()
|
hash = hashlib.sha1((salt + password).encode()).hexdigest()
|
||||||
|
@ -708,6 +717,7 @@ class MD5PasswordHasher(BasePasswordHasher):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# RemovedInDjango51Warning.
|
||||||
class UnsaltedSHA1PasswordHasher(BasePasswordHasher):
|
class UnsaltedSHA1PasswordHasher(BasePasswordHasher):
|
||||||
"""
|
"""
|
||||||
Very insecure algorithm that you should *never* use; store SHA1 hashes
|
Very insecure algorithm that you should *never* use; store SHA1 hashes
|
||||||
|
@ -720,6 +730,14 @@ class UnsaltedSHA1PasswordHasher(BasePasswordHasher):
|
||||||
|
|
||||||
algorithm = "unsalted_sha1"
|
algorithm = "unsalted_sha1"
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
warnings.warn(
|
||||||
|
"django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher is deprecated.",
|
||||||
|
RemovedInDjango51Warning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def salt(self):
|
def salt(self):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
@ -752,6 +770,7 @@ class UnsaltedSHA1PasswordHasher(BasePasswordHasher):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# RemovedInDjango51Warning.
|
||||||
class UnsaltedMD5PasswordHasher(BasePasswordHasher):
|
class UnsaltedMD5PasswordHasher(BasePasswordHasher):
|
||||||
"""
|
"""
|
||||||
Incredibly insecure algorithm that you should *never* use; stores unsalted
|
Incredibly insecure algorithm that you should *never* use; stores unsalted
|
||||||
|
@ -766,6 +785,14 @@ class UnsaltedMD5PasswordHasher(BasePasswordHasher):
|
||||||
|
|
||||||
algorithm = "unsalted_md5"
|
algorithm = "unsalted_md5"
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
warnings.warn(
|
||||||
|
"django.contrib.auth.hashers.UnsaltedMD5PasswordHasher is deprecated.",
|
||||||
|
RemovedInDjango51Warning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def salt(self):
|
def salt(self):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,10 @@ details on these changes.
|
||||||
|
|
||||||
* The ``length_is`` template filter will be removed.
|
* The ``length_is`` template filter will be removed.
|
||||||
|
|
||||||
|
* The ``django.contrib.auth.hashers.SHA1PasswordHasher``,
|
||||||
|
``django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher``, and
|
||||||
|
``django.contrib.auth.hashers.UnsaltedMD5PasswordHasher`` will be removed.
|
||||||
|
|
||||||
.. _deprecation-removed-in-5.0:
|
.. _deprecation-removed-in-5.0:
|
||||||
|
|
||||||
5.0
|
5.0
|
||||||
|
|
|
@ -332,3 +332,7 @@ Miscellaneous
|
||||||
|
|
||||||
{% if value|length_is:4 %}…{% endif %}
|
{% if value|length_is:4 %}…{% endif %}
|
||||||
{{ value|length_is:4 }}
|
{{ value|length_is:4 }}
|
||||||
|
|
||||||
|
* ``django.contrib.auth.hashers.SHA1PasswordHasher``,
|
||||||
|
``django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher``, and
|
||||||
|
``django.contrib.auth.hashers.UnsaltedMD5PasswordHasher`` are deprecated.
|
||||||
|
|
|
@ -329,12 +329,12 @@ to mitigate this by :ref:`upgrading older password hashes
|
||||||
Password upgrading without requiring a login
|
Password upgrading without requiring a login
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
If you have an existing database with an older, weak hash such as MD5 or SHA1,
|
If you have an existing database with an older, weak hash such as MD5, you
|
||||||
you might want to upgrade those hashes yourself instead of waiting for the
|
might want to upgrade those hashes yourself instead of waiting for the upgrade
|
||||||
upgrade to happen when a user logs in (which may never happen if a user doesn't
|
to happen when a user logs in (which may never happen if a user doesn't return
|
||||||
return to your site). In this case, you can use a "wrapped" password hasher.
|
to your site). In this case, you can use a "wrapped" password hasher.
|
||||||
|
|
||||||
For this example, we'll migrate a collection of SHA1 hashes to use
|
For this example, we'll migrate a collection of MD5 hashes to use
|
||||||
PBKDF2(SHA1(password)) and add the corresponding password hasher for checking
|
PBKDF2(SHA1(password)) and add the corresponding password hasher for checking
|
||||||
if a user entered the correct password on login. We assume we're using the
|
if a user entered the correct password on login. We assume we're using the
|
||||||
built-in ``User`` model and that our project has an ``accounts`` app. You can
|
built-in ``User`` model and that our project has an ``accounts`` app. You can
|
||||||
|
@ -346,37 +346,37 @@ First, we'll add the custom hasher:
|
||||||
:caption: ``accounts/hashers.py``
|
:caption: ``accounts/hashers.py``
|
||||||
|
|
||||||
from django.contrib.auth.hashers import (
|
from django.contrib.auth.hashers import (
|
||||||
PBKDF2PasswordHasher, SHA1PasswordHasher,
|
PBKDF2PasswordHasher, MD5PasswordHasher,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PBKDF2WrappedSHA1PasswordHasher(PBKDF2PasswordHasher):
|
class PBKDF2WrappedMD5PasswordHasher(PBKDF2PasswordHasher):
|
||||||
algorithm = 'pbkdf2_wrapped_sha1'
|
algorithm = 'pbkdf2_wrapped_md5'
|
||||||
|
|
||||||
def encode_sha1_hash(self, sha1_hash, salt, iterations=None):
|
def encode_md5_hash(self, md5_hash, salt, iterations=None):
|
||||||
return super().encode(sha1_hash, salt, iterations)
|
return super().encode(md5_hash, salt, iterations)
|
||||||
|
|
||||||
def encode(self, password, salt, iterations=None):
|
def encode(self, password, salt, iterations=None):
|
||||||
_, _, sha1_hash = SHA1PasswordHasher().encode(password, salt).split('$', 2)
|
_, _, md5_hash = MD5PasswordHasher().encode(password, salt).split('$', 2)
|
||||||
return self.encode_sha1_hash(sha1_hash, salt, iterations)
|
return self.encode_md5_hash(md5_hash, salt, iterations)
|
||||||
|
|
||||||
The data migration might look something like:
|
The data migration might look something like:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:caption: ``accounts/migrations/0002_migrate_sha1_passwords.py``
|
:caption: ``accounts/migrations/0002_migrate_md5_passwords.py``
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
|
|
||||||
from ..hashers import PBKDF2WrappedSHA1PasswordHasher
|
from ..hashers import PBKDF2WrappedMD5PasswordHasher
|
||||||
|
|
||||||
|
|
||||||
def forwards_func(apps, schema_editor):
|
def forwards_func(apps, schema_editor):
|
||||||
User = apps.get_model('auth', 'User')
|
User = apps.get_model('auth', 'User')
|
||||||
users = User.objects.filter(password__startswith='sha1$')
|
users = User.objects.filter(password__startswith='md5$')
|
||||||
hasher = PBKDF2WrappedSHA1PasswordHasher()
|
hasher = PBKDF2WrappedMD5PasswordHasher()
|
||||||
for user in users:
|
for user in users:
|
||||||
algorithm, salt, sha1_hash = user.password.split('$', 2)
|
algorithm, salt, md5_hash = user.password.split('$', 2)
|
||||||
user.password = hasher.encode_sha1_hash(sha1_hash, salt)
|
user.password = hasher.encode_md5_hash(md5_hash, salt)
|
||||||
user.save(update_fields=['password'])
|
user.save(update_fields=['password'])
|
||||||
|
|
||||||
|
|
||||||
|
@ -402,12 +402,11 @@ Finally, we'll add a :setting:`PASSWORD_HASHERS` setting:
|
||||||
|
|
||||||
PASSWORD_HASHERS = [
|
PASSWORD_HASHERS = [
|
||||||
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
|
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
|
||||||
'accounts.hashers.PBKDF2WrappedSHA1PasswordHasher',
|
'accounts.hashers.PBKDF2WrappedMD5PasswordHasher',
|
||||||
]
|
]
|
||||||
|
|
||||||
Include any other hashers that your site uses in this list.
|
Include any other hashers that your site uses in this list.
|
||||||
|
|
||||||
.. _sha1: https://en.wikipedia.org/wiki/SHA1
|
|
||||||
.. _pbkdf2: https://en.wikipedia.org/wiki/PBKDF2
|
.. _pbkdf2: https://en.wikipedia.org/wiki/PBKDF2
|
||||||
.. _nist: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf
|
.. _nist: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf
|
||||||
.. _bcrypt: https://en.wikipedia.org/wiki/Bcrypt
|
.. _bcrypt: https://en.wikipedia.org/wiki/Bcrypt
|
||||||
|
@ -431,10 +430,7 @@ The full list of hashers included in Django is::
|
||||||
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
|
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
|
||||||
'django.contrib.auth.hashers.BCryptPasswordHasher',
|
'django.contrib.auth.hashers.BCryptPasswordHasher',
|
||||||
'django.contrib.auth.hashers.ScryptPasswordHasher',
|
'django.contrib.auth.hashers.ScryptPasswordHasher',
|
||||||
'django.contrib.auth.hashers.SHA1PasswordHasher',
|
|
||||||
'django.contrib.auth.hashers.MD5PasswordHasher',
|
'django.contrib.auth.hashers.MD5PasswordHasher',
|
||||||
'django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher',
|
|
||||||
'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
The corresponding algorithm names are:
|
The corresponding algorithm names are:
|
||||||
|
@ -445,10 +441,7 @@ The corresponding algorithm names are:
|
||||||
* ``bcrypt_sha256``
|
* ``bcrypt_sha256``
|
||||||
* ``bcrypt``
|
* ``bcrypt``
|
||||||
* ``scrypt``
|
* ``scrypt``
|
||||||
* ``sha1``
|
|
||||||
* ``md5``
|
* ``md5``
|
||||||
* ``unsalted_sha1``
|
|
||||||
* ``unsalted_md5``
|
|
||||||
|
|
||||||
.. _write-your-own-password-hasher:
|
.. _write-your-own-password-hasher:
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ from django.contrib.auth.hashers import (
|
||||||
PBKDF2PasswordHasher,
|
PBKDF2PasswordHasher,
|
||||||
PBKDF2SHA1PasswordHasher,
|
PBKDF2SHA1PasswordHasher,
|
||||||
ScryptPasswordHasher,
|
ScryptPasswordHasher,
|
||||||
SHA1PasswordHasher,
|
|
||||||
check_password,
|
check_password,
|
||||||
get_hasher,
|
get_hasher,
|
||||||
identify_hasher,
|
identify_hasher,
|
||||||
|
@ -20,7 +19,7 @@ from django.contrib.auth.hashers import (
|
||||||
)
|
)
|
||||||
from django.test import SimpleTestCase, ignore_warnings
|
from django.test import SimpleTestCase, ignore_warnings
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils.deprecation import RemovedInDjango50Warning
|
from django.utils.deprecation import RemovedInDjango50Warning, RemovedInDjango51Warning
|
||||||
|
|
||||||
# RemovedInDjango50Warning.
|
# RemovedInDjango50Warning.
|
||||||
try:
|
try:
|
||||||
|
@ -96,6 +95,7 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||||
self.assertIs(hasher.must_update(encoded_weak_salt), True)
|
self.assertIs(hasher.must_update(encoded_weak_salt), True)
|
||||||
self.assertIs(hasher.must_update(encoded_strong_salt), False)
|
self.assertIs(hasher.must_update(encoded_strong_salt), False)
|
||||||
|
|
||||||
|
@ignore_warnings(category=RemovedInDjango51Warning)
|
||||||
@override_settings(
|
@override_settings(
|
||||||
PASSWORD_HASHERS=["django.contrib.auth.hashers.SHA1PasswordHasher"]
|
PASSWORD_HASHERS=["django.contrib.auth.hashers.SHA1PasswordHasher"]
|
||||||
)
|
)
|
||||||
|
@ -121,6 +121,14 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||||
self.assertIs(hasher.must_update(encoded_weak_salt), True)
|
self.assertIs(hasher.must_update(encoded_weak_salt), True)
|
||||||
self.assertIs(hasher.must_update(encoded_strong_salt), False)
|
self.assertIs(hasher.must_update(encoded_strong_salt), False)
|
||||||
|
|
||||||
|
@override_settings(
|
||||||
|
PASSWORD_HASHERS=["django.contrib.auth.hashers.SHA1PasswordHasher"]
|
||||||
|
)
|
||||||
|
def test_sha1_deprecation_warning(self):
|
||||||
|
msg = "django.contrib.auth.hashers.SHA1PasswordHasher is deprecated."
|
||||||
|
with self.assertRaisesMessage(RemovedInDjango51Warning, msg):
|
||||||
|
get_hasher("sha1")
|
||||||
|
|
||||||
@override_settings(
|
@override_settings(
|
||||||
PASSWORD_HASHERS=["django.contrib.auth.hashers.MD5PasswordHasher"]
|
PASSWORD_HASHERS=["django.contrib.auth.hashers.MD5PasswordHasher"]
|
||||||
)
|
)
|
||||||
|
@ -144,6 +152,7 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||||
self.assertIs(hasher.must_update(encoded_weak_salt), True)
|
self.assertIs(hasher.must_update(encoded_weak_salt), True)
|
||||||
self.assertIs(hasher.must_update(encoded_strong_salt), False)
|
self.assertIs(hasher.must_update(encoded_strong_salt), False)
|
||||||
|
|
||||||
|
@ignore_warnings(category=RemovedInDjango51Warning)
|
||||||
@override_settings(
|
@override_settings(
|
||||||
PASSWORD_HASHERS=["django.contrib.auth.hashers.UnsaltedMD5PasswordHasher"]
|
PASSWORD_HASHERS=["django.contrib.auth.hashers.UnsaltedMD5PasswordHasher"]
|
||||||
)
|
)
|
||||||
|
@ -165,6 +174,7 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||||
self.assertTrue(check_password("", blank_encoded))
|
self.assertTrue(check_password("", blank_encoded))
|
||||||
self.assertFalse(check_password(" ", blank_encoded))
|
self.assertFalse(check_password(" ", blank_encoded))
|
||||||
|
|
||||||
|
@ignore_warnings(category=RemovedInDjango51Warning)
|
||||||
@override_settings(
|
@override_settings(
|
||||||
PASSWORD_HASHERS=["django.contrib.auth.hashers.UnsaltedMD5PasswordHasher"]
|
PASSWORD_HASHERS=["django.contrib.auth.hashers.UnsaltedMD5PasswordHasher"]
|
||||||
)
|
)
|
||||||
|
@ -174,6 +184,15 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||||
with self.assertRaisesMessage(ValueError, msg):
|
with self.assertRaisesMessage(ValueError, msg):
|
||||||
hasher.encode("password", salt="salt")
|
hasher.encode("password", salt="salt")
|
||||||
|
|
||||||
|
@override_settings(
|
||||||
|
PASSWORD_HASHERS=["django.contrib.auth.hashers.UnsaltedMD5PasswordHasher"]
|
||||||
|
)
|
||||||
|
def test_unsalted_md5_deprecation_warning(self):
|
||||||
|
msg = "django.contrib.auth.hashers.UnsaltedMD5PasswordHasher is deprecated."
|
||||||
|
with self.assertRaisesMessage(RemovedInDjango51Warning, msg):
|
||||||
|
get_hasher("unsalted_md5")
|
||||||
|
|
||||||
|
@ignore_warnings(category=RemovedInDjango51Warning)
|
||||||
@override_settings(
|
@override_settings(
|
||||||
PASSWORD_HASHERS=["django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher"]
|
PASSWORD_HASHERS=["django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher"]
|
||||||
)
|
)
|
||||||
|
@ -194,6 +213,7 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||||
self.assertTrue(check_password("", blank_encoded))
|
self.assertTrue(check_password("", blank_encoded))
|
||||||
self.assertFalse(check_password(" ", blank_encoded))
|
self.assertFalse(check_password(" ", blank_encoded))
|
||||||
|
|
||||||
|
@ignore_warnings(category=RemovedInDjango51Warning)
|
||||||
@override_settings(
|
@override_settings(
|
||||||
PASSWORD_HASHERS=["django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher"]
|
PASSWORD_HASHERS=["django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher"]
|
||||||
)
|
)
|
||||||
|
@ -203,6 +223,14 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||||
with self.assertRaisesMessage(ValueError, msg):
|
with self.assertRaisesMessage(ValueError, msg):
|
||||||
hasher.encode("password", salt="salt")
|
hasher.encode("password", salt="salt")
|
||||||
|
|
||||||
|
@override_settings(
|
||||||
|
PASSWORD_HASHERS=["django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher"]
|
||||||
|
)
|
||||||
|
def test_unsalted_sha1_deprecation_warning(self):
|
||||||
|
msg = "django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher is deprecated."
|
||||||
|
with self.assertRaisesMessage(RemovedInDjango51Warning, msg):
|
||||||
|
get_hasher("unsalted_sha1")
|
||||||
|
|
||||||
@ignore_warnings(category=RemovedInDjango50Warning)
|
@ignore_warnings(category=RemovedInDjango50Warning)
|
||||||
@skipUnless(crypt, "no crypt module to generate password.")
|
@skipUnless(crypt, "no crypt module to generate password.")
|
||||||
@override_settings(
|
@override_settings(
|
||||||
|
@ -432,13 +460,13 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||||
@override_settings(
|
@override_settings(
|
||||||
PASSWORD_HASHERS=[
|
PASSWORD_HASHERS=[
|
||||||
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
|
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
|
||||||
"django.contrib.auth.hashers.SHA1PasswordHasher",
|
"django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
|
||||||
"django.contrib.auth.hashers.MD5PasswordHasher",
|
"django.contrib.auth.hashers.MD5PasswordHasher",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_upgrade(self):
|
def test_upgrade(self):
|
||||||
self.assertEqual("pbkdf2_sha256", get_hasher("default").algorithm)
|
self.assertEqual("pbkdf2_sha256", get_hasher("default").algorithm)
|
||||||
for algo in ("sha1", "md5"):
|
for algo in ("pbkdf2_sha1", "md5"):
|
||||||
with self.subTest(algo=algo):
|
with self.subTest(algo=algo):
|
||||||
encoded = make_password("lètmein", hasher=algo)
|
encoded = make_password("lètmein", hasher=algo)
|
||||||
state = {"upgraded": False}
|
state = {"upgraded": False}
|
||||||
|
@ -462,13 +490,13 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||||
@override_settings(
|
@override_settings(
|
||||||
PASSWORD_HASHERS=[
|
PASSWORD_HASHERS=[
|
||||||
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
|
"django.contrib.auth.hashers.PBKDF2PasswordHasher",
|
||||||
"django.contrib.auth.hashers.SHA1PasswordHasher",
|
"django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
|
||||||
"django.contrib.auth.hashers.MD5PasswordHasher",
|
"django.contrib.auth.hashers.MD5PasswordHasher",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_no_upgrade_on_incorrect_pass(self):
|
def test_no_upgrade_on_incorrect_pass(self):
|
||||||
self.assertEqual("pbkdf2_sha256", get_hasher("default").algorithm)
|
self.assertEqual("pbkdf2_sha256", get_hasher("default").algorithm)
|
||||||
for algo in ("sha1", "md5"):
|
for algo in ("pbkdf2_sha1", "md5"):
|
||||||
with self.subTest(algo=algo):
|
with self.subTest(algo=algo):
|
||||||
encoded = make_password("lètmein", hasher=algo)
|
encoded = make_password("lètmein", hasher=algo)
|
||||||
state = {"upgraded": False}
|
state = {"upgraded": False}
|
||||||
|
@ -583,7 +611,6 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||||
PBKDF2PasswordHasher,
|
PBKDF2PasswordHasher,
|
||||||
PBKDF2SHA1PasswordHasher,
|
PBKDF2SHA1PasswordHasher,
|
||||||
ScryptPasswordHasher,
|
ScryptPasswordHasher,
|
||||||
SHA1PasswordHasher,
|
|
||||||
]
|
]
|
||||||
msg = "salt must be provided and cannot contain $."
|
msg = "salt must be provided and cannot contain $."
|
||||||
for hasher_class in hasher_classes:
|
for hasher_class in hasher_classes:
|
||||||
|
@ -599,7 +626,6 @@ class TestUtilsHashPass(SimpleTestCase):
|
||||||
PBKDF2PasswordHasher,
|
PBKDF2PasswordHasher,
|
||||||
PBKDF2SHA1PasswordHasher,
|
PBKDF2SHA1PasswordHasher,
|
||||||
ScryptPasswordHasher,
|
ScryptPasswordHasher,
|
||||||
SHA1PasswordHasher,
|
|
||||||
]
|
]
|
||||||
msg = "password must be provided."
|
msg = "password must be provided."
|
||||||
for hasher_class in hasher_classes:
|
for hasher_class in hasher_classes:
|
||||||
|
|
Loading…
Reference in New Issue