~ubuntu-branches/debian/sid/python-django/sid

« back to all changes in this revision

Viewing changes to tests/csrf_tests/tests.py

  • Committer: Package Import Robot
  • Author(s): Luke Faraone
  • Date: 2013-11-07 15:33:49 UTC
  • mfrom: (1.3.12)
  • Revision ID: package-import@ubuntu.com-20131107153349-e31sc149l2szs3jb
Tags: 1.6-1
* New upstream version. Closes: #557474, #724637.
* python-django now also suggests the installation of ipython,
  bpython, python-django-doc, and libgdal1.
  Closes: #636511, #686333, #704203
* Set package maintainer to Debian Python Modules Team.
* Bump standards version to 3.9.5, no changes needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
from __future__ import unicode_literals
 
3
import logging
 
4
 
 
5
from django.conf import settings
 
6
from django.core.context_processors import csrf
 
7
from django.http import HttpRequest, HttpResponse
 
8
from django.middleware.csrf import CsrfViewMiddleware, CSRF_KEY_LENGTH
 
9
from django.template import RequestContext, Template
 
10
from django.test import TestCase
 
11
from django.test.utils import override_settings
 
12
from django.views.decorators.csrf import csrf_exempt, requires_csrf_token, ensure_csrf_cookie
 
13
 
 
14
 
 
15
# Response/views used for CsrfResponseMiddleware and CsrfViewMiddleware tests
 
16
def post_form_response():
 
17
    resp = HttpResponse(content="""
 
18
<html><body><h1>\u00a1Unicode!<form method="post"><input type="text" /></form></body></html>
 
19
""", mimetype="text/html")
 
20
    return resp
 
21
 
 
22
def post_form_view(request):
 
23
    """A view that returns a POST form (without a token)"""
 
24
    return post_form_response()
 
25
 
 
26
# Response/views used for template tag tests
 
27
 
 
28
def token_view(request):
 
29
    """A view that uses {% csrf_token %}"""
 
30
    context = RequestContext(request, processors=[csrf])
 
31
    template = Template("{% csrf_token %}")
 
32
    return HttpResponse(template.render(context))
 
33
 
 
34
def non_token_view_using_request_processor(request):
 
35
    """
 
36
    A view that doesn't use the token, but does use the csrf view processor.
 
37
    """
 
38
    context = RequestContext(request, processors=[csrf])
 
39
    template = Template("")
 
40
    return HttpResponse(template.render(context))
 
41
 
 
42
class TestingHttpRequest(HttpRequest):
 
43
    """
 
44
    A version of HttpRequest that allows us to change some things
 
45
    more easily
 
46
    """
 
47
    def is_secure(self):
 
48
        return getattr(self, '_is_secure_override', False)
 
49
 
 
50
class CsrfViewMiddlewareTest(TestCase):
 
51
    # The csrf token is potentially from an untrusted source, so could have
 
52
    # characters that need dealing with.
 
53
    _csrf_id_cookie = b"<1>\xc2\xa1"
 
54
    _csrf_id = "1"
 
55
 
 
56
    def _get_GET_no_csrf_cookie_request(self):
 
57
        return TestingHttpRequest()
 
58
 
 
59
    def _get_GET_csrf_cookie_request(self):
 
60
        req = TestingHttpRequest()
 
61
        req.COOKIES[settings.CSRF_COOKIE_NAME] = self._csrf_id_cookie
 
62
        return req
 
63
 
 
64
    def _get_POST_csrf_cookie_request(self):
 
65
        req = self._get_GET_csrf_cookie_request()
 
66
        req.method = "POST"
 
67
        return req
 
68
 
 
69
    def _get_POST_no_csrf_cookie_request(self):
 
70
        req = self._get_GET_no_csrf_cookie_request()
 
71
        req.method = "POST"
 
72
        return req
 
73
 
 
74
    def _get_POST_request_with_token(self):
 
75
        req = self._get_POST_csrf_cookie_request()
 
76
        req.POST['csrfmiddlewaretoken'] = self._csrf_id
 
77
        return req
 
78
 
 
79
    def _check_token_present(self, response, csrf_id=None):
 
80
        self.assertContains(response, "name='csrfmiddlewaretoken' value='%s'" % (csrf_id or self._csrf_id))
 
81
 
 
82
    def test_process_view_token_too_long(self):
 
83
        """
 
84
        Check that if the token is longer than expected, it is ignored and
 
85
        a new token is created.
 
86
        """
 
87
        req = self._get_GET_no_csrf_cookie_request()
 
88
        req.COOKIES[settings.CSRF_COOKIE_NAME] = 'x' * 10000000
 
89
        CsrfViewMiddleware().process_view(req, token_view, (), {})
 
