diff options
| author | Tim Graham <timograham@gmail.com> | 2014-09-12 14:50:36 -0400 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2014-09-12 15:05:23 -0400 |
| commit | 52ef6a47269a455113d95992f868939131f9c10c (patch) | |
| tree | fed55edbb5ab020ea5bd2d036d0588f62939d729 /tests/check_framework | |
| parent | 8f334e55be99ae271d82f9b961a2dc6258487d9c (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.py | 487 | ||||
| -rw-r--r-- | tests/check_framework/tests.py | 27 |
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 [ |
