diff options
author | django-bot <ops@djangoproject.com> | 2022-02-03 20:24:19 +0100 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2022-02-07 20:37:05 +0100 |
commit | 9c19aff7c7561e3a82978a272ecdaad40dda5c00 (patch) | |
tree | f0506b668a013d0063e5fba3dbf4863b466713ba /tests/csrf_tests | |
parent | f68fa8b45dfac545cfc4111d4e52804c86db68d3 (diff) | |
download | django-9c19aff7c7561e3a82978a272ecdaad40dda5c00.tar.gz |
Refs #33476 -- Reformatted code with Black.
Diffstat (limited to 'tests/csrf_tests')
-rw-r--r-- | tests/csrf_tests/csrf_token_error_handler_urls.py | 2 | ||||
-rw-r--r-- | tests/csrf_tests/test_context_processor.py | 7 | ||||
-rw-r--r-- | tests/csrf_tests/tests.py | 595 | ||||
-rw-r--r-- | tests/csrf_tests/views.py | 20 |
4 files changed, 354 insertions, 270 deletions
diff --git a/tests/csrf_tests/csrf_token_error_handler_urls.py b/tests/csrf_tests/csrf_token_error_handler_urls.py index 3c02f613ec..f7007d740b 100644 --- a/tests/csrf_tests/csrf_token_error_handler_urls.py +++ b/tests/csrf_tests/csrf_token_error_handler_urls.py @@ -1,3 +1,3 @@ urlpatterns = [] -handler404 = 'csrf_tests.views.csrf_token_error_handler' +handler404 = "csrf_tests.views.csrf_token_error_handler" diff --git a/tests/csrf_tests/test_context_processor.py b/tests/csrf_tests/test_context_processor.py index 26a2b7aedb..903237d68f 100644 --- a/tests/csrf_tests/test_context_processor.py +++ b/tests/csrf_tests/test_context_processor.py @@ -6,10 +6,9 @@ from .tests import CsrfFunctionTestMixin class TestContextProcessor(CsrfFunctionTestMixin, SimpleTestCase): - def test_force_token_to_string(self): request = HttpRequest() - test_secret = 32 * 'a' - request.META['CSRF_COOKIE'] = test_secret - token = csrf(request).get('csrf_token') + test_secret = 32 * "a" + request.META["CSRF_COOKIE"] = test_secret + token = csrf(request).get("csrf_token") self.assertMaskedSecretCorrect(token, test_secret) diff --git a/tests/csrf_tests/tests.py b/tests/csrf_tests/tests.py index 71e75854db..6c8f5e1f04 100644 --- a/tests/csrf_tests/tests.py +++ b/tests/csrf_tests/tests.py @@ -5,11 +5,22 @@ from django.contrib.sessions.backends.cache import SessionStore from django.core.exceptions import ImproperlyConfigured from django.http import HttpRequest, HttpResponse, UnreadablePostError from django.middleware.csrf import ( - CSRF_ALLOWED_CHARS, CSRF_SECRET_LENGTH, CSRF_SESSION_KEY, - CSRF_TOKEN_LENGTH, REASON_BAD_ORIGIN, REASON_CSRF_TOKEN_MISSING, - REASON_NO_CSRF_COOKIE, CsrfViewMiddleware, InvalidTokenFormat, - RejectRequest, _check_token_format, _does_token_match, _mask_cipher_secret, - _unmask_cipher_token, get_token, rotate_token, + CSRF_ALLOWED_CHARS, + CSRF_SECRET_LENGTH, + CSRF_SESSION_KEY, + CSRF_TOKEN_LENGTH, + REASON_BAD_ORIGIN, + REASON_CSRF_TOKEN_MISSING, + REASON_NO_CSRF_COOKIE, + CsrfViewMiddleware, + InvalidTokenFormat, + RejectRequest, + _check_token_format, + _does_token_match, + _mask_cipher_secret, + _unmask_cipher_token, + get_token, + rotate_token, ) from django.test import SimpleTestCase, override_settings from django.test.utils import ignore_warnings @@ -17,16 +28,20 @@ from django.utils.deprecation import RemovedInDjango50Warning from django.views.decorators.csrf import csrf_exempt, requires_csrf_token from .views import ( - ensure_csrf_cookie_view, ensured_and_protected_view, - non_token_view_using_request_processor, post_form_view, protected_view, - sandwiched_rotate_token_view, token_view, + ensure_csrf_cookie_view, + ensured_and_protected_view, + non_token_view_using_request_processor, + post_form_view, + protected_view, + sandwiched_rotate_token_view, + token_view, ) # This is a test (unmasked) CSRF cookie / secret. -TEST_SECRET = 'lcccccccX2kcccccccY2jcccccccssIC' +TEST_SECRET = "lcccccccX2kcccccccY2jcccccccssIC" # Two masked versions of TEST_SECRET for testing purposes. -MASKED_TEST_SECRET1 = '1bcdefghij2bcdefghij3bcdefghij4bcdefghij5bcdefghij6bcdefghijABCD' -MASKED_TEST_SECRET2 = '2JgchWvM1tpxT2lfz9aydoXW9yT1DN3NdLiejYxOOlzzV4nhBbYqmqZYbAV3V5Bf' +MASKED_TEST_SECRET1 = "1bcdefghij2bcdefghij3bcdefghij4bcdefghij5bcdefghij6bcdefghijABCD" +MASKED_TEST_SECRET2 = "2JgchWvM1tpxT2lfz9aydoXW9yT1DN3NdLiejYxOOlzzV4nhBbYqmqZYbAV3V5Bf" class CsrfFunctionTestMixin: @@ -38,27 +53,26 @@ class CsrfFunctionTestMixin: self.assertEqual(len(secret), CSRF_SECRET_LENGTH) self.assertTrue( set(masked_secret).issubset(set(CSRF_ALLOWED_CHARS)), - msg=f'invalid characters in {masked_secret!r}', + msg=f"invalid characters in {masked_secret!r}", ) actual = _unmask_cipher_token(masked_secret) self.assertEqual(actual, secret) class CsrfFunctionTests(CsrfFunctionTestMixin, SimpleTestCase): - def test_unmask_cipher_token(self): cases = [ (TEST_SECRET, MASKED_TEST_SECRET1), (TEST_SECRET, MASKED_TEST_SECRET2), ( - 32 * 'a', - 'vFioG3XOLyGyGsPRFyB9iYUs341ufzIEvFioG3XOLyGyGsPRFyB9iYUs341ufzIE', + 32 * "a", + "vFioG3XOLyGyGsPRFyB9iYUs341ufzIEvFioG3XOLyGyGsPRFyB9iYUs341ufzIE", ), - (32 * 'a', 64 * 'a'), - (32 * 'a', 64 * 'b'), - (32 * 'b', 32 * 'a' + 32 * 'b'), - (32 * 'b', 32 * 'b' + 32 * 'c'), - (32 * 'c', 32 * 'a' + 32 * 'c'), + (32 * "a", 64 * "a"), + (32 * "a", 64 * "b"), + (32 * "b", 32 * "a" + 32 * "b"), + (32 * "b", 32 * "b" + 32 * "c"), + (32 * "c", 32 * "a" + 32 * "c"), ] for secret, masked_secret in cases: with self.subTest(masked_secret=masked_secret): @@ -67,9 +81,9 @@ class CsrfFunctionTests(CsrfFunctionTestMixin, SimpleTestCase): def test_mask_cipher_secret(self): cases = [ - 32 * 'a', + 32 * "a", TEST_SECRET, - 'da4SrUiHJYoJ0HYQ0vcgisoIuFOxx4ER', + "da4SrUiHJYoJ0HYQ0vcgisoIuFOxx4ER", ] for secret in cases: with self.subTest(secret=secret): @@ -78,33 +92,33 @@ class CsrfFunctionTests(CsrfFunctionTestMixin, SimpleTestCase): def test_get_token_csrf_cookie_set(self): request = HttpRequest() - request.META['CSRF_COOKIE'] = TEST_SECRET - self.assertNotIn('CSRF_COOKIE_NEEDS_UPDATE', request.META) + request.META["CSRF_COOKIE"] = TEST_SECRET + self.assertNotIn("CSRF_COOKIE_NEEDS_UPDATE", request.META) token = get_token(request) self.assertMaskedSecretCorrect(token, TEST_SECRET) # The existing cookie is preserved. - self.assertEqual(request.META['CSRF_COOKIE'], TEST_SECRET) - self.assertIs(request.META['CSRF_COOKIE_NEEDS_UPDATE'], True) + self.assertEqual(request.META["CSRF_COOKIE"], TEST_SECRET) + self.assertIs(request.META["CSRF_COOKIE_NEEDS_UPDATE"], True) def test_get_token_csrf_cookie_not_set(self): request = HttpRequest() - self.assertNotIn('CSRF_COOKIE', request.META) - self.assertNotIn('CSRF_COOKIE_NEEDS_UPDATE', request.META) + self.assertNotIn("CSRF_COOKIE", request.META) + self.assertNotIn("CSRF_COOKIE_NEEDS_UPDATE", request.META) token = get_token(request) - cookie = request.META['CSRF_COOKIE'] + cookie = request.META["CSRF_COOKIE"] self.assertMaskedSecretCorrect(token, cookie) - self.assertIs(request.META['CSRF_COOKIE_NEEDS_UPDATE'], True) + self.assertIs(request.META["CSRF_COOKIE_NEEDS_UPDATE"], True) def test_rotate_token(self): request = HttpRequest() - request.META['CSRF_COOKIE'] = TEST_SECRET - self.assertNotIn('CSRF_COOKIE_NEEDS_UPDATE', request.META) + request.META["CSRF_COOKIE"] = TEST_SECRET + self.assertNotIn("CSRF_COOKIE_NEEDS_UPDATE", request.META) rotate_token(request) # The underlying secret was changed. - cookie = request.META['CSRF_COOKIE'] + cookie = request.META["CSRF_COOKIE"] self.assertEqual(len(cookie), CSRF_SECRET_LENGTH) self.assertNotEqual(cookie, TEST_SECRET) - self.assertIs(request.META['CSRF_COOKIE_NEEDS_UPDATE'], True) + self.assertIs(request.META["CSRF_COOKIE_NEEDS_UPDATE"], True) def test_check_token_format_valid(self): cases = [ @@ -112,7 +126,7 @@ class CsrfFunctionTests(CsrfFunctionTestMixin, SimpleTestCase): TEST_SECRET, # A token of length CSRF_TOKEN_LENGTH. MASKED_TEST_SECRET1, - 64 * 'a', + 64 * "a", ] for token in cases: with self.subTest(token=token): @@ -121,8 +135,8 @@ class CsrfFunctionTests(CsrfFunctionTestMixin, SimpleTestCase): def test_check_token_format_invalid(self): cases = [ - (64 * '*', 'has invalid characters'), - (16 * 'a', 'has incorrect length'), + (64 * "*", "has invalid characters"), + (16 * "a", "has incorrect length"), ] for token, expected_message in cases: with self.subTest(token=token): @@ -134,13 +148,13 @@ class CsrfFunctionTests(CsrfFunctionTestMixin, SimpleTestCase): # Masked tokens match. ((MASKED_TEST_SECRET1, TEST_SECRET), True), ((MASKED_TEST_SECRET2, TEST_SECRET), True), - ((64 * 'a', _unmask_cipher_token(64 * 'a')), True), + ((64 * "a", _unmask_cipher_token(64 * "a")), True), # Unmasked tokens match. ((TEST_SECRET, TEST_SECRET), True), - ((32 * 'a', 32 * 'a'), True), + ((32 * "a", 32 * "a"), True), # Incorrect tokens don't match. - ((32 * 'a', TEST_SECRET), False), - ((64 * 'a', TEST_SECRET), False), + ((32 * "a", TEST_SECRET), False), + ((64 * "a", TEST_SECRET), False), ] for (token, secret), expected in cases: with self.subTest(token=token, secret=secret): @@ -149,7 +163,7 @@ class CsrfFunctionTests(CsrfFunctionTestMixin, SimpleTestCase): def test_does_token_match_wrong_token_length(self): with self.assertRaises(AssertionError): - _does_token_match(16 * 'a', TEST_SECRET) + _does_token_match(16 * "a", TEST_SECRET) class TestingSessionStore(SessionStore): @@ -157,6 +171,7 @@ class TestingSessionStore(SessionStore): A version of SessionStore that stores what cookie values are passed to set_cookie() when CSRF_USE_SESSIONS=True. """ + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # This is a list of the cookie values passed to set_cookie() over @@ -173,18 +188,20 @@ class TestingHttpRequest(HttpRequest): A version of HttpRequest that lets one track and change some things more easily. """ + def __init__(self): super().__init__() self.session = TestingSessionStore() def is_secure(self): - return getattr(self, '_is_secure_override', False) + return getattr(self, "_is_secure_override", False) class PostErrorRequest(TestingHttpRequest): """ TestingHttpRequest that can raise errors when accessing POST data. """ + post_error = None def _get_post(self): @@ -207,24 +224,24 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): _csrf_id_token = MASKED_TEST_SECRET2 def _set_csrf_cookie(self, req, cookie): - raise NotImplementedError('This method must be implemented by a subclass.') + raise NotImplementedError("This method must be implemented by a subclass.") def _read_csrf_cookie(self, req, resp): """ Return the CSRF cookie as a string, or False if no cookie is present. """ - raise NotImplementedError('This method must be implemented by a subclass.') + raise NotImplementedError("This method must be implemented by a subclass.") def _get_cookies_set(self, req, resp): """ Return a list of the cookie values passed to set_cookie() over the course of the request-response. """ - raise NotImplementedError('This method must be implemented by a subclass.') + raise NotImplementedError("This method must be implemented by a subclass.") def _get_request(self, method=None, cookie=None, request_class=None): if method is None: - method = 'GET' + method = "GET" if request_class is None: request_class = TestingHttpRequest req = request_class() @@ -234,8 +251,13 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): return req def _get_csrf_cookie_request( - self, method=None, cookie=None, post_token=None, meta_token=None, - token_header=None, request_class=None, + self, + method=None, + cookie=None, + post_token=None, + meta_token=None, + token_header=None, + request_class=None, ): """ The method argument defaults to "GET". The cookie argument defaults to @@ -248,25 +270,32 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): if cookie is None: cookie = self._csrf_id_cookie if token_header is None: - token_header = 'HTTP_X_CSRFTOKEN' + token_header = "HTTP_X_CSRFTOKEN" req = self._get_request( method=method, cookie=cookie, request_class=request_class, ) if post_token is not None: - req.POST['csrfmiddlewaretoken'] = post_token + req.POST["csrfmiddlewaretoken"] = post_token if meta_token is not None: req.META[token_header] = meta_token return req def _get_POST_csrf_cookie_request( - self, cookie=None, post_token=None, meta_token=None, token_header=None, + self, + cookie=None, + post_token=None, + meta_token=None, + token_header=None, request_class=None, ): return self._get_csrf_cookie_request( - method='POST', cookie=cookie, post_token=post_token, - meta_token=meta_token, token_header=token_header, + method="POST", + cookie=cookie, + post_token=post_token, + meta_token=meta_token, + token_header=token_header, request_class=request_class, ) @@ -285,7 +314,8 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): text = str(response.content, response.charset) match = re.search('name="csrfmiddlewaretoken" value="(.*?)"', text) self.assertTrue( - match, f'Could not find a csrfmiddlewaretoken value in: {text}', + match, + f"Could not find a csrfmiddlewaretoken value in: {text}", ) csrf_token = match[1] self.assertMaskedSecretCorrect(csrf_token, csrf_secret) @@ -313,13 +343,13 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): def _check_bad_or_missing_cookie(self, cookie, expected): """Passing None for cookie includes no cookie.""" - req = self._get_request(method='POST', cookie=cookie) + req = self._get_request(method="POST", cookie=cookie) mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) - with self.assertLogs('django.security.csrf', 'WARNING') as cm: + with self.assertLogs("django.security.csrf", "WARNING") as cm: resp = mw.process_view(req, post_form_view, (), {}) self.assertEqual(403, resp.status_code) - self.assertEqual(cm.records[0].getMessage(), 'Forbidden (%s): ' % expected) + self.assertEqual(cm.records[0].getMessage(), "Forbidden (%s): " % expected) def test_no_csrf_cookie(self): """ @@ -329,7 +359,11 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): self._check_bad_or_missing_cookie(None, REASON_NO_CSRF_COOKIE) def _check_bad_or_missing_token( - self, expected, post_token=None, meta_token=None, token_header=None, + self, + expected, + post_token=None, + meta_token=None, + token_header=None, ): req = self._get_POST_csrf_cookie_request( post_token=post_token, @@ -338,10 +372,10 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): ) mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) - with self.assertLogs('django.security.csrf', 'WARNING') as cm: + with self.assertLogs("django.security.csrf", "WARNING") as cm: resp = mw.process_view(req, post_form_view, (), {}) self.assertEqual(403, resp.status_code) - self.assertEqual(cm.records[0].getMessage(), 'Forbidden (%s): ' % expected) + self.assertEqual(cm.records[0].getMessage(), "Forbidden (%s): " % expected) def test_csrf_cookie_bad_or_missing_token(self): """ @@ -350,22 +384,22 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): """ cases = [ (None, None, REASON_CSRF_TOKEN_MISSING), - (16 * 'a', None, 'CSRF token from POST has incorrect length.'), - (64 * '*', None, 'CSRF token from POST has invalid characters.'), - (64 * 'a', None, 'CSRF token from POST incorrect.'), + (16 * "a", None, "CSRF token from POST has incorrect length."), + (64 * "*", None, "CSRF token from POST has invalid characters."), + (64 * "a", None, "CSRF token from POST incorrect."), ( None, - 16 * 'a', + 16 * "a", "CSRF token from the 'X-Csrftoken' HTTP header has incorrect length.", ), ( None, - 64 * '*', + 64 * "*", "CSRF token from the 'X-Csrftoken' HTTP header has invalid characters.", ), ( None, - 64 * 'a', + 64 * "a", "CSRF token from the 'X-Csrftoken' HTTP header incorrect.", ), ] @@ -377,7 +411,7 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): meta_token=meta_token, ) - @override_settings(CSRF_HEADER_NAME='HTTP_X_CSRFTOKEN_CUSTOMIZED') + @override_settings(CSRF_HEADER_NAME="HTTP_X_CSRFTOKEN_CUSTOMIZED") def test_csrf_cookie_bad_token_custom_header(self): """ If a CSRF cookie is present and an invalid token is passed via a @@ -389,8 +423,8 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): ) self._check_bad_or_missing_token( expected, - meta_token=16 * 'a', - token_header='HTTP_X_CSRFTOKEN_CUSTOMIZED', + meta_token=16 * "a", + token_header="HTTP_X_CSRFTOKEN_CUSTOMIZED", ) def test_process_request_csrf_cookie_and_token(self): @@ -424,14 +458,14 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp) - @override_settings(CSRF_HEADER_NAME='HTTP_X_CSRFTOKEN_CUSTOMIZED') + @override_settings(CSRF_HEADER_NAME="HTTP_X_CSRFTOKEN_CUSTOMIZED") def test_csrf_token_in_header_with_customized_name(self): """ settings.CSRF_HEADER_NAME can be used to customize the CSRF header name """ req = self._get_POST_csrf_cookie_request( meta_token=self._csrf_id_token, - token_header='HTTP_X_CSRFTOKEN_CUSTOMIZED', + token_header="HTTP_X_CSRFTOKEN_CUSTOMIZED", ) mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) @@ -442,30 +476,38 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): """ HTTP PUT and DELETE methods have protection """ - req = self._get_request(method='PUT') + req = self._get_request(method="PUT") mw = CsrfViewMiddleware(post_form_view) - with self.assertLogs('django.security.csrf', 'WARNING') as cm: + with self.assertLogs("django.security.csrf", "WARNING") as cm: resp = mw.process_view(req, post_form_view, (), {}) self.assertEqual(403, resp.status_code) - self.assertEqual(cm.records[0].getMessage(), 'Forbidden (%s): ' % REASON_NO_CSRF_COOKIE) + self.assertEqual( + cm.records[0].getMessage(), "Forbidden (%s): " % REASON_NO_CSRF_COOKIE + ) - req = self._get_request(method='DELETE') - with self.assertLogs('django.security.csrf', 'WARNING') as cm: + req = self._get_request(method="DELETE") + with self.assertLogs("django.security.csrf", "WARNING") as cm: resp = mw.process_view(req, post_form_view, (), {}) self.assertEqual(403, resp.status_code) - self.assertEqual(cm.records[0].getMessage(), 'Forbidden (%s): ' % REASON_NO_CSRF_COOKIE) + self.assertEqual( + cm.records[0].getMessage(), "Forbidden (%s): " % REASON_NO_CSRF_COOKIE + ) def test_put_and_delete_allowed(self): """ HTTP PUT and DELETE can get through with X-CSRFToken and a cookie. """ - req = self._get_csrf_cookie_request(method='PUT', meta_token=self._csrf_id_token) + req = self._get_csrf_cookie_request( + method="PUT", meta_token=self._csrf_id_token + ) mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp) - req = self._get_csrf_cookie_request(method='DELETE', meta_token=self._csrf_id_token) + req = self._get_csrf_cookie_request( + method="DELETE", meta_token=self._csrf_id_token + ) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp) @@ -478,7 +520,7 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): """ req = self._get_POST_request_with_token() resp = sandwiched_rotate_token_view(req) - self.assertContains(resp, 'OK') + self.assertContains(resp, "OK") actual_secret = self._read_csrf_cookie(req, resp) # set_cookie() was called a second time with a different secret. cookies_set = self._get_cookies_set(req, resp) @@ -504,7 +546,7 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): """ A new token is sent if the csrf_cookie is the empty string. """ - req = self._get_request(cookie='') + req = self._get_request(cookie="") mw = CsrfViewMiddleware(token_view) mw.process_view(req, token_view, (), {}) resp = token_view(req) @@ -569,26 +611,27 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): resp = mw(req) csrf_cookie = self._read_csrf_cookie(req, resp) self.assertEqual( - csrf_cookie, TEST_SECRET, - 'CSRF cookie was changed on an accepted request', + csrf_cookie, + TEST_SECRET, + "CSRF cookie was changed on an accepted request", ) - @override_settings(DEBUG=True, ALLOWED_HOSTS=['www.example.com']) + @override_settings(DEBUG=True, ALLOWED_HOSTS=["www.example.com"]) def test_https_bad_referer(self): """ A POST HTTPS request with a bad referer is rejected """ req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_REFERER'] = 'https://www.evil.org/somepage' - req.META['SERVER_PORT'] = '443' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_REFERER"] = "https://www.evil.org/somepage" + req.META["SERVER_PORT"] = "443" mw = CsrfViewMiddleware(post_form_view) response = mw.process_view(req, post_form_view, (), {}) self.assertContains( response, - 'Referer checking failed - https://www.evil.org/somepage does not ' - 'match any trusted origins.', + "Referer checking failed - https://www.evil.org/somepage does not " + "match any trusted origins.", status_code=403, ) @@ -606,7 +649,7 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): response = mw.process_view(req, post_form_view, (), {}) self.assertContains( response, - 'Referer checking failed - no Referer.', + "Referer checking failed - no Referer.", status_code=403, ) @@ -615,15 +658,15 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): CsrfViewMiddleware generates a 403 response if it receives an HTTPS request with a bad host. """ - req = self._get_request(method='POST') + req = self._get_request(method="POST") req._is_secure_override = True - req.META['HTTP_HOST'] = '@malformed' - req.META['HTTP_REFERER'] = 'https://www.evil.org/somepage' - req.META['SERVER_PORT'] = '443' + req.META["HTTP_HOST"] = "@malformed" + req.META["HTTP_REFERER"] = "https://www.evil.org/somepage" + req.META["SERVER_PORT"] = "443" mw = CsrfViewMiddleware(token_view) expected = ( - 'Referer checking failed - https://www.evil.org/somepage does not ' - 'match any trusted origins.' + "Referer checking failed - https://www.evil.org/somepage does not " + "match any trusted origins." ) with self.assertRaisesMessage(RejectRequest, expected): mw._check_referer(req) @@ -631,10 +674,10 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): self.assertEqual(response.status_code, 403) def test_origin_malformed_host(self): - req = self._get_request(method='POST') + req = self._get_request(method="POST") req._is_secure_override = True - req.META['HTTP_HOST'] = '@malformed' - req.META['HTTP_ORIGIN'] = 'https://www.evil.org' + req.META["HTTP_HOST"] = "@malformed" + req.META["HTTP_ORIGIN"] = "https://www.evil.org" mw = CsrfViewMiddleware(token_view) self._check_referer_rejects(mw, req) response = mw.process_view(req, token_view, (), {}) @@ -645,65 +688,65 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): """ A POST HTTPS request with a bad referer is rejected. """ - malformed_referer_msg = 'Referer checking failed - Referer is malformed.' + malformed_referer_msg = "Referer checking failed - Referer is malformed." req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_REFERER'] = 'http://http://www.example.com/' + req.META["HTTP_REFERER"] = "http://http://www.example.com/" mw = CsrfViewMiddleware(post_form_view) self._check_referer_rejects(mw, req) response = mw.process_view(req, post_form_view, (), {}) self.assertContains( response, - 'Referer checking failed - Referer is insecure while host is secure.', + "Referer checking failed - Referer is insecure while host is secure.", status_code=403, ) # Empty - req.META['HTTP_REFERER'] = '' + req.META["HTTP_REFERER"] = "" self._check_referer_rejects(mw, req) response = mw.process_view(req, post_form_view, (), {}) self.assertContains(response, malformed_referer_msg, status_code=403) # Non-ASCII - req.META['HTTP_REFERER'] = 'ØBöIß' + req.META["HTTP_REFERER"] = "ØBöIß" self._check_referer_rejects(mw, req) response = mw.process_view(req, post_form_view, (), {}) self.assertContains(response, malformed_referer_msg, status_code=403) # missing scheme # >>> urlparse('//example.com/') # ParseResult(scheme='', netloc='example.com', path='/', params='', query='', fragment='') - req.META['HTTP_REFERER'] = '//example.com/' + req.META["HTTP_REFERER"] = "//example.com/" self._check_referer_rejects(mw, req) response = mw.process_view(req, post_form_view, (), {}) self.assertContains(response, malformed_referer_msg, status_code=403) # missing netloc # >>> urlparse('https://') # ParseResult(scheme='https', netloc='', path='', params='', query='', fragment='') - req.META['HTTP_REFERER'] = 'https://' + req.META["HTTP_REFERER"] = "https://" self._check_referer_rejects(mw, req) response = mw.process_view(req, post_form_view, (), {}) self.assertContains(response, malformed_referer_msg, status_code=403) # Invalid URL # >>> urlparse('https://[') # ValueError: Invalid IPv6 URL - req.META['HTTP_REFERER'] = 'https://[' + req.META["HTTP_REFERER"] = "https://[" self._check_referer_rejects(mw, req) response = mw.process_view(req, post_form_view, (), {}) self.assertContains(response, malformed_referer_msg, status_code=403) - @override_settings(ALLOWED_HOSTS=['www.example.com']) + @override_settings(ALLOWED_HOSTS=["www.example.com"]) def test_https_good_referer(self): """ A POST HTTPS request with a good referer is accepted. """ req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_REFERER'] = 'https://www.example.com/somepage' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_REFERER"] = "https://www.example.com/somepage" mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp) - @override_settings(ALLOWED_HOSTS=['www.example.com']) + @override_settings(ALLOWED_HOSTS=["www.example.com"]) def test_https_good_referer_2(self): """ A POST HTTPS request with a good referer is accepted where the referer @@ -712,8 +755,8 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): # See ticket #15617 req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_REFERER'] = 'https://www.example.com' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_REFERER"] = "https://www.example.com" mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) @@ -722,19 +765,21 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): def _test_https_good_referer_behind_proxy(self): req = self._get_POST_request_with_token() req._is_secure_override = True - req.META.update({ - 'HTTP_HOST': '10.0.0.2', - 'HTTP_REFERER': 'https://www.example.com/somepage', - 'SERVER_PORT': '8080', - 'HTTP_X_FORWARDED_HOST': 'www.example.com', - 'HTTP_X_FORWARDED_PORT': '443', - }) + req.META.update( + { + "HTTP_HOST": "10.0.0.2", + "HTTP_REFERER": "https://www.example.com/somepage", + "SERVER_PORT": "8080", + "HTTP_X_FORWARDED_HOST": "www.example.com", + "HTTP_X_FORWARDED_PORT": "443", + } + ) mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp) - @override_settings(CSRF_TRUSTED_ORIGINS=['https://dashboard.example.com']) + @override_settings(CSRF_TRUSTED_ORIGINS=["https://dashboard.example.com"]) def test_https_good_referer_malformed_host(self): """ A POST HTTPS request is accepted if it receives a good referer with @@ -742,14 +787,17 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): """ req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_HOST'] = '@malformed' - req.META['HTTP_REFERER'] = 'https://dashboard.example.com/somepage' + req.META["HTTP_HOST"] = "@malformed" + req.META["HTTP_REFERER"] = "https://dashboard.example.com/somepage" mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp) - @override_settings(ALLOWED_HOSTS=['www.example.com'], CSRF_TRUSTED_ORIGINS=['https://dashboard.example.com']) + @override_settings( + ALLOWED_HOSTS=["www.example.com"], + CSRF_TRUSTED_ORIGINS=["https://dashboard.example.com"], + ) def test_https_csrf_trusted_origin_allowed(self): """ A POST HTTPS request with a referer added to the CSRF_TRUSTED_ORIGINS @@ -757,14 +805,17 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): """ req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_REFERER'] = 'https://dashboard.example.com' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_REFERER"] = "https://dashboard.example.com" mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp) - @override_settings(ALLOWED_HOSTS=['www.example.com'], CSRF_TRUSTED_ORIGINS=['https://*.example.com']) + @override_settings( + ALLOWED_HOSTS=["www.example.com"], + CSRF_TRUSTED_ORIGINS=["https://*.example.com"], + ) def test_https_csrf_wildcard_trusted_origin_allowed(self): """ A POST HTTPS request with a referer that matches a CSRF_TRUSTED_ORIGINS @@ -772,8 +823,8 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): """ req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_REFERER'] = 'https://dashboard.example.com' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_REFERER"] = "https://dashboard.example.com" mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) response = mw.process_view(req, post_form_view, (), {}) @@ -782,8 +833,8 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): def _test_https_good_referer_matches_cookie_domain(self): req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_REFERER'] = 'https://foo.example.com/' - req.META['SERVER_PORT'] = '443' + req.META["HTTP_REFERER"] = "https://foo.example.com/" + req.META["SERVER_PORT"] = "443" mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) response = mw.process_view(req, post_form_view, (), {}) @@ -792,9 +843,9 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): def _test_https_good_referer_matches_cookie_domain_with_different_port(self): req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_REFERER'] = 'https://foo.example.com:4443/' - req.META['SERVER_PORT'] = '4443' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_REFERER"] = "https://foo.example.com:4443/" + req.META["SERVER_PORT"] = "4443" mw = CsrfViewMiddleware(post_form_view) mw.process_request(req) response = mw.process_view(req, post_form_view, (), {}) @@ -804,7 +855,7 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): """ ensure_csrf_cookie() doesn't log warnings (#19436). """ - with self.assertNoLogs('django.request', 'WARNING'): + with self.assertNoLogs("django.request", "WARNING"): req = self._get_request() ensure_csrf_cookie_view(req) @@ -820,14 +871,14 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): self.assertIsNone(resp) req = self._get_POST_request_with_token(request_class=PostErrorRequest) - req.post_error = UnreadablePostError('Error reading input data.') + req.post_error = UnreadablePostError("Error reading input data.") mw.process_request(req) - with self.assertLogs('django.security.csrf', 'WARNING') as cm: + with self.assertLogs("django.security.csrf", "WARNING") as cm: resp = mw.process_view(req, post_form_view, (), {}) self.assertEqual(resp.status_code, 403) self.assertEqual( cm.records[0].getMessage(), - 'Forbidden (%s): ' % REASON_CSRF_TOKEN_MISSING, + "Forbidden (%s): " % REASON_CSRF_TOKEN_MISSING, ) def test_reading_post_data_raises_os_error(self): @@ -837,64 +888,64 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): """ mw = CsrfViewMiddleware(post_form_view) req = self._get_POST_request_with_token(request_class=PostErrorRequest) - req.post_error = OSError('Deleted directories/Missing permissions.') + req.post_error = OSError("Deleted directories/Missing permissions.") mw.process_request(req) with self.assertRaises(OSError): mw.process_view(req, post_form_view, (), {}) - @override_settings(ALLOWED_HOSTS=['www.example.com']) + @override_settings(ALLOWED_HOSTS=["www.example.com"]) def test_bad_origin_bad_domain(self): """A request with a bad origin is rejected.""" req = self._get_POST_request_with_token() - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_ORIGIN'] = 'https://www.evil.org' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_ORIGIN"] = "https://www.evil.org" mw = CsrfViewMiddleware(post_form_view) self._check_referer_rejects(mw, req) self.assertIs(mw._origin_verified(req), False) - with self.assertLogs('django.security.csrf', 'WARNING') as cm: + with self.assertLogs("django.security.csrf", "WARNING") as cm: response = mw.process_view(req, post_form_view, (), {}) self.assertEqual(response.status_code, 403) - msg = REASON_BAD_ORIGIN % req.META['HTTP_ORIGIN'] - self.assertEqual(cm.records[0].getMessage(), 'Forbidden (%s): ' % msg) + msg = REASON_BAD_ORIGIN % req.META["HTTP_ORIGIN"] + self.assertEqual(cm.records[0].getMessage(), "Forbidden (%s): " % msg) - @override_settings(ALLOWED_HOSTS=['www.example.com']) + @override_settings(ALLOWED_HOSTS=["www.example.com"]) def test_bad_origin_null_origin(self): """A request with a null origin is rejected.""" req = self._get_POST_request_with_token() - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_ORIGIN'] = 'null' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_ORIGIN"] = "null" mw = CsrfViewMiddleware(post_form_view) self._check_referer_rejects(mw, req) self.assertIs(mw._origin_verified(req), False) - with self.assertLogs('django.security.csrf', 'WARNING') as cm: + with self.assertLogs("django.security.csrf", "WARNING") as cm: response = mw.process_view(req, post_form_view, (), {}) self.assertEqual(response.status_code, 403) - msg = REASON_BAD_ORIGIN % req.META['HTTP_ORIGIN'] - self.assertEqual(cm.records[0].getMessage(), 'Forbidden (%s): ' % msg) + msg = REASON_BAD_ORIGIN % req.META["HTTP_ORIGIN"] + self.assertEqual(cm.records[0].getMessage(), "Forbidden (%s): " % msg) - @override_settings(ALLOWED_HOSTS=['www.example.com']) + @override_settings(ALLOWED_HOSTS=["www.example.com"]) def test_bad_origin_bad_protocol(self): """A request with an origin with wrong protocol is rejected.""" req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_ORIGIN'] = 'http://example.com' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_ORIGIN"] = "http://example.com" mw = CsrfViewMiddleware(post_form_view) self._check_referer_rejects(mw, req) self.assertIs(mw._origin_verified(req), False) - with self.assertLogs('django.security.csrf', 'WARNING') as cm: + with self.assertLogs("django.security.csrf", "WARNING") as cm: response = mw.process_view(req, post_form_view, (), {}) self.assertEqual(response.status_code, 403) - msg = REASON_BAD_ORIGIN % req.META['HTTP_ORIGIN'] - self.assertEqual(cm.records[0].getMessage(), 'Forbidden (%s): ' % msg) + msg = REASON_BAD_ORIGIN % req.META["HTTP_ORIGIN"] + self.assertEqual(cm.records[0].getMessage(), "Forbidden (%s): " % msg) @override_settings( - ALLOWED_HOSTS=['www.example.com'], + ALLOWED_HOSTS=["www.example.com"], CSRF_TRUSTED_ORIGINS=[ - 'http://no-match.com', - 'https://*.example.com', - 'http://*.no-match.com', - 'http://*.no-match-2.com', + "http://no-match.com", + "https://*.example.com", + "http://*.no-match.com", + "http://*.no-match-2.com", ], ) def test_bad_origin_csrf_trusted_origin_bad_protocol(self): @@ -904,64 +955,70 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): """ req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_ORIGIN'] = 'http://foo.example.com' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_ORIGIN"] = "http://foo.example.com" mw = CsrfViewMiddleware(post_form_view) self._check_referer_rejects(mw, req) self.assertIs(mw._origin_verified(req), False) - with self.assertLogs('django.security.csrf', 'WARNING') as cm: + with self.assertLogs("django.security.csrf", "WARNING") as cm: response = mw.process_view(req, post_form_view, (), {}) self.assertEqual(response.status_code, 403) - msg = REASON_BAD_ORIGIN % req.META['HTTP_ORIGIN'] - self.assertEqual(cm.records[0].getMessage(), 'Forbidden (%s): ' % msg) - self.assertEqual(mw.allowed_origins_exact, {'http://no-match.com'}) - self.assertEqual(mw.allowed_origin_subdomains, { - 'https': ['.example.com'], - 'http': ['.no-match.com', '.no-match-2.com'], - }) - - @override_settings(ALLOWED_HOSTS=['www.example.com']) + msg = REASON_BAD_ORIGIN % req.META["HTTP_ORIGIN"] + self.assertEqual(cm.records[0].getMessage(), "Forbidden (%s): " % msg) + self.assertEqual(mw.allowed_origins_exact, {"http://no-match.com"}) + self.assertEqual( + mw.allowed_origin_subdomains, + { + "https": [".example.com"], + "http": [".no-match.com", ".no-match-2.com"], + }, + ) + + @override_settings(ALLOWED_HOSTS=["www.example.com"]) def test_bad_origin_cannot_be_parsed(self): """ A POST request with an origin that can't be parsed by urlparse() is rejected. """ req = self._get_POST_request_with_token() - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_ORIGIN'] = 'https://[' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_ORIGIN"] = "https://[" mw = CsrfViewMiddleware(post_form_view) self._check_referer_rejects(mw, req) self.assertIs(mw._origin_verified(req), False) - with self.assertLogs('django.security.csrf', 'WARNING') as cm: + with self.assertLogs("django.security.csrf", "WARNING") as cm: response = mw.process_view(req, post_form_view, (), {}) self.assertEqual(response.status_code, 403) - msg = REASON_BAD_ORIGIN % req.META['HTTP_ORIGIN'] - self.assertEqual(cm.records[0].getMessage(), 'Forbidden (%s): ' % msg) + msg = REASON_BAD_ORIGIN % req.META["HTTP_ORIGIN"] + self.assertEqual(cm.records[0].getMessage(), "Forbidden (%s): " % msg) - @override_settings(ALLOWED_HOSTS=['www.example.com']) + @override_settings(ALLOWED_HOSTS=["www.example.com"]) def test_good_origin_insecure(self): """A POST HTTP request with a good origin is accepted.""" req = self._get_POST_request_with_token() - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_ORIGIN'] = 'http://www.example.com' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_ORIGIN"] = "http://www.example.com" mw = CsrfViewMiddleware(post_form_view) self.assertIs(mw._origin_verified(req), True) response = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(response) - @override_settings(ALLOWED_HOSTS=['www.example.com']) + @override_settings(ALLOWED_HOSTS=["www.example.com"]) def test_good_origin_secure(self): """A POST HTTPS request with a good origin is accepted.""" req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_ORIGIN'] = 'https://www.example.com' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_ORIGIN"] = "https://www.example.com" mw = CsrfViewMiddleware(post_form_view) self.assertIs(mw._origin_verified(req), True) response = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(response) - @override_settings(ALLOWED_HOSTS=['www.example.com'], CSRF_TRUSTED_ORIGINS=['https://dashboard.example.com']) + @override_settings( + ALLOWED_HOSTS=["www.example.com"], + CSRF_TRUSTED_ORIGINS=["https://dashboard.example.com"], + ) def test_good_origin_csrf_trusted_origin_allowed(self): """ A POST request with an origin added to the CSRF_TRUSTED_ORIGINS @@ -969,16 +1026,19 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): """ req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_ORIGIN'] = 'https://dashboard.example.com' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_ORIGIN"] = "https://dashboard.example.com" mw = CsrfViewMiddleware(post_form_view) self.assertIs(mw._origin_verified(req), True) resp = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(resp) - self.assertEqual(mw.allowed_origins_exact, {'https://dashboard.example.com'}) + self.assertEqual(mw.allowed_origins_exact, {"https://dashboard.example.com"}) self.assertEqual(mw.allowed_origin_subdomains, {}) - @override_settings(ALLOWED_HOSTS=['www.example.com'], CSRF_TRUSTED_ORIGINS=['https://*.example.com']) + @override_settings( + ALLOWED_HOSTS=["www.example.com"], + CSRF_TRUSTED_ORIGINS=["https://*.example.com"], + ) def test_good_origin_wildcard_csrf_trusted_origin_allowed(self): """ A POST request with an origin that matches a CSRF_TRUSTED_ORIGINS @@ -986,18 +1046,17 @@ class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin): """ req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_HOST'] = 'www.example.com' - req.META['HTTP_ORIGIN'] = 'https://foo.example.com' + req.META["HTTP_HOST"] = "www.example.com" + req.META["HTTP_ORIGIN"] = "https://foo.example.com" mw = CsrfViewMiddleware(post_form_view) self.assertIs(mw._origin_verified(req), True) response = mw.process_view(req, post_form_view, (), {}) self.assertIsNone(response) self.assertEqual(mw.allowed_origins_exact, set()) - self.assertEqual(mw.allowed_origin_subdomains, {'https': ['.example.com']}) + self.assertEqual(mw.allowed_origin_subdomains, {"https": [".example.com"]}) class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase): - def _set_csrf_cookie(self, req, cookie): req.COOKIES[settings.CSRF_COOKIE_NAME] = cookie @@ -1021,7 +1080,7 @@ class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase): resp = ensure_csrf_cookie_view(req) csrf_cookie = self._read_csrf_cookie(req, resp) self.assertTrue(csrf_cookie) - self.assertIn('Cookie', resp.get('Vary', '')) + self.assertIn("Cookie", resp.get("Vary", "")) def test_ensures_csrf_cookie_with_middleware(self): """ @@ -1034,7 +1093,7 @@ class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase): resp = mw(req) csrf_cookie = self._read_csrf_cookie(req, resp) self.assertTrue(csrf_cookie) - self.assertIn('Cookie', resp.get('Vary', '')) + self.assertIn("Cookie", resp.get("Vary", "")) def test_csrf_cookie_age(self): """ @@ -1043,17 +1102,19 @@ class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase): req = self._get_request() MAX_AGE = 123 - with self.settings(CSRF_COOKIE_NAME='csrfcookie', - CSRF_COOKIE_DOMAIN='.example.com', - CSRF_COOKIE_AGE=MAX_AGE, - CSRF_COOKIE_PATH='/test/', - CSRF_COOKIE_SECURE=True, - CSRF_COOKIE_HTTPONLY=True): + with self.settings( + CSRF_COOKIE_NAME="csrfcookie", + CSRF_COOKIE_DOMAIN=".example.com", + CSRF_COOKIE_AGE=MAX_AGE, + CSRF_COOKIE_PATH="/test/", + CSRF_COOKIE_SECURE=True, + CSRF_COOKIE_HTTPONLY=True, + ): # token_view calls get_token() indirectly mw = CsrfViewMiddleware(token_view) mw.process_view(req, token_view, (), {}) resp = mw(req) - max_age = resp.cookies.get('csrfcookie').get('max-age') + max_age = resp.cookies.get("csrfcookie").get("max-age") self.assertEqual(max_age, MAX_AGE) def test_csrf_cookie_age_none(self): @@ -1064,47 +1125,53 @@ class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase): req = self._get_request() MAX_AGE = None - with self.settings(CSRF_COOKIE_NAME='csrfcookie', - CSRF_COOKIE_DOMAIN='.example.com', - CSRF_COOKIE_AGE=MAX_AGE, - CSRF_COOKIE_PATH='/test/', - CSRF_COOKIE_SECURE=True, - CSRF_COOKIE_HTTPONLY=True): + with self.settings( + CSRF_COOKIE_NAME="csrfcookie", + CSRF_COOKIE_DOMAIN=".example.com", + CSRF_COOKIE_AGE=MAX_AGE, + CSRF_COOKIE_PATH="/test/", + CSRF_COOKIE_SECURE=True, + CSRF_COOKIE_HTTPONLY=True, + ): # token_view calls get_token() indirectly mw = CsrfViewMiddleware(token_view) mw.process_view(req, token_view, (), {}) resp = mw(req) - max_age = resp.cookies.get('csrfcookie').get('max-age') - self.assertEqual(max_age, '') + max_age = resp.cookies.get("csrfcookie").get("max-age") + self.assertEqual(max_age, "") def test_csrf_cookie_samesite(self): req = self._get_request() - with self.settings(CSRF_COOKIE_NAME='csrfcookie', CSRF_COOKIE_SAMESITE='Strict'): + with self.settings( + CSRF_COOKIE_NAME="csrfcookie", CSRF_COOKIE_SAMESITE="Strict" + ): mw = CsrfViewMiddleware(token_view) mw.process_view(req, token_view, (), {}) resp = mw(req) - self.assertEqual(resp.cookies['csrfcookie']['samesite'], 'Strict') + self.assertEqual(resp.cookies["csrfcookie"]["samesite"], "Strict") def test_bad_csrf_cookie_characters(self): """ If the CSRF cookie has invalid characters in a POST request, the middleware rejects the incoming request. """ - self._check_bad_or_missing_cookie(64 * '*', 'CSRF cookie has invalid characters.') + self._check_bad_or_missing_cookie( + 64 * "*", "CSRF cookie has invalid characters." + ) def test_bad_csrf_cookie_length(self): """ If the CSRF cookie has an incorrect length in a POST request, the middleware rejects the incoming request. """ - self._check_bad_or_missing_cookie(16 * 'a', 'CSRF cookie has incorrect length.') + self._check_bad_or_missing_cookie(16 * "a", "CSRF cookie has incorrect length.") def test_process_view_token_too_long(self): """ If the token is longer than expected, it is ignored and a new token is created. """ - req = self._get_request(cookie='x' * 100000) + req = self._get_request(cookie="x" * 100000) mw = CsrfViewMiddleware(token_view) mw.process_view(req, token_view, (), {}) resp = mw(req) @@ -1116,7 +1183,7 @@ class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase): If the token contains non-alphanumeric characters, it is ignored and a new token is created. """ - token = ('!@#' + self._csrf_id_token)[:CSRF_TOKEN_LENGTH] + token = ("!@#" + self._csrf_id_token)[:CSRF_TOKEN_LENGTH] req = self._get_request(cookie=token) mw = CsrfViewMiddleware(token_view) mw.process_view(req, token_view, (), {}) @@ -1145,7 +1212,9 @@ class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase): with self.subTest(args=args): cookie, post_token, meta_token = args req = self._get_POST_csrf_cookie_request( - cookie=cookie, post_token=post_token, meta_token=meta_token, + cookie=cookie, + post_token=post_token, + meta_token=meta_token, ) mw = CsrfViewMiddleware(token_view) mw.process_request(req) @@ -1159,7 +1228,7 @@ class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase): """ req = self._get_POST_request_with_token() resp = ensured_and_protected_view(req) - self.assertContains(resp, 'OK') + self.assertContains(resp, "OK") csrf_cookie = self._read_csrf_cookie(req, resp) self.assertEqual(csrf_cookie, TEST_SECRET) # set_cookie() was called only once and with the expected secret. @@ -1170,11 +1239,11 @@ class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase): """ A CSRF cookie with the wrong format is replaced during a GET request. """ - req = self._get_request(cookie='badvalue') + req = self._get_request(cookie="badvalue") resp = protected_view(req) - self.assertContains(resp, 'OK') + self.assertContains(resp, "OK") csrf_cookie = self._read_csrf_cookie(req, resp) - self.assertTrue(csrf_cookie, msg='No CSRF cookie was sent.') + self.assertTrue(csrf_cookie, msg="No CSRF cookie was sent.") self.assertEqual(len(csrf_cookie), CSRF_SECRET_LENGTH) def test_valid_secret_not_replaced_on_GET(self): @@ -1189,9 +1258,9 @@ class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase): with self.subTest(cookie=cookie): req = self._get_request(cookie=cookie) resp = protected_view(req) - self.assertContains(resp, 'OK') + self.assertContains(resp, "OK") csrf_cookie = self._read_csrf_cookie(req, resp) - self.assertFalse(csrf_cookie, msg='A CSRF cookie was sent.') + self.assertFalse(csrf_cookie, msg="A CSRF cookie was sent.") def test_masked_secret_accepted_and_replaced(self): """ @@ -1222,14 +1291,20 @@ class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase): self.assertEqual(csrf_cookie, TEST_SECRET) self._check_token_present(resp, csrf_cookie) - @override_settings(ALLOWED_HOSTS=['www.example.com'], CSRF_COOKIE_DOMAIN='.example.com', USE_X_FORWARDED_PORT=True) + @override_settings( + ALLOWED_HOSTS=["www.example.com"], + CSRF_COOKIE_DOMAIN=".example.com", + USE_X_FORWARDED_PORT=True, + ) def test_https_good_referer_behind_proxy(self): """ A POST HTTPS request is accepted when USE_X_FORWARDED_PORT=True. """ self._test_https_good_referer_behind_proxy() - @override_settings(ALLOWED_HOSTS=['www.example.com'], CSRF_COOKIE_DOMAIN='.example.com') + @override_settings( + ALLOWED_HOSTS=["www.example.com"], CSRF_COOKIE_DOMAIN=".example.com" + ) def test_https_good_referer_matches_cookie_domain(self): """ A POST HTTPS request with a good referer should be accepted from a @@ -1237,7 +1312,9 @@ class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase): """ self._test_https_good_referer_matches_cookie_domain() - @override_settings(ALLOWED_HOSTS=['www.example.com'], CSRF_COOKIE_DOMAIN='.example.com') + @override_settings( + ALLOWED_HOSTS=["www.example.com"], CSRF_COOKIE_DOMAIN=".example.com" + ) def test_https_good_referer_matches_cookie_domain_with_different_port(self): """ A POST HTTPS request with a good referer should be accepted from a @@ -1245,21 +1322,21 @@ class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase): """ self._test_https_good_referer_matches_cookie_domain_with_different_port() - @override_settings(CSRF_COOKIE_DOMAIN='.example.com', DEBUG=True) + @override_settings(CSRF_COOKIE_DOMAIN=".example.com", DEBUG=True) def test_https_reject_insecure_referer(self): """ A POST HTTPS request from an insecure referer should be rejected. """ req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_REFERER'] = 'http://example.com/' - req.META['SERVER_PORT'] = '443' + req.META["HTTP_REFERER"] = "http://example.com/" + req.META["SERVER_PORT"] = "443" mw = CsrfViewMiddleware(post_form_view) self._check_referer_rejects(mw, req) response = mw.process_view(req, post_form_view, (), {}) self.assertContains( response, - 'Referer checking failed - Referer is insecure while host is secure.', + "Referer checking failed - Referer is insecure while host is secure.", status_code=403, ) @@ -1286,8 +1363,8 @@ class CsrfViewMiddlewareUseSessionsTests(CsrfViewMiddlewareTestMixin, SimpleTest def test_no_session_on_request(self): msg = ( - 'CSRF_USE_SESSIONS is enabled, but request.session is not set. ' - 'SessionMiddleware must appear before CsrfViewMiddleware in MIDDLEWARE.' + "CSRF_USE_SESSIONS is enabled, but request.session is not set. " + "SessionMiddleware must appear before CsrfViewMiddleware in MIDDLEWARE." ) with self.assertRaisesMessage(ImproperlyConfigured, msg): mw = CsrfViewMiddleware(lambda req: HttpResponse()) @@ -1309,7 +1386,9 @@ class CsrfViewMiddlewareUseSessionsTests(CsrfViewMiddlewareTestMixin, SimpleTest with self.subTest(args=args): cookie, post_token, meta_token = args req = self._get_POST_csrf_cookie_request( - cookie=cookie, post_token=post_token, meta_token=meta_token, + cookie=cookie, + post_token=post_token, + meta_token=meta_token, ) mw = CsrfViewMiddleware(token_view) mw.process_request(req) @@ -1349,8 +1428,8 @@ class CsrfViewMiddlewareUseSessionsTests(CsrfViewMiddlewareTestMixin, SimpleTest self.assertTrue(csrf_cookie) @override_settings( - ALLOWED_HOSTS=['www.example.com'], - SESSION_COOKIE_DOMAIN='.example.com', + ALLOWED_HOSTS=["www.example.com"], + SESSION_COOKIE_DOMAIN=".example.com", USE_X_FORWARDED_PORT=True, DEBUG=True, ) @@ -1360,7 +1439,9 @@ class CsrfViewMiddlewareUseSessionsTests(CsrfViewMiddlewareTestMixin, SimpleTest """ self._test_https_good_referer_behind_proxy() - @override_settings(ALLOWED_HOSTS=['www.example.com'], SESSION_COOKIE_DOMAIN='.example.com') + @override_settings( + ALLOWED_HOSTS=["www.example.com"], SESSION_COOKIE_DOMAIN=".example.com" + ) def test_https_good_referer_matches_cookie_domain(self): """ A POST HTTPS request with a good referer should be accepted from a @@ -1368,7 +1449,9 @@ class CsrfViewMiddlewareUseSessionsTests(CsrfViewMiddlewareTestMixin, SimpleTest """ self._test_https_good_referer_matches_cookie_domain() - @override_settings(ALLOWED_HOSTS=['www.example.com'], SESSION_COOKIE_DOMAIN='.example.com') + @override_settings( + ALLOWED_HOSTS=["www.example.com"], SESSION_COOKIE_DOMAIN=".example.com" + ) def test_https_good_referer_matches_cookie_domain_with_different_port(self): """ A POST HTTPS request with a good referer should be accepted from a @@ -1376,34 +1459,34 @@ class CsrfViewMiddlewareUseSessionsTests(CsrfViewMiddlewareTestMixin, SimpleTest """ self._test_https_good_referer_matches_cookie_domain_with_different_port() - @override_settings(SESSION_COOKIE_DOMAIN='.example.com', DEBUG=True) + @override_settings(SESSION_COOKIE_DOMAIN=".example.com", DEBUG=True) def test_https_reject_insecure_referer(self): """ A POST HTTPS request from an insecure referer should be rejected. """ req = self._get_POST_request_with_token() req._is_secure_override = True - req.META['HTTP_REFERER'] = 'http://example.com/' - req.META['SERVER_PORT'] = '443' + req.META["HTTP_REFERER"] = "http://example.com/" + req.META["SERVER_PORT"] = "443" mw = CsrfViewMiddleware(post_form_view) response = mw.process_view(req, post_form_view, (), {}) self.assertContains( response, - 'Referer checking failed - Referer is insecure while host is secure.', + "Referer checking failed - Referer is insecure while host is secure.", status_code=403, ) -@override_settings(ROOT_URLCONF='csrf_tests.csrf_token_error_handler_urls', DEBUG=False) +@override_settings(ROOT_URLCONF="csrf_tests.csrf_token_error_handler_urls", DEBUG=False) class CsrfInErrorHandlingViewsTests(CsrfFunctionTestMixin, SimpleTestCase): def test_csrf_token_on_404_stays_constant(self): - response = self.client.get('/does not exist/') + response = self.client.get("/does not exist/") # The error handler returns status code 599. self.assertEqual(response.status_code, 599) - token1 = response.content.decode('ascii') - response = self.client.get('/does not exist/') + token1 = response.content.decode("ascii") + response = self.client.get("/does not exist/") self.assertEqual(response.status_code, 599) - token2 = response.content.decode('ascii') + token2 = response.content.decode("ascii") secret2 = _unmask_cipher_token(token2) self.assertMaskedSecretCorrect(token1, secret2) @@ -1413,24 +1496,24 @@ class CsrfCookieMaskedTests(CsrfFunctionTestMixin, SimpleTestCase): @override_settings(CSRF_COOKIE_MASKED=True) def test_get_token_csrf_cookie_not_set(self): request = HttpRequest() - self.assertNotIn('CSRF_COOKIE', request.META) - self.assertNotIn('CSRF_COOKIE_NEEDS_UPDATE', request.META) + self.assertNotIn("CSRF_COOKIE", request.META) + self.assertNotIn("CSRF_COOKIE_NEEDS_UPDATE", request.META) token = get_token(request) - cookie = request.META['CSRF_COOKIE'] + cookie = request.META["CSRF_COOKIE"] self.assertEqual(len(cookie), CSRF_TOKEN_LENGTH) unmasked_cookie = _unmask_cipher_token(cookie) self.assertMaskedSecretCorrect(token, unmasked_cookie) - self.assertIs(request.META['CSRF_COOKIE_NEEDS_UPDATE'], True) + self.assertIs(request.META["CSRF_COOKIE_NEEDS_UPDATE"], True) @override_settings(CSRF_COOKIE_MASKED=True) def test_rotate_token(self): request = HttpRequest() - request.META['CSRF_COOKIE'] = MASKED_TEST_SECRET1 - self.assertNotIn('CSRF_COOKIE_NEEDS_UPDATE', request.META) + request.META["CSRF_COOKIE"] = MASKED_TEST_SECRET1 + self.assertNotIn("CSRF_COOKIE_NEEDS_UPDATE", request.META) rotate_token(request) # The underlying secret was changed. - cookie = request.META['CSRF_COOKIE'] + cookie = request.META["CSRF_COOKIE"] self.assertEqual(len(cookie), CSRF_TOKEN_LENGTH) unmasked_cookie = _unmask_cipher_token(cookie) self.assertNotEqual(unmasked_cookie, TEST_SECRET) - self.assertIs(request.META['CSRF_COOKIE_NEEDS_UPDATE'], True) + self.assertIs(request.META["CSRF_COOKIE_NEEDS_UPDATE"], True) diff --git a/tests/csrf_tests/views.py b/tests/csrf_tests/views.py index 774d72650d..35c7fb95d6 100644 --- a/tests/csrf_tests/views.py +++ b/tests/csrf_tests/views.py @@ -12,6 +12,7 @@ class TestingHttpResponse(HttpResponse): A version of HttpResponse that stores what cookie values are passed to set_cookie() when CSRF_USE_SESSIONS=False. """ + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # This is a list of the cookie values passed to set_cookie() over @@ -24,7 +25,6 @@ class TestingHttpResponse(HttpResponse): class _CsrfCookieRotator(MiddlewareMixin): - def process_response(self, request, response): rotate_token(request) return response @@ -35,18 +35,18 @@ csrf_rotating_token = decorator_from_middleware(_CsrfCookieRotator) @csrf_protect def protected_view(request): - return HttpResponse('OK') + return HttpResponse("OK") @ensure_csrf_cookie def ensure_csrf_cookie_view(request): - return HttpResponse('OK') + return HttpResponse("OK") @csrf_protect @ensure_csrf_cookie def ensured_and_protected_view(request): - return TestingHttpResponse('OK') + return TestingHttpResponse("OK") @csrf_protect @@ -57,26 +57,28 @@ def sandwiched_rotate_token_view(request): This is a view that calls rotate_token() in process_response() between two calls to CsrfViewMiddleware.process_response(). """ - return TestingHttpResponse('OK') + return TestingHttpResponse("OK") def post_form_view(request): """Return a POST form (without a token).""" - return HttpResponse(content=""" + return HttpResponse( + content=""" <html><body><h1>\u00a1Unicode!<form method="post"><input type="text"></form></body></html> -""") +""" + ) def token_view(request): context = RequestContext(request, processors=[csrf]) - template = Template('{% csrf_token %}') + template = Template("{% csrf_token %}") return HttpResponse(template.render(context)) def non_token_view_using_request_processor(request): """Use the csrf view processor instead of the token.""" context = RequestContext(request, processors=[csrf]) - template = Template('') + template = Template("") return HttpResponse(template.render(context)) |