Commit 16945f0e authored by Raphael Michel's avatar Raphael Michel Committed by Tim Graham
Browse files

Fixed #25695 -- Added template_name parameter to csrf_failure() view.

parent 20d27785
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
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')
+9 −0
Original line number Diff line number Diff line
@@ -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
+3 −1
Original line number Diff line number Diff line
@@ -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
^^^^^^^^^^^^^^^^^
+31 −1
Original line number Diff line number Diff line
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")