-BL{K*7>9U9S^`Xf*}okdGS$!w&UI$moewCmff1Y!0dk;h^Gi{CKyI
z8vz5BP?C)$;mD~jAE$tbvwovg$`#lAmIyO>>Zr|UNuhj}ATuc+v9-YsEKw#R&WxYy
zv>~8?XNzlPW34QgAFLZbDwfhP>0Hn*Kt;O>Q2CAmkq#f10HaoWUEEj^2kWVJyIEA3
z0@6}jF$AgyO`bYz^HCivJ}RCj<$$aC7890gaU8NasKomvV*^rgI4-x@98?zJpn`Dx
zxajIol8r^+NZ9Y=#=wZ9LsvG6_t$wUfF!~`n}4|4Dy@K5mP
z@cZza@JnzL>Tn)D3rAruhR`;2C
z){REZyJ^RzJ^?78joewTjNYRH7zR#58!{=h8f-j!f&v%-A})-R-8}+&&eRyrE|X}L
zGHu{dQk9<+G$}`j9v;@O)6Agd9i}T762K_%;W`}D4kE6`dbOKGS_d^mhlvgXE>9@|
zLUEd+Lneh5#O9@qG#TPjI4O1sU<9~~i{B*CGQ?W=It4HYcwC621xWzsK)s!SCY=_o
zj&z>rUo-pxe*UAEes(bg7y<_n0sQ=D0Dk`akV~I?1N?>;;7NGz@yBF42t;Xg6znXNwM^d7
z?w3~`9?hC0e`!9IyqS`3CNEx3$>EyZuzV&Uqbr=#!*ULJ&{vS_c=pCkd3N#ob@}u2
zS7(y*OY*hU(pi&jO)D5-c~jd!?v;%*iD<-TrVP}Jl*T^yv{$7zpKiD-Q=)aXEzVw@
zTTIDk!nL)Yl@WF?lLna7+N6~tyhs5r1Lc6#t`eE1X99j{VQhCq&Bi%#G$|cy{=a|Lgw@Ot
zc-#?S^Z&=ahnRj0f&D`OKmP%m^nVuS{riUktC=D2DIrj42ko5H(Q&Q>07xb^y^vcY
z!L!DeR#?v)PZc*-N~@Z3GNYZ(8Yk6EJd+sDBn(5(OeEB}8jELieL_*=dMq289ABQy
zsM+(A%c!1M@`hY*p|GPo+cRqJmlm-XEmmRB?cu9gRTH;8s!LrK7Sx<2Ai`RdaCc%p7;-}-j3%A~|5>bP>Hbg8T@FNft!v6!!Q
z51?EvTh47FCqjel(tWi4j1l$bAdSfvS8{7%S=Y)&Iae@hg*L%AO|F}nXgQb7!nV+|
zu~oM52}HJoK~YjwuycvDLw_E9by~DO{UJ^p4^o%ARURCBZJhg__3-?Jwe|IMUdtGc
zThfcIfV@DDX0cry)f&;#tXU2%AhPwp1{RNz83G3Y0X+WO;4u!q3x5ZH2EUEI{au17
zL|_*~;27n>s1RK9uNwJ@VgIw1H*s2(Fp-k
zNFts+Oe2v2bP&K$XsEiW0q0axc>do8H4gq2{t}(a^9T4HsKHm^%LlpZS=$)`pBMuD
z!axLgn+*gnLZ*)kqFp!%?2s*v;a+oJm-Kk)1Lm(boz_NgX$_l+_`{JzopPBgC^=)Sa!`<
z=>i5hWWz|~nY`zGe(I=Sx)Iq04NHs#1Wor=&UT5?@G#gObk2zJO=$suqLO#(QI6eo
zuT4fC8z}W6T4zCP7uFU^uSugZ=w9
zSXspkfzKiWl??FBY%e6^`f@CuP;@=6D(d*8ro<=CN0DzXrY^_y*n~cNdnq<^JEh*e
zsjtr7zN*gNT#DY9PQ{m=UrNkO&nYw0*{#{>t1sN0zPh#aVk&<3_KbRC`d%`*rfek_
zR&PyT*;>u2^Q%kh{CYqySzjd_Frj
zd+XwwzL_nQ^LL+1rEbmTU(~N$exN@$zn-~$YwO~oele<+W&-(ye(m0!#rpx%|95^&
znUrJE3yJ83*aY$nDvB~;`v2bH;5(niE@C<}1Q-Gh5I6~Ez;3pSy#E9EHxB)rN`Ttt5!FU0!<>o_Ww5t6k}ruv>*a_{P)3i4t@kbfd7K;
z!-w!M@Xzp%@VD?S!oz_!fK(eieQNZlnJau!#z=iy^=e*fRn?2tZpO
z2_+Kt;!q5cu!n@*IP`as@F)q7;Lz7e!XODda458s@GuDjIE05t*hWGThrFMJJ`xHz
z1dxP02?2Zl@3{+E0fs=!Ab{upKJFpMJp?)4$G;A5v`o`zLn=Z@l%5_1l`(Q04&Dyo
zIFuu;WHJ-W>SU~jew@0Bug*@V?$n(kW0wlcH)iW{v1^y^*s#w5id2sEiqf@7P?@T#
zK{jYPlqsd-v4m!***MXrF1z1DsX8XR4u@`aOjt#eh!4Z5JRzC7r5>f5VnmgAc4FCE
zw}GZ~v+CGQx9ScR>{*XgPW6e>ToP2SR23v{cM?>Y5r9#3`FzyW(Uao|4?R5@t*RWV
zdh%f?Nd{5$sbiwFfD~QaO;HO8f~IH1gH3B{)zyruRj>%M?D^kn_KvlOA<#SmZ2UKm
z72{+Gv>F0z{I^<{k2(a=M2RZ*bcvjBJ4WA2)s0aKCX>`$`J8hSswtKU!cpKy~;y1i8HOuLNf
znQ~`h$C>lf=Ey6@k)w7DR0eB&XT(wI;o39lvRi?wKh0gN);DJ6x}A5RUzDCf3Jf<;
z!0DVNE<3Z5q1`l~LLEPwG*P07y*^estWYme#;+88c1nj56Ly`4xv^dr^6CI
f{{eg#o&R%yZ+q5shCr(#@B~cKgMqz1{{{aCeAhGM
diff --git a/testing/tests/__init__.py b/testing/tests/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/testing/urls.py b/testing/urls.py
deleted file mode 100644
index 4428048..0000000
--- a/testing/urls.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (c) 2011, SD Elements. See ../LICENSE.txt for details.
-
-from django.conf.urls import url
-from django.http import HttpResponse
-from django.contrib.auth.views import LoginView, PasswordChangeView
-
-from security.auth_throttling.views import reset_username_throttle
-from security.views import csp_report
-
-urlpatterns = [
- url("^accounts/login/$", LoginView.as_view(), {}, "login"),
- url("^change_password/$", PasswordChangeView.as_view(),
- {"post_change_redirect": "/home/"}, "change_password"),
- url(r"^admin/reset-account-throttling/(?P-?[0-9]+)/",
- reset_username_throttle,
- {"redirect_url": "/admin"}, "reset_username_throttle"),
- url("^home/$", lambda request: HttpResponse()),
- url("^custom-login/$", lambda request: HttpResponse()),
- url("^test1/$", lambda request: HttpResponse(), {}, "test1"),
- url("^test2/$", lambda request: HttpResponse(), {}, "test2"),
- url("^test3/$", lambda request: HttpResponse(), {}, "test3"),
- url("^test4/$", lambda request: HttpResponse(), {}, "test4"),
- url("^csp-report/$", csp_report),
-]
diff --git a/security/south_migrations/__init__.py b/tests/__init__.py
similarity index 100%
rename from security/south_migrations/__init__.py
rename to tests/__init__.py
diff --git a/testing/tests/models.py b/tests/models.py
similarity index 100%
rename from testing/tests/models.py
rename to tests/models.py
diff --git a/tests/settings.py b/tests/settings.py
new file mode 100644
index 0000000..55aea59
--- /dev/null
+++ b/tests/settings.py
@@ -0,0 +1,151 @@
+import os as _os
+
+_PROJECT_PATH = _os.path.abspath(_os.path.dirname(__file__))
+
+DEBUG = True
+ADMINS = ()
+MANAGERS = ADMINS
+DATABASES = {
+ "default": {
+ "ENGINE": "django.db.backends.sqlite3",
+ "NAME": "testing.db",
+ "USER": "",
+ "PASSWORD": "",
+ "HOST": "",
+ "PORT": "",
+ }
+}
+TIME_ZONE = "America/Chicago"
+USE_TZ = True
+LANGUAGE_CODE = "en-us"
+SITE_ID = 1
+USE_I18N = True
+USE_L10N = True
+MEDIA_ROOT = ""
+MEDIA_URL = ""
+STATIC_ROOT = ""
+STATIC_URL = "/static/"
+STATICFILES_DIRS = ()
+STATICFILES_FINDERS = (
+ "django.contrib.staticfiles.finders.FileSystemFinder",
+ "django.contrib.staticfiles.finders.AppDirectoriesFinder",
+)
+SECRET_KEY = "foobar"
+DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
+
+MIDDLEWARE = (
+ "django.middleware.common.CommonMiddleware",
+ "django.contrib.sessions.middleware.SessionMiddleware",
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
+ "django.middleware.csrf.CsrfViewMiddleware",
+ "django.contrib.messages.middleware.MessageMiddleware",
+ "security.middleware.SessionExpiryPolicyMiddleware",
+ "security.middleware.LoginRequiredMiddleware",
+ "security.middleware.XFrameOptionsMiddleware",
+ "security.middleware.ContentSecurityPolicyMiddleware",
+ "security.middleware.MandatoryPasswordChangeMiddleware",
+ "security.middleware.NoConfidentialCachingMiddleware",
+ "security.auth_throttling.Middleware",
+ "security.middleware.ReferrerPolicyMiddleware",
+ "security.middleware.ProfilingMiddleware",
+)
+
+ROOT_URLCONF = "tests.urls"
+
+TEMPLATES = [
+ {
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "DIRS": [_os.path.join(_PROJECT_PATH, "templates")],
+ "OPTIONS": {
+ "context_processors": [
+ "django.template.context_processors.request",
+ "django.contrib.auth.context_processors.auth",
+ "django.contrib.messages.context_processors.messages",
+ ]
+ },
+ }
+]
+
+
+INSTALLED_APPS = (
+ "django.contrib.auth",
+ "django.contrib.contenttypes",
+ "django.contrib.sessions",
+ "django.contrib.sites",
+ "django.contrib.staticfiles",
+ "django.contrib.messages",
+ "django.contrib.admin",
+ "security",
+ "tests",
+)
+
+TEST_RUNNER = "django.test.runner.DiscoverRunner"
+
+LOGIN_REDIRECT_URL = "/home/"
+
+# The tests for django.contrib.auth use certain URLs, and they'll fail if we
+# interfere with these.
+_DJANGO_TESTING_URLS = [
+ "login/",
+ "login_required/",
+ "login_required_login_url/",
+ "admin_password_reset/",
+ "logout/",
+ "password_reset/",
+ "password_reset_from_email/",
+ "reset/",
+ "password_change/",
+ "remote_user/",
+ "auth_processor_messages/",
+ "auth_processor_perms/",
+ "auth_processor_user/",
+ "auth_processor_perm_in_perms/",
+ "admin/auth/user/",
+]
+
+LOGIN_EXEMPT_URLS = [
+ "accounts/login",
+ "custom-login",
+ "admin/reset-account-throttling",
+] + _DJANGO_TESTING_URLS
+
+SESSION_EXPIRY_EXEMPT_URLS = LOGIN_EXEMPT_URLS
+
+CUSTOM_LOGOUT_MODULE = "tests.tests.mocked_custom_logout"
+
+MANDATORY_PASSWORD_CHANGE = {
+ "URL_NAME": "change_password",
+ "EXEMPT_URL_NAMES": (),
+ "EXEMPT_URLS": _DJANGO_TESTING_URLS,
+}
+
+AUTHENTICATION_THROTTLING = {
+ "DELAY_FUNCTION": lambda x, y: (0, 0),
+ "LOGIN_URLS_WITH_TEMPLATES": [("accounts/login/", "login.html")],
+}
+
+XSS_PROTECT = "on"
+X_FRAME_OPTIONS = "allow-from: http://example.com"
+X_FRAME_OPTIONS_EXCLUDE_URLS = (r"^/test\d/$",)
+CSP_STRING = "allow 'self'; script-src *.google.com"
+CSP_MODE = "enforce"
+
+LOGGING = {
+ "version": 1,
+ "disable_existing_loggers": False,
+ "handlers": {
+ "console": {
+ "level": "DEBUG",
+ "class": "logging.StreamHandler",
+ },
+ },
+ "loggers": {
+ "": {
+ "handlers": ["console"],
+ "level": "WARNING",
+ "propagate": True,
+ },
+ },
+}
+
+CLEAR_SITE_DATA_URL_WHITELIST = "/home/"
diff --git a/testing/templates/404.html b/tests/templates/404.html
similarity index 100%
rename from testing/templates/404.html
rename to tests/templates/404.html
diff --git a/testing/templates/registration/login.html b/tests/templates/registration/login.html
similarity index 100%
rename from testing/templates/registration/login.html
rename to tests/templates/registration/login.html
diff --git a/testing/templates/registration/password_change_form.html b/tests/templates/registration/password_change_form.html
similarity index 100%
rename from testing/templates/registration/password_change_form.html
rename to tests/templates/registration/password_change_form.html
diff --git a/testing/tests/tests.py b/tests/tests.py
similarity index 60%
rename from testing/tests/tests.py
rename to tests/tests.py
index 3ce346d..2f249cd 100644
--- a/testing/tests/tests.py
+++ b/tests/tests.py
@@ -5,30 +5,32 @@
import time # We monkeypatch this.
from django.conf import settings
-from django.contrib.auth.models import User
from django.contrib.auth import logout
+from django.contrib.auth.models import User
from django.core.cache import cache
from django.core.exceptions import ImproperlyConfigured, MiddlewareNotUsed
-from django.urls import reverse
from django.forms import ValidationError
-from django.http import HttpResponseForbidden, HttpRequest, HttpResponse
+from django.http import HttpRequest, HttpResponse, HttpResponseForbidden
from django.test import TestCase
from django.test.utils import override_settings
+from django.urls import reverse
from django.utils import timezone
from security.auth import min_length
-from security.auth_throttling import (
- attempt_count, default_delay_function, delay_message, increment_counters,
- reset_counters, Middleware as AuthThrottlingMiddleware
-)
-from security.middleware import (
- BaseMiddleware, ContentSecurityPolicyMiddleware, DoNotTrackMiddleware,
- SessionExpiryPolicyMiddleware, MandatoryPasswordChangeMiddleware,
- XssProtectMiddleware, XFrameOptionsMiddleware, ReferrerPolicyMiddleware
-)
+from security.auth_throttling import Middleware as AuthThrottlingMiddleware
+from security.auth_throttling import (attempt_count, default_delay_function,
+ delay_message, increment_counters,
+ reset_counters)
+from security.middleware import (BaseMiddleware,
+ ContentSecurityPolicyMiddleware,
+ DoNotTrackMiddleware,
+ MandatoryPasswordChangeMiddleware,
+ ReferrerPolicyMiddleware,
+ SessionExpiryPolicyMiddleware,
+ XFrameOptionsMiddleware)
from security.models import PasswordExpiry
from security.password_expiry import never_expire_password
-from security.views import require_ajax, csp_report
+from security.views import csp_report, require_ajax
try:
# Python 3
@@ -46,10 +48,11 @@ def login_user(func):
then log that user in. We expect self to be a DjangoTestCase,
or some object with a similar interface.
"""
+
def wrapper(self, *args, **kwargs):
- username_local = 'a2fcf54f63993b7'
- password_local = 'd8327deb882cf90'
- email_local = 'testuser@example.com'
+ username_local = "a2fcf54f63993b7"
+ password_local = "d8327deb882cf90"
+ email_local = "testuser@example.com"
user = User.objects.create_user(
username=username_local,
email=email_local,
@@ -62,21 +65,23 @@ def wrapper(self, *args, **kwargs):
func(self, *args, **kwargs)
self.client.logout()
user.delete()
+
return wrapper
class CustomLoginURLMiddleware(BaseMiddleware):
"""Used to test the custom url support in the login required middleware."""
+
def process_request(self, request):
- request.login_url = '/custom-login/'
+ request.login_url = "/custom-login/"
class BaseMiddlewareTestMiddleware(BaseMiddleware):
- REQUIRED_SETTINGS = ('R1', 'R2')
- OPTIONAL_SETTINGS = ('O1', 'O2')
+ REQUIRED_SETTINGS = ("R1", "R2")
+ OPTIONAL_SETTINGS = ("O1", "O2")
def load_setting(self, setting, value):
- if not hasattr(self, 'loaded_settings'):
+ if not hasattr(self, "loaded_settings"):
self.loaded_settings = {}
self.loaded_settings[setting] = value
@@ -92,96 +97,90 @@ class BaseMiddlewareTests(TestCase):
def __init__(self, *args, **kwargs):
super(BaseMiddlewareTests, self).__init__(*args, **kwargs)
module_name = BaseMiddlewareTests.__module__
- self.MIDDLEWARE_NAME = module_name + '.BaseMiddlewareTestMiddleware'
+ self.MIDDLEWARE_NAME = module_name + ".BaseMiddlewareTestMiddleware"
def test_settings_initially_loaded(self):
- expected_settings = {'R1': 1, 'R2': 2, 'O1': 3, 'O2': 4}
- with self.settings(
- MIDDLEWARE=(self.MIDDLEWARE_NAME,), **expected_settings
- ):
- response = self.client.get('/home/')
+ expected_settings = {"R1": 1, "R2": 2, "O1": 3, "O2": 4}
+ with self.settings(MIDDLEWARE=(self.MIDDLEWARE_NAME,), **expected_settings):
+ response = self.client.get("/home/")
self.assertEqual(expected_settings, response.loaded_settings)
def test_required_settings(self):
with self.settings(MIDDLEWARE=(self.MIDDLEWARE_NAME,)):
- self.assertRaises(ImproperlyConfigured, self.client.get, '/home/')
+ self.assertRaises(ImproperlyConfigured, self.client.get, "/home/")
def test_optional_settings(self):
- with self.settings(
- MIDDLEWARE=(self.MIDDLEWARE_NAME,), R1=True, R2=True
- ):
- response = self.client.get('/home/')
- self.assertEqual(None, response.loaded_settings['O1'])
- self.assertEqual(None, response.loaded_settings['O2'])
+ with self.settings(MIDDLEWARE=(self.MIDDLEWARE_NAME,), R1=True, R2=True):
+ response = self.client.get("/home/")
+ self.assertEqual(None, response.loaded_settings["O1"])
+ self.assertEqual(None, response.loaded_settings["O2"])
def test_setting_change(self):
- with self.settings(
- MIDDLEWARE=(self.MIDDLEWARE_NAME,), R1=123, R2=True
- ):
- response = self.client.get('/home/')
- self.assertEqual(123, response.loaded_settings['R1'])
+ with self.settings(MIDDLEWARE=(self.MIDDLEWARE_NAME,), R1=123, R2=True):
+ response = self.client.get("/home/")
+ self.assertEqual(123, response.loaded_settings["R1"])
with override_settings(R1=456):
- response = self.client.get('/home/')
- self.assertEqual(456, response.loaded_settings['R1'])
+ response = self.client.get("/home/")
+ self.assertEqual(456, response.loaded_settings["R1"])
- response = self.client.get('/home/')
- self.assertEqual(123, response.loaded_settings['R1'])
+ response = self.client.get("/home/")
+ self.assertEqual(123, response.loaded_settings["R1"])
def test_load_setting_abstract_method(self):
base = BaseMiddleware()
self.assertRaises(NotImplementedError, base.load_setting, None, None)
-@override_settings(MIDDLEWARE=(
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'security.middleware.LoginRequiredMiddleware',
-))
+@override_settings(
+ MIDDLEWARE=(
+ "django.contrib.sessions.middleware.SessionMiddleware",
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
+ "security.middleware.LoginRequiredMiddleware",
+ )
+)
class LoginRequiredMiddlewareTests(TestCase):
def setUp(self):
self.login_url = reverse("login")
def test_aborts_if_auth_middleware_missing(self):
middleware_classes = settings.MIDDLEWARE
- auth_mw = 'django.contrib.auth.middleware.AuthenticationMiddleware'
- middleware_classes = [
- m for m in middleware_classes if m != auth_mw
- ]
+ auth_mw = "django.contrib.auth.middleware.AuthenticationMiddleware"
+ middleware_classes = [m for m in middleware_classes if m != auth_mw]
with self.settings(MIDDLEWARE=middleware_classes):
- self.assertRaises(ImproperlyConfigured, self.client.get, '/home/')
+ self.assertRaises(ImproperlyConfigured, self.client.get, "/home/")
def test_redirects_unauthenticated_request(self):
- response = self.client.get('/home/')
+ response = self.client.get("/home/")
self.assertRedirects(response, self.login_url + "?next=/home/")
def test_redirects_unauthenticated_ajax_request(self):
response = self.client.get(
- '/home/',
- HTTP_X_REQUESTED_WITH='XMLHttpRequest',
+ "/home/",
+ HTTP_X_REQUESTED_WITH="XMLHttpRequest",
)
self.assertEqual(response.status_code, 401)
self.assertEqual(
- json.loads(response.content.decode('utf-8')),
+ json.loads(response.content.decode("utf-8")),
{"login_url": self.login_url},
)
def test_redirects_to_custom_login_url(self):
middlware_classes = list(settings.MIDDLEWARE)
- custom_login_middleware = 'tests.tests.CustomLoginURLMiddleware'
+ custom_login_middleware = "tests.tests.CustomLoginURLMiddleware"
with self.settings(
MIDDLEWARE=[custom_login_middleware] + middlware_classes,
):
- response = self.client.get('/home/')
- self.assertRedirects(response, '/custom-login/')
+ response = self.client.get("/home/")
+ self.assertRedirects(response, "/custom-login/")
response = self.client.get(
- '/home/',
- HTTP_X_REQUESTED_WITH='XMLHttpRequest',
+ "/home/",
+ HTTP_X_REQUESTED_WITH="XMLHttpRequest",
)
self.assertEqual(response.status_code, 401)
self.assertEqual(
- json.loads(response.content.decode('utf-8')),
- {"login_url": '/custom-login/'},
+ json.loads(response.content.decode("utf-8")),
+ {"login_url": "/custom-login/"},
)
def test_logs_out_inactive_users(self):
@@ -192,28 +191,30 @@ def test_logs_out_inactive_users(self):
)
never_expire_password(user)
self.client.login(username="foo", password="foo")
- resp = self.client.get('/home/')
+ resp = self.client.get("/home/")
self.assertEqual(resp.status_code, 200) # check we are logged in
user.is_active = False
user.save()
- resp = self.client.get('/home/')
+ resp = self.client.get("/home/")
self.assertRedirects(resp, self.login_url + "?next=/home/")
-@override_settings(MIDDLEWARE=(
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'security.middleware.MandatoryPasswordChangeMiddleware',
-))
+@override_settings(
+ MIDDLEWARE=(
+ "django.contrib.sessions.middleware.SessionMiddleware",
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
+ "security.middleware.MandatoryPasswordChangeMiddleware",
+ )
+)
class RequirePasswordChangeTests(TestCase):
def test_require_password_change(self):
"""
A brand-new user should have an already-expired password, and therefore
be redirected to the password change form on any request.
"""
- user = User.objects.create_user(username="foo",
- password="foo",
- email="foo@foo.com")
+ user = User.objects.create_user(
+ username="foo", password="foo", email="foo@foo.com"
+ )
self.client.login(username="foo", password="foo")
try:
with self.settings(
@@ -233,19 +234,20 @@ def test_superuser_password_change(self):
"""
A superuser can be forced to change their password via settings.
"""
- user = User.objects.create_superuser(username="foo",
- password="foo",
- email="foo@foo.com")
+ user = User.objects.create_superuser(
+ username="foo", password="foo", email="foo@foo.com"
+ )
self.client.login(username="foo", password="foo")
- with self.settings(MANDATORY_PASSWORD_CHANGE={
- "URL_NAME": "change_password"}):
+ with self.settings(MANDATORY_PASSWORD_CHANGE={"URL_NAME": "change_password"}):
self.assertEqual(self.client.get("/home/").status_code, 200)
try:
- with self.settings(MANDATORY_PASSWORD_CHANGE={
- "URL_NAME": "change_password",
- "INCLUDE_SUPERUSERS": True
- }):
+ with self.settings(
+ MANDATORY_PASSWORD_CHANGE={
+ "URL_NAME": "change_password",
+ "INCLUDE_SUPERUSERS": True,
+ }
+ ):
self.assertRedirects(
self.client.get("/home/"),
reverse("change_password"),
@@ -256,18 +258,18 @@ def test_superuser_password_change(self):
def test_dont_redirect_exempt_urls(self):
user = User.objects.create_user(
- username="foo",
- password="foo",
- email="foo@foo.com"
+ username="foo", password="foo", email="foo@foo.com"
)
self.client.login(username="foo", password="foo")
try:
- with self.settings(MANDATORY_PASSWORD_CHANGE={
- "URL_NAME": "change_password",
- "EXEMPT_URLS": (r'^test1/$', r'^test2/$'),
- "EXEMPT_URL_NAMES": ("test3", "test4"),
- }):
+ with self.settings(
+ MANDATORY_PASSWORD_CHANGE={
+ "URL_NAME": "change_password",
+ "EXEMPT_URLS": (r"^test1/$", r"^test2/$"),
+ "EXEMPT_URL_NAMES": ("test3", "test4"),
+ }
+ ):
# Redirect pages in general
self.assertRedirects(
self.client.get("/home/"),
@@ -290,16 +292,18 @@ def test_dont_redirect_exempt_urls(self):
user.delete()
def test_dont_choke_on_exempt_urls_that_dont_resolve(self):
- user = User.objects.create_user(username="foo",
- password="foo",
- email="foo@foo.com")
+ user = User.objects.create_user(
+ username="foo", password="foo", email="foo@foo.com"
+ )
self.client.login(username="foo", password="foo")
try:
- with self.settings(MANDATORY_PASSWORD_CHANGE={
- "URL_NAME": "change_password",
- "EXEMPT_URL_NAMES": ("fake1", "fake2"),
- }):
+ with self.settings(
+ MANDATORY_PASSWORD_CHANGE={
+ "URL_NAME": "change_password",
+ "EXEMPT_URL_NAMES": ("fake1", "fake2"),
+ }
+ ):
# Redirect pages in general
self.assertRedirects(
self.client.get("/home/"),
@@ -314,8 +318,8 @@ def test_raises_improperly_configured(self):
self.assertRaises(
ImproperlyConfigured,
change.load_setting,
- 'MANDATORY_PASSWORD_CHANGE',
- {'EXEMPT_URLS': []},
+ "MANDATORY_PASSWORD_CHANGE",
+ {"EXEMPT_URLS": []},
)
@@ -327,38 +331,38 @@ class DecoratorTest(TestCase):
def require_ajax_test(self):
@require_ajax
def ajax_only_view(request):
- self.assertTrue(request.is_ajax())
+ self.assertTrue(request.headers.get("x-requested-with") == "XMLHttpRequest")
request = HttpRequest()
response = ajax_only_view(request)
self.assertTrue(isinstance(response, HttpResponseForbidden))
- request.META['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
+ request.META["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest"
response = ajax_only_view(request)
self.assertFalse(isinstance(response, HttpResponseForbidden))
-@override_settings(MIDDLEWARE=(
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'security.middleware.SessionExpiryPolicyMiddleware',
- 'security.middleware.LoginRequiredMiddleware',
-))
+@override_settings(
+ MIDDLEWARE=(
+ "django.contrib.sessions.middleware.SessionMiddleware",
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
+ "security.middleware.SessionExpiryPolicyMiddleware",
+ "security.middleware.LoginRequiredMiddleware",
+ )
+)
class SessionExpiryTests(TestCase):
def test_session_variables_are_set(self):
"""
Verify the session cookie stores the start time and last active time.
"""
- self.client.get('/home/')
+ self.client.get("/home/")
now = timezone.now()
start_time = SessionExpiryPolicyMiddleware._get_datetime_in_session(
- SessionExpiryPolicyMiddleware.START_TIME_KEY,
- self.client.session
+ SessionExpiryPolicyMiddleware.START_TIME_KEY, self.client.session
)
last_activity = SessionExpiryPolicyMiddleware._get_datetime_in_session(
- SessionExpiryPolicyMiddleware.LAST_ACTIVITY_KEY,
- self.client.session
+ SessionExpiryPolicyMiddleware.LAST_ACTIVITY_KEY, self.client.session
)
self.assertTrue(now - start_time < datetime.timedelta(seconds=10))
@@ -369,17 +373,12 @@ def session_expiry_test(self, key, expired):
Verify that expired sessions are cleared from the system. (And that we
redirect to the login page.)
"""
- self.assertTrue(self.client.get('/home/').status_code, 200)
+ self.assertTrue(self.client.get("/home/").status_code, 200)
session = self.client.session
- SessionExpiryPolicyMiddleware._set_datetime_in_session(
- key,
- expired,
- session
- )
+ SessionExpiryPolicyMiddleware._set_datetime_in_session(key, expired, session)
session.save()
- response = self.client.get('/home/')
- self.assertRedirects(response,
- reverse("login") + '?next=/home/')
+ response = self.client.get("/home/")
+ self.assertRedirects(response, reverse("login") + "?next=/home/")
@login_user
def test_session_too_old(self):
@@ -389,8 +388,7 @@ def test_session_too_old(self):
"""
delta = SessionExpiryPolicyMiddleware().SESSION_COOKIE_AGE + 1
expired = timezone.now() - datetime.timedelta(seconds=delta)
- self.session_expiry_test(SessionExpiryPolicyMiddleware.START_TIME_KEY,
- expired)
+ self.session_expiry_test(SessionExpiryPolicyMiddleware.START_TIME_KEY, expired)
@login_user
def test_session_inactive_too_long(self):
@@ -410,22 +408,19 @@ def test_exempted_session_expiry_urls(self):
delta = SessionExpiryPolicyMiddleware().SESSION_INACTIVITY_TIMEOUT + 1
expired = timezone.now() - datetime.timedelta(seconds=delta)
- self.assertTrue(self.client.get('/home/').status_code, 200)
+ self.assertTrue(self.client.get("/home/").status_code, 200)
session = self.client.session
SessionExpiryPolicyMiddleware._set_datetime_in_session(
- SessionExpiryPolicyMiddleware.LAST_ACTIVITY_KEY,
- expired,
- session
+ SessionExpiryPolicyMiddleware.LAST_ACTIVITY_KEY, expired, session
)
session.save()
- exempted_response = self.client.get('/accounts/login/')
- not_exempted_response = self.client.get('/home/')
+ exempted_response = self.client.get("/accounts/login/")
+ not_exempted_response = self.client.get("/home/")
self.assertTrue(exempted_response.status_code, 200)
- self.assertRedirects(not_exempted_response,
- reverse("login") + '?next=/home/')
+ self.assertRedirects(not_exempted_response, reverse("login") + "?next=/home/")
@login_user
def test_custom_logout(self):
@@ -438,26 +433,26 @@ def test_custom_logout(self):
assert mocked_custom_logout.called
-@override_settings(MIDDLEWARE=(
- 'security.middleware.NoConfidentialCachingMiddleware',
-))
+@override_settings(MIDDLEWARE=("security.middleware.NoConfidentialCachingMiddleware",))
class ConfidentialCachingTests(TestCase):
def setUp(self):
self.header_values = {
- "Cache-Control": 'no-cache, no-store, max-age=0, must-revalidate',
+ "Cache-Control": "no-cache, no-store, max-age=0, must-revalidate",
"Pragma": "no-cache",
- "Expires": '-1'
+ "Expires": "-1",
}
- @override_settings(NO_CONFIDENTIAL_CACHING={
- "WHITELIST_ON": True,
- "BLACKLIST_ON": False,
- "WHITELIST_REGEXES": ["accounts/login/$"],
- "BLACKLIST_REGEXES": ["accounts/logout/$"]
- })
+ @override_settings(
+ NO_CONFIDENTIAL_CACHING={
+ "WHITELIST_ON": True,
+ "BLACKLIST_ON": False,
+ "WHITELIST_REGEXES": ["accounts/login/$"],
+ "BLACKLIST_REGEXES": ["accounts/logout/$"],
+ }
+ )
def test_whitelisting(self):
# Get Non Confidential Page
- response = self.client.get('/accounts/login/')
+ response = self.client.get("/accounts/login/")
for header, value in self.header_values.items():
self.assertNotEqual(response.get(header, None), value)
# Get Confidential Page
@@ -465,15 +460,17 @@ def test_whitelisting(self):
for header, value in self.header_values.items():
self.assertEqual(response.get(header, None), value)
- @override_settings(NO_CONFIDENTIAL_CACHING={
- "WHITELIST_ON": False,
- "BLACKLIST_ON": True,
- "WHITELIST_REGEXES": ["accounts/login/$"],
- "BLACKLIST_REGEXES": ["accounts/logout/$"]
- })
+ @override_settings(
+ NO_CONFIDENTIAL_CACHING={
+ "WHITELIST_ON": False,
+ "BLACKLIST_ON": True,
+ "WHITELIST_REGEXES": ["accounts/login/$"],
+ "BLACKLIST_REGEXES": ["accounts/logout/$"],
+ }
+ )
def test_blacklisting(self):
# Get Non Confidential Page
- response = self.client.get('/accounts/login/')
+ response = self.client.get("/accounts/login/")
for header, value in self.header_values.items():
self.assertNotEqual(response.get(header, None), value)
# Get Confidential Page
@@ -482,124 +479,69 @@ def test_blacklisting(self):
self.assertEqual(response.get(header, None), value)
-@override_settings(MIDDLEWARE=('security.middleware.XFrameOptionsMiddleware',))
+@override_settings(MIDDLEWARE=("security.middleware.XFrameOptionsMiddleware",))
class XFrameOptionsDenyTests(TestCase):
def test_option_set(self):
"""
Verify the HTTP Response Header is set.
"""
- response = self.client.get('/accounts/login/')
- self.assertEqual(response['X-Frame-Options'], settings.X_FRAME_OPTIONS)
+ response = self.client.get("/accounts/login/")
+ self.assertEqual(response["X-Frame-Options"], settings.X_FRAME_OPTIONS)
def test_exclude_urls(self):
"""
Verify that pages can be excluded from the X-Frame-Options header.
"""
- response = self.client.get('/home/')
- self.assertEqual(response['X-Frame-Options'], settings.X_FRAME_OPTIONS)
- response = self.client.get('/test1/')
- self.assertNotIn('X-Frame-Options', response)
+ response = self.client.get("/home/")
+ self.assertEqual(response["X-Frame-Options"], settings.X_FRAME_OPTIONS)
+ response = self.client.get("/test1/")
+ self.assertNotIn("X-Frame-Options", response)
def test_improperly_configured(self):
xframe = XFrameOptionsMiddleware()
self.assertRaises(
ImproperlyConfigured,
xframe.load_setting,
- 'X_FRAME_OPTIONS',
- 'invalid',
+ "X_FRAME_OPTIONS",
+ "invalid",
)
self.assertRaises(
ImproperlyConfigured,
xframe.load_setting,
- 'X_FRAME_OPTIONS_EXCLUDE_URLS',
+ "X_FRAME_OPTIONS_EXCLUDE_URLS",
1,
)
@override_settings(X_FRAME_OPTIONS_EXCLUDE_URLS=None)
def test_default_exclude_urls(self):
# This URL is excluded in other tests, see settings.py
- response = self.client.get('/test1/')
+ response = self.client.get("/test1/")
self.assertEqual(
- response['X-Frame-Options'],
+ response["X-Frame-Options"],
settings.X_FRAME_OPTIONS,
)
@override_settings(X_FRAME_OPTIONS=None)
def test_default_xframe_option(self):
- response = self.client.get('/home/')
+ response = self.client.get("/home/")
self.assertEqual(
- response['X-Frame-Options'],
- 'deny',
+ response["X-Frame-Options"],
+ "deny",
)
-@override_settings(MIDDLEWARE=('security.middleware.XssProtectMiddleware',))
-class XXssProtectTests(TestCase):
-
- def test_option_set(self):
- """
- Verify the HTTP Response Header is set.
- """
- response = self.client.get('/accounts/login/')
- self.assertNotEqual(response['X-XSS-Protection'], None)
-
- def test_default_setting(self):
- with self.settings(XSS_PROTECT=None):
- response = self.client.get('/accounts/login/')
- self.assertEqual(response['X-XSS-Protection'], '1') # sanitize
-
- def test_option_off(self):
- with self.settings(XSS_PROTECT='off'):
- response = self.client.get('/accounts/login/')
- self.assertEqual(response['X-XSS-Protection'], '0') # off
-
- def test_improper_configuration_raises(self):
- xss = XssProtectMiddleware()
- self.assertRaises(
- ImproperlyConfigured,
- xss.load_setting,
- 'XSS_PROTECT',
- 'invalid',
- )
-
-
-@override_settings(MIDDLEWARE=('security.middleware.ContentNoSniff',))
-class ContentNoSniffTests(TestCase):
-
- def test_option_set(self):
- """
- Verify the HTTP Response Header is set.
- """
- response = self.client.get('/accounts/login/')
- self.assertEqual(response['X-Content-Options'], 'nosniff')
-
-
-@override_settings(MIDDLEWARE=(
- 'security.middleware.StrictTransportSecurityMiddleware',
-))
-class StrictTransportSecurityTests(TestCase):
-
- def test_option_set(self):
- """
- Verify the HTTP Response Header is set.
- """
- response = self.client.get('/accounts/login/')
- self.assertNotEqual(response['Strict-Transport-Security'], None)
-
-
@override_settings(
AUTHENTICATION_THROTTLING={
"DELAY_FUNCTION": lambda x, _: (2 ** (x - 1) if x else 0, 0),
- "LOGIN_URLS_WITH_TEMPLATES": [
- ("accounts/login/", "registration/login.html")
- ]
+ "LOGIN_URLS_WITH_TEMPLATES": [("accounts/login/", "registration/login.html")],
},
MIDDLEWARE=(
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'security.auth_throttling.Middleware',)
+ "django.contrib.sessions.middleware.SessionMiddleware",
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
+ "security.auth_throttling.Middleware",
+ ),
)
class AuthenticationThrottlingTests(TestCase):
def setUp(self):
@@ -607,17 +549,17 @@ def setUp(self):
self.old_time = time.time
self.time = 0
time.time = lambda: self.time
- self.user = User.objects.create_user(username="foo", password="foo",
- email="a@foo.org")
+ self.user = User.objects.create_user(
+ username="foo", password="foo", email="a@foo.org"
+ )
def tearDown(self):
time.time = self.old_time
def attempt(self, password):
- return self.client.post("/accounts/login/",
- {"username": "foo",
- "password": password},
- follow=True)
+ return self.client.post(
+ "/accounts/login/", {"username": "foo", "password": password}, follow=True
+ )
def reset(self):
self.client.logout()
@@ -627,8 +569,7 @@ def typo(self):
self.assertTemplateUsed(self.attempt("bar"), "registration/login.html")
def _succeed(self):
- self.assertTemplateNotUsed(self.attempt("foo"),
- "registration/login.html")
+ self.assertTemplateNotUsed(self.attempt("foo"), "registration/login.html")
self.reset()
def _fail(self):
@@ -712,12 +653,12 @@ def test_per_account_throttling(self):
self.set_time(3)
self._succeed()
- @override_settings(AUTHENTICATION_THROTTLING={
- "DELAY_FUNCTION": lambda x, y: (x, y),
- "LOGIN_URLS_WITH_TEMPLATES": [
- ("accounts/login/", None)
- ]
- })
+ @override_settings(
+ AUTHENTICATION_THROTTLING={
+ "DELAY_FUNCTION": lambda x, y: (x, y),
+ "LOGIN_URLS_WITH_TEMPLATES": [("accounts/login/", None)],
+ }
+ )
def test_too_many_requests_error_when_no_template_provided(self):
"""
Verify we simply return a 429 error when there is no login template
@@ -745,8 +686,9 @@ def test_reset_button(self):
"""
self.set_time(0)
self.typo()
- admin = User.objects.create_user(username="bar", password="bar",
- email="a@bar.org")
+ admin = User.objects.create_user(
+ username="bar", password="bar", email="a@bar.org"
+ )
admin.is_superuser = True
admin.save()
self.client.login(username="bar", password="bar")
@@ -756,9 +698,11 @@ def test_reset_button(self):
self.client.logout()
self._succeed()
- @override_settings(AUTHENTICATION_THROTTLING={
- "DELAY_FUNCTION": lambda x, y: (x, y),
- })
+ @override_settings(
+ AUTHENTICATION_THROTTLING={
+ "DELAY_FUNCTION": lambda x, y: (x, y),
+ }
+ )
def test_improperly_configured_middleware(self):
self.assertRaises(ImproperlyConfigured, AuthThrottlingMiddleware)
@@ -785,32 +729,18 @@ def test_throttle_reset_404_on_not_found(self):
self.assertEqual(resp.status_code, 404)
-@override_settings(MIDDLEWARE=('security.middleware.P3PPolicyMiddleware',))
-class P3PPolicyTests(TestCase):
-
- def setUp(self):
- self.policy = "NN AD BLAH"
- settings.P3P_COMPACT_POLICY = self.policy
-
- def test_p3p_header(self):
- expected_header = 'policyref="/w3c/p3p.xml" CP="%s"' % self.policy
- response = self.client.get('/accounts/login/')
- self.assertEqual(response["P3P"], expected_header)
-
-
class AuthTests(TestCase):
def test_min_length(self):
self.assertRaises(ValidationError, min_length(6), "abcde")
min_length(6)("abcdef")
-@override_settings(MIDDLEWARE=(
- 'security.middleware.ContentSecurityPolicyMiddleware',
-))
+@override_settings(MIDDLEWARE=("security.middleware.ContentSecurityPolicyMiddleware",))
class ContentSecurityPolicyTests(TestCase):
class FakeHttpRequest(object):
- method = 'POST'
- body = """{
+ method = "POST"
+ body = (
+ """{
"csp-report": {
"document-uri": "http://example.org/page.html",
"referrer": "http://evil.example.com/haxor.html",
@@ -819,20 +749,22 @@ class FakeHttpRequest(object):
"original-policy": "%s"
}
}
- """ % settings.CSP_STRING
+ """
+ % settings.CSP_STRING
+ )
META = {
- 'CONTENT_TYPE': 'application/json',
- 'REMOTE_ADDR': '127.0.0.1',
- 'HTTP_USER_AGENT': 'FakeHTTPRequest'
+ "CONTENT_TYPE": "application/json",
+ "REMOTE_ADDR": "127.0.0.1",
+ "HTTP_USER_AGENT": "FakeHTTPRequest",
}
def test_option_set(self):
"""
Verify the HTTP Response Header is set.
"""
- response = self.client.get('/accounts/login/')
+ response = self.client.get("/accounts/login/")
self.assertEqual(
- response['Content-Security-Policy'],
+ response["Content-Security-Policy"],
settings.CSP_STRING,
)
@@ -857,19 +789,29 @@ def test_csp_view(self):
def test_csp_gen_1(self):
csp_dict = {
- 'default-src': ['self', 'cdn.example.com'],
- 'script-src': ['self', 'js.example.com'],
- 'style-src': ['self', 'css.example.com'],
- 'img-src': ['self', 'img.example.com'],
- 'connect-src': ['self', ],
- 'font-src': ['fonts.example.com', ],
- 'object-src': ['self'],
- 'media-src': ['media.example.com', ],
- 'frame-src': ['*', ],
- 'sandbox': ['', ],
- 'reflected-xss': 'filter',
- 'referrer': 'origin',
- 'report-uri': 'http://example.com/csp-report',
+ "default-src": ["self", "cdn.example.com"],
+ "script-src": ["self", "js.example.com"],
+ "style-src": ["self", "css.example.com"],
+ "img-src": ["self", "img.example.com"],
+ "connect-src": [
+ "self",
+ ],
+ "font-src": [
+ "fonts.example.com",
+ ],
+ "object-src": ["self"],
+ "media-src": [
+ "media.example.com",
+ ],
+ "frame-src": [
+ "*",
+ ],
+ "sandbox": [
+ "",
+ ],
+ "reflected-xss": "filter",
+ "referrer": "origin",
+ "report-uri": "http://example.com/csp-report",
}
expected = (
@@ -894,36 +836,33 @@ def test_csp_gen_1(self):
# We can't assume the iteration order on the csp_dict, so we split the
# output, sort, and ensure we got all the results back, regardless of
# the order.
- expected_list = sorted(x.strip() for x in expected.split(';'))
- generated_list = sorted(x.strip() for x in generated.split(';'))
+ expected_list = sorted(x.strip() for x in expected.split(";"))
+ generated_list = sorted(x.strip() for x in generated.split(";"))
self.assertEqual(generated_list, expected_list)
def test_csp_gen_2(self):
- csp_dict = {'default-src': ('none',), 'script-src': ['none']}
+ csp_dict = {"default-src": ("none",), "script-src": ["none"]}
expected = "default-src 'none'; script-src 'none'"
csp = ContentSecurityPolicyMiddleware()
generated = csp._csp_builder(csp_dict)
- expected_list = sorted(x.strip() for x in expected.split(';'))
- generated_list = sorted(x.strip() for x in generated.split(';'))
+ expected_list = sorted(x.strip() for x in expected.split(";"))
+ generated_list = sorted(x.strip() for x in generated.split(";"))
self.assertEqual(generated_list, expected_list)
def test_csp_gen_3(self):
csp_dict = {
- 'script-src': [
- 'self',
- 'www.google-analytics.com',
- 'ajax.googleapis.com',
+ "script-src": [
+ "self",
+ "www.google-analytics.com",
+ "ajax.googleapis.com",
],
}
- expected = (
- "script-src "
- "'self' www.google-analytics.com ajax.googleapis.com"
- )
+ expected = "script-src " "'self' www.google-analytics.com ajax.googleapis.com"
csp = ContentSecurityPolicyMiddleware()
generated = csp._csp_builder(csp_dict)
@@ -932,40 +871,40 @@ def test_csp_gen_3(self):
def test_csp_gen_err(self):
# argument not passed as array, expect failure
- csp_dict = {'default-src': 'self'}
+ csp_dict = {"default-src": "self"}
csp = ContentSecurityPolicyMiddleware()
self.assertRaises(MiddlewareNotUsed, csp._csp_builder, csp_dict)
def test_csp_gen_err2(self):
- csp_dict = {'invalid': 'self'} # invalid directive
+ csp_dict = {"invalid": "self"} # invalid directive
csp = ContentSecurityPolicyMiddleware()
self.assertRaises(MiddlewareNotUsed, csp._csp_builder, csp_dict)
def test_csp_gen_err3(self):
- csp_dict = {'sandbox': 'none'} # not a list or tuple, expect failure
+ csp_dict = {"sandbox": "none"} # not a list or tuple, expect failure
csp = ContentSecurityPolicyMiddleware()
self.assertRaises(MiddlewareNotUsed, csp._csp_builder, csp_dict)
def test_csp_gen_err4(self):
# Not an allowed directive, expect failure
- csp_dict = {'sandbox': ('invalid', )}
+ csp_dict = {"sandbox": ("invalid",)}
csp = ContentSecurityPolicyMiddleware()
self.assertRaises(MiddlewareNotUsed, csp._csp_builder, csp_dict)
def test_csp_gen_err5(self):
# Not an allowed directive, expect failure
- csp_dict = {'referrer': 'invalid'}
+ csp_dict = {"referrer": "invalid"}
csp = ContentSecurityPolicyMiddleware()
self.assertRaises(MiddlewareNotUsed, csp._csp_builder, csp_dict)
def test_csp_gen_err6(self):
# Not an allowed directive, expect failure
- csp_dict = {'reflected-xss': 'invalid'}
+ csp_dict = {"reflected-xss": "invalid"}
csp = ContentSecurityPolicyMiddleware()
self.assertRaises(MiddlewareNotUsed, csp._csp_builder, csp_dict)
@@ -973,29 +912,29 @@ def test_csp_gen_err6(self):
def test_enforced_by_default(self):
with self.settings(CSP_MODE=None):
response = self.client.get(settings.LOGIN_URL)
- self.assertIn('Content-Security-Policy', response)
- self.assertNotIn('Content-Security-Policy-Report-Only', response)
+ self.assertIn("Content-Security-Policy", response)
+ self.assertNotIn("Content-Security-Policy-Report-Only", response)
def test_enforced_when_on(self):
- with self.settings(CSP_MODE='enforce'):
+ with self.settings(CSP_MODE="enforce"):
response = self.client.get(settings.LOGIN_URL)
- self.assertIn('Content-Security-Policy', response)
- self.assertNotIn('Content-Security-Policy-Report-Only', response)
+ self.assertIn("Content-Security-Policy", response)
+ self.assertNotIn("Content-Security-Policy-Report-Only", response)
def test_report_only_set(self):
- with self.settings(CSP_MODE='report-only'):
+ with self.settings(CSP_MODE="report-only"):
response = self.client.get(settings.LOGIN_URL)
- self.assertNotIn('Content-Security-Policy', response)
- self.assertIn('Content-Security-Policy-Report-Only', response)
+ self.assertNotIn("Content-Security-Policy", response)
+ self.assertIn("Content-Security-Policy-Report-Only", response)
def test_both_enforce_and_report_only(self):
- with self.settings(CSP_MODE='enforce-and-report-only'):
+ with self.settings(CSP_MODE="enforce-and-report-only"):
response = self.client.get(settings.LOGIN_URL)
- self.assertIn('Content-Security-Policy', response)
- self.assertIn('Content-Security-Policy-Report-Only', response)
+ self.assertIn("Content-Security-Policy", response)
+ self.assertIn("Content-Security-Policy-Report-Only", response)
def test_invalid_csp_mode(self):
- with self.settings(CSP_MODE='invalid'):
+ with self.settings(CSP_MODE="invalid"):
self.assertRaises(
MiddlewareNotUsed,
ContentSecurityPolicyMiddleware,
@@ -1009,7 +948,7 @@ def test_no_csp_options_set(self):
)
def test_both_csp_options_set(self):
- with self.settings(CSP_DICT={'x': 'y'}, CSP_STRING='x y;'):
+ with self.settings(CSP_DICT={"x": "y"}, CSP_STRING="x y;"):
self.assertRaises(
MiddlewareNotUsed,
ContentSecurityPolicyMiddleware,
@@ -1017,31 +956,31 @@ def test_both_csp_options_set(self):
def test_sets_from_csp_dict(self):
with self.settings(
- CSP_DICT={'default-src': ('self',)},
+ CSP_DICT={"default-src": ("self",)},
CSP_STRING=None,
):
- response = self.client.get('/accounts/login/')
+ response = self.client.get("/accounts/login/")
self.assertEqual(
- response['Content-Security-Policy'],
+ response["Content-Security-Policy"],
"default-src 'self'",
)
-@override_settings(MIDDLEWARE=('security.middleware.DoNotTrackMiddleware',))
+@override_settings(MIDDLEWARE=("security.middleware.DoNotTrackMiddleware",))
class DoNotTrackTests(TestCase):
def setUp(self):
- self.dnt = DoNotTrackMiddleware()
self.request = HttpRequest()
self.response = HttpResponse()
+ self.dnt = DoNotTrackMiddleware(self.response)
def test_set_DNT_on(self):
- self.request.META['HTTP_DNT'] = '1'
+ self.request.META["HTTP_DNT"] = "1"
self.dnt.process_request(self.request)
self.assertTrue(self.request.dnt)
def test_set_DNT_off(self):
- self.request.META['HTTP_DNT'] = 'off'
+ self.request.META["HTTP_DNT"] = "off"
self.dnt.process_request(self.request)
self.assertFalse(self.request.dnt)
@@ -1050,19 +989,20 @@ def test_default_DNT(self):
self.assertFalse(self.request.dnt)
def test_DNT_echo_on(self):
- self.request.META['HTTP_DNT'] = '1'
+ self.request.META["HTTP_DNT"] = "1"
self.dnt.process_response(self.request, self.response)
- self.assertIn('DNT', self.response)
- self.assertEqual(self.response['DNT'], '1')
+ self.assertIn("DNT", self.response)
+ self.assertEqual(self.response["DNT"], "1")
def test_DNT_echo_off(self):
- self.request.META['HTTP_DNT'] = 'off'
+ self.request.META["HTTP_DNT"] = "off"
self.dnt.process_response(self.request, self.response)
- self.assertEqual(self.response['DNT'], 'off')
+ self.assertEqual(self.response["DNT"], "off")
def test_DNT_echo_default(self):
self.dnt.process_response(self.request, self.response)
- self.assertNotIn('DNT', self.response)
+ self.assertNotIn("DNT", self.response)
+
class ReferrerPolicyTests(TestCase):
@@ -1070,64 +1010,66 @@ def test_option_set(self):
"""
Verify the HTTP Referrer-Policy Header is set.
"""
- response = self.client.get('/accounts/login/')
- self.assertNotEqual(response['Referrer-Policy'], None)
+ response = self.client.get("/accounts/login/")
+ self.assertNotEqual(response["Referrer-Policy"], None)
def test_default_setting(self):
with self.settings(REFERRER_POLICY=None):
- response = self.client.get('/accounts/login/')
- self.assertEqual(response['Referrer-Policy'], 'same-origin')
+ response = self.client.get("/accounts/login/")
+ self.assertEqual(response["Referrer-Policy"], "same-origin")
def test_no_referrer_setting(self):
- with self.settings(REFERRER_POLICY='no-referrer'):
- response = self.client.get('/accounts/login/')
- self.assertEqual(response['Referrer-Policy'], 'no-referrer')
+ with self.settings(REFERRER_POLICY="no-referrer"):
+ response = self.client.get("/accounts/login/")
+ self.assertEqual(response["Referrer-Policy"], "no-referrer")
def test_no_referrer_when_downgrade_setting(self):
- with self.settings(REFERRER_POLICY='no-referrer-when-downgrade'):
- response = self.client.get('/accounts/login/')
- self.assertEqual(response['Referrer-Policy'], 'no-referrer-when-downgrade')
+ with self.settings(REFERRER_POLICY="no-referrer-when-downgrade"):
+ response = self.client.get("/accounts/login/")
+ self.assertEqual(response["Referrer-Policy"], "no-referrer-when-downgrade")
def test_origin_setting(self):
- with self.settings(REFERRER_POLICY='origin'):
- response = self.client.get('/accounts/login/')
- self.assertEqual(response['Referrer-Policy'], 'origin')
+ with self.settings(REFERRER_POLICY="origin"):
+ response = self.client.get("/accounts/login/")
+ self.assertEqual(response["Referrer-Policy"], "origin")
def test_origin_when_cross_origin_setting(self):
- with self.settings(REFERRER_POLICY='origin-when-cross-origin'):
- response = self.client.get('/accounts/login/')
- self.assertEqual(response['Referrer-Policy'], 'origin-when-cross-origin')
+ with self.settings(REFERRER_POLICY="origin-when-cross-origin"):
+ response = self.client.get("/accounts/login/")
+ self.assertEqual(response["Referrer-Policy"], "origin-when-cross-origin")
def test_same_origin_setting(self):
- with self.settings(REFERRER_POLICY='same-origin'):
- response = self.client.get('/accounts/login/')
- self.assertEqual(response['Referrer-Policy'], 'same-origin')
+ with self.settings(REFERRER_POLICY="same-origin"):
+ response = self.client.get("/accounts/login/")
+ self.assertEqual(response["Referrer-Policy"], "same-origin")
def test_strict_origin_setting(self):
- with self.settings(REFERRER_POLICY='strict-origin'):
- response = self.client.get('/accounts/login/')
- self.assertEqual(response['Referrer-Policy'], 'strict-origin')
+ with self.settings(REFERRER_POLICY="strict-origin"):
+ response = self.client.get("/accounts/login/")
+ self.assertEqual(response["Referrer-Policy"], "strict-origin")
def test_strict_origin_when_cross_origin_setting(self):
- with self.settings(REFERRER_POLICY='strict-origin-when-cross-origin'):
- response = self.client.get('/accounts/login/')
- self.assertEqual(response['Referrer-Policy'], 'strict-origin-when-cross-origin')
+ with self.settings(REFERRER_POLICY="strict-origin-when-cross-origin"):
+ response = self.client.get("/accounts/login/")
+ self.assertEqual(
+ response["Referrer-Policy"], "strict-origin-when-cross-origin"
+ )
def test_unsafe_url_setting(self):
- with self.settings(REFERRER_POLICY='unsafe-url'):
- response = self.client.get('/accounts/login/')
- self.assertEqual(response['Referrer-Policy'], 'unsafe-url')
+ with self.settings(REFERRER_POLICY="unsafe-url"):
+ response = self.client.get("/accounts/login/")
+ self.assertEqual(response["Referrer-Policy"], "unsafe-url")
def test_off_setting(self):
- with self.settings(REFERRER_POLICY='off'):
- response = self.client.get('/accounts/login/')
- self.assertEqual('Referrer-Policy' in response, False)
+ with self.settings(REFERRER_POLICY="off"):
+ response = self.client.get("/accounts/login/")
+ self.assertEqual("Referrer-Policy" in response, False)
def test_improper_configuration_raises(self):
referer_policy_middleware = ReferrerPolicyMiddleware()
self.assertRaises(
ImproperlyConfigured,
referer_policy_middleware.load_setting,
- 'REFERRER_POLICY',
- 'invalid',
+ "REFERRER_POLICY",
+ "invalid",
)
diff --git a/tests/urls.py b/tests/urls.py
new file mode 100644
index 0000000..5c302a2
--- /dev/null
+++ b/tests/urls.py
@@ -0,0 +1,31 @@
+# Copyright (c) 2011, SD Elements. See ../LICENSE.txt for details.
+
+from django.contrib.auth.views import LoginView, PasswordChangeView
+from django.http import HttpResponse
+from django.urls import path, re_path
+
+from security.auth_throttling.views import reset_username_throttle
+from security.views import csp_report
+
+urlpatterns = [
+ path("accounts/login/", LoginView.as_view(), {}, "login"),
+ path(
+ "change_password/",
+ PasswordChangeView.as_view(),
+ {"post_change_redirect": "/home/"},
+ "change_password",
+ ),
+ re_path(
+ r"^admin/reset-account-throttling/(?P-?[0-9]+)/",
+ reset_username_throttle,
+ {"redirect_url": "/admin"},
+ "reset_username_throttle",
+ ),
+ path("home/", lambda request: HttpResponse()),
+ path("custom-login/", lambda request: HttpResponse()),
+ path("test1/", lambda request: HttpResponse(), {}, "test1"),
+ path("test2/", lambda request: HttpResponse(), {}, "test2"),
+ path("test3/", lambda request: HttpResponse(), {}, "test3"),
+ path("test4/", lambda request: HttpResponse(), {}, "test4"),
+ path("csp-report/", csp_report),
+]
diff --git a/tox.ini b/tox.ini
deleted file mode 100644
index b2e8add..0000000
--- a/tox.ini
+++ /dev/null
@@ -1,43 +0,0 @@
-[tox]
-envlist = {py36}-django{111,22,30}, docs, pep8
-
-[testenv]
-whitelist_externals = make
-commands = coverage run --source {envsitepackagesdir}/security --omit="*migrations/*" testing/manage.py test tests
-commands_post = coverage report
-basepython =
- py36: python3.6
-deps =
- django-discover-runner
- django111: django==1.11
- django22: django==2.2
- django30: django==3.0
- coverage
- ua_parser==0.7.1
- mock==2.0.0
-
-[testenv:docs]
-basepython = python3.6
-deps =
- Sphinx
- django==3.0
- ua_parser==0.7.1
- coverage
-commands =
- make clean
- make html
-commands_post = - coverage report
-
-[testenv:pep8]
-basepython = python3.6
-deps=
- pep8-naming
- hacking
- flake8
- coverage
-commands=flake8 security testing
-
-[flake8]
-ignore=E131,H306,H301,H404,H405,H101,N802,N812,W503
-max-complexity=10
-exclude=*migrations*