diff options
| author | Jon Janzen <jon@jonjanzen.com> | 2023-05-06 20:20:00 -0700 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2023-06-23 13:29:40 +0200 |
| commit | 38e391e95fe5258bc6d2467332dc9cd44ce6ba52 (patch) | |
| tree | 68f0c84d7968703f213ea3492cdc985ccc993e48 /tests/view_tests | |
| parent | f8092ee9adafaa052172712349a32bd5889b5ccb (diff) | |
Refs #31949 -- Made @sensitive_variables/sensitive_post_parameters decorators to work with async functions.
Co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com>
Diffstat (limited to 'tests/view_tests')
| -rw-r--r-- | tests/view_tests/tests/test_debug.py | 108 | ||||
| -rw-r--r-- | tests/view_tests/views.py | 83 |
2 files changed, 187 insertions, 4 deletions
diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py index 15e69f6811..65f9db89bf 100644 --- a/tests/view_tests/tests/test_debug.py +++ b/tests/view_tests/tests/test_debug.py @@ -9,6 +9,8 @@ from io import StringIO from pathlib import Path from unittest import mock, skipIf, skipUnless +from asgiref.sync import async_to_sync, iscoroutinefunction + from django.core import mail from django.core.files.uploadedfile import SimpleUploadedFile from django.db import DatabaseError, connection @@ -39,6 +41,10 @@ from django.views.debug import ( from django.views.decorators.debug import sensitive_post_parameters, sensitive_variables from ..views import ( + async_sensitive_method_view, + async_sensitive_method_view_nested, + async_sensitive_view, + async_sensitive_view_nested, custom_exception_reporter_filter_view, index_page, multivalue_dict_key_error, @@ -1351,7 +1357,10 @@ class ExceptionReportTestMixin: Asserts that potentially sensitive info are displayed in the response. """ request = self.rf.post("/some_url/", self.breakfast_data) - response = view(request) + if iscoroutinefunction(view): + response = async_to_sync(view)(request) + else: + response = view(request) if check_for_vars: # All variables are shown. self.assertContains(response, "cooked_eggs", status_code=500) @@ -1371,7 +1380,10 @@ class ExceptionReportTestMixin: Asserts that certain sensitive info are not displayed in the response. """ request = self.rf.post("/some_url/", self.breakfast_data) - response = view(request) + if iscoroutinefunction(view): + response = async_to_sync(view)(request) + else: + response = view(request) if check_for_vars: # Non-sensitive variable's name and value are shown. self.assertContains(response, "cooked_eggs", status_code=500) @@ -1418,7 +1430,10 @@ class ExceptionReportTestMixin: with self.settings(ADMINS=[("Admin", "admin@fattie-breakie.com")]): mail.outbox = [] # Empty outbox request = self.rf.post("/some_url/", self.breakfast_data) - view(request) + if iscoroutinefunction(view): + async_to_sync(view)(request) + else: + view(request) self.assertEqual(len(mail.outbox), 1) email = mail.outbox[0] @@ -1451,7 +1466,10 @@ class ExceptionReportTestMixin: with self.settings(ADMINS=[("Admin", "admin@fattie-breakie.com")]): mail.outbox = [] # Empty outbox request = self.rf.post("/some_url/", self.breakfast_data) - view(request) + if iscoroutinefunction(view): + async_to_sync(view)(request) + else: + view(request) self.assertEqual(len(mail.outbox), 1) email = mail.outbox[0] @@ -1543,6 +1561,24 @@ class ExceptionReporterFilterTests( self.verify_safe_response(sensitive_view) self.verify_safe_email(sensitive_view) + def test_async_sensitive_request(self): + with self.settings(DEBUG=True): + self.verify_unsafe_response(async_sensitive_view) + self.verify_unsafe_email(async_sensitive_view) + + with self.settings(DEBUG=False): + self.verify_safe_response(async_sensitive_view) + self.verify_safe_email(async_sensitive_view) + + def test_async_sensitive_nested_request(self): + with self.settings(DEBUG=True): + self.verify_unsafe_response(async_sensitive_view_nested) + self.verify_unsafe_email(async_sensitive_view_nested) + + with self.settings(DEBUG=False): + self.verify_safe_response(async_sensitive_view_nested) + self.verify_safe_email(async_sensitive_view_nested) + def test_paranoid_request(self): """ No POST parameters and frame variables can be seen in the @@ -1598,6 +1634,46 @@ class ExceptionReporterFilterTests( ) self.verify_safe_email(sensitive_method_view, check_for_POST_params=False) + def test_async_sensitive_method(self): + """ + The sensitive_variables decorator works with async object methods. + """ + with self.settings(DEBUG=True): + self.verify_unsafe_response( + async_sensitive_method_view, check_for_POST_params=False + ) + self.verify_unsafe_email( + async_sensitive_method_view, check_for_POST_params=False + ) + + with self.settings(DEBUG=False): + self.verify_safe_response( + async_sensitive_method_view, check_for_POST_params=False + ) + self.verify_safe_email( + async_sensitive_method_view, check_for_POST_params=False + ) + + def test_async_sensitive_method_nested(self): + """ + The sensitive_variables decorator works with async object methods. + """ + with self.settings(DEBUG=True): + self.verify_unsafe_response( + async_sensitive_method_view_nested, check_for_POST_params=False + ) + self.verify_unsafe_email( + async_sensitive_method_view_nested, check_for_POST_params=False + ) + + with self.settings(DEBUG=False): + self.verify_safe_response( + async_sensitive_method_view_nested, check_for_POST_params=False + ) + self.verify_safe_email( + async_sensitive_method_view_nested, check_for_POST_params=False + ) + def test_sensitive_function_arguments(self): """ Sensitive variables don't leak in the sensitive_variables decorator's @@ -1890,6 +1966,30 @@ class NonHTMLResponseExceptionReporterFilter( with self.settings(DEBUG=False): self.verify_safe_response(sensitive_view, check_for_vars=False) + def test_async_sensitive_request(self): + """ + Sensitive POST parameters cannot be seen in the default + error reports for sensitive requests. + """ + with self.settings(DEBUG=True): + self.verify_unsafe_response(async_sensitive_view, check_for_vars=False) + + with self.settings(DEBUG=False): + self.verify_safe_response(async_sensitive_view, check_for_vars=False) + + def test_async_sensitive_request_nested(self): + """ + Sensitive POST parameters cannot be seen in the default + error reports for sensitive requests. + """ + with self.settings(DEBUG=True): + self.verify_unsafe_response( + async_sensitive_view_nested, check_for_vars=False + ) + + with self.settings(DEBUG=False): + self.verify_safe_response(async_sensitive_view_nested, check_for_vars=False) + def test_paranoid_request(self): """ No POST parameters can be seen in the default error reports diff --git a/tests/view_tests/views.py b/tests/view_tests/views.py index a9eeee3cd2..9eb7a352d6 100644 --- a/tests/view_tests/views.py +++ b/tests/view_tests/views.py @@ -178,6 +178,46 @@ def sensitive_view(request): return technical_500_response(request, *exc_info) +@sensitive_variables("sauce") +@sensitive_post_parameters("bacon-key", "sausage-key") +async def async_sensitive_view(request): + # Do not just use plain strings for the variables' values in the code so + # that the tests don't return false positives when the function's source is + # displayed in the exception report. + cooked_eggs = "".join(["s", "c", "r", "a", "m", "b", "l", "e", "d"]) # NOQA + sauce = "".join( # NOQA + ["w", "o", "r", "c", "e", "s", "t", "e", "r", "s", "h", "i", "r", "e"] + ) + try: + raise Exception + except Exception: + exc_info = sys.exc_info() + send_log(request, exc_info) + return technical_500_response(request, *exc_info) + + +@sensitive_variables("sauce") +@sensitive_post_parameters("bacon-key", "sausage-key") +async def async_sensitive_function(request): + # Do not just use plain strings for the variables' values in the code so + # that the tests don't return false positives when the function's source is + # displayed in the exception report. + cooked_eggs = "".join(["s", "c", "r", "a", "m", "b", "l", "e", "d"]) # NOQA + sauce = "".join( # NOQA + ["w", "o", "r", "c", "e", "s", "t", "e", "r", "s", "h", "i", "r", "e"] + ) + raise Exception + + +async def async_sensitive_view_nested(request): + try: + await async_sensitive_function(request) + except Exception: + exc_info = sys.exc_info() + send_log(request, exc_info) + return technical_500_response(request, *exc_info) + + @sensitive_variables() @sensitive_post_parameters() def paranoid_view(request): @@ -309,11 +349,54 @@ class Klass: send_log(request, exc_info) return technical_500_response(request, *exc_info) + @sensitive_variables("sauce") + async def async_method(self, request): + # Do not just use plain strings for the variables' values in the code + # so that the tests don't return false positives when the function's + # source is displayed in the exception report. + cooked_eggs = "".join(["s", "c", "r", "a", "m", "b", "l", "e", "d"]) # NOQA + sauce = "".join( # NOQA + ["w", "o", "r", "c", "e", "s", "t", "e", "r", "s", "h", "i", "r", "e"] + ) + try: + raise Exception + except Exception: + exc_info = sys.exc_info() + send_log(request, exc_info) + return technical_500_response(request, *exc_info) + + @sensitive_variables("sauce") + async def _async_method_inner(self, request): + # Do not just use plain strings for the variables' values in the code + # so that the tests don't return false positives when the function's + # source is displayed in the exception report. + cooked_eggs = "".join(["s", "c", "r", "a", "m", "b", "l", "e", "d"]) # NOQA + sauce = "".join( # NOQA + ["w", "o", "r", "c", "e", "s", "t", "e", "r", "s", "h", "i", "r", "e"] + ) + raise Exception + + async def async_method_nested(self, request): + try: + await self._async_method_inner(request) + except Exception: + exc_info = sys.exc_info() + send_log(request, exc_info) + return technical_500_response(request, *exc_info) + def sensitive_method_view(request): return Klass().method(request) +async def async_sensitive_method_view(request): + return await Klass().async_method(request) + + +async def async_sensitive_method_view_nested(request): + return await Klass().async_method_nested(request) + + @sensitive_variables("sauce") @sensitive_post_parameters("bacon-key", "sausage-key") def multivalue_dict_key_error(request): |
