Django

Code

Changeset 9554

Show
Ignore:
Timestamp:
12/02/08 18:34:18 (1 month ago)
Author:
lukeplant
Message:

New CsrfMiddleware? features: automatic exceptions for known AJAX and decorator for manual exceptions

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/contrib/csrf/middleware.py

    r9553 r9554  
    88import re 
    99import itertools 
     10try: 
     11    from functools import wraps 
     12except ImportError: 
     13    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback. 
    1014 
    1115from django.conf import settings 
     
    3135    def process_view(self, request, callback, callback_args, callback_kwargs): 
    3236        if request.method == 'POST': 
     37            if getattr(callback, 'csrf_exempt', False): 
     38                return None 
     39 
     40            if request.is_ajax(): 
     41                return None 
     42 
    3343            try: 
    3444                session_id = request.COOKIES[settings.SESSION_COOKIE_NAME] 
     
    108118    """ 
    109119    pass 
     120 
     121def csrf_exempt(view_func): 
     122    """ 
     123    Marks a view function as being exempt from the CSRF checks 
     124    """ 
     125    def wrapped_view(*args, **kwargs): 
     126        return view_func(*args, **kwargs) 
     127    # We could just do view.csrf_exempt = True, but decorators are 
     128    # nicer if they don't have side-effects. 
     129    wrapped_view.csrf_exempt = True 
     130    return wraps(view_func)(wrapped_view) 
  • django/trunk/django/contrib/csrf/tests.py

    r9553 r9554  
    33from django.test import TestCase 
    44from django.http import HttpRequest, HttpResponse, HttpResponseForbidden 
    5 from django.contrib.csrf.middleware import CsrfMiddleware, _make_token 
     5from django.contrib.csrf.middleware import CsrfMiddleware, _make_token, csrf_exempt 
    66from django.conf import settings 
    77 
     8 
     9def post_form_response(): 
     10    resp = HttpResponse(content=""" 
     11<html><body><form method="POST"><input type="text" /></form></body></html> 
     12""", mimetype="text/html") 
     13    return resp 
     14 
     15def test_view(request): 
     16    return post_form_response() 
    817 
    918class CsrfMiddlewareTest(TestCase): 
     
    3544 
    3645    def _get_post_form_response(self): 
    37         resp = HttpResponse(content=""" 
    38 <html><body><form method="POST"><input type="text" /></form></body></html> 
    39 """, mimetype="text/html") 
    40         return resp 
     46        return post_form_response() 
    4147 
    4248    def _get_new_session_response(self): 
     
    4955 
    5056    def get_view(self): 
    51         def dummyview(request): 
    52             return self._get_post_form_response() 
     57        return test_view 
    5358 
    5459    # Check the post processing 
     
    110115        req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {}) 
    111116        self.assertEquals(None, req2) 
     117 
     118    def test_process_request_session_no_token_exempt_view(self): 
     119        """ 
     120        Check that if a session is present and no token, but the csrf_exempt 
     121        decorator has been applied to the view, the middleware lets it through 
     122        """ 
     123        req = self._get_POST_session_request() 
     124        req2 = CsrfMiddleware().process_view(req, csrf_exempt(self.get_view()), (), {}) 
     125        self.assertEquals(None, req2) 
     126 
     127    def test_ajax_exemption(self): 
     128        """ 
     129        Check the AJAX requests are automatically exempted. 
     130        """ 
     131        req = self._get_POST_session_request() 
     132        req.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' 
     133        req2 = CsrfMiddleware().process_view(req, self.get_view(), (), {}) 
     134        self.assertEquals(None, req2) 
  • django/trunk/docs/ref/contrib/csrf.txt

    r8506 r9554  
    2727the response after the SessionMiddleware, so must come before it in the 
    2828list. It also must process the response before things like compression 
    29 happen to the response, so it must come after GZipMiddleware in the list. 
     29happen to the response, so it must come after GZipMiddleware in the 
     30list. 
     31 
     32Exceptions 
     33---------- 
     34 
     35To manually exclude a view function from being handled by the 
     36CsrfMiddleware, you can use the ``csrf_exempt`` decorator (found in 
     37the ``django.contrib.csrf.middleware`` module). 
     38 
     39AJAX requests sent with "X-Requested-With: XMLHttpRequest" are 
     40automatically exempt (see below). 
    3041 
    3142How it works 
     
    6071are modified. 
    6172 
     73AJAX requests sent with "X-Requested-With: XMLHttpRequest", as done by 
     74many AJAX toolkits, are detected and automatically excepted from this 
     75mechanism.  This is because in the context of a browser, this header 
     76can only be added by using XMLHttpRequest, and browsers already 
     77implement a same-domain policy for XMLHttpRequest.  This is not secure 
     78if you do not trust content within the same domain or sub-domains. 
     79 
     80The above two functions of ``CsrfMiddleware`` are split between two 
     81classes: ``CsrfResponseMiddleware`` and ``CsrfViewMiddleware`` 
     82respectively.  This allows the individual components to be used and/or 
     83replaced instead of using ``CsrfMiddleware``. 
     84 
    6285.. _9.1.1 Safe Methods, HTTP 1.1, RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html 
    6386