summaryrefslogtreecommitdiff
path: root/tests/check_framework
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2014-09-12 14:50:36 -0400
committerTim Graham <timograham@gmail.com>2014-09-12 15:05:23 -0400
commit52ef6a47269a455113d95992f868939131f9c10c (patch)
treefed55edbb5ab020ea5bd2d036d0588f62939d729 /tests/check_framework
parent8f334e55be99ae271d82f9b961a2dc6258487d9c (diff)
Fixed #17101 -- Integrated django-secure and added check --deploy option
Thanks Carl Meyer for django-secure and for reviewing. Thanks also to Zach Borboa, Erik Romijn, Collin Anderson, and Jorge Carleitao for reviews.
Diffstat (limited to 'tests/check_framework')
-rw-r--r--tests/check_framework/test_security.py487
-rw-r--r--tests/check_framework/tests.py27
2 files changed, 514 insertions, 0 deletions
diff --git a/tests/check_framework/test_security.py b/tests/check_framework/test_security.py
new file mode 100644
index 0000000000..4a72e60029
--- /dev/null
+++ b/tests/check_framework/test_security.py
@@ -0,0 +1,487 @@
+from django.conf import settings
+from django.test import TestCase
+from django.test.utils import override_settings
+
+from django.core.checks.security import base
+from django.core.checks.security import csrf
+from django.core.checks.security import sessions
+
+
+class CheckSessionCookieSecureTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.sessions import check_session_cookie_secure
+ return check_session_cookie_secure
+
+ @override_settings(
+ SESSION_COOKIE_SECURE=False,
+ INSTALLED_APPS=["django.contrib.sessions"],
+ MIDDLEWARE_CLASSES=[])
+ def test_session_cookie_secure_with_installed_app(self):
+ """
+ Warn if SESSION_COOKIE_SECURE is off and "django.contrib.sessions" is
+ in INSTALLED_APPS.
+ """
+ self.assertEqual(self.func(None), [sessions.W010])
+
+ @override_settings(
+ SESSION_COOKIE_SECURE=False,
+ INSTALLED_APPS=[],
+ MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
+ def test_session_cookie_secure_with_middleware(self):
+ """
+ Warn if SESSION_COOKIE_SECURE is off and
+ "django.contrib.sessions.middleware.SessionMiddleware" is in
+ MIDDLEWARE_CLASSES.
+ """
+ self.assertEqual(self.func(None), [sessions.W011])
+
+ @override_settings(
+ SESSION_COOKIE_SECURE=False,
+ INSTALLED_APPS=["django.contrib.sessions"],
+ MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
+ def test_session_cookie_secure_both(self):
+ """
+ If SESSION_COOKIE_SECURE is off and we find both the session app and
+ the middleware, provide one common warning.
+ """
+ self.assertEqual(self.func(None), [sessions.W012])
+
+ @override_settings(
+ SESSION_COOKIE_SECURE=True,
+ INSTALLED_APPS=["django.contrib.sessions"],
+ MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
+ def test_session_cookie_secure_true(self):
+ """
+ If SESSION_COOKIE_SECURE is on, there's no warning about it.
+ """
+ self.assertEqual(self.func(None), [])
+
+
+class CheckSessionCookieHttpOnlyTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.sessions import check_session_cookie_httponly
+ return check_session_cookie_httponly
+
+ @override_settings(
+ SESSION_COOKIE_HTTPONLY=False,
+ INSTALLED_APPS=["django.contrib.sessions"],
+ MIDDLEWARE_CLASSES=[])
+ def test_session_cookie_httponly_with_installed_app(self):
+ """
+ Warn if SESSION_COOKIE_HTTPONLY is off and "django.contrib.sessions"
+ is in INSTALLED_APPS.
+ """
+ self.assertEqual(self.func(None), [sessions.W013])
+
+ @override_settings(
+ SESSION_COOKIE_HTTPONLY=False,
+ INSTALLED_APPS=[],
+ MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
+ def test_session_cookie_httponly_with_middleware(self):
+ """
+ Warn if SESSION_COOKIE_HTTPONLY is off and
+ "django.contrib.sessions.middleware.SessionMiddleware" is in
+ MIDDLEWARE_CLASSES.
+ """
+ self.assertEqual(self.func(None), [sessions.W014])
+
+ @override_settings(
+ SESSION_COOKIE_HTTPONLY=False,
+ INSTALLED_APPS=["django.contrib.sessions"],
+ MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
+ def test_session_cookie_httponly_both(self):
+ """
+ If SESSION_COOKIE_HTTPONLY is off and we find both the session app and
+ the middleware, provide one common warning.
+ """
+ self.assertEqual(self.func(None), [sessions.W015])
+
+ @override_settings(
+ SESSION_COOKIE_HTTPONLY=True,
+ INSTALLED_APPS=["django.contrib.sessions"],
+ MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
+ def test_session_cookie_httponly_true(self):
+ """
+ If SESSION_COOKIE_HTTPONLY is on, there's no warning about it.
+ """
+ self.assertEqual(self.func(None), [])
+
+
+class CheckCSRFMiddlewareTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.csrf import check_csrf_middleware
+ return check_csrf_middleware
+
+ @override_settings(MIDDLEWARE_CLASSES=[])
+ def test_no_csrf_middleware(self):
+ """
+ Warn if CsrfViewMiddleware isn't in MIDDLEWARE_CLASSES.
+ """
+ self.assertEqual(self.func(None), [csrf.W003])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"])
+ def test_with_csrf_middleware(self):
+ self.assertEqual(self.func(None), [])
+
+
+class CheckCSRFCookieSecureTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.csrf import check_csrf_cookie_secure
+ return check_csrf_cookie_secure
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"],
+ CSRF_COOKIE_SECURE=False)
+ def test_with_csrf_cookie_secure_false(self):
+ """
+ Warn if CsrfViewMiddleware is in MIDDLEWARE_CLASSES but
+ CSRF_COOKIE_SECURE isn't True.
+ """
+ self.assertEqual(self.func(None), [csrf.W016])
+
+ @override_settings(MIDDLEWARE_CLASSES=[], CSRF_COOKIE_SECURE=False)
+ def test_with_csrf_cookie_secure_false_no_middleware(self):
+ """
+ No warning if CsrfViewMiddleware isn't in MIDDLEWARE_CLASSES, even if
+ CSRF_COOKIE_SECURE is False.
+ """
+ self.assertEqual(self.func(None), [])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"],
+ CSRF_COOKIE_SECURE=True)
+ def test_with_csrf_cookie_secure_true(self):
+ self.assertEqual(self.func(None), [])
+
+
+class CheckCSRFCookieHttpOnlyTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.csrf import check_csrf_cookie_httponly
+ return check_csrf_cookie_httponly
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"],
+ CSRF_COOKIE_HTTPONLY=False)
+ def test_with_csrf_cookie_httponly_false(self):
+ """
+ Warn if CsrfViewMiddleware is in MIDDLEWARE_CLASSES but
+ CSRF_COOKIE_HTTPONLY isn't True.
+ """
+ self.assertEqual(self.func(None), [csrf.W017])
+
+ @override_settings(MIDDLEWARE_CLASSES=[], CSRF_COOKIE_HTTPONLY=False)
+ def test_with_csrf_cookie_httponly_false_no_middleware(self):
+ """
+ No warning if CsrfViewMiddleware isn't in MIDDLEWARE_CLASSES, even if
+ CSRF_COOKIE_HTTPONLY is False.
+ """
+ self.assertEqual(self.func(None), [])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"],
+ CSRF_COOKIE_HTTPONLY=True)
+ def test_with_csrf_cookie_httponly_true(self):
+ self.assertEqual(self.func(None), [])
+
+
+class CheckSecurityMiddlewareTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.base import check_security_middleware
+ return check_security_middleware
+
+ @override_settings(MIDDLEWARE_CLASSES=[])
+ def test_no_security_middleware(self):
+ """
+ Warn if SecurityMiddleware isn't in MIDDLEWARE_CLASSES.
+ """
+ self.assertEqual(self.func(None), [base.W001])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"])
+ def test_with_security_middleware(self):
+ self.assertEqual(self.func(None), [])
+
+
+class CheckStrictTransportSecurityTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.base import check_sts
+ return check_sts
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ SECURE_HSTS_SECONDS=0)
+ def test_no_sts(self):
+ """
+ Warn if SECURE_HSTS_SECONDS isn't > 0.
+ """
+ self.assertEqual(self.func(None), [base.W004])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=[],
+ SECURE_HSTS_SECONDS=0)
+ def test_no_sts_no_middlware(self):
+ """
+ Don't warn if SECURE_HSTS_SECONDS isn't > 0 and SecurityMiddleware isn't
+ installed.
+ """
+ self.assertEqual(self.func(None), [])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ SECURE_HSTS_SECONDS=3600)
+ def test_with_sts(self):
+ self.assertEqual(self.func(None), [])
+
+
+class CheckStrictTransportSecuritySubdomainsTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.base import check_sts_include_subdomains
+ return check_sts_include_subdomains
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ SECURE_HSTS_INCLUDE_SUBDOMAINS=False,
+ SECURE_HSTS_SECONDS=3600)
+ def test_no_sts_subdomains(self):
+ """
+ Warn if SECURE_HSTS_INCLUDE_SUBDOMAINS isn't True.
+ """
+ self.assertEqual(self.func(None), [base.W005])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=[],
+ SECURE_HSTS_INCLUDE_SUBDOMAINS=False,
+ SECURE_HSTS_SECONDS=3600)
+ def test_no_sts_subdomains_no_middlware(self):
+ """
+ Don't warn if SecurityMiddleware isn't installed.
+ """
+ self.assertEqual(self.func(None), [])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ SECURE_SSL_REDIRECT=False,
+ SECURE_HSTS_SECONDS=None)
+ def test_no_sts_subdomains_no_seconds(self):
+ """
+ Don't warn if SECURE_HSTS_SECONDS isn't set.
+ """
+ self.assertEqual(self.func(None), [])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ SECURE_HSTS_INCLUDE_SUBDOMAINS=True,
+ SECURE_HSTS_SECONDS=3600)
+ def test_with_sts_subdomains(self):
+ self.assertEqual(self.func(None), [])
+
+
+class CheckXFrameOptionsMiddlewareTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.base import check_xframe_options_middleware
+ return check_xframe_options_middleware
+
+ @override_settings(MIDDLEWARE_CLASSES=[])
+ def test_middleware_not_installed(self):
+ """
+ Warn if XFrameOptionsMiddleware isn't in MIDDLEWARE_CLASSES.
+ """
+ self.assertEqual(self.func(None), [base.W002])
+
+ @override_settings(MIDDLEWARE_CLASSES=["django.middleware.clickjacking.XFrameOptionsMiddleware"])
+ def test_middleware_installed(self):
+ self.assertEqual(self.func(None), [])
+
+
+class CheckXFrameOptionsDenyTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.base import check_xframe_deny
+ return check_xframe_deny
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.clickjacking.XFrameOptionsMiddleware"],
+ X_FRAME_OPTIONS='SAMEORIGIN',
+ )
+ def test_x_frame_options_not_deny(self):
+ """
+ Warn if XFrameOptionsMiddleware is in MIDDLEWARE_CLASSES but
+ X_FRAME_OPTIONS isn't 'DENY'.
+ """
+ self.assertEqual(self.func(None), [base.W019])
+
+ @override_settings(MIDDLEWARE_CLASSES=[], X_FRAME_OPTIONS='SAMEORIGIN')
+ def test_middleware_not_installed(self):
+ """
+ No error if XFrameOptionsMiddleware isn't in MIDDLEWARE_CLASSES even if
+ X_FRAME_OPTIONS isn't 'DENY'.
+ """
+ self.assertEqual(self.func(None), [])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.clickjacking.XFrameOptionsMiddleware"],
+ X_FRAME_OPTIONS='DENY',
+ )
+ def test_xframe_deny(self):
+ self.assertEqual(self.func(None), [])
+
+
+class CheckContentTypeNosniffTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.base import check_content_type_nosniff
+ return check_content_type_nosniff
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ SECURE_CONTENT_TYPE_NOSNIFF=False)
+ def test_no_content_type_nosniff(self):
+ """
+ Warn if SECURE_CONTENT_TYPE_NOSNIFF isn't True.
+ """
+ self.assertEqual(self.func(None), [base.W006])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=[],
+ SECURE_CONTENT_TYPE_NOSNIFF=False)
+ def test_no_content_type_nosniff_no_middleware(self):
+ """
+ Don't warn if SECURE_CONTENT_TYPE_NOSNIFF isn't True and
+ SecurityMiddleware isn't in MIDDLEWARE_CLASSES.
+ """
+ self.assertEqual(self.func(None), [])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ SECURE_CONTENT_TYPE_NOSNIFF=True)
+ def test_with_content_type_nosniff(self):
+ self.assertEqual(self.func(None), [])
+
+
+class CheckXssFilterTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.base import check_xss_filter
+ return check_xss_filter
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ SECURE_BROWSER_XSS_FILTER=False)
+ def test_no_xss_filter(self):
+ """
+ Warn if SECURE_BROWSER_XSS_FILTER isn't True.
+ """
+ self.assertEqual(self.func(None), [base.W007])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=[],
+ SECURE_BROWSER_XSS_FILTER=False)
+ def test_no_xss_filter_no_middleware(self):
+ """
+ Don't warn if SECURE_BROWSER_XSS_FILTER isn't True and
+ SecurityMiddleware isn't in MIDDLEWARE_CLASSES.
+ """
+ self.assertEqual(self.func(None), [])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ SECURE_BROWSER_XSS_FILTER=True)
+ def test_with_xss_filter(self):
+ self.assertEqual(self.func(None), [])
+
+
+class CheckSSLRedirectTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.base import check_ssl_redirect
+ return check_ssl_redirect
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ SECURE_SSL_REDIRECT=False)
+ def test_no_ssl_redirect(self):
+ """
+ Warn if SECURE_SSL_REDIRECT isn't True.
+ """
+ self.assertEqual(self.func(None), [base.W008])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=[],
+ SECURE_SSL_REDIRECT=False)
+ def test_no_ssl_redirect_no_middlware(self):
+ """
+ Don't warn if SECURE_SSL_REDIRECT is False and SecurityMiddleware isn't
+ installed.
+ """
+ self.assertEqual(self.func(None), [])
+
+ @override_settings(
+ MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ SECURE_SSL_REDIRECT=True)
+ def test_with_ssl_redirect(self):
+ self.assertEqual(self.func(None), [])
+
+
+class CheckSecretKeyTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.base import check_secret_key
+ return check_secret_key
+
+ @override_settings(SECRET_KEY=('abcdefghijklmnopqrstuvwx' * 2) + 'ab')
+ def test_okay_secret_key(self):
+ self.assertEqual(len(settings.SECRET_KEY), base.SECRET_KEY_MIN_LENGTH)
+ self.assertGreater(len(set(settings.SECRET_KEY)), base.SECRET_KEY_MIN_UNIQUE_CHARACTERS)
+ self.assertEqual(self.func(None), [])
+
+ @override_settings(SECRET_KEY='')
+ def test_empty_secret_key(self):
+ self.assertEqual(self.func(None), [base.W009])
+
+ @override_settings(SECRET_KEY=None)
+ def test_missing_secret_key(self):
+ del settings.SECRET_KEY
+ self.assertEqual(self.func(None), [base.W009])
+
+ @override_settings(SECRET_KEY=None)
+ def test_none_secret_key(self):
+ self.assertEqual(self.func(None), [base.W009])
+
+ @override_settings(SECRET_KEY=('abcdefghijklmnopqrstuvwx' * 2) + 'a')
+ def test_low_length_secret_key(self):
+ self.assertEqual(len(settings.SECRET_KEY), base.SECRET_KEY_MIN_LENGTH - 1)
+ self.assertEqual(self.func(None), [base.W009])
+
+ @override_settings(SECRET_KEY='abcd' * 20)
+ def test_low_entropy_secret_key(self):
+ self.assertGreater(len(settings.SECRET_KEY), base.SECRET_KEY_MIN_LENGTH)
+ self.assertLess(len(set(settings.SECRET_KEY)), base.SECRET_KEY_MIN_UNIQUE_CHARACTERS)
+ self.assertEqual(self.func(None), [base.W009])
+
+
+class CheckDebugTest(TestCase):
+ @property
+ def func(self):
+ from django.core.checks.security.base import check_debug
+ return check_debug
+
+ @override_settings(DEBUG=True)
+ def test_debug_true(self):
+ """
+ Warn if DEBUG is True.
+ """
+ self.assertEqual(self.func(None), [base.W018])
+
+ @override_settings(DEBUG=False)
+ def test_debug_false(self):
+ self.assertEqual(self.func(None), [])
diff --git a/tests/check_framework/tests.py b/tests/check_framework/tests.py
index 47936c3a4e..2fd80fd1ac 100644
--- a/tests/check_framework/tests.py
+++ b/tests/check_framework/tests.py
@@ -194,6 +194,12 @@ def tagged_system_check(**kwargs):
tagged_system_check.tags = ['simpletag']
+def deployment_system_check(**kwargs):
+ deployment_system_check.kwargs = kwargs
+ return [checks.Warning('Deployment Check')]
+deployment_system_check.tags = ['deploymenttag']
+
+
class CheckCommandTests(TestCase):
def setUp(self):
@@ -239,6 +245,27 @@ class CheckCommandTests(TestCase):
call_command('check', list_tags=True)
self.assertEqual('simpletag\n', sys.stdout.getvalue())
+ @override_system_checks([tagged_system_check], deployment_checks=[deployment_system_check])
+ def test_list_deployment_check_omitted(self):
+ call_command('check', list_tags=True)
+ self.assertEqual('simpletag\n', sys.stdout.getvalue())
+
+ @override_system_checks([tagged_system_check], deployment_checks=[deployment_system_check])
+ def test_list_deployment_check_included(self):
+ call_command('check', deploy=True, list_tags=True)
+ self.assertEqual('deploymenttag\nsimpletag\n', sys.stdout.getvalue())
+
+ @override_system_checks([tagged_system_check], deployment_checks=[deployment_system_check])
+ def test_tags_deployment_check_omitted(self):
+ msg = 'There is no system check with the "deploymenttag" tag.'
+ with self.assertRaisesMessage(CommandError, msg):
+ call_command('check', tags=['deploymenttag'])
+
+ @override_system_checks([tagged_system_check], deployment_checks=[deployment_system_check])
+ def test_tags_deployment_check_included(self):
+ call_command('check', deploy=True, tags=['deploymenttag'])
+ self.assertIn('Deployment Check', sys.stderr.getvalue())
+
def custom_error_system_check(app_configs, **kwargs):
return [