summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Walls <jacobtylerwalls@gmail.com>2026-05-04 16:26:26 -0400
committerJacob Walls <jacobtylerwalls@gmail.com>2026-05-06 12:00:27 -0400
commit7f66c3b41f0fb0fb938d7b96e20a28dccdaa2ecd (patch)
tree63ee939720a1145ff3b2b7243844a6f7dc81959e
parent90afa9b0f4782d2344b01dab92e8aa0227ce8fe8 (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__.py4
-rw-r--r--tests/auth_tests/test_auth_backends.py16
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"]
)