diff --git a/django/contrib/auth/middleware.py b/django/contrib/auth/middleware.py index a28e1705a378..bedb749d9237 100644 --- a/django/contrib/auth/middleware.py +++ b/django/contrib/auth/middleware.py @@ -138,7 +138,7 @@ def process_request(self, request): " authentication middleware to be installed. Edit your" " MIDDLEWARE setting to insert" " 'django.contrib.auth.middleware.AuthenticationMiddleware'" - " before the RemoteUserMiddleware class." + f" before the {self.__class__.__name__} class." ) try: username = request.META[self.header] @@ -164,9 +164,8 @@ def process_request(self, request): # to authenticate the user. user = auth.authenticate(request, remote_user=username) if user: - # User is valid. Set request.user and persist user in the session - # by logging the user in. - request.user = user + # User is valid. Persist the user in the session by logging the + # user in. auth.login(request, user) async def __acall__(self, request): @@ -174,14 +173,14 @@ async def __acall__(self, request): return await self.get_response(request) async def aprocess_request(self, request): - # AuthenticationMiddleware is required so that request.user exists. - if not hasattr(request, "user"): + # AuthenticationMiddleware is required so that request.auser exists. + if not hasattr(request, "auser"): raise ImproperlyConfigured( "The Django remote user auth middleware requires the" " authentication middleware to be installed. Edit your" " MIDDLEWARE setting to insert" " 'django.contrib.auth.middleware.AuthenticationMiddleware'" - " before the RemoteUserMiddleware class." + f" before the {self.__class__.__name__} class." ) try: username = request.META["HTTP_" + self.header] @@ -199,7 +198,7 @@ async def aprocess_request(self, request): # getting passed in the headers, then the correct user is already # persisted in the session and we don't need to continue. if user.is_authenticated: - if user.get_username() == self.clean_username(username, request): + if user.get_username() == await self.aclean_username(username, request): return else: # An authenticated user is associated with the request, but @@ -210,9 +209,8 @@ async def aprocess_request(self, request): # to authenticate the user. user = await auth.aauthenticate(request, remote_user=username) if user: - # User is valid. Set request.user and persist user in the session - # by logging the user in. - request.user = user + # User is valid. Persist the user in the session by logging the + # user in. await auth.alogin(request, user) def clean_username(self, username, request): @@ -228,6 +226,16 @@ def clean_username(self, username, request): pass return username + async def aclean_username(self, username, request): + """See clean_username.""" + backend_str = await request.session.aget(auth.BACKEND_SESSION_KEY) + backend = auth.load_backend(backend_str) + try: + username = backend.clean_username(username) + except AttributeError: # Backend has no clean_username method. + pass + return username + def _remove_invalid_user(self, request): """ Remove the current authenticated user in the request which is invalid diff --git a/tests/auth_tests/test_remote_user.py b/tests/auth_tests/test_remote_user.py index 4a97fc2120bb..f88d966bad40 100644 --- a/tests/auth_tests/test_remote_user.py +++ b/tests/auth_tests/test_remote_user.py @@ -5,6 +5,7 @@ from django.contrib.auth.backends import RemoteUserBackend from django.contrib.auth.middleware import RemoteUserMiddleware from django.contrib.auth.models import User +from django.core.exceptions import ImproperlyConfigured from django.middleware.csrf import _get_new_csrf_string, _mask_cipher_secret from django.test import ( AsyncClient, @@ -389,6 +390,13 @@ def configure_user(self, request, user, created=True): user.save() return user + async def aconfigure_user(self, request, user, created=True): + user.email = request.META.get("HTTP_" + RemoteUserTest.email_header, "") + if not created: + user.last_name = user.username + await user.asave() + return user + class RemoteUserCustomTest(RemoteUserTest): """ @@ -435,6 +443,32 @@ def test_unknown_user(self): newuser = User.objects.get(username="newuser") self.assertEqual(newuser.email, "user@example.com") + async def test_known_user_async(self): + """See test_known_user.""" + await super().test_known_user_async() + knownuser = await User.objects.aget(username="knownuser") + knownuser2 = await User.objects.aget(username="knownuser2") + self.assertEqual(knownuser.email, "") + self.assertEqual(knownuser2.email, "") + self.assertEqual(knownuser.last_name, "knownuser") + self.assertEqual(knownuser2.last_name, "knownuser2") + + async def test_unknown_user_async(self): + num_users = await User.objects.acount() + response = await self.async_client.get( + "/remote_user/", + **{ + self.header: "newuser", + self.email_header: "user@example.com", + }, + ) + self.assertEqual(response.context["user"].username, "newuser") + self.assertEqual(response.context["user"].email, "user@example.com") + self.assertEqual(response.context["user"].last_name, "") + self.assertEqual(await User.objects.acount(), num_users + 1) + newuser = await User.objects.aget(username="newuser") + self.assertEqual(newuser.email, "user@example.com") + class CustomHeaderMiddleware(RemoteUserMiddleware): """ @@ -489,3 +523,48 @@ async def test_header_disappears_async(self): response = await self.async_client.get("/remote_user/") self.assertFalse(response.context["user"].is_anonymous) self.assertEqual(response.context["user"].username, "knownuser") + + +@override_settings(ROOT_URLCONF="auth_tests.urls") +class RemoteUserImproperlyConfigured(TestCase): + msg = ( + "The Django remote user auth middleware requires the authentication middleware " + "to be installed. Edit your MIDDLEWARE setting to insert 'django.contrib.auth." + "middleware.AuthenticationMiddleware' before the %s class." + ) + + @override_settings( + MIDDLEWARE=["django.contrib.auth.middleware.RemoteUserMiddleware"] + ) + def test_improperly_configured_message_remote_user(self): + with self.assertRaisesMessage( + ImproperlyConfigured, self.msg % "RemoteUserMiddleware" + ): + self.client.get("/remote_user/") + + @override_settings( + MIDDLEWARE=["django.contrib.auth.middleware.PersistentRemoteUserMiddleware"] + ) + def test_improperly_configured_message_persistent_remote_user(self): + with self.assertRaisesMessage( + ImproperlyConfigured, self.msg % "PersistentRemoteUserMiddleware" + ): + self.client.get("/remote_user/") + + @override_settings( + MIDDLEWARE=["django.contrib.auth.middleware.RemoteUserMiddleware"] + ) + async def test_improperly_configured_message_remote_user_async(self): + with self.assertRaisesMessage( + ImproperlyConfigured, self.msg % "RemoteUserMiddleware" + ): + await self.async_client.get("/remote_user/") + + @override_settings( + MIDDLEWARE=["django.contrib.auth.middleware.PersistentRemoteUserMiddleware"] + ) + async def test_improperly_configured_message_persistent_remote_user_async(self): + with self.assertRaisesMessage( + ImproperlyConfigured, self.msg % "PersistentRemoteUserMiddleware" + ): + await self.async_client.get("/remote_user/")