summaryrefslogtreecommitdiff
path: root/tests/middleware/test_csp.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/middleware/test_csp.py')
-rw-r--r--tests/middleware/test_csp.py135
1 files changed, 135 insertions, 0 deletions
diff --git a/tests/middleware/test_csp.py b/tests/middleware/test_csp.py
new file mode 100644
index 0000000000..de55f0c6a0
--- /dev/null
+++ b/tests/middleware/test_csp.py
@@ -0,0 +1,135 @@
+import time
+
+from utils_tests.test_csp import basic_config, basic_policy
+
+from django.contrib.staticfiles.testing import StaticLiveServerTestCase
+from django.test import SimpleTestCase
+from django.test.selenium import SeleniumTestCase
+from django.test.utils import modify_settings, override_settings
+from django.utils.csp import CSP
+
+from .views import csp_reports
+
+
+@override_settings(
+ MIDDLEWARE=["django.middleware.csp.ContentSecurityPolicyMiddleware"],
+ ROOT_URLCONF="middleware.urls",
+)
+class CSPMiddlewareTest(SimpleTestCase):
+ @override_settings(SECURE_CSP=None, SECURE_CSP_REPORT_ONLY=None)
+ def test_csp_defaults_off(self):
+ response = self.client.get("/csp-base/")
+ self.assertNotIn(CSP.HEADER_ENFORCE, response)
+ self.assertNotIn(CSP.HEADER_REPORT_ONLY, response)
+
+ @override_settings(SECURE_CSP=basic_config, SECURE_CSP_REPORT_ONLY=None)
+ def test_csp_basic(self):
+ """
+ With SECURE_CSP set to a valid value, the middleware adds a
+ "Content-Security-Policy" header to the response.
+ """
+ response = self.client.get("/csp-base/")
+ self.assertEqual(response[CSP.HEADER_ENFORCE], basic_policy)
+ self.assertNotIn(CSP.HEADER_REPORT_ONLY, response)
+
+ @override_settings(SECURE_CSP={"default-src": [CSP.SELF, CSP.NONCE]})
+ def test_csp_basic_with_nonce(self):
+ """
+ Test the nonce is added to the header and matches what is in the view.
+ """
+ response = self.client.get("/csp-nonce/")
+ nonce = response.text
+ self.assertTrue(nonce)
+ self.assertEqual(
+ response[CSP.HEADER_ENFORCE], f"default-src 'self' 'nonce-{nonce}'"
+ )
+
+ @override_settings(SECURE_CSP={"default-src": [CSP.SELF, CSP.NONCE]})
+ def test_csp_basic_with_nonce_but_unused(self):
+ """
+ Test if `request.csp_nonce` is never accessed, it is not added to the header.
+ """
+ response = self.client.get("/csp-base/")
+ nonce = response.text
+ self.assertIsNotNone(nonce)
+ self.assertEqual(response[CSP.HEADER_ENFORCE], basic_policy)
+
+ @override_settings(SECURE_CSP=None, SECURE_CSP_REPORT_ONLY=basic_config)
+ def test_csp_report_only_basic(self):
+ """
+ With SECURE_CSP_REPORT_ONLY set to a valid value, the middleware adds a
+ "Content-Security-Policy-Report-Only" header to the response.
+ """
+ response = self.client.get("/csp-base/")
+ self.assertEqual(response[CSP.HEADER_REPORT_ONLY], basic_policy)
+ self.assertNotIn(CSP.HEADER_ENFORCE, response)
+
+ @override_settings(
+ SECURE_CSP=basic_config,
+ SECURE_CSP_REPORT_ONLY=basic_config,
+ )
+ def test_csp_both(self):
+ """
+ If both SECURE_CSP and SECURE_CSP_REPORT_ONLY are set, the middleware
+ adds both headers to the response.
+ """
+ response = self.client.get("/csp-base/")
+ self.assertEqual(response[CSP.HEADER_ENFORCE], basic_policy)
+ self.assertEqual(response[CSP.HEADER_REPORT_ONLY], basic_policy)
+
+ @override_settings(
+ DEBUG=True,
+ SECURE_CSP=basic_config,
+ SECURE_CSP_REPORT_ONLY=basic_config,
+ )
+ def test_csp_404_debug_view(self):
+ """
+ Test that the CSP headers are not added to the debug view.
+ """
+ response = self.client.get("/csp-404/")
+ self.assertNotIn(CSP.HEADER_ENFORCE, response)
+ self.assertNotIn(CSP.HEADER_REPORT_ONLY, response)
+
+ @override_settings(
+ DEBUG=True,
+ SECURE_CSP=basic_config,
+ SECURE_CSP_REPORT_ONLY=basic_config,
+ )
+ def test_csp_500_debug_view(self):
+ """
+ Test that the CSP headers are not added to the debug view.
+ """
+ response = self.client.get("/csp-500/")
+ self.assertNotIn(CSP.HEADER_ENFORCE, response)
+ self.assertNotIn(CSP.HEADER_REPORT_ONLY, response)
+
+
+@override_settings(
+ ROOT_URLCONF="middleware.urls",
+ SECURE_CSP_REPORT_ONLY={
+ "default-src": [CSP.NONE],
+ "img-src": [CSP.SELF],
+ "script-src": [CSP.SELF],
+ "style-src": [CSP.SELF],
+ "report-uri": "/csp-report/",
+ },
+)
+@modify_settings(
+ MIDDLEWARE={"append": "django.middleware.csp.ContentSecurityPolicyMiddleware"}
+)
+class CSPSeleniumTestCase(SeleniumTestCase, StaticLiveServerTestCase):
+ available_apps = ["middleware"]
+
+ def setUp(self):
+ self.addCleanup(csp_reports.clear)
+ super().setUp()
+
+ def test_reports_are_generated(self):
+ url = self.live_server_url + "/csp-failure/"
+ self.selenium.get(url)
+ time.sleep(1) # Allow time for the CSP report to be sent.
+ reports = sorted(
+ (r["csp-report"]["document-uri"], r["csp-report"]["violated-directive"])
+ for r in csp_reports
+ )
+ self.assertEqual(reports, [(url, "img-src"), (url, "style-src-elem")])