summaryrefslogtreecommitdiff
path: root/tests/middleware
diff options
context:
space:
mode:
authorRob Hudson <rob@cogit8.org>2025-08-23 12:23:53 -0700
committernessita <124304+nessita@users.noreply.github.com>2025-08-28 17:23:48 -0300
commit550822bceea227b07445d1852c4376b663c09ea4 (patch)
treec7b9a032939c7611156b54767c10059d7d6e373c /tests/middleware
parent292b9e6fe8f23491680d9cc60f328562e2b1c823 (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.py69
-rw-r--r--tests/middleware/urls.py6
-rw-r--r--tests/middleware/views.py40
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