tests.py 14 KB

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