Allow validation of CSRF cookie to be done in view using a CBV mixin or an helper function (refs #5617)

Use the CBV for a do-nothing use or on a function based view you must
apply the decorators @csrf_exempt and @ensure_csrf_cookie on your view
(in this order) and use utils.csrf_token_check(request, form) to check
for the cookie before validating your form.
This commit is contained in:
Benjamin Dauvergne 2015-01-13 14:35:03 +01:00 committed by bdauvergne
parent 25ef99ffae
commit 31c743d879
2 changed files with 35 additions and 0 deletions

26
src/authentic2/cbv.py Normal file
View File

@ -0,0 +1,26 @@
from django.views.decorators.csrf import ensure_csrf_cookie, csrf_exempt
from django.utils.decorators import method_decorator
from django.forms import Form
from . import utils
class ValidateCSRFMixin(object):
'''Move CSRF token validation inside the form validation.
This mixin must always be the leftest one and if your class override
form_valid() or dispatch() you should move those overrides in a base
class.
'''
@method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):
return super(ValidateCSRFMixin, self).dispatch(*args, **kwargs)
@method_decorator(ensure_csrf_cookie)
def form_valid(self, *args, **kwargs):
for form in args:
if isinstance(form, Form):
utils.csrf_token_check(self.request, form)
if not form.is_valid():
return self.form_invalid(form)
return super(ValidateCSRFMixin, self).form_valid(*args, **kwargs)

View File

@ -17,6 +17,7 @@ from django.contrib.auth import REDIRECT_FIELD_NAME, login as auth_login
from django import forms
from django.forms.util import ErrorList
from django.utils import html, http
from django.utils.translation import ugettext as _
from authentic2.saml.saml2utils import filter_attribute_private_key, \
filter_element_private_key
@ -430,3 +431,11 @@ def attribute_values_to_identifier(values):
normalized = normalize_attribute_values(values)
assert len(normalized) == 1, 'multi-valued attribute cannot be used as an identifier'
return list(normalized)[0]
def csrf_token_check(request, form):
'''Check a request for CSRF cookie validation, and add an error to the form
if check fails.
'''
if form.is_valid() and not getattr(request, 'csrf_processing_done', False):
msg = _('The form was out of date, please try again.')
form._errors[forms.forms.NON_FIELD_ERRORS] = ErrorList([msg])