90
        resp = token_view(req)
 
91
        resp2 = CsrfViewMiddleware().process_response(req, resp)
 
92
        csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, False)
 
93
        self.assertEqual(len(csrf_cookie.value), CSRF_KEY_LENGTH)
 
94
 
 
95
    def test_process_response_get_token_used(self):
 
96
        """
 
97
        When get_token is used, check that the cookie is created and headers
 
98
        patched.
 
99
        """
 
100
        req = self._get_GET_no_csrf_cookie_request()
 
101
 
 
102
        # Put tests for CSRF_COOKIE_* settings here
 
103
        with self.settings(CSRF_COOKIE_NAME='myname',
 
104
                           CSRF_COOKIE_DOMAIN='.example.com',
 
105
                           CSRF_COOKIE_PATH='/test/',
 
106
                           CSRF_COOKIE_SECURE=True,
 
107
                           CSRF_COOKIE_HTTPONLY=True):
 
108
            # token_view calls get_token() indirectly
 
109
            CsrfViewMiddleware().process_view(req, token_view, (), {})
 
110
            resp = token_view(req)
 
111
            resp2 = CsrfViewMiddleware().process_response(req, resp)
 
112
        csrf_cookie = resp2.cookies.get('myname', False)
 
113
        self.assertNotEqual(csrf_cookie, False)
 
114
        self.assertEqual(csrf_cookie['domain'], '.example.com')
 
115
        self.assertEqual(csrf_cookie['secure'], True)
 
116
        self.assertEqual(csrf_cookie['httponly'], True)
 
117
        self.assertEqual(csrf_cookie['path'], '/test/')
 
118
        self.assertTrue('Cookie' in resp2.get('Vary',''))
 
119
 
 
120
    def test_process_response_get_token_not_used(self):
 
121
        """
 
122
        Check that if get_token() is not called, the view middleware does not
 
123
        add a cookie.
 
124
        """
 
125
        # This is important to make pages cacheable.  Pages which do call
 
126
        # get_token(), assuming they use the token, are not cacheable because
 
127
        # the token is specific to the user
 
128
        req = self._get_GET_no_csrf_cookie_request()
 
129
        # non_token_view_using_request_processor does not call get_token(), but
 
130
        # does use the csrf request processor.  By using this, we are testing
 
131
        # that the view processor is properly lazy and doesn't call get_token()
 
132
        # until needed.
 
133
        CsrfViewMiddleware().process_view(req, non_token_view_using_request_processor, (), {})
 
134
        resp = non_token_view_using_request_processor(req)
 
135
        resp2 = CsrfViewMiddleware().process_response(req, resp)
 
136
 
 
137
        csrf_cookie = resp2.cookies.get(settings.CSRF_COOKIE_NAME, False)
 
138
        self.assertEqual(csrf_cookie, False)
 
139
 
 
140
    # Check the request processing
 
141
    def test_process_request_no_csrf_cookie(self):
 
142
        """
 
143
        Check that if no CSRF cookies is present, the middleware rejects the
 
144
        incoming request.  This will stop login CSRF.
 
145
        """
 
146
        req = self._get_POST_no_csrf_cookie_request()
 
147
        req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
 
148
        self.assertEqual(403, req2.status_code)
 
149
 
 
150
    def test_process_request_csrf_cookie_no_token(self):
 
151
        """
 
152
        Check that if a CSRF cookie is present but no token, the middleware
 
153
        rejects the incoming request.
 
154
        """
 
155
        req = self._get_POST_csrf_cookie_request()
 
156
        req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
 
157
        self.assertEqual(403, req2.status_code)
 
158
 
 
159
    def test_process_request_csrf_cookie_and_token(self):
 
160
        """
 
161
        Check that if both a cookie and a token is present, the middleware lets it through.
 
162
        """
 
163
        req = self._get_POST_request_with_token()
 
164
        req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
 
165
        self.assertEqual(None, req2)
 
166
 
 
167
    def test_process_request_csrf_cookie_no_token_exempt_view(self):
 
168
        """
 
169
        Check that if a CSRF cookie is present and no token, but the csrf_exempt
 
170
        decorator has been applied to the view, the middleware lets it through
 
171
        """
 
172
        req = self._get_POST_csrf_cookie_request()
 
173
        req2 = CsrfViewMiddleware().process_view(req, csrf_exempt(post_form_view), (), {})
 
174
        self.assertEqual(None, req2)
 
175
 
 
176
    def test_csrf_token_in_header(self):
 
177
        """
 
178
        Check that we can pass in the token in a header instead of in the form
 
179
        """
 
180
        req = self._get_POST_csrf_cookie_request()
 
