summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphael Michel <mail@raphaelmichel.de>2015-11-07 14:18:06 +0100
committerTim Graham <timograham@gmail.com>2015-11-17 14:28:18 -0500
commit16945f0e9c57aeabadb6f2e2f150a2687455be40 (patch)
tree6d16352dea219959fa54fcc2e4279121bfb5cecc
parent20d2778597e89fc2de084bdaa128a438fbf12c7b (diff)
Fixed #25695 -- Added template_name parameter to csrf_failure() view.
-rw-r--r--django/views/csrf.py15
-rw-r--r--docs/ref/settings.txt9
-rw-r--r--docs/releases/1.10.txt4
-rw-r--r--tests/view_tests/tests/test_csrf.py32
4 files changed, 55 insertions, 5 deletions
diff --git a/django/views/csrf.py b/django/views/csrf.py
index 9ab9c44171..7d5f4e113e 100644
--- a/django/views/csrf.py
+++ b/django/views/csrf.py
@@ -1,6 +1,6 @@
from django.conf import settings
from django.http import HttpResponseForbidden
-from django.template import Context, Engine
+from django.template import Context, Engine, TemplateDoesNotExist, loader
from django.utils.translation import ugettext as _
from django.utils.version import get_docs_version
@@ -95,14 +95,14 @@ CSRF_FAILURE_TEMPLATE = """
</body>
</html>
"""
+CSRF_FAILURE_TEMPLATE_NAME = "403_csrf.html"
-def csrf_failure(request, reason=""):
+def csrf_failure(request, reason="", template_name=CSRF_FAILURE_TEMPLATE_NAME):
"""
Default view used when request fails CSRF protection
"""
from django.middleware.csrf import REASON_NO_REFERER, REASON_NO_CSRF_COOKIE
- t = Engine().from_string(CSRF_FAILURE_TEMPLATE)
c = Context({
'title': _("Forbidden"),
'main': _("CSRF verification failed. Request aborted."),
@@ -131,4 +131,13 @@ def csrf_failure(request, reason=""):
'docs_version': get_docs_version(),
'more': _("More information is available with DEBUG=True."),
})
+ try:
+ t = loader.get_template(template_name)
+ except TemplateDoesNotExist:
+ if template_name == CSRF_FAILURE_TEMPLATE_NAME:
+ # If the default template doesn't exist, use the string template.
+ t = Engine().from_string(CSRF_FAILURE_TEMPLATE)
+ else:
+ # Raise if a developer-specified template doesn't exist.
+ raise
return HttpResponseForbidden(t.render(c), content_type='text/html')
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index ff3d420433..92a2ad4980 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -385,6 +385,15 @@ where ``reason`` is a short message (intended for developers or logging, not for
end users) indicating the reason the request was rejected. See
:doc:`/ref/csrf`.
+``django.views.csrf.csrf_failure()`` accepts an additional ``template_name``
+parameter that defaults to ``'403_csrf.html'``. If a template with that name
+exists, it will be used to render the page.
+
+.. versionchanged:: 1.10
+
+ The ``template_name`` parameter and the behavior of searching for a template
+ called ``403_csrf.html`` were added to ``csrf_failure()``.
+
.. setting:: CSRF_HEADER_NAME
CSRF_HEADER_NAME
diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt
index 6dbe0362b9..1e51c1dec9 100644
--- a/docs/releases/1.10.txt
+++ b/docs/releases/1.10.txt
@@ -114,7 +114,9 @@ Cache
CSRF
^^^^
-* ...
+* The default :setting:`CSRF_FAILURE_VIEW`, ``views.csrf.csrf_failure()`` now
+ accepts an optional ``template_name`` parameter, defaulting to
+ ``'403_csrf.html'``, to control the template used to render the page.
Database backends
^^^^^^^^^^^^^^^^^
diff --git a/tests/view_tests/tests/test_csrf.py b/tests/view_tests/tests/test_csrf.py
index f6531b882c..f595652978 100644
--- a/tests/view_tests/tests/test_csrf.py
+++ b/tests/view_tests/tests/test_csrf.py
@@ -1,5 +1,9 @@
-from django.test import Client, SimpleTestCase, override_settings
+from django.template import TemplateDoesNotExist
+from django.test import (
+ Client, RequestFactory, SimpleTestCase, override_settings,
+)
from django.utils.translation import override
+from django.views.csrf import CSRF_FAILURE_TEMPLATE_NAME, csrf_failure
@override_settings(ROOT_URLCONF="view_tests.urls")
@@ -70,3 +74,29 @@ class CsrfViewTests(SimpleTestCase):
"""
response = self.client.post('/')
self.assertContains(response, "Forbidden", status_code=403)
+
+ @override_settings(TEMPLATES=[{
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'OPTIONS': {
+ 'loaders': [
+ ('django.template.loaders.locmem.Loader', {
+ CSRF_FAILURE_TEMPLATE_NAME: 'Test template for CSRF failure'
+ }),
+ ],
+ },
+ }])
+ def test_custom_template(self):
+ """
+ A custom CSRF_FAILURE_TEMPLATE_NAME is used.
+ """
+ response = self.client.post('/')
+ self.assertContains(response, "Test template for CSRF failure", status_code=403)
+
+ def test_custom_template_does_not_exist(self):
+ """
+ An exception is raised if a nonexistent template is supplied.
+ """
+ factory = RequestFactory()
+ request = factory.post('/')
+ with self.assertRaises(TemplateDoesNotExist):
+ csrf_failure(request, template_name="nonexistent.html")