Commit 8e70cef9 authored by Luke Plant's avatar Luke Plant
Browse files

Fixed #9977 - CsrfMiddleware gets template tag added, session dependency...

Fixed #9977 - CsrfMiddleware gets template tag added, session dependency removed, and turned on by default.

This is a large change to CSRF protection for Django.  It includes:

 * removing the dependency on the session framework.
 * deprecating CsrfResponseMiddleware, and replacing with a core template tag.
 * turning on CSRF protection by default by adding CsrfViewMiddleware to
   the default value of MIDDLEWARE_CLASSES.
 * protecting all contrib apps (whatever is in settings.py)
   using a decorator.

For existing users of the CSRF functionality, it should be a seamless update,
but please note that it includes DEPRECATION of features in Django 1.1,
and there are upgrade steps which are detailed in the docs.

Many thanks to 'Glenn' and 'bthomas', who did a lot of the thinking and work
on the patch, and to lots of other people including Simon Willison and
Russell Keith-Magee who refined the ideas.

Details of the rationale for these changes is found here:

http://code.djangoproject.com/wiki/CsrfProtection

As of this commit, the CSRF code is mainly in 'contrib'.  The code will be
moved to core in a separate commit, to make the changeset as readable as
possible.



git-svn-id: http://code.djangoproject.com/svn/django/trunk@11660 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent d1da2614
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -470,6 +470,8 @@ answer newbie questions, and generally made Django that much better:
    Gasper Zejn <zejn@kiberpipa.org>
    Jarek Zgoda <jarek.zgoda@gmail.com>
    Cheng Zhang
    Glenn
    bthomas

A big THANK YOU goes to:

+13 −0
Original line number Diff line number Diff line
@@ -300,6 +300,7 @@ DEFAULT_INDEX_TABLESPACE = ''
MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.csrf.middleware.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
#     'django.middleware.http.ConditionalGetMiddleware',
#     'django.middleware.gzip.GZipMiddleware',
@@ -374,6 +375,18 @@ LOGIN_REDIRECT_URL = '/accounts/profile/'
# The number of days a password reset link is valid for
PASSWORD_RESET_TIMEOUT_DAYS = 3

########
# CSRF #
########

# Dotted path to callable to be used as view when a request is
# rejected by the CSRF middleware.
CSRF_FAILURE_VIEW = 'django.contrib.csrf.views.csrf_failure'

# Name and domain for CSRF cookie.
CSRF_COOKIE_NAME = 'csrftoken'
CSRF_COOKIE_DOMAIN = None

###########
# TESTING #
###########
+1 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ TEMPLATE_LOADERS = (
MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.csrf.middleware.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
)

+7 −2
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ from django.contrib.contenttypes.models import ContentType
from django.contrib.admin import widgets
from django.contrib.admin import helpers
from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_ngettext, model_format_dict
from django.contrib.csrf.decorators import csrf_protect
from django.core.exceptions import PermissionDenied
from django.db import models, transaction
from django.db.models.fields import BLANK_CHOICE_DASH
@@ -701,6 +702,8 @@ class ModelAdmin(BaseModelAdmin):
            else:
                return HttpResponseRedirect(".")

    @csrf_protect
    @transaction.commit_on_success
    def add_view(self, request, form_url='', extra_context=None):
        "The 'add' admin view for this model."
        model = self.model
@@ -782,8 +785,9 @@ class ModelAdmin(BaseModelAdmin):
        }
        context.update(extra_context or {})
        return self.render_change_form(request, context, form_url=form_url, add=True)
    add_view = transaction.commit_on_success(add_view)

    @csrf_protect
    @transaction.commit_on_success
    def change_view(self, request, object_id, extra_context=None):
        "The 'change' admin view for this model."
        model = self.model
@@ -871,8 +875,8 @@ class ModelAdmin(BaseModelAdmin):
        }
        context.update(extra_context or {})
        return self.render_change_form(request, context, change=True, obj=obj)
    change_view = transaction.commit_on_success(change_view)

    @csrf_protect
    def changelist_view(self, request, extra_context=None):
        "The 'change list' admin view for this model."
        from django.contrib.admin.views.main import ChangeList, ERROR_FLAG
@@ -985,6 +989,7 @@ class ModelAdmin(BaseModelAdmin):
            'admin/change_list.html'
        ], context, context_instance=context_instance)

    @csrf_protect
    def delete_view(self, request, object_id, extra_context=None):
        "The 'delete' admin view for this model."
        opts = self.model._meta
+5 −0
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@ from django import http, template
from django.contrib.admin import ModelAdmin
from django.contrib.admin import actions
from django.contrib.auth import authenticate, login
from django.contrib.csrf.middleware import csrf_response_exempt
from django.contrib.csrf.decorators import csrf_protect
from django.db.models.base import ModelBase
from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import reverse
@@ -186,6 +188,9 @@ class AdminSite(object):
            return view(request, *args, **kwargs)
        if not cacheable:
            inner = never_cache(inner)
        # We add csrf_protect here so this function can be used as a utility
        # function for any view, without having to repeat 'csrf_protect'.
        inner = csrf_response_exempt(csrf_protect(inner))
        return update_wrapper(inner, view)

    def get_urls(self):
Loading