tests.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. import logging
  4. from django.conf import settings
  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.template.context_processors import csrf
  9. from django.test import TestCase, 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.assertIn('Cookie', 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_malformed_referer(self):
  250. """
  251. Test that a POST HTTPS request with a bad referer is rejected
  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'] = 'http://http://www.example.com/'
  257. req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
  258. self.assertNotEqual(None, req2)
  259. self.assertEqual(403, req2.status_code)
  260. @override_settings(ALLOWED_HOSTS=['www.example.com'])
  261. def test_https_good_referer(self):
  262. """
  263. Test that a POST HTTPS request with a good referer is accepted
  264. """
  265. req = self._get_POST_request_with_token()
  266. req._is_secure_override = True
  267. req.META['HTTP_HOST'] = 'www.example.com'
  268. req.META['HTTP_REFERER'] = 'https://www.example.com/somepage'
  269. req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
  270. self.assertEqual(None, req2)
  271. @override_settings(ALLOWED_HOSTS=['www.example.com'])
  272. def test_https_good_referer_2(self):
  273. """
  274. Test that a POST HTTPS request with a good referer is accepted
  275. where the referer contains no trailing slash
  276. """
  277. # See ticket #15617
  278. req = self._get_POST_request_with_token()
  279. req._is_secure_override = True
  280. req.META['HTTP_HOST'] = 'www.example.com'
  281. req.META['HTTP_REFERER'] = 'https://www.example.com'
  282. req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
  283. self.assertEqual(None, req2)
  284. def test_ensures_csrf_cookie_no_middleware(self):
  285. """
  286. Tests that ensures_csrf_cookie decorator fulfils its promise
  287. with no middleware
  288. """
  289. @ensure_csrf_cookie
  290. def view(request):
  291. # Doesn't insert a token or anything
  292. return HttpResponse(content="")
  293. req = self._get_GET_no_csrf_cookie_request()
  294. resp = view(req)
  295. self.assertTrue(resp.cookies.get(settings.CSRF_COOKIE_NAME, False))
  296. self.assertIn('Cookie', resp.get('Vary', ''))
  297. def test_ensures_csrf_cookie_with_middleware(self):
  298. """
  299. Tests that ensures_csrf_cookie decorator fulfils its promise
  300. with the middleware enabled.
  301. """
  302. @ensure_csrf_cookie
  303. def view(request):
  304. # Doesn't insert a token or anything
  305. return HttpResponse(content="")
  306. req = self._get_GET_no_csrf_cookie_request()
  307. CsrfViewMiddleware().process_view(req, view, (), {})
  308. resp = view(req)
  309. resp2 = CsrfViewMiddleware().process_response(req, resp)
  310. self.assertTrue(resp2.cookies.get(settings.CSRF_COOKIE_NAME, False))
  311. self.assertIn('Cookie', resp2.get('Vary', ''))
  312. def test_ensures_csrf_cookie_no_logging(self):
  313. """
  314. Tests that ensure_csrf_cookie doesn't log warnings. See #19436.
  315. """
  316. @ensure_csrf_cookie
  317. def view(request):
  318. # Doesn't insert a token or anything
  319. return HttpResponse(content="")
  320. class TestHandler(logging.Handler):
  321. def emit(self, record):
  322. raise Exception("This shouldn't have happened!")
  323. logger = logging.getLogger('django.request')
  324. test_handler = TestHandler()
  325. old_log_level = logger.level
  326. try:
  327. logger.addHandler(test_handler)
  328. logger.setLevel(logging.WARNING)
  329. req = self._get_GET_no_csrf_cookie_request()
  330. view(req)
  331. finally:
  332. logger.removeHandler(test_handler)
  333. logger.setLevel(old_log_level)
  334. def test_csrf_cookie_age(self):
  335. """
  336. Test to verify CSRF cookie age can be set using
  337. settings.CSRF_COOKIE_AGE.
  338. """
  339. req = self._get_GET_no_csrf_cookie_request()
  340. MAX_AGE = 123
  341. with self.settings(CSRF_COOKIE_NAME='csrfcookie',
  342. CSRF_COOKIE_DOMAIN='.example.com',
  343. CSRF_COOKIE_AGE=MAX_AGE,
  344. CSRF_COOKIE_PATH='/test/',
  345. CSRF_COOKIE_SECURE=True,
  346. CSRF_COOKIE_HTTPONLY=True):
  347. # token_view calls get_token() indirectly
  348. CsrfViewMiddleware().process_view(req, token_view, (), {})
  349. resp = token_view(req)
  350. resp2 = CsrfViewMiddleware().process_response(req, resp)
  351. max_age = resp2.cookies.get('csrfcookie').get('max-age')
  352. self.assertEqual(max_age, MAX_AGE)
  353. def test_csrf_cookie_age_none(self):
  354. """
  355. Test to verify CSRF cookie age does not have max age set and therefore
  356. uses session-based cookies.
  357. """
  358. req = self._get_GET_no_csrf_cookie_request()
  359. MAX_AGE = None
  360. with self.settings(CSRF_COOKIE_NAME='csrfcookie',
  361. CSRF_COOKIE_DOMAIN='.example.com',
  362. CSRF_COOKIE_AGE=MAX_AGE,
  363. CSRF_COOKIE_PATH='/test/',
  364. CSRF_COOKIE_SECURE=True,
  365. CSRF_COOKIE_HTTPONLY=True):
  366. # token_view calls get_token() indirectly
  367. CsrfViewMiddleware().process_view(req, token_view, (), {})
  368. resp = token_view(req)
  369. resp2 = CsrfViewMiddleware().process_response(req, resp)
  370. max_age = resp2.cookies.get('csrfcookie').get('max-age')
  371. self.assertEqual(max_age, '')
  372. def test_post_data_read_failure(self):
  373. """
  374. #20128 -- IOErrors during POST data reading should be caught and
  375. treated as if the POST data wasn't there.
  376. """
  377. class CsrfPostRequest(HttpRequest):
  378. """
  379. HttpRequest that can raise an IOError when accessing POST data
  380. """
  381. def __init__(self, token, raise_error):
  382. super(CsrfPostRequest, self).__init__()
  383. self.method = 'POST'
  384. self.raise_error = False
  385. self.COOKIES[settings.CSRF_COOKIE_NAME] = token
  386. self.POST['csrfmiddlewaretoken'] = token
  387. self.raise_error = raise_error
  388. def _load_post_and_files(self):
  389. raise IOError('error reading input data')
  390. def _get_post(self):
  391. if self.raise_error:
  392. self._load_post_and_files()
  393. return self._post
  394. def _set_post(self, post):
  395. self._post = post
  396. POST = property(_get_post, _set_post)
  397. token = 'ABC'
  398. req = CsrfPostRequest(token, raise_error=False)
  399. resp = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
  400. self.assertEqual(resp, None)
  401. req = CsrfPostRequest(token, raise_error=True)
  402. resp = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
  403. self.assertEqual(resp.status_code, 403)