diff options
| author | Rob Hudson <rob@cogit8.org> | 2025-08-23 12:23:53 -0700 |
|---|---|---|
| committer | nessita <124304+nessita@users.noreply.github.com> | 2025-08-28 17:23:48 -0300 |
| commit | 550822bceea227b07445d1852c4376b663c09ea4 (patch) | |
| tree | c7b9a032939c7611156b54767c10059d7d6e373c /tests/middleware | |
| parent | 292b9e6fe8f23491680d9cc60f328562e2b1c823 (diff) | |
Fixed #36532 -- Added Content Security Policy view decorators to override or disable policies.
Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
Diffstat (limited to 'tests/middleware')
| -rw-r--r-- | tests/middleware/test_csp.py | 69 | ||||
| -rw-r--r-- | tests/middleware/urls.py | 6 | ||||
| -rw-r--r-- | tests/middleware/views.py | 40 |
3 files changed, 115 insertions, 0 deletions
diff --git a/tests/middleware/test_csp.py b/tests/middleware/test_csp.py index e7a2452240..3ab732fe2f 100644 --- a/tests/middleware/test_csp.py +++ b/tests/middleware/test_csp.py @@ -107,6 +107,75 @@ class CSPMiddlewareTest(SimpleTestCase): @override_settings( + MIDDLEWARE=["django.middleware.csp.ContentSecurityPolicyMiddleware"], + ROOT_URLCONF="middleware.urls", + SECURE_CSP=basic_config, + SECURE_CSP_REPORT_ONLY=basic_config, +) +class CSPMiddlewareWithDecoratedViewsTest(SimpleTestCase): + def test_no_decorators(self): + response = self.client.get("/csp-base/") + self.assertEqual(response[CSP.HEADER_ENFORCE], basic_policy) + self.assertEqual(response[CSP.HEADER_REPORT_ONLY], basic_policy) + + def test_csp_disabled_enforced(self): + """ + `csp_override({})` only disables the enforced CSP header. + """ + response = self.client.get("/csp-disabled-enforced/") + self.assertNotIn(CSP.HEADER_ENFORCE, response) + self.assertEqual(response[CSP.HEADER_REPORT_ONLY], basic_policy) + + def test_csp_report_only_disabled(self): + """ + `csp_report_only_override({})` only disables the report-only header. + """ + response = self.client.get("/csp-disabled-report-only/") + self.assertNotIn(CSP.HEADER_REPORT_ONLY, response) + self.assertEqual(response[CSP.HEADER_ENFORCE], basic_policy) + + def test_csp_disabled_both(self): + """ + Using both CSP decorators with empty mappings will clear both headers. + """ + response = self.client.get("/csp-disabled-both/") + self.assertNotIn(CSP.HEADER_ENFORCE, response) + self.assertNotIn(CSP.HEADER_REPORT_ONLY, response) + + def test_csp_override_enforced(self): + """ + `csp_override` only overrides the enforced header. + """ + response = self.client.get("/csp-override-enforced/") + self.assertEqual( + response[CSP.HEADER_ENFORCE], "default-src 'self'; img-src 'self' data:" + ) + self.assertEqual(response[CSP.HEADER_REPORT_ONLY], basic_policy) + + def test_csp_report_only_override(self): + """ + `csp_report_only_override` only overrides the report-only header. + """ + response = self.client.get("/csp-override-report-only/") + self.assertEqual( + response[CSP.HEADER_REPORT_ONLY], "default-src 'self'; img-src 'self' data:" + ) + self.assertEqual(response[CSP.HEADER_ENFORCE], basic_policy) + + def test_csp_override_both_decorator(self): + """ + Using both CSP decorators overrides both CSP Django settings. + """ + response = self.client.get("/csp-override-both/") + self.assertEqual( + response[CSP.HEADER_ENFORCE], "default-src 'self'; img-src 'self' data:" + ) + self.assertEqual( + response[CSP.HEADER_REPORT_ONLY], "default-src 'self'; img-src 'self' data:" + ) + + +@override_settings( ROOT_URLCONF="middleware.urls", SECURE_CSP_REPORT_ONLY={ "default-src": [CSP.NONE], diff --git a/tests/middleware/urls.py b/tests/middleware/urls.py index 37120c7a54..bbd68d2050 100644 --- a/tests/middleware/urls.py +++ b/tests/middleware/urls.py @@ -17,5 +17,11 @@ urlpatterns = [ path("csp-report/", views.csp_report_view), path("csp-base/", views.empty_view), path("csp-nonce/", views.csp_nonce), + path("csp-disabled-both/", views.csp_disabled_both), + path("csp-disabled-enforced/", views.csp_disabled_enforced), + path("csp-disabled-report-only/", views.csp_disabled_ro), + path("csp-override-both/", views.csp_override_both), + path("csp-override-enforced/", views.csp_override_enforced), + path("csp-override-report-only/", views.csp_override_report_only), path("csp-500/", views.csp_500), ] diff --git a/tests/middleware/views.py b/tests/middleware/views.py index 6dc3ca24c7..716ddec5fd 100644 --- a/tests/middleware/views.py +++ b/tests/middleware/views.py @@ -3,9 +3,11 @@ import sys from django.http import HttpResponse from django.middleware.csp import get_nonce +from django.utils.csp import CSP from django.utils.decorators import method_decorator from django.views.debug import technical_500_response from django.views.decorators.common import no_append_slash +from django.views.decorators.csp import csp_override, csp_report_only_override from django.views.decorators.csrf import csrf_exempt from django.views.generic import View @@ -29,6 +31,44 @@ def csp_nonce(request): return HttpResponse(get_nonce(request)) +@csp_override({}) +def csp_disabled_enforced(request): + return HttpResponse() + + +@csp_report_only_override({}) +def csp_disabled_ro(request): + return HttpResponse() + + +@csp_override({}) +@csp_report_only_override({}) +def csp_disabled_both(request): + return HttpResponse() + + +csp_policy_override = { + "default-src": [CSP.SELF], + "img-src": [CSP.SELF, "data:"], +} + + +@csp_override(csp_policy_override) +def csp_override_enforced(request): + return HttpResponse() + + +@csp_report_only_override(csp_policy_override) +def csp_override_report_only(request): + return HttpResponse() + + +@csp_override(csp_policy_override) +@csp_report_only_override(csp_policy_override) +def csp_override_both(request): + return HttpResponse() + + def csp_500(request): try: raise Exception |
