From 933d1d7addf9587eb20be38ade206bcc4ecb89cb Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Tue, 13 Jan 2015 14:35:03 +0100 Subject: [PATCH 2/5] 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. --- src/authentic2/cbv.py | 26 ++++++++++++++++++++++++++ src/authentic2/utils.py | 8 ++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/authentic2/cbv.py diff --git a/src/authentic2/cbv.py b/src/authentic2/cbv.py new file mode 100644 index 0000000..c264929 --- /dev/null +++ b/src/authentic2/cbv.py @@ -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) diff --git a/src/authentic2/utils.py b/src/authentic2/utils.py index 4483098..553443d 100644 --- a/src/authentic2/utils.py +++ b/src/authentic2/utils.py @@ -425,8 +425,16 @@ def normalize_attribute_values(values): values_set.add(unicode(value)) return values_set def attribute_values_to_identifier(values): '''Try to find an identifier from attribute 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[NON_FIELD_ERRORS] = ErrorList([msg]) -- 1.9.1