Commit eef95ea9 authored by Jay Cox's avatar Jay Cox Committed by Tim Graham
Browse files

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.
parent 0894643e
Loading
Loading
Loading
Loading
+4 −11
Original line number Diff line number Diff line
@@ -40,15 +40,17 @@ def _get_new_csrf_key():
def get_token(request):
    """
    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
    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
    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
    return request.META.get("CSRF_COOKIE", None)
    return request.META["CSRF_COOKIE"]


def rotate_token(request):
@@ -112,9 +114,6 @@ class CsrfViewMiddleware(object):
            request.META['CSRF_COOKIE'] = csrf_token
        except KeyError:
            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
        # bailing out, so that get_token still works
@@ -194,12 +193,6 @@ class CsrfViewMiddleware(object):
        if getattr(response, 'csrf_processing_done', False):
            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):
            return response

+3 −2
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ from django.core import mail
from django.core.urlresolvers import NoReverseMatch, reverse, reverse_lazy
from django.db import connection
from django.http import HttpRequest, QueryDict
from django.middleware.csrf import CsrfViewMiddleware
from django.middleware.csrf import CsrfViewMiddleware, get_token
from django.test import (
    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.
        req = HttpRequest()
        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)
        resp2 = CsrfViewMiddleware().process_response(req, resp)
        csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, None)
+10 −3
Original line number Diff line number Diff line
@@ -5,7 +5,9 @@ import logging

from django.conf import settings
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.context_processors import csrf
from django.test import TestCase, override_settings
@@ -237,7 +239,10 @@ class CsrfViewMiddlewareTest(TestCase):
        """
        req = self._get_GET_no_csrf_cookie_request()
        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):
        """
@@ -248,7 +253,9 @@ class CsrfViewMiddlewareTest(TestCase):
        CsrfViewMiddleware().process_view(req, token_view, (), {})
        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):
        """