1 # -*- coding: utf-8 -*-
2 from __future__
import with_statement
4 from django
.conf
import settings
5 from django
.core
.context_processors
import csrf
6 from django
.http
import HttpRequest
, HttpResponse
7 from django
.middleware
.csrf
import CsrfViewMiddleware
, CSRF_KEY_LENGTH
8 from django
.template
import RequestContext
, Template
9 from django
.test
import TestCase
10 from django
.views
.decorators
.csrf
import csrf_exempt
, requires_csrf_token
, ensure_csrf_cookie
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")
20 def post_form_view(request
):
21 """A view that returns a POST form (without a token)"""
22 return post_form_response()
24 # Response/views used for template tag tests
26 def token_view(request
):
27 """A view that uses {% csrf_token %}"""
28 context
= RequestContext(request
, processors
=[csrf
])
29 template
= Template("{% csrf_token %}")
30 return HttpResponse(template
.render(context
))
32 def non_token_view_using_request_processor(request
):
34 A view that doesn't use the token, but does use the csrf view processor.
36 context
= RequestContext(request
, processors
=[csrf
])
37 template
= Template("")
38 return HttpResponse(template
.render(context
))
40 class TestingHttpRequest(HttpRequest
):
42 A version of HttpRequest that allows us to change some things
46 return getattr(self
, '_is_secure_override', False)
48 class CsrfViewMiddlewareTest(TestCase
):
49 # The csrf token is potentially from an untrusted source, so could have
50 # characters that need dealing with.
51 _csrf_id_cookie
= "<1>\xc2\xa1"
54 def _get_GET_no_csrf_cookie_request(self
):
55 return TestingHttpRequest()
57 def _get_GET_csrf_cookie_request(self
):
58 req
= TestingHttpRequest()
59 req
.COOKIES
[settings
.CSRF_COOKIE_NAME
] = self
._csrf
_id
_cookie
62 def _get_POST_csrf_cookie_request(self
):
63 req
= self
._get
_GET
_csrf
_cookie
_request
()
67 def _get_POST_no_csrf_cookie_request(self
):
68 req
= self
._get
_GET
_no
_csrf
_cookie
_request
()
72 def _get_POST_request_with_token(self
):
73 req
= self
._get
_POST
_csrf
_cookie
_request
()
74 req
.POST
['csrfmiddlewaretoken'] = self
._csrf
_id
77 def _check_token_present(self
, response
, csrf_id
=None):
78 self
.assertContains(response
, "name='csrfmiddlewaretoken' value='%s'" % (csrf_id
or self
._csrf
_id
))
80 def test_process_view_token_too_long(self
):
82 Check that if the token is longer than expected, it is ignored and
83 a new token is created.
85 req
= self
._get
_GET
_no
_csrf
_cookie
_request
()
86 req
.COOKIES
[settings
.CSRF_COOKIE_NAME
] = 'x' * 10000000
87 CsrfViewMiddleware().process_view(req
, token_view
, (), {})
88 resp
= token_view(req
)
89 resp2
= CsrfViewMiddleware().process_response(req
, resp
)
90 csrf_cookie
= resp2
.cookies
.get(settings
.CSRF_COOKIE_NAME
, False)
91 self
.assertEqual(len(csrf_cookie
.value
), CSRF_KEY_LENGTH
)
93 def test_process_response_get_token_used(self
):
95 When get_token is used, check that the cookie is created and headers
98 req
= self
._get
_GET
_no
_csrf
_cookie
_request
()
100 # Put tests for CSRF_COOKIE_* settings here
101 with self
.settings(CSRF_COOKIE_NAME
='myname',
102 CSRF_COOKIE_DOMAIN
='.example.com',
103 CSRF_COOKIE_PATH
='/test/',
104 CSRF_COOKIE_SECURE
=True):
105 # token_view calls get_token() indirectly
106 CsrfViewMiddleware().process_view(req
, token_view
, (), {})
107 resp
= token_view(req
)
108 resp2
= CsrfViewMiddleware().process_response(req
, resp
)
109 csrf_cookie
= resp2
.cookies
.get('myname', False)
110 self
.assertNotEqual(csrf_cookie
, False)
111 self
.assertEqual(csrf_cookie
['domain'], '.example.com')
112 self
.assertEqual(csrf_cookie
['secure'], True)
113 self
.assertEqual(csrf_cookie
['path'], '/test/')
114 self
.assertTrue('Cookie' in resp2
.get('Vary',''))
116 def test_process_response_get_token_not_used(self
):
118 Check that if get_token() is not called, the view middleware does not
121 # This is important to make pages cacheable. Pages which do call
122 # get_token(), assuming they use the token, are not cacheable because
123 # the token is specific to the user
124 req
= self
._get
_GET
_no
_csrf
_cookie
_request
()
125 # non_token_view_using_request_processor does not call get_token(), but
126 # does use the csrf request processor. By using this, we are testing
127 # that the view processor is properly lazy and doesn't call get_token()
129 CsrfViewMiddleware().process_view(req
, non_token_view_using_request_processor
, (), {})
130 resp
= non_token_view_using_request_processor(req
)
131 resp2
= CsrfViewMiddleware().process_response(req
, resp
)
133 csrf_cookie
= resp2
.cookies
.get(settings
.CSRF_COOKIE_NAME
, False)
134 self
.assertEqual(csrf_cookie
, False)
136 # Check the request processing
137 def test_process_request_no_csrf_cookie(self
):
139 Check that if no CSRF cookies is present, the middleware rejects the
140 incoming request. This will stop login CSRF.
142 req
= self
._get
_POST
_no
_csrf
_cookie
_request
()
143 req2
= CsrfViewMiddleware().process_view(req
, post_form_view
, (), {})
144 self
.assertEqual(403, req2
.status_code
)
146 def test_process_request_csrf_cookie_no_token(self
):
148 Check that if a CSRF cookie is present but no token, the middleware
149 rejects the incoming request.
151 req
= self
._get
_POST
_csrf
_cookie
_request
()
152 req2
= CsrfViewMiddleware().process_view(req
, post_form_view
, (), {})
153 self
.assertEqual(403, req2
.status_code
)
155 def test_process_request_csrf_cookie_and_token(self
):
157 Check that if both a cookie and a token is present, the middleware lets it through.
159 req
= self
._get
_POST
_request
_with
_token
()
160 req2
= CsrfViewMiddleware().process_view(req
, post_form_view
, (), {})
161 self
.assertEqual(None, req2
)
163 def test_process_request_csrf_cookie_no_token_exempt_view(self
):
165 Check that if a CSRF cookie is present and no token, but the csrf_exempt
166 decorator has been applied to the view, the middleware lets it through
168 req
= self
._get
_POST
_csrf
_cookie
_request
()
169 req2
= CsrfViewMiddleware().process_view(req
, csrf_exempt(post_form_view
), (), {})
170 self
.assertEqual(None, req2
)
172 def test_csrf_token_in_header(self
):
174 Check that we can pass in the token in a header instead of in the form
176 req
= self
._get
_POST
_csrf
_cookie
_request
()
177 req
.META
['HTTP_X_CSRFTOKEN'] = self
._csrf
_id
178 req2
= CsrfViewMiddleware().process_view(req
, post_form_view
, (), {})
179 self
.assertEqual(None, req2
)
181 def test_put_and_delete_rejected(self
):
183 Tests that HTTP PUT and DELETE methods have protection
185 req
= TestingHttpRequest()
187 req2
= CsrfViewMiddleware().process_view(req
, post_form_view
, (), {})
188 self
.assertEqual(403, req2
.status_code
)
190 req
= TestingHttpRequest()
191 req
.method
= 'DELETE'
192 req2
= CsrfViewMiddleware().process_view(req
, post_form_view
, (), {})
193 self
.assertEqual(403, req2
.status_code
)
195 def test_put_and_delete_allowed(self
):
197 Tests that HTTP PUT and DELETE methods can get through with
198 X-CSRFToken and a cookie
200 req
= self
._get
_GET
_csrf
_cookie
_request
()
202 req
.META
['HTTP_X_CSRFTOKEN'] = self
._csrf
_id
203 req2
= CsrfViewMiddleware().process_view(req
, post_form_view
, (), {})
204 self
.assertEqual(None, req2
)
206 req
= self
._get
_GET
_csrf
_cookie
_request
()
207 req
.method
= 'DELETE'
208 req
.META
['HTTP_X_CSRFTOKEN'] = self
._csrf
_id
209 req2
= CsrfViewMiddleware().process_view(req
, post_form_view
, (), {})
210 self
.assertEqual(None, req2
)
212 # Tests for the template tag method
213 def test_token_node_no_csrf_cookie(self
):
215 Check that CsrfTokenNode works when no CSRF cookie is set
217 req
= self
._get
_GET
_no
_csrf
_cookie
_request
()
218 resp
= token_view(req
)
219 self
.assertEqual(u
"", resp
.content
)
221 def test_token_node_empty_csrf_cookie(self
):
223 Check that we get a new token if the csrf_cookie is the empty string
225 req
= self
._get
_GET
_no
_csrf
_cookie
_request
()
226 req
.COOKIES
[settings
.CSRF_COOKIE_NAME
] = ""
227 CsrfViewMiddleware().process_view(req
, token_view
, (), {})
228 resp
= token_view(req
)
230 self
.assertNotEqual(u
"", resp
.content
)
232 def test_token_node_with_csrf_cookie(self
):
234 Check that CsrfTokenNode works when a CSRF cookie is set
236 req
= self
._get
_GET
_csrf
_cookie
_request
()
237 CsrfViewMiddleware().process_view(req
, token_view
, (), {})
238 resp
= token_view(req
)
239 self
._check
_token
_present
(resp
)
241 def test_get_token_for_exempt_view(self
):
243 Check that get_token still works for a view decorated with 'csrf_exempt'.
245 req
= self
._get
_GET
_csrf
_cookie
_request
()
246 CsrfViewMiddleware().process_view(req
, csrf_exempt(token_view
), (), {})
247 resp
= token_view(req
)
248 self
._check
_token
_present
(resp
)
250 def test_get_token_for_requires_csrf_token_view(self
):
252 Check that get_token works for a view decorated solely with requires_csrf_token
254 req
= self
._get
_GET
_csrf
_cookie
_request
()
255 resp
= requires_csrf_token(token_view
)(req
)
256 self
._check
_token
_present
(resp
)
258 def test_token_node_with_new_csrf_cookie(self
):
260 Check that CsrfTokenNode works when a CSRF cookie is created by
261 the middleware (when one was not already present)
263 req
= self
._get
_GET
_no
_csrf
_cookie
_request
()
264 CsrfViewMiddleware().process_view(req
, token_view
, (), {})
265 resp
= token_view(req
)
266 resp2
= CsrfViewMiddleware().process_response(req
, resp
)
267 csrf_cookie
= resp2
.cookies
[settings
.CSRF_COOKIE_NAME
]
268 self
._check
_token
_present
(resp
, csrf_id
=csrf_cookie
.value
)
270 def test_https_bad_referer(self
):
272 Test that a POST HTTPS request with a bad referer is rejected
274 req
= self
._get
_POST
_request
_with
_token
()
275 req
._is
_secure
_override
= True
276 req
.META
['HTTP_HOST'] = 'www.example.com'
277 req
.META
['HTTP_REFERER'] = 'https://www.evil.org/somepage'
278 req2
= CsrfViewMiddleware().process_view(req
, post_form_view
, (), {})
279 self
.assertNotEqual(None, req2
)
280 self
.assertEqual(403, req2
.status_code
)
282 def test_https_good_referer(self
):
284 Test that a POST HTTPS request with a good referer is accepted
286 req
= self
._get
_POST
_request
_with
_token
()
287 req
._is
_secure
_override
= True
288 req
.META
['HTTP_HOST'] = 'www.example.com'
289 req
.META
['HTTP_REFERER'] = 'https://www.example.com/somepage'
290 req2
= CsrfViewMiddleware().process_view(req
, post_form_view
, (), {})
291 self
.assertEqual(None, req2
)
293 def test_https_good_referer_2(self
):
295 Test that a POST HTTPS request with a good referer is accepted
296 where the referer contains no trailing slash
299 req
= self
._get
_POST
_request
_with
_token
()
300 req
._is
_secure
_override
= True
301 req
.META
['HTTP_HOST'] = 'www.example.com'
302 req
.META
['HTTP_REFERER'] = 'https://www.example.com'
303 req2
= CsrfViewMiddleware().process_view(req
, post_form_view
, (), {})
304 self
.assertEqual(None, req2
)
306 def test_ensures_csrf_cookie_no_middleware(self
):
308 Tests that ensures_csrf_cookie decorator fulfils its promise
313 # Doesn't insert a token or anything
314 return HttpResponse(content
="")
316 req
= self
._get
_GET
_no
_csrf
_cookie
_request
()
318 self
.assertTrue(resp
.cookies
.get(settings
.CSRF_COOKIE_NAME
, False))
319 self
.assertTrue('Cookie' in resp
.get('Vary',''))
321 def test_ensures_csrf_cookie_with_middleware(self
):
323 Tests that ensures_csrf_cookie decorator fulfils its promise
324 with the middleware enabled.
328 # Doesn't insert a token or anything
329 return HttpResponse(content
="")
331 req
= self
._get
_GET
_no
_csrf
_cookie
_request
()
332 CsrfViewMiddleware().process_view(req
, view
, (), {})
334 resp2
= CsrfViewMiddleware().process_response(req
, resp
)
335 self
.assertTrue(resp2
.cookies
.get(settings
.CSRF_COOKIE_NAME
, False))
336 self
.assertTrue('Cookie' in resp2
.get('Vary',''))