PageRenderTime 280ms CodeModel.GetById 95ms app.highlight 50ms RepoModel.GetById 91ms app.codeStats 0ms

/tests/regressiontests/csrf_tests/tests.py

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