mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
				
					committed by
					
						 Carlton Gibson
						Carlton Gibson
					
				
			
			
				
	
			
			
			
						parent
						
							f10553ec93
						
					
				
				
					commit
					7aba820aca
				
			| @@ -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): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user