Loading django/middleware/csrf.py +20 −16 Original line number Diff line number Diff line Loading @@ -88,18 +88,22 @@ class CsrfViewMiddleware(object): This middleware should be used in conjunction with the csrf_token template tag. """ def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None reject = lambda s: _get_failure_view()(request, reason=s) def accept(): # The _accept and _reject methods currently only exist for the sake of the # requires_csrf_token decorator. def _accept(self, request): # Avoid checking the request twice by adding a custom attribute to # request. This will be relevant when both decorator and middleware # are used. request.csrf_processing_done = True return None def _reject(self, request, reason): return _get_failure_view()(request, reason=reason) def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None # If the user doesn't have a CSRF cookie, generate one and store it in the # request, so it's available to the view. We'll store it in a cookie when # we reach the response. Loading Loading @@ -128,7 +132,7 @@ class CsrfViewMiddleware(object): # the creation of CSRF cookies, so that everything else continues to # work exactly the same (e.g. cookies are sent etc), but before the # any branches that call reject() return accept() return self._accept(request) if request.is_ajax(): # .is_ajax() is based on the presence of X-Requested-With. In Loading @@ -153,7 +157,7 @@ class CsrfViewMiddleware(object): # allowing the cross-domain POST request. # # So in all cases, it is safe to allow these requests through. return accept() return self._accept(request) if request.is_secure(): # Suppose user visits http://example.com/ Loading @@ -179,7 +183,7 @@ class CsrfViewMiddleware(object): 'request': request, } ) return reject(REASON_NO_REFERER) return self._reject(request, REASON_NO_REFERER) # The following check ensures that the referer is HTTPS, # the domains match and the ports match - the same origin policy. Loading @@ -192,7 +196,7 @@ class CsrfViewMiddleware(object): 'request': request, } ) return reject(reason) return self._reject(request, reason) # If the user didn't already have a CSRF cookie, then fall back to # the Django 1.1 method (hash of session ID), so a request is not Loading @@ -212,7 +216,7 @@ class CsrfViewMiddleware(object): 'request': request, } ) return reject(REASON_NO_COOKIE) return self._reject(request, REASON_NO_COOKIE) else: csrf_token = request.META["CSRF_COOKIE"] Loading @@ -227,7 +231,7 @@ class CsrfViewMiddleware(object): 'request': request, } ) return reject(REASON_NO_CSRF_COOKIE) return self._reject(request, REASON_NO_CSRF_COOKIE) else: logger.warning('Forbidden (%s): %s' % (REASON_BAD_TOKEN, request.path), extra={ Loading @@ -235,9 +239,9 @@ class CsrfViewMiddleware(object): 'request': request, } ) return reject(REASON_BAD_TOKEN) return self._reject(request, REASON_BAD_TOKEN) return accept() return self._accept(request) def process_response(self, request, response): if getattr(response, 'csrf_processing_done', False): Loading django/views/decorators/csrf.py +16 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,22 @@ CsrfViewMiddleware, but it can be used on a per view basis. Using both, or using the decorator multiple times, is harmless and efficient. """ class _EnsureCsrfToken(CsrfViewMiddleware): # We need this to behave just like the CsrfViewMiddleware, but not reject # requests. def _reject(self, request, reason): return None requires_csrf_token = decorator_from_middleware(_EnsureCsrfToken) requires_csrf_token.__name__ = 'requires_csrf_token' csrf_protect.__doc__ = """ Use this decorator on views that need a correct csrf_token available to RequestContext, but without the CSRF protection that csrf_protect enforces. """ def csrf_response_exempt(view_func): """ Modifies a view function so that its response is exempt Loading django/views/defaults.py +8 −0 Original line number Diff line number Diff line from django import http from django.views.decorators.csrf import requires_csrf_token from django.template import Context, RequestContext, loader # This can be called when CsrfViewMiddleware.process_view has not run, therefore # need @requires_csrf_token in case the template needs {% csrf_token %}. @requires_csrf_token def page_not_found(request, template_name='404.html'): """ Default 404 handler. Loading @@ -13,6 +18,8 @@ def page_not_found(request, template_name='404.html'): t = loader.get_template(template_name) # You need to create a 404.html template. return http.HttpResponseNotFound(t.render(RequestContext(request, {'request_path': request.path}))) @requires_csrf_token def server_error(request, template_name='500.html'): """ 500 error handler. Loading @@ -23,6 +30,7 @@ def server_error(request, template_name='500.html'): t = loader.get_template(template_name) # You need to create a 500.html template. return http.HttpResponseServerError(t.render(Context({}))) def shortcut(request, content_type_id, object_id): # TODO: Remove this in Django 2.0. # This is a legacy view that depends on the contenttypes framework. Loading tests/regressiontests/csrf_tests/tests.py +9 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ import warnings from django.test import TestCase from django.http import HttpRequest, HttpResponse from django.middleware.csrf import CsrfMiddleware, CsrfViewMiddleware from django.views.decorators.csrf import csrf_exempt, csrf_view_exempt from django.views.decorators.csrf import csrf_exempt, csrf_view_exempt, requires_csrf_token from django.core.context_processors import csrf from django.contrib.sessions.middleware import SessionMiddleware from django.utils.importlib import import_module Loading Loading @@ -331,6 +331,14 @@ class CsrfMiddlewareTest(TestCase): resp = token_view(req) self._check_token_present(resp) def test_get_token_for_requires_csrf_token_view(self): """ Check that get_token works for a view decorated solely with requires_csrf_token """ req = self._get_GET_csrf_cookie_request() resp = requires_csrf_token(token_view)(req) self._check_token_present(resp) def test_token_node_with_new_csrf_cookie(self): """ Check that CsrfTokenNode works when a CSRF cookie is created by Loading tests/regressiontests/views/tests/defaults.py +14 −3 Original line number Diff line number Diff line Loading @@ -9,6 +9,8 @@ from regressiontests.views.models import Author, Article, UrlArticle class DefaultsTests(TestCase): """Test django views in django/views/defaults.py""" fixtures = ['testdata.json'] non_existing_urls = ['/views/non_existing_url/', # this is in urls.py '/views/other_non_existing_url/'] # this NOT in urls.py def test_shortcut_with_absolute_url(self): "Can view a shortcut for an Author object that has a get_absolute_url method" Loading Loading @@ -49,12 +51,21 @@ class DefaultsTests(TestCase): def test_page_not_found(self): "A 404 status is returned by the page_not_found view" non_existing_urls = ['/views/non_existing_url/', # this is in urls.py '/views/other_non_existing_url/'] # this NOT in urls.py for url in non_existing_urls: for url in self.non_existing_urls: response = self.client.get(url) self.assertEquals(response.status_code, 404) def test_csrf_token_in_404(self): """ The 404 page should have the csrf_token available in the context """ # See ticket #14565 for url in self.non_existing_urls: response = self.client.get(url) csrf_token = response.context['csrf_token'] self.assertNotEqual(str(csrf_token), 'NOTPROVIDED') self.assertNotEqual(str(csrf_token), '') def test_server_error(self): "The server_error view raises a 500 status" response = self.client.get('/views/server_error/') Loading Loading
django/middleware/csrf.py +20 −16 Original line number Diff line number Diff line Loading @@ -88,18 +88,22 @@ class CsrfViewMiddleware(object): This middleware should be used in conjunction with the csrf_token template tag. """ def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None reject = lambda s: _get_failure_view()(request, reason=s) def accept(): # The _accept and _reject methods currently only exist for the sake of the # requires_csrf_token decorator. def _accept(self, request): # Avoid checking the request twice by adding a custom attribute to # request. This will be relevant when both decorator and middleware # are used. request.csrf_processing_done = True return None def _reject(self, request, reason): return _get_failure_view()(request, reason=reason) def process_view(self, request, callback, callback_args, callback_kwargs): if getattr(request, 'csrf_processing_done', False): return None # If the user doesn't have a CSRF cookie, generate one and store it in the # request, so it's available to the view. We'll store it in a cookie when # we reach the response. Loading Loading @@ -128,7 +132,7 @@ class CsrfViewMiddleware(object): # the creation of CSRF cookies, so that everything else continues to # work exactly the same (e.g. cookies are sent etc), but before the # any branches that call reject() return accept() return self._accept(request) if request.is_ajax(): # .is_ajax() is based on the presence of X-Requested-With. In Loading @@ -153,7 +157,7 @@ class CsrfViewMiddleware(object): # allowing the cross-domain POST request. # # So in all cases, it is safe to allow these requests through. return accept() return self._accept(request) if request.is_secure(): # Suppose user visits http://example.com/ Loading @@ -179,7 +183,7 @@ class CsrfViewMiddleware(object): 'request': request, } ) return reject(REASON_NO_REFERER) return self._reject(request, REASON_NO_REFERER) # The following check ensures that the referer is HTTPS, # the domains match and the ports match - the same origin policy. Loading @@ -192,7 +196,7 @@ class CsrfViewMiddleware(object): 'request': request, } ) return reject(reason) return self._reject(request, reason) # If the user didn't already have a CSRF cookie, then fall back to # the Django 1.1 method (hash of session ID), so a request is not Loading @@ -212,7 +216,7 @@ class CsrfViewMiddleware(object): 'request': request, } ) return reject(REASON_NO_COOKIE) return self._reject(request, REASON_NO_COOKIE) else: csrf_token = request.META["CSRF_COOKIE"] Loading @@ -227,7 +231,7 @@ class CsrfViewMiddleware(object): 'request': request, } ) return reject(REASON_NO_CSRF_COOKIE) return self._reject(request, REASON_NO_CSRF_COOKIE) else: logger.warning('Forbidden (%s): %s' % (REASON_BAD_TOKEN, request.path), extra={ Loading @@ -235,9 +239,9 @@ class CsrfViewMiddleware(object): 'request': request, } ) return reject(REASON_BAD_TOKEN) return self._reject(request, REASON_BAD_TOKEN) return accept() return self._accept(request) def process_response(self, request, response): if getattr(response, 'csrf_processing_done', False): Loading
django/views/decorators/csrf.py +16 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,22 @@ CsrfViewMiddleware, but it can be used on a per view basis. Using both, or using the decorator multiple times, is harmless and efficient. """ class _EnsureCsrfToken(CsrfViewMiddleware): # We need this to behave just like the CsrfViewMiddleware, but not reject # requests. def _reject(self, request, reason): return None requires_csrf_token = decorator_from_middleware(_EnsureCsrfToken) requires_csrf_token.__name__ = 'requires_csrf_token' csrf_protect.__doc__ = """ Use this decorator on views that need a correct csrf_token available to RequestContext, but without the CSRF protection that csrf_protect enforces. """ def csrf_response_exempt(view_func): """ Modifies a view function so that its response is exempt Loading
django/views/defaults.py +8 −0 Original line number Diff line number Diff line from django import http from django.views.decorators.csrf import requires_csrf_token from django.template import Context, RequestContext, loader # This can be called when CsrfViewMiddleware.process_view has not run, therefore # need @requires_csrf_token in case the template needs {% csrf_token %}. @requires_csrf_token def page_not_found(request, template_name='404.html'): """ Default 404 handler. Loading @@ -13,6 +18,8 @@ def page_not_found(request, template_name='404.html'): t = loader.get_template(template_name) # You need to create a 404.html template. return http.HttpResponseNotFound(t.render(RequestContext(request, {'request_path': request.path}))) @requires_csrf_token def server_error(request, template_name='500.html'): """ 500 error handler. Loading @@ -23,6 +30,7 @@ def server_error(request, template_name='500.html'): t = loader.get_template(template_name) # You need to create a 500.html template. return http.HttpResponseServerError(t.render(Context({}))) def shortcut(request, content_type_id, object_id): # TODO: Remove this in Django 2.0. # This is a legacy view that depends on the contenttypes framework. Loading
tests/regressiontests/csrf_tests/tests.py +9 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ import warnings from django.test import TestCase from django.http import HttpRequest, HttpResponse from django.middleware.csrf import CsrfMiddleware, CsrfViewMiddleware from django.views.decorators.csrf import csrf_exempt, csrf_view_exempt from django.views.decorators.csrf import csrf_exempt, csrf_view_exempt, requires_csrf_token from django.core.context_processors import csrf from django.contrib.sessions.middleware import SessionMiddleware from django.utils.importlib import import_module Loading Loading @@ -331,6 +331,14 @@ class CsrfMiddlewareTest(TestCase): resp = token_view(req) self._check_token_present(resp) def test_get_token_for_requires_csrf_token_view(self): """ Check that get_token works for a view decorated solely with requires_csrf_token """ req = self._get_GET_csrf_cookie_request() resp = requires_csrf_token(token_view)(req) self._check_token_present(resp) def test_token_node_with_new_csrf_cookie(self): """ Check that CsrfTokenNode works when a CSRF cookie is created by Loading
tests/regressiontests/views/tests/defaults.py +14 −3 Original line number Diff line number Diff line Loading @@ -9,6 +9,8 @@ from regressiontests.views.models import Author, Article, UrlArticle class DefaultsTests(TestCase): """Test django views in django/views/defaults.py""" fixtures = ['testdata.json'] non_existing_urls = ['/views/non_existing_url/', # this is in urls.py '/views/other_non_existing_url/'] # this NOT in urls.py def test_shortcut_with_absolute_url(self): "Can view a shortcut for an Author object that has a get_absolute_url method" Loading Loading @@ -49,12 +51,21 @@ class DefaultsTests(TestCase): def test_page_not_found(self): "A 404 status is returned by the page_not_found view" non_existing_urls = ['/views/non_existing_url/', # this is in urls.py '/views/other_non_existing_url/'] # this NOT in urls.py for url in non_existing_urls: for url in self.non_existing_urls: response = self.client.get(url) self.assertEquals(response.status_code, 404) def test_csrf_token_in_404(self): """ The 404 page should have the csrf_token available in the context """ # See ticket #14565 for url in self.non_existing_urls: response = self.client.get(url) csrf_token = response.context['csrf_token'] self.assertNotEqual(str(csrf_token), 'NOTPROVIDED') self.assertNotEqual(str(csrf_token), '') def test_server_error(self): "The server_error view raises a 500 status" response = self.client.get('/views/server_error/') Loading