diff options
| author | HappyDingning <ssdyny@foxmail.com> | 2023-05-15 00:12:22 +0800 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2023-05-18 09:39:04 +0200 |
| commit | 674c23999cb6982a9d447fedec4d72e135201fee (patch) | |
| tree | ee9a368e355adca083a2a3583b06ba8a07c935fb /django | |
| parent | 4e73d8c04d15f9cbae067249c7ff39dec9d66eb1 (diff) | |
Fixed #34565 -- Added support for async checking of user passwords.
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/auth/base_user.py | 12 | ||||
| -rw-r--r-- | django/contrib/auth/hashers.py | 34 |
2 files changed, 38 insertions, 8 deletions
diff --git a/django/contrib/auth/base_user.py b/django/contrib/auth/base_user.py index e205ccccf2..da0eac731f 100644 --- a/django/contrib/auth/base_user.py +++ b/django/contrib/auth/base_user.py @@ -8,6 +8,7 @@ import warnings from django.conf import settings from django.contrib.auth import password_validation from django.contrib.auth.hashers import ( + acheck_password, check_password, is_password_usable, make_password, @@ -122,6 +123,17 @@ class AbstractBaseUser(models.Model): return check_password(raw_password, self.password, setter) + async def acheck_password(self, raw_password): + """See check_password().""" + + async def setter(raw_password): + self.set_password(raw_password) + # Password hash upgrades shouldn't be considered password changes. + self._password = None + await self.asave(update_fields=["password"]) + + return await acheck_password(raw_password, self.password, setter) + def set_unusable_password(self): # Set a value that will never be a valid hash self.password = make_password(None) diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py index e6544c7b55..b63904cd75 100644 --- a/django/contrib/auth/hashers.py +++ b/django/contrib/auth/hashers.py @@ -34,23 +34,21 @@ def is_password_usable(encoded): return encoded is None or not encoded.startswith(UNUSABLE_PASSWORD_PREFIX) -def check_password(password, encoded, setter=None, preferred="default"): +def verify_password(password, encoded, preferred="default"): """ - Return a boolean of whether the raw password matches the three - part encoded digest. - - If setter is specified, it'll be called when you need to - regenerate the password. + Return two booleans. The first is whether the raw password matches the + three part encoded digest, and the second whether to regenerate the + password. """ if password is None or not is_password_usable(encoded): - return False + return False, False preferred = get_hasher(preferred) try: hasher = identify_hasher(encoded) except ValueError: # encoded is gibberish or uses a hasher that's no longer installed. - return False + return False, False hasher_changed = hasher.algorithm != preferred.algorithm must_update = hasher_changed or preferred.must_update(encoded) @@ -63,11 +61,31 @@ def check_password(password, encoded, setter=None, preferred="default"): if not is_correct and not hasher_changed and must_update: hasher.harden_runtime(password, encoded) + return is_correct, must_update + + +def check_password(password, encoded, setter=None, preferred="default"): + """ + Return a boolean of whether the raw password matches the three part encoded + digest. + + If setter is specified, it'll be called when you need to regenerate the + password. + """ + is_correct, must_update = verify_password(password, encoded, preferred=preferred) if setter and is_correct and must_update: setter(password) return is_correct +async def acheck_password(password, encoded, setter=None, preferred="default"): + """See check_password().""" + is_correct, must_update = verify_password(password, encoded, preferred=preferred) + if setter and is_correct and must_update: + await setter(password) + return is_correct + + def make_password(password, salt=None, hasher="default"): """ Turn a plain-text password into a hash for database storage |
