From 3c8f01b985396c9bfe802f0d1e25bbb59ea2a1a9 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 15 Oct 2012 14:03:36 +0100 Subject: [PATCH] Explicit CSRF failure message. Fixes #60. --- rest_framework/authentication.py | 22 +++++++++++++++++----- rest_framework/renderers.py | 7 +++++-- rest_framework/views.py | 6 +++--- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py index d7624708e..30c78ebc8 100644 --- a/rest_framework/authentication.py +++ b/rest_framework/authentication.py @@ -4,6 +4,7 @@ Provides a set of pluggable authentication policies. from django.contrib.auth import authenticate from django.utils.encoding import smart_unicode, DjangoUnicodeDecodeError +from rest_framework import exceptions from rest_framework.compat import CsrfViewMiddleware from rest_framework.authtoken.models import Token import base64 @@ -71,12 +72,23 @@ class SessionAuthentication(BaseAuthentication): http_request = request._request user = getattr(http_request, 'user', None) - if user and user.is_active: - # Enforce CSRF validation for session based authentication. - resp = CsrfViewMiddleware().process_view(http_request, None, (), {}) + # Unauthenticated, CSRF validation not required + if not user or not user.is_active: + return - if resp is None: # csrf passed - return (user, None) + # Enforce CSRF validation for session based authentication. + class CSRFCheck(CsrfViewMiddleware): + def _reject(self, request, reason): + # Return the failure reason instead of an HttpResponse + return reason + + reason = CSRFCheck().process_view(http_request, None, (), {}) + if reason: + # CSRF failed, bail with explicit error message + raise exceptions.PermissionDenied('CSRF Failed: %s' % reason) + + # CSRF passed with authenticated user + return (user, None) class TokenAuthentication(BaseAuthentication): diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 2a3b0b6ca..94d253c94 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -235,8 +235,11 @@ class BrowsableAPIRenderer(BaseRenderer): return # Cannot use form overloading request = clone_request(request, method) - if not view.has_permission(request): - return # Don't have permission + try: + if not view.has_permission(request): + return # Don't have permission + except: + return # Don't have permission and exception explicitly raise if method == 'DELETE' or method == 'OPTIONS': return True # Don't actually need to return a form diff --git a/rest_framework/views.py b/rest_framework/views.py index 92d4445f5..62fc92f96 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -156,14 +156,14 @@ class APIView(View): """ raise exceptions.Throttled(wait) - def get_parser_context(self, request): + def get_parser_context(self, http_request): """ Returns a dict that is passed through to Parser.parse_stream(), as the `parser_context` keyword argument. """ return { - 'upload_handlers': request.upload_handlers, - 'meta': request.META, + 'upload_handlers': http_request.upload_handlers, + 'meta': http_request.META, } def get_renderer_context(self):