Fixed #28699 -- Fixed CSRF validation with remote user middleware.
Ensured process_view() always accesses the CSRF token from the session or cookie, rather than the request, as rotate_token() may have been called by an authentication middleware during the process_request() phase.
This commit is contained in:
parent
bc1c034076
commit
f283ffaa84
1
AUTHORS
1
AUTHORS
|
@ -201,6 +201,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Colin Wood <cwood06@gmail.com>
|
Colin Wood <cwood06@gmail.com>
|
||||||
Collin Anderson <cmawebsite@gmail.com>
|
Collin Anderson <cmawebsite@gmail.com>
|
||||||
Collin Grady <collin@collingrady.com>
|
Collin Grady <collin@collingrady.com>
|
||||||
|
Colton Hicks <coltonbhicks@gmail.com>
|
||||||
Craig Blaszczyk <masterjakul@gmail.com>
|
Craig Blaszczyk <masterjakul@gmail.com>
|
||||||
crankycoder@gmail.com
|
crankycoder@gmail.com
|
||||||
Curtis Maloney (FunkyBob) <curtis@tinbrain.net>
|
Curtis Maloney (FunkyBob) <curtis@tinbrain.net>
|
||||||
|
|
|
@ -280,7 +280,10 @@ class CsrfViewMiddleware(MiddlewareMixin):
|
||||||
reason = REASON_BAD_REFERER % referer.geturl()
|
reason = REASON_BAD_REFERER % referer.geturl()
|
||||||
return self._reject(request, reason)
|
return self._reject(request, reason)
|
||||||
|
|
||||||
csrf_token = request.META.get('CSRF_COOKIE')
|
# Access csrf_token via self._get_token() as rotate_token() may
|
||||||
|
# have been called by an authentication middleware during the
|
||||||
|
# process_request() phase.
|
||||||
|
csrf_token = self._get_token(request)
|
||||||
if csrf_token is None:
|
if csrf_token is None:
|
||||||
# No CSRF cookie. For POST requests, we insist on a CSRF cookie,
|
# No CSRF cookie. For POST requests, we insist on a CSRF cookie,
|
||||||
# and in this way we can avoid all CSRF attacks, including login
|
# and in this way we can avoid all CSRF attacks, including login
|
||||||
|
|
|
@ -5,7 +5,8 @@ from django.contrib.auth import authenticate
|
||||||
from django.contrib.auth.backends import RemoteUserBackend
|
from django.contrib.auth.backends import RemoteUserBackend
|
||||||
from django.contrib.auth.middleware import RemoteUserMiddleware
|
from django.contrib.auth.middleware import RemoteUserMiddleware
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.test import TestCase, modify_settings, override_settings
|
from django.middleware.csrf import _get_new_csrf_string, _mask_cipher_secret
|
||||||
|
from django.test import Client, TestCase, modify_settings, override_settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,6 +51,35 @@ class RemoteUserTest(TestCase):
|
||||||
self.assertTrue(response.context['user'].is_anonymous)
|
self.assertTrue(response.context['user'].is_anonymous)
|
||||||
self.assertEqual(User.objects.count(), num_users)
|
self.assertEqual(User.objects.count(), num_users)
|
||||||
|
|
||||||
|
def test_csrf_validation_passes_after_process_request_login(self):
|
||||||
|
"""
|
||||||
|
CSRF check must access the CSRF token from the session or cookie,
|
||||||
|
rather than the request, as rotate_token() may have been called by an
|
||||||
|
authentication middleware during the process_request() phase.
|
||||||
|
"""
|
||||||
|
csrf_client = Client(enforce_csrf_checks=True)
|
||||||
|
csrf_secret = _get_new_csrf_string()
|
||||||
|
csrf_token = _mask_cipher_secret(csrf_secret)
|
||||||
|
csrf_token_form = _mask_cipher_secret(csrf_secret)
|
||||||
|
headers = {self.header: 'fakeuser'}
|
||||||
|
data = {'csrfmiddlewaretoken': csrf_token_form}
|
||||||
|
|
||||||
|
# Verify that CSRF is configured for the view
|
||||||
|
csrf_client.cookies.load({settings.CSRF_COOKIE_NAME: csrf_token})
|
||||||
|
response = csrf_client.post('/remote_user/', **headers)
|
||||||
|
self.assertEqual(response.status_code, 403)
|
||||||
|
self.assertIn(b'CSRF verification failed.', response.content)
|
||||||
|
|
||||||
|
# This request will call django.contrib.auth.login() which will call
|
||||||
|
# django.middleware.csrf.rotate_token() thus changing the value of
|
||||||
|
# request.META['CSRF_COOKIE'] from the user submitted value set by
|
||||||
|
# CsrfViewMiddleware.process_request() to the new csrftoken value set
|
||||||
|
# by rotate_token(). Csrf validation should still pass when the view is
|
||||||
|
# later processed by CsrfViewMiddleware.process_view()
|
||||||
|
csrf_client.cookies.load({settings.CSRF_COOKIE_NAME: csrf_token})
|
||||||
|
response = csrf_client.post('/remote_user/', data, **headers)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_unknown_user(self):
|
def test_unknown_user(self):
|
||||||
"""
|
"""
|
||||||
Tests the case where the username passed in the header does not exist
|
Tests the case where the username passed in the header does not exist
|
||||||
|
|
Loading…
Reference in New Issue