commit c9e3b9949cd55f090591fbdc4a114fcb8368b6d9
Author: Preston Holmes <preston@ptone.com>
Date:   Mon Aug 11 12:04:53 2014 -0400

    [1.4.x] Fixed #23066 -- Modified RemoteUserMiddleware to logout on REMOTE_USE change.
    
    This is a security fix. Disclosure following shortly.

--- a/django/contrib/auth/middleware.py
+++ b/django/contrib/auth/middleware.py
@@ -1,4 +1,5 @@
 from django.contrib import auth
+from django.contrib.auth.backends import RemoteUserBackend
 from django.core.exceptions import ImproperlyConfigured
 from django.utils.functional import SimpleLazyObject
 
@@ -47,9 +48,11 @@
         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():
+                self._remove_invalid_user(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
@@ -57,6 +60,11 @@
         if request.user.is_authenticated():
             if request.user.username == self.clean_username(username, request):
                 return
+            else:
+                # An authenticated user is associated with the request, but
+                # it does not match the authorized user in the header.
+                self._remove_invalid_user(request)
+
         # We are seeing this user for the first time in this session, attempt
         # to authenticate the user.
         user = auth.authenticate(remote_user=username)
@@ -78,3 +86,17 @@
         except AttributeError: # Backend has no clean_username method.
             pass
         return username
+
+    def _remove_invalid_user(self, request):
+        """
+        Removes the current authenticated user in the request which is invalid
+        but only if the user is authenticated via the RemoteUserBackend.
+        """
+        try:
+            stored_backend = auth.load_backend(request.session.get(auth.BACKEND_SESSION_KEY, ''))
+        except ImproperlyConfigured:
+            # backend failed to load
+            auth.logout(request)
+        else:
+            if isinstance(stored_backend, RemoteUserBackend):
+                auth.logout(request)
--- a/django/contrib/auth/tests/remote_user.py
+++ b/django/contrib/auth/tests/remote_user.py
@@ -95,6 +95,24 @@
         response = self.client.get('/remote_user/', REMOTE_USER=self.known_user)
         self.assertEqual(default_login, response.context['user'].last_login)
 
+    def test_user_switch_forces_new_login(self):
+        """
+        Tests that if the username in the header changes between requests
+        that the original user is logged out
+        """
+        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 changes to a different user.
+        response = self.client.get('/remote_user/',
+                                   **{'REMOTE_USER': "newnewuser"})
+        # Ensure that the current user is not the prior remote_user
+        # In backends that create a new user, username is "newnewuser"
+        # In backends that do not create new users, it is '' (anonymous user)
+        self.assertNotEqual(response.context['user'].username, 'knownuser')
+
     def tearDown(self):
         """Restores settings to avoid breaking other tests."""
         settings.MIDDLEWARE_CLASSES = self.curr_middleware
