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.
This commit is contained in:
Preston Holmes 2012-09-09 16:25:06 -04:00
parent 2b5f848207
commit 9741912a9a
3 changed files with 40 additions and 5 deletions

View File

@ -1,4 +1,6 @@
from django.contrib import auth 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.core.exceptions import ImproperlyConfigured
from django.utils.functional import SimpleLazyObject from django.utils.functional import SimpleLazyObject
@ -47,9 +49,18 @@ class RemoteUserMiddleware(object):
try: try:
username = request.META[self.header] username = request.META[self.header]
except KeyError: except KeyError:
# If specified header doesn't exist then return (leaving # If specified header doesn't exist then remove any existing
# request.user set to AnonymousUser by the # authenticated remote-user, or return (leaving request.user set to
# AuthenticationMiddleware). # 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 return
# If the user is already authenticated and that user is the user we are # 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 # getting passed in the headers, then the correct user is already

View File

@ -1,8 +1,9 @@
from datetime import datetime from datetime import datetime
from django.conf import settings from django.conf import settings
from django.contrib.auth import authenticate
from django.contrib.auth.backends import RemoteUserBackend 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.contrib.auth.tests.utils import skipIfCustomUser
from django.test import TestCase from django.test import TestCase
from django.utils import timezone from django.utils import timezone
@ -23,7 +24,7 @@ class RemoteUserTest(TestCase):
self.curr_middleware = settings.MIDDLEWARE_CLASSES self.curr_middleware = settings.MIDDLEWARE_CLASSES
self.curr_auth = settings.AUTHENTICATION_BACKENDS self.curr_auth = settings.AUTHENTICATION_BACKENDS
settings.MIDDLEWARE_CLASSES += (self.middleware,) settings.MIDDLEWARE_CLASSES += (self.middleware,)
settings.AUTHENTICATION_BACKENDS = (self.backend,) settings.AUTHENTICATION_BACKENDS += (self.backend,)
def test_no_remote_user(self): def test_no_remote_user(self):
""" """
@ -97,6 +98,26 @@ class RemoteUserTest(TestCase):
response = self.client.get('/remote_user/', REMOTE_USER=self.known_user) response = self.client.get('/remote_user/', REMOTE_USER=self.known_user)
self.assertEqual(default_login, response.context['user'].last_login) 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): def tearDown(self):
"""Restores settings to avoid breaking other tests.""" """Restores settings to avoid breaking other tests."""
settings.MIDDLEWARE_CLASSES = self.curr_middleware settings.MIDDLEWARE_CLASSES = self.curr_middleware

View File

@ -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 you to test equality for XML content at a semantic level, without caring for
syntax differences (spaces, attribute order, etc.). 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 Backwards incompatible changes in 1.5
===================================== =====================================