Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c9e3b99

Browse files
ptonetimgraham
authored andcommitted
[1.4.x] Fixed #23066 -- Modified RemoteUserMiddleware to logout on REMOTE_USE change.
This is a security fix. Disclosure following shortly.
1 parent 30042d4 commit c9e3b99

File tree

3 files changed

+52
-3
lines changed

3 files changed

+52
-3
lines changed

django/contrib/auth/middleware.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from django.contrib import auth
2+
from django.contrib.auth.backends import RemoteUserBackend
23
from django.core.exceptions import ImproperlyConfigured
34
from django.utils.functional import SimpleLazyObject
45

@@ -47,16 +48,23 @@ def process_request(self, request):
4748
try:
4849
username = request.META[self.header]
4950
except KeyError:
50-
# If specified header doesn't exist then return (leaving
51-
# request.user set to AnonymousUser by the
52-
# AuthenticationMiddleware).
51+
# If specified header doesn't exist then remove any existing
52+
# authenticated remote-user, or return (leaving request.user set to
53+
# AnonymousUser by the AuthenticationMiddleware).
54+
if request.user.is_authenticated():
55+
self._remove_invalid_user(request)
5356
return
5457
# If the user is already authenticated and that user is the user we are
5558
# getting passed in the headers, then the correct user is already
5659
# persisted in the session and we don't need to continue.
5760
if request.user.is_authenticated():
5861
if request.user.username == self.clean_username(username, request):
5962
return
63+
else:
64+
# An authenticated user is associated with the request, but
65+
# it does not match the authorized user in the header.
66+
self._remove_invalid_user(request)
67+
6068
# We are seeing this user for the first time in this session, attempt
6169
# to authenticate the user.
6270
user = auth.authenticate(remote_user=username)
@@ -78,3 +86,17 @@ def clean_username(self, username, request):
7886
except AttributeError: # Backend has no clean_username method.
7987
pass
8088
return username
89+
90+
def _remove_invalid_user(self, request):
91+
"""
92+
Removes the current authenticated user in the request which is invalid
93+
but only if the user is authenticated via the RemoteUserBackend.
94+
"""
95+
try:
96+
stored_backend = auth.load_backend(request.session.get(auth.BACKEND_SESSION_KEY, ''))
97+
except ImproperlyConfigured:
98+
# backend failed to load
99+
auth.logout(request)
100+
else:
101+
if isinstance(stored_backend, RemoteUserBackend):
102+
auth.logout(request)

django/contrib/auth/tests/remote_user.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,24 @@ def test_last_login(self):
9595
response = self.client.get('/remote_user/', REMOTE_USER=self.known_user)
9696
self.assertEqual(default_login, response.context['user'].last_login)
9797

98+
def test_user_switch_forces_new_login(self):
99+
"""
100+
Tests that if the username in the header changes between requests
101+
that the original user is logged out
102+
"""
103+
User.objects.create(username='knownuser')
104+
# Known user authenticates
105+
response = self.client.get('/remote_user/',
106+
**{'REMOTE_USER': self.known_user})
107+
self.assertEqual(response.context['user'].username, 'knownuser')
108+
# During the session, the REMOTE_USER changes to a different user.
109+
response = self.client.get('/remote_user/',
110+
**{'REMOTE_USER': "newnewuser"})
111+
# Ensure that the current user is not the prior remote_user
112+
# In backends that create a new user, username is "newnewuser"
113+
# In backends that do not create new users, it is '' (anonymous user)
114+
self.assertNotEqual(response.context['user'].username, 'knownuser')
115+
98116
def tearDown(self):
99117
"""Restores settings to avoid breaking other tests."""
100118
settings.MIDDLEWARE_CLASSES = self.curr_middleware

docs/releases/1.4.14.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,12 @@ if a file with the uploaded name already exists.
3838
underscore plus a random 7 character alphanumeric string (e.g. ``"_x3a1gho"``),
3939
rather than iterating through an underscore followed by a number (e.g. ``"_1"``,
4040
``"_2"``, etc.).
41+
42+
``RemoteUserMiddleware`` session hijacking
43+
==========================================
44+
45+
When using the :class:`~django.contrib.auth.middleware.RemoteUserMiddleware`
46+
and the ``RemoteUserBackend``, a change to the ``REMOTE_USER`` header between
47+
requests without an intervening logout could result in the prior user's session
48+
being co-opted by the subsequent user. The middleware now logs the user out on
49+
a failed login attempt.

0 commit comments

Comments
 (0)