diff options
| author | Jacob Walls <jacobtylerwalls@gmail.com> | 2026-05-04 16:26:26 -0400 |
|---|---|---|
| committer | Jacob Walls <jacobtylerwalls@gmail.com> | 2026-05-06 12:00:27 -0400 |
| commit | 7f66c3b41f0fb0fb938d7b96e20a28dccdaa2ecd (patch) | |
| tree | 63ee939720a1145ff3b2b7243844a6f7dc81959e | |
| parent | 90afa9b0f4782d2344b01dab92e8aa0227ce8fe8 (diff) | |
Refs #36439 -- Added sync_to_async() to dummy password hasher path.
Since the existing user path eventually calls sync_to_async() in acheck_password,
aim for parity with the nonexistent/inactive user branch by adding sync_to_async().
Follow-up to 748ca0a146175c4868ece87f5e845a75416c30e3.
| -rw-r--r-- | django/contrib/auth/__init__.py | 4 | ||||
| -rw-r--r-- | tests/auth_tests/test_auth_backends.py | 16 |
2 files changed, 19 insertions, 1 deletions
diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py index aa56df9a3a..d5d9acff88 100644 --- a/django/contrib/auth/__init__.py +++ b/django/contrib/auth/__init__.py @@ -1,5 +1,7 @@ import re +from asgiref.sync import sync_to_async + from django.apps import apps as django_apps from django.conf import settings from django.core.exceptions import ImproperlyConfigured, PermissionDenied @@ -407,6 +409,6 @@ def check_password_with_timing_attack_mitigation(user, password): async def acheck_password_with_timing_attack_mitigation(user, password): """See check_user_with_timing_attack_mitigation.""" if user is None: - get_user_model()().set_password(password) + await sync_to_async(get_user_model()().set_password)(password) else: return await user.acheck_password(password) diff --git a/tests/auth_tests/test_auth_backends.py b/tests/auth_tests/test_auth_backends.py index 77eeed3d60..40d686dfc5 100644 --- a/tests/auth_tests/test_auth_backends.py +++ b/tests/auth_tests/test_auth_backends.py @@ -498,6 +498,22 @@ class BaseModelBackendTest: await aauthenticate(username="no_such_user", password="test") self.assertEqual(CountingMD5PasswordHasher.calls, 1) + async def test_aauthentication_timing_async_bridge(self): + with patch( + "django.contrib.auth.hashers.sync_to_async", + return_value=mock.AsyncMock(return_value=(True, False)), + ) as mocked_adapter: + username = getattr(self.user, self.UserModel.USERNAME_FIELD) + await aauthenticate(username=username, password="test") + mocked_adapter.assert_called_once() + + with patch( + "django.contrib.auth.sync_to_async", return_value=mock.AsyncMock() + ) as mocked_adapter: + username = getattr(self.user, self.UserModel.USERNAME_FIELD) + await aauthenticate(username="no_such_user", password="test") + mocked_adapter.assert_called_once() + @override_settings( PASSWORD_HASHERS=["auth_tests.test_auth_backends.CountingMD5PasswordHasher"] ) |
