1
0
mirror of https://github.com/django/django.git synced 2025-04-01 12:06:43 +00:00

Fixed #24696 -- Made CSRF_COOKIE computation lazy.

Only compute the CSRF_COOKIE when it is actually used. This is a
significant speedup for clients not using cookies.

Changed result of the “test_token_node_no_csrf_cookie” test:  It gets
a valid CSRF token now which seems like the correct behavior.

Changed auth_tests.test_views.LoginTest.test_login_csrf_rotate to
use get_token() to trigger CSRF cookie inclusion instead of changing
request.META["CSRF_COOKIE_USED"] directly.
This commit is contained in:
Jay Cox 2015-04-23 23:24:38 -07:00 committed by Tim Graham
parent 0894643e40
commit eef95ea96f
3 changed files with 17 additions and 16 deletions

View File

@ -40,15 +40,17 @@ def _get_new_csrf_key():
def get_token(request): def get_token(request):
""" """
Returns the CSRF token required for a POST form. The token is an Returns the CSRF token required for a POST form. The token is an
alphanumeric value. alphanumeric value. A new token is created if one is not already set.
A side effect of calling this function is to make the csrf_protect A side effect of calling this function is to make the csrf_protect
decorator and the CsrfViewMiddleware add a CSRF cookie and a 'Vary: Cookie' decorator and the CsrfViewMiddleware add a CSRF cookie and a 'Vary: Cookie'
header to the outgoing response. For this reason, you may need to use this header to the outgoing response. For this reason, you may need to use this
function lazily, as is done by the csrf context processor. function lazily, as is done by the csrf context processor.
""" """
if "CSRF_COOKIE" not in request.META:
request.META["CSRF_COOKIE"] = _get_new_csrf_key()
request.META["CSRF_COOKIE_USED"] = True request.META["CSRF_COOKIE_USED"] = True
return request.META.get("CSRF_COOKIE", None) return request.META["CSRF_COOKIE"]
def rotate_token(request): def rotate_token(request):
@ -112,9 +114,6 @@ class CsrfViewMiddleware(object):
request.META['CSRF_COOKIE'] = csrf_token request.META['CSRF_COOKIE'] = csrf_token
except KeyError: except KeyError:
csrf_token = None csrf_token = None
# Generate token and store it in the request, so it's
# available to the view.
request.META["CSRF_COOKIE"] = _get_new_csrf_key()
# Wait until request.META["CSRF_COOKIE"] has been manipulated before # Wait until request.META["CSRF_COOKIE"] has been manipulated before
# bailing out, so that get_token still works # bailing out, so that get_token still works
@ -194,12 +193,6 @@ class CsrfViewMiddleware(object):
if getattr(response, 'csrf_processing_done', False): if getattr(response, 'csrf_processing_done', False):
return response return response
# If CSRF_COOKIE is unset, then CsrfViewMiddleware.process_view was
# never called, probably because a request middleware returned a response
# (for example, contrib.auth redirecting to a login page).
if request.META.get("CSRF_COOKIE") is None:
return response
if not request.META.get("CSRF_COOKIE_USED", False): if not request.META.get("CSRF_COOKIE_USED", False):
return response return response

View File

@ -23,7 +23,7 @@ from django.core import mail
from django.core.urlresolvers import NoReverseMatch, reverse, reverse_lazy from django.core.urlresolvers import NoReverseMatch, reverse, reverse_lazy
from django.db import connection from django.db import connection
from django.http import HttpRequest, QueryDict from django.http import HttpRequest, QueryDict
from django.middleware.csrf import CsrfViewMiddleware from django.middleware.csrf import CsrfViewMiddleware, get_token
from django.test import ( from django.test import (
TestCase, ignore_warnings, modify_settings, override_settings, TestCase, ignore_warnings, modify_settings, override_settings,
) )
@ -606,7 +606,8 @@ class LoginTest(AuthViewsTestCase):
# TestClient isn't used here as we're testing middleware, essentially. # TestClient isn't used here as we're testing middleware, essentially.
req = HttpRequest() req = HttpRequest()
CsrfViewMiddleware().process_view(req, login_view, (), {}) CsrfViewMiddleware().process_view(req, login_view, (), {})
req.META["CSRF_COOKIE_USED"] = True # get_token() triggers CSRF token inclusion in the response
get_token(req)
resp = login_view(req) resp = login_view(req)
resp2 = CsrfViewMiddleware().process_response(req, resp) resp2 = CsrfViewMiddleware().process_response(req, resp)
csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, None) csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, None)

View File

@ -5,7 +5,9 @@ import logging
from django.conf import settings from django.conf import settings
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from django.middleware.csrf import CSRF_KEY_LENGTH, CsrfViewMiddleware from django.middleware.csrf import (
CSRF_KEY_LENGTH, CsrfViewMiddleware, get_token,
)
from django.template import RequestContext, Template from django.template import RequestContext, Template
from django.template.context_processors import csrf from django.template.context_processors import csrf
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
@ -237,7 +239,10 @@ class CsrfViewMiddlewareTest(TestCase):
""" """
req = self._get_GET_no_csrf_cookie_request() req = self._get_GET_no_csrf_cookie_request()
resp = token_view(req) resp = token_view(req)
self.assertEqual(resp.content, b'')
token = get_token(req)
self.assertIsNotNone(token)
self._check_token_present(resp, token)
def test_token_node_empty_csrf_cookie(self): def test_token_node_empty_csrf_cookie(self):
""" """
@ -248,7 +253,9 @@ class CsrfViewMiddlewareTest(TestCase):
CsrfViewMiddleware().process_view(req, token_view, (), {}) CsrfViewMiddleware().process_view(req, token_view, (), {})
resp = token_view(req) resp = token_view(req)
self.assertNotEqual("", resp.content) token = get_token(req)
self.assertIsNotNone(token)
self._check_token_present(resp, token)
def test_token_node_with_csrf_cookie(self): def test_token_node_with_csrf_cookie(self):
""" """