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
This commit is contained in:
Luke Plant 2008-12-03 00:31:31 +00:00
parent 01ec6d0085
commit c0f9e85fbe
2 changed files with 41 additions and 21 deletions

View File

@ -23,25 +23,12 @@ _HTML_TYPES = ('text/html', 'application/xhtml+xml')
def _make_token(session_id): def _make_token(session_id):
return md5_constructor(settings.SECRET_KEY + session_id).hexdigest() return md5_constructor(settings.SECRET_KEY + session_id).hexdigest()
class CsrfMiddleware(object): class CsrfViewMiddleware(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.
""" """
Middleware that requires a present and correct csrfmiddlewaretoken
def process_request(self, request): for POST requests that have an active session.
"""
def process_view(self, request, callback, callback_args, callback_kwargs):
if request.method == 'POST': if request.method == 'POST':
try: try:
session_id = request.COOKIES[settings.SESSION_COOKIE_NAME] session_id = request.COOKIES[settings.SESSION_COOKIE_NAME]
@ -61,6 +48,12 @@ class CsrfMiddleware(object):
return None 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): def process_response(self, request, response):
csrf_token = None csrf_token = None
try: try:
@ -92,3 +85,25 @@ class CsrfMiddleware(object):
# Modify any POST forms # Modify any POST forms
response.content = _POST_FORM_RE.sub(add_csrf_field, response.content) response.content = _POST_FORM_RE.sub(add_csrf_field, response.content)
return response 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

View File

@ -5,6 +5,7 @@ from django.http import HttpRequest, HttpResponse, HttpResponseForbidden
from django.contrib.csrf.middleware import CsrfMiddleware, _make_token from django.contrib.csrf.middleware import CsrfMiddleware, _make_token
from django.conf import settings from django.conf import settings
class CsrfMiddlewareTest(TestCase): class CsrfMiddlewareTest(TestCase):
_session_id = "1" _session_id = "1"
@ -46,6 +47,10 @@ class CsrfMiddlewareTest(TestCase):
def _check_token_present(self, response): def _check_token_present(self, response):
self.assertContains(response, "name='csrfmiddlewaretoken' value='%s'" % _make_token(self._session_id)) 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 # Check the post processing
def test_process_response_no_session(self): def test_process_response_no_session(self):
""" """
@ -86,7 +91,7 @@ class CsrfMiddlewareTest(TestCase):
to the incoming request. to the incoming request.
""" """
req = self._get_POST_no_session_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) self.assertEquals(None, req2)
def test_process_request_session_no_token(self): 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' Check that if a session is present but no token, we get a 'forbidden'
""" """
req = self._get_POST_session_request() req = self._get_POST_session_request()
req2 = CsrfMiddleware().process_request(req) req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {})
self.assertEquals(HttpResponseForbidden, req2.__class__) self.assertEquals(HttpResponseForbidden, req2.__class__)
def test_process_request_session_and_token(self): 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 Check that if a session is present and a token, the middleware lets it through
""" """
req = self._get_POST_session_request_with_token() 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) self.assertEquals(None, req2)