181
        req.META['HTTP_X_CSRFTOKEN'] = self._csrf_id
 
182
        req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
 
183
        self.assertEqual(None, req2)
 
184
 
 
185
    def test_put_and_delete_rejected(self):
 
186
        """
 
187
        Tests that HTTP PUT and DELETE methods have protection
 
188
        """
 
189
        req = TestingHttpRequest()
 
190
        req.method = 'PUT'
 
191
        req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
 
192
        self.assertEqual(403, req2.status_code)
 
193
 
 
194
        req = TestingHttpRequest()
 
195
        req.method = 'DELETE'
 
196
        req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
 
197
        self.assertEqual(403, req2.status_code)
 
198
 
 
199
    def test_put_and_delete_allowed(self):
 
200
        """
 
201
        Tests that HTTP PUT and DELETE methods can get through with
 
202
        X-CSRFToken and a cookie
 
203
        """
 
204
        req = self._get_GET_csrf_cookie_request()
 
205
        req.method = 'PUT'
 
206
        req.META['HTTP_X_CSRFTOKEN'] = self._csrf_id
 
207
        req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
 
208
        self.assertEqual(None, req2)
 
209
 
 
210
        req = self._get_GET_csrf_cookie_request()
 
211
        req.method = 'DELETE'
 
212
        req.META['HTTP_X_CSRFTOKEN'] = self._csrf_id
 
213
        req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
 
214
        self.assertEqual(None, req2)
 
215
 
 
216
    # Tests for the template tag method
 
217
    def test_token_node_no_csrf_cookie(self):
 
218
        """
 
219
        Check that CsrfTokenNode works when no CSRF cookie is set
 
220
        """
 
221
        req = self._get_GET_no_csrf_cookie_request()
 
222
        resp = token_view(req)
 
223
        self.assertEqual(resp.content, b'')
 
224
 
 
225
    def test_token_node_empty_csrf_cookie(self):
 
226
        """
 
227
        Check that we get a new token if the csrf_cookie is the empty string
 
228
        """
 
229
        req = self._get_GET_no_csrf_cookie_request()
 
230
        req.COOKIES[settings.CSRF_COOKIE_NAME] = b""
 
231
        CsrfViewMiddleware().process_view(req, token_view, (), {})
 
232
        resp = token_view(req)
 
233
 
 
234
        self.assertNotEqual("", resp.content)
 
235
 
 
236
    def test_token_node_with_csrf_cookie(self):
 
237
        """
 
238
        Check that CsrfTokenNode works when a CSRF cookie is set
 
239
        """
 
240
        req = self._get_GET_csrf_cookie_request()
 
241
        CsrfViewMiddleware().process_view(req, token_view, (), {})
 
242
        resp = token_view(req)
 
243
        self._check_token_present(resp)
 
244
 
 
245
    def test_get_token_for_exempt_view(self):
 
246
        """
 
247
        Check that get_token still works for a view decorated with 'csrf_exempt'.
 
248
        """
 
249
        req = self._get_GET_csrf_cookie_request()
 
250
        CsrfViewMiddleware().process_view(req, csrf_exempt(token_view), (), {})
 
251
        resp = token_view(req)
 
252
        self._check_token_present(resp)
 
253
 
 
254
    def test_get_token_for_requires_csrf_token_view(self):
 
255
        """
 
256
        Check that get_token works for a view decorated solely with requires_csrf_token
 
257
        """
 
258
        req = self._get_GET_csrf_cookie_request()
 
259
        resp = requires_csrf_token(token_view)(req)
 
260
        self._check_token_present(resp)
 
261
 
 
262
    def test_token_node_with_new_csrf_cookie(self):
 
263
        """
 
264
        Check that CsrfTokenNode works when a CSRF cookie is created by
 
265
        the middleware (when one was not already present)
 
266
        """
 
267
        req = self._get_GET_no_csrf_cookie_request()
 
268
        CsrfViewMiddleware().process_view(req, token_view, (), {})
 
269
        resp = token_view(req)
 
270
        resp2 = CsrfViewMiddleware().process_response(req, resp)
 
271
        csrf_cookie = resp2.cookies[settings.CSRF_COOKIE_NAME]
 
272
        self._check_token_present(resp, csrf_id=csrf_cookie.value)
 
273
 
 
274
    @override_settings(ALLOWED_HOSTS=['www.example.com'])
 
275
    def test_https_bad_referer(self):
 
276
        """
 
277
        Test that a POST HTTPS request with a bad referer is rejected
 
278
        """
 
279
        req = self._get_POST_request_with_token()
 
280
        req._is_secure_override = True
 
281
        req.META['HTTP_HOST'] = 'www.example.com'
 
