Kaydet (Commit) eef95ea9 authored tarafından Jay Cox's avatar Jay Cox Kaydeden (comit) Tim Graham

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.
üst 0894643e
...@@ -40,15 +40,17 @@ def _get_new_csrf_key(): ...@@ -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): ...@@ -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): ...@@ -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
......
...@@ -23,7 +23,7 @@ from django.core import mail ...@@ -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): ...@@ -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)
......
...@@ -5,7 +5,9 @@ import logging ...@@ -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): ...@@ -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): ...@@ -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):
""" """
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment