From 9741912a9aaad083eaa8b9780cde37e1843cc4ae Mon Sep 17 00:00:00 2001 From: Preston Holmes Date: Sun, 9 Sep 2012 16:25:06 -0400 Subject: [PATCH] Fixed #17869 - force logout when REMOTE_USER header disappears If the current sessions user was logged in via a remote user backend log out the user if REMOTE_USER header not available - otherwise leave it to other auth middleware to install the AnonymousUser. Thanks to Sylvain Bouchard for the initial patch and ticket maintenance. --- django/contrib/auth/middleware.py | 17 +++++++++++++--- django/contrib/auth/tests/remote_user.py | 25 ++++++++++++++++++++++-- docs/releases/1.5.txt | 3 +++ 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/django/contrib/auth/middleware.py b/django/contrib/auth/middleware.py index 0398cfaf1e..f38efdd1d2 100644 --- a/django/contrib/auth/middleware.py +++ b/django/contrib/auth/middleware.py @@ -1,4 +1,6 @@ from django.contrib import auth +from django.contrib.auth import load_backend +from django.contrib.auth.backends import RemoteUserBackend from django.core.exceptions import ImproperlyConfigured from django.utils.functional import SimpleLazyObject @@ -47,9 +49,18 @@ class RemoteUserMiddleware(object): try: username = request.META[self.header] except KeyError: - # If specified header doesn't exist then return (leaving - # request.user set to AnonymousUser by the - # AuthenticationMiddleware). + # If specified header doesn't exist then remove any existing + # authenticated remote-user, or return (leaving request.user set to + # AnonymousUser by the AuthenticationMiddleware). + if request.user.is_authenticated(): + try: + stored_backend = load_backend(request.session.get( + auth.BACKEND_SESSION_KEY, '')) + if isinstance(stored_backend, RemoteUserBackend): + auth.logout(request) + except ImproperlyConfigured as e: + # backend failed to load + auth.logout(request) return # If the user is already authenticated and that user is the user we are # getting passed in the headers, then the correct user is already diff --git a/django/contrib/auth/tests/remote_user.py b/django/contrib/auth/tests/remote_user.py index 9b0f6f8be3..0e59b291a8 100644 --- a/django/contrib/auth/tests/remote_user.py +++ b/django/contrib/auth/tests/remote_user.py @@ -1,8 +1,9 @@ from datetime import datetime from django.conf import settings +from django.contrib.auth import authenticate from django.contrib.auth.backends import RemoteUserBackend -from django.contrib.auth.models import User +from django.contrib.auth.models import User, AnonymousUser from django.contrib.auth.tests.utils import skipIfCustomUser from django.test import TestCase from django.utils import timezone @@ -23,7 +24,7 @@ class RemoteUserTest(TestCase): self.curr_middleware = settings.MIDDLEWARE_CLASSES self.curr_auth = settings.AUTHENTICATION_BACKENDS settings.MIDDLEWARE_CLASSES += (self.middleware,) - settings.AUTHENTICATION_BACKENDS = (self.backend,) + settings.AUTHENTICATION_BACKENDS += (self.backend,) def test_no_remote_user(self): """ @@ -97,6 +98,26 @@ class RemoteUserTest(TestCase): response = self.client.get('/remote_user/', REMOTE_USER=self.known_user) self.assertEqual(default_login, response.context['user'].last_login) + def test_header_disappears(self): + """ + Tests that a logged in user is logged out automatically when + the REMOTE_USER header disappears during the same browser session. + """ + User.objects.create(username='knownuser') + # Known user authenticates + response = self.client.get('/remote_user/', REMOTE_USER=self.known_user) + self.assertEqual(response.context['user'].username, 'knownuser') + # During the session, the REMOTE_USER header disappears. Should trigger logout. + response = self.client.get('/remote_user/') + self.assertEqual(response.context['user'].is_anonymous(), True) + # verify the remoteuser middleware will not remove a user + # authenticated via another backend + User.objects.create_user(username='modeluser', password='foo') + self.client.login(username='modeluser', password='foo') + authenticate(username='modeluser', password='foo') + response = self.client.get('/remote_user/') + self.assertEqual(response.context['user'].username, 'modeluser') + def tearDown(self): """Restores settings to avoid breaking other tests.""" settings.MIDDLEWARE_CLASSES = self.curr_middleware diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt index ebf88e83b9..3ee1b2d21f 100644 --- a/docs/releases/1.5.txt +++ b/docs/releases/1.5.txt @@ -296,6 +296,9 @@ Django 1.5 also includes several smaller improvements worth noting: you to test equality for XML content at a semantic level, without caring for syntax differences (spaces, attribute order, etc.). +* RemoteUserMiddleware now forces logout when the REMOTE_USER header + disappears during the same browser session. + Backwards incompatible changes in 1.5 =====================================