282
        req.META['HTTP_REFERER'] = 'https://www.evil.org/somepage'
 
283
        req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
 
284
        self.assertNotEqual(None, req2)
 
285
        self.assertEqual(403, req2.status_code)
 
286
 
 
287
    @override_settings(ALLOWED_HOSTS=['www.example.com'])
 
288
    def test_https_malformed_referer(self):
 
289
        """
 
290
        Test that a POST HTTPS request with a bad referer is rejected
 
291
        """
 
292
        req = self._get_POST_request_with_token()
 
293
        req._is_secure_override = True
 
294
        req.META['HTTP_HOST'] = 'www.example.com'
 
295
        req.META['HTTP_REFERER'] = 'http://http://www.example.com/'
 
296
        req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
 
297
        self.assertNotEqual(None, req2)
 
298
        self.assertEqual(403, req2.status_code)
 
299
 
 
300
    @override_settings(ALLOWED_HOSTS=['www.example.com'])
 
301
    def test_https_good_referer(self):
 
302
        """
 
303
        Test that a POST HTTPS request with a good referer is accepted
 
304
        """
 
305
        req = self._get_POST_request_with_token()
 
306
        req._is_secure_override = True
 
307
        req.META['HTTP_HOST'] = 'www.example.com'
 
308
        req.META['HTTP_REFERER'] = 'https://www.example.com/somepage'
 
309
        req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
 
310
        self.assertEqual(None, req2)
 
311
 
 
312
    @override_settings(ALLOWED_HOSTS=['www.example.com'])
 
313
    def test_https_good_referer_2(self):
 
314
        """
 
315
        Test that a POST HTTPS request with a good referer is accepted
 
316
        where the referer contains no trailing slash
 
317
        """
 
318
        # See ticket #15617
 
319
        req = self._get_POST_request_with_token()
 
320
        req._is_secure_override = True
 
321
        req.META['HTTP_HOST'] = 'www.example.com'
 
322
        req.META['HTTP_REFERER'] = 'https://www.example.com'
 
323
        req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
 
324
        self.assertEqual(None, req2)
 
325
 
 
326
    def test_ensures_csrf_cookie_no_middleware(self):
 
327
        """
 
328
        Tests that ensures_csrf_cookie decorator fulfils its promise
 
329
        with no middleware
 
330
        """
 
331
        @ensure_csrf_cookie
 
332
        def view(request):
 
333
            # Doesn't insert a token or anything
 
334
            return HttpResponse(content="")
 
335
 
 
336
        req = self._get_GET_no_csrf_cookie_request()
 
337
        resp = view(req)
 
338
        self.assertTrue(resp.cookies.get(settings.CSRF_COOKIE_NAME, False))
 
339
        self.assertTrue('Cookie' in resp.get('Vary',''))
 
340
 
 
341
    def test_ensures_csrf_cookie_with_middleware(self):
 
342
        """
 
343
        Tests that ensures_csrf_cookie decorator fulfils its promise
 
344
        with the middleware enabled.
 
345
        """
 
346
        @ensure_csrf_cookie
 
347
        def view(request):
 
348
            # Doesn't insert a token or anything
 
349
            return HttpResponse(content="")
 
350
 
 
351
        req = self._get_GET_no_csrf_cookie_request()
 
352
        CsrfViewMiddleware().process_view(req, view, (), {})
 
353
        resp = view(req)
 
354
        resp2 = CsrfViewMiddleware().process_response(req, resp)
 
355
        self.assertTrue(resp2.cookies.get(settings.CSRF_COOKIE_NAME, False))
 
356
        self.assertTrue('Cookie' in resp2.get('Vary',''))
 
357
 
 
358
    def test_ensures_csrf_cookie_no_logging(self):
 
359
        """
 
360
        Tests that ensure_csrf_cookie doesn't log warnings. See #19436.
 
361
        """
 
362
        @ensure_csrf_cookie
 
363
        def view(request):
 
364
            # Doesn't insert a token or anything
 
365
            return HttpResponse(content="")
 
366
 
 
367
        class TestHandler(logging.Handler):
 
368
            def emit(self, record):
 
369
                raise Exception("This shouldn't have happened!")
 
370
 
 
371
        logger = logging.getLogger('django.request')
 
372
        test_handler = TestHandler()
 
373
        old_log_level = logger.level
 
374
        try:
 
375
            logger.addHandler(test_handler)
 
376
            logger.setLevel(logging.WARNING)
 
377
 
 
378
            req = self._get_GET_no_csrf_cookie_request()
 
379
            resp = view(req)
 
380
        finally:
 
381
            logger.removeHandler(test_handler)
 
382
            logger.setLevel(old_log_level)