parts/django/tests/regressiontests/csrf_tests/tests.py
changeset 307 c6bca38c1cbf
equal deleted inserted replaced
306:5ff1fc726848 307:c6bca38c1cbf
       
     1 # -*- coding: utf-8 -*-
       
     2 
       
     3 from django.test import TestCase
       
     4 from django.http import HttpRequest, HttpResponse
       
     5 from django.middleware.csrf import CsrfMiddleware, CsrfViewMiddleware
       
     6 from django.views.decorators.csrf import csrf_exempt, csrf_view_exempt, requires_csrf_token
       
     7 from django.core.context_processors import csrf
       
     8 from django.contrib.sessions.middleware import SessionMiddleware
       
     9 from django.utils.importlib import import_module
       
    10 from django.conf import settings
       
    11 from django.template import RequestContext, Template
       
    12 
       
    13 # Response/views used for CsrfResponseMiddleware and CsrfViewMiddleware tests
       
    14 def post_form_response():
       
    15     resp = HttpResponse(content=u"""
       
    16 <html><body><h1>\u00a1Unicode!<form method="post"><input type="text" /></form></body></html>
       
    17 """, mimetype="text/html")
       
    18     return resp
       
    19 
       
    20 def post_form_response_non_html():
       
    21     resp = post_form_response()
       
    22     resp["Content-Type"] = "application/xml"
       
    23     return resp
       
    24 
       
    25 def post_form_view(request):
       
    26     """A view that returns a POST form (without a token)"""
       
    27     return post_form_response()
       
    28 
       
    29 # Response/views used for template tag tests
       
    30 def _token_template():
       
    31     return Template("{% csrf_token %}")
       
    32 
       
    33 def _render_csrf_token_template(req):
       
    34     context = RequestContext(req, processors=[csrf])
       
    35     template = _token_template()
       
    36     return template.render(context)
       
    37 
       
    38 def token_view(request):
       
    39     """A view that uses {% csrf_token %}"""
       
    40     return HttpResponse(_render_csrf_token_template(request))
       
    41 
       
    42 def non_token_view_using_request_processor(request):
       
    43     """
       
    44     A view that doesn't use the token, but does use the csrf view processor.
       
    45     """
       
    46     context = RequestContext(request, processors=[csrf])
       
    47     template = Template("")
       
    48     return HttpResponse(template.render(context))
       
    49 
       
    50 class TestingHttpRequest(HttpRequest):
       
    51     """
       
    52     A version of HttpRequest that allows us to change some things
       
    53     more easily
       
    54     """
       
    55     def is_secure(self):
       
    56         return getattr(self, '_is_secure', False)
       
    57 
       
    58 class CsrfMiddlewareTest(TestCase):
       
    59     # The csrf token is potentially from an untrusted source, so could have
       
    60     # characters that need dealing with.
       
    61     _csrf_id_cookie = "<1>\xc2\xa1"
       
    62     _csrf_id = "1"
       
    63 
       
    64     # This is a valid session token for this ID and secret key.  This was generated using
       
    65     # the old code that we're to be backwards-compatible with.  Don't use the CSRF code
       
    66     # to generate this hash, or we're merely testing the code against itself and not
       
    67     # checking backwards-compatibility.  This is also the output of (echo -n test1 | md5sum).
       
    68     _session_token = "5a105e8b9d40e1329780d62ea2265d8a"
       
    69     _session_id = "1"
       
    70     _secret_key_for_session_test= "test"
       
    71 
       
    72     def _get_GET_no_csrf_cookie_request(self):
       
    73         return TestingHttpRequest()
       
    74 
       
    75     def _get_GET_csrf_cookie_request(self):
       
    76         req = TestingHttpRequest()
       
    77         req.COOKIES[settings.CSRF_COOKIE_NAME] = self._csrf_id_cookie
       
    78         return req
       
    79 
       
    80     def _get_POST_csrf_cookie_request(self):
       
    81         req = self._get_GET_csrf_cookie_request()
       
    82         req.method = "POST"
       
    83         return req
       
    84 
       
    85     def _get_POST_no_csrf_cookie_request(self):
       
    86         req = self._get_GET_no_csrf_cookie_request()
       
    87         req.method = "POST"
       
    88         return req
       
    89 
       
    90     def _get_POST_request_with_token(self):
       
    91         req = self._get_POST_csrf_cookie_request()
       
    92         req.POST['csrfmiddlewaretoken'] = self._csrf_id
       
    93         return req
       
    94 
       
    95     def _get_POST_session_request_with_token(self):
       
    96         req = self._get_POST_no_csrf_cookie_request()
       
    97         req.COOKIES[settings.SESSION_COOKIE_NAME] = self._session_id
       
    98         req.POST['csrfmiddlewaretoken'] = self._session_token
       
    99         return req
       
   100 
       
   101     def _get_POST_session_request_no_token(self):
       
   102         req = self._get_POST_no_csrf_cookie_request()
       
   103         req.COOKIES[settings.SESSION_COOKIE_NAME] = self._session_id
       
   104         return req
       
   105 
       
   106     def _check_token_present(self, response, csrf_id=None):
       
   107         self.assertContains(response, "name='csrfmiddlewaretoken' value='%s'" % (csrf_id or self._csrf_id))
       
   108 
       
   109     # Check the post processing and outgoing cookie
       
   110     def test_process_response_no_csrf_cookie(self):
       
   111         """
       
   112         When no prior CSRF cookie exists, check that the cookie is created and a
       
   113         token is inserted.
       
   114         """
       
   115         req = self._get_GET_no_csrf_cookie_request()
       
   116         CsrfMiddleware().process_view(req, post_form_view, (), {})
       
   117 
       
   118         resp = post_form_response()
       
   119         resp_content = resp.content # needed because process_response modifies resp
       
   120         resp2 = CsrfMiddleware().process_response(req, resp)
       
   121 
       
   122         csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, False)
       
   123         self.assertNotEqual(csrf_cookie, False)
       
   124         self.assertNotEqual(resp_content, resp2.content)
       
   125         self._check_token_present(resp2, csrf_cookie.value)
       
   126         # Check the Vary header got patched correctly
       
   127         self.assert_('Cookie' in resp2.get('Vary',''))
       
   128 
       
   129     def test_process_response_for_exempt_view(self):
       
   130         """
       
   131         Check that a view decorated with 'csrf_view_exempt' is still
       
   132         post-processed to add the CSRF token.
       
   133         """
       
   134         req = self._get_GET_no_csrf_cookie_request()
       
   135         CsrfMiddleware().process_view(req, csrf_view_exempt(post_form_view), (), {})
       
   136 
       
   137         resp = post_form_response()
       
   138         resp_content = resp.content # needed because process_response modifies resp
       
   139         resp2 = CsrfMiddleware().process_response(req, resp)
       
   140 
       
   141         csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, False)
       
   142         self.assertNotEqual(csrf_cookie, False)
       
   143         self.assertNotEqual(resp_content, resp2.content)
       
   144         self._check_token_present(resp2, csrf_cookie.value)
       
   145 
       
   146     def test_process_response_no_csrf_cookie_view_only_get_token_used(self):
       
   147         """
       
   148         When no prior CSRF cookie exists, check that the cookie is created, even
       
   149         if only CsrfViewMiddleware is used.
       
   150         """
       
   151         # This is checking that CsrfViewMiddleware has the cookie setting
       
   152         # code. Most of the other tests use CsrfMiddleware.
       
   153         req = self._get_GET_no_csrf_cookie_request()
       
   154         # token_view calls get_token() indirectly
       
   155         CsrfViewMiddleware().process_view(req, token_view, (), {})
       
   156         resp = token_view(req)
       
   157         resp2 = CsrfViewMiddleware().process_response(req, resp)
       
   158 
       
   159         csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, False)
       
   160         self.assertNotEqual(csrf_cookie, False)
       
   161 
       
   162     def test_process_response_get_token_not_used(self):
       
   163         """
       
   164         Check that if get_token() is not called, the view middleware does not
       
   165         add a cookie.
       
   166         """
       
   167         # This is important to make pages cacheable.  Pages which do call
       
   168         # get_token(), assuming they use the token, are not cacheable because
       
   169         # the token is specific to the user
       
   170         req = self._get_GET_no_csrf_cookie_request()
       
   171         # non_token_view_using_request_processor does not call get_token(), but
       
   172         # does use the csrf request processor.  By using this, we are testing
       
   173         # that the view processor is properly lazy and doesn't call get_token()
       
   174         # until needed.
       
   175         CsrfViewMiddleware().process_view(req, non_token_view_using_request_processor, (), {})
       
   176         resp = non_token_view_using_request_processor(req)
       
   177         resp2 = CsrfViewMiddleware().process_response(req, resp)
       
   178 
       
   179         csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, False)
       
   180         self.assertEqual(csrf_cookie, False)
       
   181 
       
   182     def test_process_response_existing_csrf_cookie(self):
       
   183         """
       
   184         Check that the token is inserted when a prior CSRF cookie exists
       
   185         """
       
   186         req = self._get_GET_csrf_cookie_request()
       
   187         CsrfMiddleware().process_view(req, post_form_view, (), {})
       
   188 
       
   189         resp = post_form_response()
       
   190         resp_content = resp.content # needed because process_response modifies resp
       
   191         resp2 = CsrfMiddleware().process_response(req, resp)
       
   192         self.assertNotEqual(resp_content, resp2.content)
       
   193         self._check_token_present(resp2)
       
   194 
       
   195     def test_process_response_non_html(self):
       
   196         """
       
   197         Check the the post-processor does nothing for content-types not in _HTML_TYPES.
       
   198         """
       
   199         req = self._get_GET_no_csrf_cookie_request()
       
   200         CsrfMiddleware().process_view(req, post_form_view, (), {})
       
   201         resp = post_form_response_non_html()
       
   202         resp_content = resp.content # needed because process_response modifies resp
       
   203         resp2 = CsrfMiddleware().process_response(req, resp)
       
   204         self.assertEquals(resp_content, resp2.content)
       
   205 
       
   206     def test_process_response_exempt_view(self):
       
   207         """
       
   208         Check that no post processing is done for an exempt view
       
   209         """
       
   210         req = self._get_GET_csrf_cookie_request()
       
   211         view = csrf_exempt(post_form_view)
       
   212         CsrfMiddleware().process_view(req, view, (), {})
       
   213 
       
   214         resp = view(req)
       
   215         resp_content = resp.content
       
   216         resp2 = CsrfMiddleware().process_response(req, resp)
       
   217         self.assertEquals(resp_content, resp2.content)
       
   218 
       
   219     # Check the request processing
       
   220     def test_process_request_no_session_no_csrf_cookie(self):
       
   221         """
       
   222         Check that if neither a CSRF cookie nor a session cookie are present,
       
   223         the middleware rejects the incoming request.  This will stop login CSRF.
       
   224         """
       
   225         req = self._get_POST_no_csrf_cookie_request()
       
   226         req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
       
   227         self.assertEquals(403, req2.status_code)
       
   228 
       
   229     def test_process_request_csrf_cookie_no_token(self):
       
   230         """
       
   231         Check that if a CSRF cookie is present but no token, the middleware
       
   232         rejects the incoming request.
       
   233         """
       
   234         req = self._get_POST_csrf_cookie_request()
       
   235         req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
       
   236         self.assertEquals(403, req2.status_code)
       
   237 
       
   238     def test_process_request_csrf_cookie_and_token(self):
       
   239         """
       
   240         Check that if both a cookie and a token is present, the middleware lets it through.
       
   241         """
       
   242         req = self._get_POST_request_with_token()
       
   243         req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
       
   244         self.assertEquals(None, req2)
       
   245 
       
   246     def test_process_request_session_cookie_no_csrf_cookie_token(self):
       
   247         """
       
   248         When no CSRF cookie exists, but the user has a session, check that a token
       
   249         using the session cookie as a legacy CSRF cookie is accepted.
       
   250         """
       
   251         orig_secret_key = settings.SECRET_KEY
       
   252         settings.SECRET_KEY = self._secret_key_for_session_test
       
   253         try:
       
   254             req = self._get_POST_session_request_with_token()
       
   255             req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
       
   256             self.assertEquals(None, req2)
       
   257         finally:
       
   258             settings.SECRET_KEY = orig_secret_key
       
   259 
       
   260     def test_process_request_session_cookie_no_csrf_cookie_no_token(self):
       
   261         """
       
   262         Check that if a session cookie is present but no token and no CSRF cookie,
       
   263         the request is rejected.
       
   264         """
       
   265         req = self._get_POST_session_request_no_token()
       
   266         req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
       
   267         self.assertEquals(403, req2.status_code)
       
   268 
       
   269     def test_process_request_csrf_cookie_no_token_exempt_view(self):
       
   270         """
       
   271         Check that if a CSRF cookie is present and no token, but the csrf_exempt
       
   272         decorator has been applied to the view, the middleware lets it through
       
   273         """
       
   274         req = self._get_POST_csrf_cookie_request()
       
   275         req2 = CsrfMiddleware().process_view(req, csrf_exempt(post_form_view), (), {})
       
   276         self.assertEquals(None, req2)
       
   277 
       
   278     def test_ajax_exemption(self):
       
   279         """
       
   280         Check that AJAX requests are automatically exempted.
       
   281         """
       
   282         req = self._get_POST_csrf_cookie_request()
       
   283         req.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
       
   284         req2 = CsrfMiddleware().process_view(req, post_form_view, (), {})
       
   285         self.assertEquals(None, req2)
       
   286 
       
   287     # Tests for the template tag method
       
   288     def test_token_node_no_csrf_cookie(self):
       
   289         """
       
   290         Check that CsrfTokenNode works when no CSRF cookie is set
       
   291         """
       
   292         req = self._get_GET_no_csrf_cookie_request()
       
   293         resp = token_view(req)
       
   294         self.assertEquals(u"", resp.content)
       
   295 
       
   296     def test_token_node_empty_csrf_cookie(self):
       
   297         """
       
   298         Check that we get a new token if the csrf_cookie is the empty string
       
   299         """
       
   300         req = self._get_GET_no_csrf_cookie_request()
       
   301         req.COOKIES[settings.CSRF_COOKIE_NAME] = ""
       
   302         CsrfViewMiddleware().process_view(req, token_view, (), {})
       
   303         resp = token_view(req)
       
   304 
       
   305         self.assertNotEqual(u"", resp.content)
       
   306 
       
   307     def test_token_node_with_csrf_cookie(self):
       
   308         """
       
   309         Check that CsrfTokenNode works when a CSRF cookie is set
       
   310         """
       
   311         req = self._get_GET_csrf_cookie_request()
       
   312         CsrfViewMiddleware().process_view(req, token_view, (), {})
       
   313         resp = token_view(req)
       
   314         self._check_token_present(resp)
       
   315 
       
   316     def test_get_token_for_exempt_view(self):
       
   317         """
       
   318         Check that get_token still works for a view decorated with 'csrf_view_exempt'.
       
   319         """
       
   320         req = self._get_GET_csrf_cookie_request()
       
   321         CsrfViewMiddleware().process_view(req, csrf_view_exempt(token_view), (), {})
       
   322         resp = token_view(req)
       
   323         self._check_token_present(resp)
       
   324 
       
   325     def test_get_token_for_requires_csrf_token_view(self):
       
   326         """
       
   327         Check that get_token works for a view decorated solely with requires_csrf_token
       
   328         """
       
   329         req = self._get_GET_csrf_cookie_request()
       
   330         resp = requires_csrf_token(token_view)(req)
       
   331         self._check_token_present(resp)
       
   332 
       
   333     def test_token_node_with_new_csrf_cookie(self):
       
   334         """
       
   335         Check that CsrfTokenNode works when a CSRF cookie is created by
       
   336         the middleware (when one was not already present)
       
   337         """
       
   338         req = self._get_GET_no_csrf_cookie_request()
       
   339         CsrfViewMiddleware().process_view(req, token_view, (), {})
       
   340         resp = token_view(req)
       
   341         resp2 = CsrfViewMiddleware().process_response(req, resp)
       
   342         csrf_cookie = resp2.cookies[settings.CSRF_COOKIE_NAME]
       
   343         self._check_token_present(resp, csrf_id=csrf_cookie.value)
       
   344 
       
   345     def test_response_middleware_without_view_middleware(self):
       
   346         """
       
   347         Check that CsrfResponseMiddleware finishes without error if the view middleware
       
   348         has not been called, as is the case if a request middleware returns a response.
       
   349         """
       
   350         req = self._get_GET_no_csrf_cookie_request()
       
   351         resp = post_form_view(req)
       
   352         CsrfMiddleware().process_response(req, resp)
       
   353 
       
   354     def test_https_bad_referer(self):
       
   355         """
       
   356         Test that a POST HTTPS request with a bad referer is rejected
       
   357         """
       
   358         req = self._get_POST_request_with_token()
       
   359         req._is_secure = True
       
   360         req.META['HTTP_HOST'] = 'www.example.com'
       
   361         req.META['HTTP_REFERER'] = 'https://www.evil.org/somepage'
       
   362         req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
       
   363         self.assertNotEqual(None, req2)
       
   364         self.assertEquals(403, req2.status_code)
       
   365 
       
   366     def test_https_good_referer(self):
       
   367         """
       
   368         Test that a POST HTTPS request with a good referer is accepted
       
   369         """
       
   370         req = self._get_POST_request_with_token()
       
   371         req._is_secure = True
       
   372         req.META['HTTP_HOST'] = 'www.example.com'
       
   373         req.META['HTTP_REFERER'] = 'https://www.example.com/somepage'
       
   374         req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
       
   375         self.assertEquals(None, req2)