summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Jerdonek <chris.jerdonek@gmail.com>2021-08-02 14:38:04 -0400
committerCarlton Gibson <carlton@noumenal.es>2021-08-17 12:23:54 +0200
commit7aba820aca98a3db77d405b616c9a2d39562f076 (patch)
tree0eae519b5f5ce8d53a5723b5203a13cbb6afd91d
parentf10553ec93b853029f3b3c6fe215648f48bd1223 (diff)
Refs #32800 -- Improved CsrfViewMiddlewareTestMixin._check_token_present().
This changes CsrfViewMiddlewareTestMixin._check_token_present() to give more detailed information if the check fails, and in particular why it failed. It also moves CsrfFunctionTests.assertMaskedSecretCorrect() to a separate CsrfFunctionTestMixin so the helper can be used in CsrfViewMiddlewareTestMixin.
-rw-r--r--tests/csrf_tests/tests.py56
1 files changed, 33 insertions, 23 deletions
diff --git a/tests/csrf_tests/tests.py b/tests/csrf_tests/tests.py
index 61da1367ac..10171adb2a 100644
--- a/tests/csrf_tests/tests.py
+++ b/tests/csrf_tests/tests.py
@@ -5,10 +5,11 @@ 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_SESSION_KEY, CSRF_TOKEN_LENGTH, REASON_BAD_ORIGIN,
- REASON_CSRF_TOKEN_MISSING, REASON_NO_CSRF_COOKIE, CsrfViewMiddleware,
- InvalidTokenFormat, RejectRequest, _does_token_match, _mask_cipher_secret,
- _sanitize_token, _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, _does_token_match, _mask_cipher_secret, _sanitize_token,
+ _unmask_cipher_token, get_token, rotate_token,
)
from django.test import SimpleTestCase, override_settings
from django.views.decorators.csrf import csrf_exempt, requires_csrf_token
@@ -26,7 +27,22 @@ MASKED_TEST_SECRET1 = '1bcdefghij2bcdefghij3bcdefghij4bcdefghij5bcdefghij6bcdefg
MASKED_TEST_SECRET2 = '2JgchWvM1tpxT2lfz9aydoXW9yT1DN3NdLiejYxOOlzzV4nhBbYqmqZYbAV3V5Bf'
-class CsrfFunctionTests(SimpleTestCase):
+class CsrfFunctionTestMixin:
+
+ # This method depends on _unmask_cipher_token() being correct.
+ def assertMaskedSecretCorrect(self, masked_secret, secret):
+ """Test that a string is a valid masked version of a secret."""
+ self.assertEqual(len(masked_secret), CSRF_TOKEN_LENGTH)
+ 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}',
+ )
+ actual = _unmask_cipher_token(masked_secret)
+ self.assertEqual(actual, secret)
+
+
+class CsrfFunctionTests(CsrfFunctionTestMixin, SimpleTestCase):
def test_unmask_cipher_token(self):
cases = [
@@ -47,17 +63,6 @@ class CsrfFunctionTests(SimpleTestCase):
actual = _unmask_cipher_token(masked_secret)
self.assertEqual(actual, secret)
- # This method depends on _unmask_cipher_token() being correct.
- def assertMaskedSecretCorrect(self, masked_secret, secret):
- """Test that a string is a valid masked version of a secret."""
- self.assertEqual(len(masked_secret), CSRF_TOKEN_LENGTH)
- self.assertTrue(
- set(masked_secret).issubset(set(CSRF_ALLOWED_CHARS)),
- msg=f'invalid characters in {masked_secret!r}',
- )
- actual = _unmask_cipher_token(masked_secret)
- self.assertEqual(actual, secret)
-
def test_mask_cipher_secret(self):
cases = [
32 * 'a',
@@ -186,7 +191,7 @@ class PostErrorRequest(TestingHttpRequest):
POST = property(_get_post, _set_post)
-class CsrfViewMiddlewareTestMixin:
+class CsrfViewMiddlewareTestMixin(CsrfFunctionTestMixin):
"""
Shared methods and tests for session-based and cookie-based tokens.
"""
@@ -274,14 +279,19 @@ class CsrfViewMiddlewareTestMixin:
request_class=request_class,
)
- def _check_token_present(self, response, csrf_id=None):
+ # This method depends on _unmask_cipher_token() being correct.
+ def _check_token_present(self, response, csrf_token=None):
+ if csrf_token is None:
+ csrf_secret = TEST_SECRET
+ else:
+ csrf_secret = _unmask_cipher_token(csrf_token)
text = str(response.content, response.charset)
match = re.search('name="csrfmiddlewaretoken" value="(.*?)"', text)
- csrf_token = csrf_id or self._csrf_id_token
self.assertTrue(
- match and _does_token_match(csrf_token, match[1]),
- "Could not find csrfmiddlewaretoken to match %s" % csrf_token
+ match, f'Could not find a csrfmiddlewaretoken value in: {text}',
)
+ csrf_token = match[1]
+ self.assertMaskedSecretCorrect(csrf_token, csrf_secret)
def test_process_response_get_token_not_used(self):
"""
@@ -543,7 +553,7 @@ class CsrfViewMiddlewareTestMixin:
mw.process_view(req, token_view, (), {})
resp = mw(req)
csrf_cookie = self._read_csrf_cookie(req, resp)
- self._check_token_present(resp, csrf_id=csrf_cookie)
+ self._check_token_present(resp, csrf_cookie)
def test_cookie_not_reset_on_accepted_request(self):
"""
@@ -1179,7 +1189,7 @@ class CsrfViewMiddlewareTests(CsrfViewMiddlewareTestMixin, SimpleTestCase):
resp = mw(req)
csrf_cookie = self._read_csrf_cookie(req, resp)
self.assertEqual(len(csrf_cookie), CSRF_TOKEN_LENGTH)
- self._check_token_present(resp, csrf_id=csrf_cookie)
+ self._check_token_present(resp, csrf_cookie)
@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):