From c0f9e85fbe616a38255cd568fc5f2f0a870586ea Mon Sep 17 00:00:00 2001 From: Luke Plant Date: Wed, 3 Dec 2008 00:31:31 +0000 Subject: [PATCH] Split CsrfMiddleware into two to make it more reusable. Also converted it to be a view middleware instead of request, as this allows more options. git-svn-id: http://code.djangoproject.com/svn/django/trunk@9553 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/csrf/middleware.py | 51 ++++++++++++++++++++----------- django/contrib/csrf/tests.py | 11 +++++-- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/django/contrib/csrf/middleware.py b/django/contrib/csrf/middleware.py index 24c1511c91..7da79ba59c 100644 --- a/django/contrib/csrf/middleware.py +++ b/django/contrib/csrf/middleware.py @@ -23,25 +23,12 @@ _HTML_TYPES = ('text/html', 'application/xhtml+xml') def _make_token(session_id): return md5_constructor(settings.SECRET_KEY + session_id).hexdigest() -class CsrfMiddleware(object): - """Django middleware that adds protection against Cross Site - Request Forgeries by adding hidden form fields to POST forms and - checking requests for the correct value. - - In the list of middlewares, SessionMiddleware is required, and must come - after this middleware. CsrfMiddleWare must come after compression - middleware. - - If a session ID cookie is present, it is hashed with the SECRET_KEY - setting to create an authentication token. This token is added to all - outgoing POST forms and is expected on all incoming POST requests that - have a session ID cookie. - - If you are setting cookies directly, instead of using Django's session - framework, this middleware will not work. +class CsrfViewMiddleware(object): """ - - def process_request(self, request): + Middleware that requires a present and correct csrfmiddlewaretoken + for POST requests that have an active session. + """ + def process_view(self, request, callback, callback_args, callback_kwargs): if request.method == 'POST': try: session_id = request.COOKIES[settings.SESSION_COOKIE_NAME] @@ -61,6 +48,12 @@ class CsrfMiddleware(object): return None +class CsrfResponseMiddleware(object): + """ + Middleware that post-processes a response to add a + csrfmiddlewaretoken if the response/request have an active + session. + """ def process_response(self, request, response): csrf_token = None try: @@ -92,3 +85,25 @@ class CsrfMiddleware(object): # Modify any POST forms response.content = _POST_FORM_RE.sub(add_csrf_field, response.content) return response + +class CsrfMiddleware(CsrfViewMiddleware, CsrfResponseMiddleware): + """Django middleware that adds protection against Cross Site + Request Forgeries by adding hidden form fields to POST forms and + checking requests for the correct value. + + In the list of middlewares, SessionMiddleware is required, and + must come after this middleware. CsrfMiddleWare must come after + compression middleware. + + If a session ID cookie is present, it is hashed with the + SECRET_KEY setting to create an authentication token. This token + is added to all outgoing POST forms and is expected on all + incoming POST requests that have a session ID cookie. + + If you are setting cookies directly, instead of using Django's + session framework, this middleware will not work. + + CsrfMiddleWare is composed of two middleware, CsrfViewMiddleware + and CsrfResponseMiddleware which can be used independently. + """ + pass diff --git a/django/contrib/csrf/tests.py b/django/contrib/csrf/tests.py index 9152ee8d81..071099ea91 100644 --- a/django/contrib/csrf/tests.py +++ b/django/contrib/csrf/tests.py @@ -5,6 +5,7 @@ from django.http import HttpRequest, HttpResponse, HttpResponseForbidden from django.contrib.csrf.middleware import CsrfMiddleware, _make_token from django.conf import settings + class CsrfMiddlewareTest(TestCase): _session_id = "1" @@ -46,6 +47,10 @@ class CsrfMiddlewareTest(TestCase): def _check_token_present(self, response): self.assertContains(response, "name='csrfmiddlewaretoken' value='%s'" % _make_token(self._session_id)) + def get_view(self): + def dummyview(request): + return self._get_post_form_response() + # Check the post processing def test_process_response_no_session(self): """ @@ -86,7 +91,7 @@ class CsrfMiddlewareTest(TestCase): to the incoming request. """ req = self._get_POST_no_session_request() - req2 = CsrfMiddleware().process_request(req) + req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {}) self.assertEquals(None, req2) def test_process_request_session_no_token(self): @@ -94,7 +99,7 @@ class CsrfMiddlewareTest(TestCase): Check that if a session is present but no token, we get a 'forbidden' """ req = self._get_POST_session_request() - req2 = CsrfMiddleware().process_request(req) + req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {}) self.assertEquals(HttpResponseForbidden, req2.__class__) def test_process_request_session_and_token(self): @@ -102,5 +107,5 @@ class CsrfMiddlewareTest(TestCase): Check that if a session is present and a token, the middleware lets it through """ req = self._get_POST_session_request_with_token() - req2 = CsrfMiddleware().process_request(req) + req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {}) self.assertEquals(None, req2)