kopia lustrzana https://github.com/jedie/PyInventory
Activate secure settings by default
rodzic
e7cb83633c
commit
d019a98b78
|
@ -10,6 +10,7 @@ from inventory.models import ItemImageModel
|
|||
from inventory.tests.fixtures.users import get_normal_pyinventory_user
|
||||
|
||||
|
||||
# @override_settings(SECURE_SSL_REDIRECT=False)
|
||||
class ItemImagesTestCase(TestCase):
|
||||
def test_basics(self):
|
||||
with mock.patch('secrets.token_urlsafe', return_value='user1token'):
|
||||
|
@ -40,23 +41,47 @@ class ItemImagesTestCase(TestCase):
|
|||
url = image_instance.image.url
|
||||
assert url == '/media/user1token/12345678901234567890/mock_img.jpeg'
|
||||
|
||||
# HTTP -> HTTPS redirect:
|
||||
response = self.client.get(
|
||||
'/media/user1token/12345678901234567890/mock_img.jpeg',
|
||||
secure=False
|
||||
)
|
||||
self.assertRedirects(
|
||||
response,
|
||||
status_code=301,
|
||||
expected_url='https://testserver/media/user1token/12345678901234567890/mock_img.jpeg',
|
||||
fetch_redirect_response=False,
|
||||
)
|
||||
|
||||
# Anonymous has no access:
|
||||
response = self.client.get('/media/user1token/12345678901234567890/mock_img.jpeg')
|
||||
response = self.client.get(
|
||||
'/media/user1token/12345678901234567890/mock_img.jpeg',
|
||||
secure=True,
|
||||
)
|
||||
assert response.status_code == 403
|
||||
|
||||
# Can't access with wrong user:
|
||||
self.client.force_login(pyinventory_user2)
|
||||
response = self.client.get('/media/user1token/12345678901234567890/mock_img.jpeg')
|
||||
response = self.client.get(
|
||||
'/media/user1token/12345678901234567890/mock_img.jpeg',
|
||||
secure=True,
|
||||
)
|
||||
assert response.status_code == 403
|
||||
|
||||
# Can access with the right user:
|
||||
self.client.force_login(pyinventory_user1)
|
||||
response = self.client.get('/media/user1token/12345678901234567890/mock_img.jpeg')
|
||||
response = self.client.get(
|
||||
'/media/user1token/12345678901234567890/mock_img.jpeg',
|
||||
secure=True,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert isinstance(response, FileResponse)
|
||||
assert response.getvalue() == image_instance.image.open('rb').read()
|
||||
|
||||
# Test whats happen, if token was deleted
|
||||
UserMediaTokenModel.objects.all().delete()
|
||||
response = self.client.get('/media/user1token/12345678901234567890/mock_img.jpeg')
|
||||
response = self.client.get(
|
||||
'/media/user1token/12345678901234567890/mock_img.jpeg',
|
||||
secure=True,
|
||||
)
|
||||
assert response.status_code == 400 # SuspiciousOperation -> HttpResponseBadRequest
|
||||
|
|
|
@ -131,6 +131,31 @@ TEMPLATES = [
|
|||
},
|
||||
]
|
||||
|
||||
# _____________________________________________________________________________
|
||||
|
||||
# Mark CSRF cookie as "secure" -> browsers sent cookie only with an HTTPS connection:
|
||||
CSRF_COOKIE_SECURE = True
|
||||
|
||||
# Mark session cookie as "secure" -> browsers sent cookie only with an HTTPS connection:
|
||||
SESSION_COOKIE_SECURE = True
|
||||
|
||||
# HTTP header/value combination that signifies a request is secure
|
||||
# Your nginx.conf must set "X-Forwarded-Protocol" proxy header!
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https')
|
||||
|
||||
# SecurityMiddleware should redirects all non-HTTPS requests to HTTPS:
|
||||
SECURE_SSL_REDIRECT = True
|
||||
|
||||
# SecurityMiddleware should preload directive to the HTTP Strict Transport Security header:
|
||||
SECURE_HSTS_PRELOAD = True
|
||||
|
||||
# Instruct modern browsers to refuse to connect to your domain name via an insecure connection:
|
||||
SECURE_HSTS_SECONDS = 3600
|
||||
|
||||
# SecurityMiddleware should add the "includeSubDomains" directive to the Strict-Transport-Security
|
||||
# header: All subdomains of your domain should be served exclusively via SSL!
|
||||
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
||||
|
||||
# _____________________________________________________________________________
|
||||
# Internationalization
|
||||
|
||||
|
|
|
@ -34,6 +34,16 @@ DATABASES = {
|
|||
}
|
||||
}
|
||||
print(f'Use Database: {DATABASES["default"]["NAME"]!r}', file=__sys.stderr)
|
||||
# _____________________________________________________________________________
|
||||
|
||||
# Disable security features, because development server doesn't support HTTPS
|
||||
CSRF_COOKIE_SECURE = False
|
||||
SESSION_COOKIE_SECURE = False
|
||||
SECURE_PROXY_SSL_HEADER = None
|
||||
SECURE_SSL_REDIRECT = False
|
||||
SECURE_HSTS_PRELOAD = False
|
||||
SECURE_HSTS_SECONDS = 0
|
||||
SECURE_HSTS_INCLUDE_SUBDOMAINS = False
|
||||
|
||||
# _____________________________________________________________________________
|
||||
# AlwaysLoggedInAsSuperUser
|
||||
|
|
|
@ -10,7 +10,7 @@ DATABASES = {
|
|||
}
|
||||
}
|
||||
|
||||
SECRET_KEY = 'No individual secret for tests ;)'
|
||||
SECRET_KEY = 'No individual secret... But this settings should only be used in tests ;)'
|
||||
|
||||
# Run the tests as on production: Without DBEUG:
|
||||
DEBUG = False
|
||||
|
|
|
@ -2,7 +2,7 @@ import os
|
|||
import unittest
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase
|
||||
from django.test import TestCase, override_settings
|
||||
from django_processinfo.models import ProcessInfo, SiteStatistics
|
||||
from django_tools.selenium.chromedriver import chromium_available
|
||||
from django_tools.selenium.django import (
|
||||
|
@ -22,14 +22,15 @@ class AdminAnonymousTests(TestCase):
|
|||
"""
|
||||
|
||||
def test_login_en(self):
|
||||
response = self.client.get("/admin/", HTTP_ACCEPT_LANGUAGE="en")
|
||||
self.assertRedirects(response, expected_url="/admin/login/?next=/admin/")
|
||||
response = self.client.get('/admin/', secure=True, HTTP_ACCEPT_LANGUAGE='en')
|
||||
self.assertRedirects(response, expected_url='/admin/login/?next=/admin/', fetch_redirect_response=False)
|
||||
|
||||
def test_login_de(self):
|
||||
response = self.client.get("/admin/", HTTP_ACCEPT_LANGUAGE="de")
|
||||
self.assertRedirects(response, expected_url="/admin/login/?next=/admin/")
|
||||
response = self.client.get('/admin/', secure=True, HTTP_ACCEPT_LANGUAGE='de')
|
||||
self.assertRedirects(response, expected_url='/admin/login/?next=/admin/', fetch_redirect_response=False)
|
||||
|
||||
|
||||
@override_settings(SECURE_SSL_REDIRECT=False)
|
||||
class ProcessinfoAdminTestCase(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
|
@ -87,6 +88,7 @@ class ProcessinfoAdminTestCase(TestCase):
|
|||
|
||||
@unittest.skipIf('CI' in os.environ, 'Skip, selenium tests does not work on CI run!')
|
||||
@unittest.skipUnless(chromium_available(), "Skip because Chromium is not available!")
|
||||
@override_settings(SECURE_SSL_REDIRECT=False)
|
||||
class AdminChromiumTests(SeleniumChromiumStaticLiveServerTestCase):
|
||||
def test_admin_login_page(self):
|
||||
self.driver.get(self.live_server_url + "/admin/login/")
|
||||
|
@ -97,6 +99,7 @@ class AdminChromiumTests(SeleniumChromiumStaticLiveServerTestCase):
|
|||
|
||||
@unittest.skipIf('CI' in os.environ, 'Skip, selenium tests does not work on CI run!')
|
||||
@unittest.skipUnless(firefox_available(), "Skip because Firefox is not available!")
|
||||
@override_settings(SECURE_SSL_REDIRECT=False)
|
||||
class AdminFirefoxTests(SeleniumFirefoxStaticLiveServerTestCase):
|
||||
def test_admin_login_page(self):
|
||||
self.driver.get(self.live_server_url + "/admin/login/")
|
||||
|
|
|
@ -7,7 +7,7 @@ from bx_django_utils.test_utils.html_assertion import HtmlAssertionMixin
|
|||
from bx_py_utils.test_utils.snapshot import assert_html_snapshot
|
||||
from django.contrib.auth.models import User
|
||||
from django.template.defaulttags import CsrfTokenNode, NowNode
|
||||
from django.test import TestCase
|
||||
from django.test import TestCase, override_settings
|
||||
from django.utils import timezone
|
||||
from django_tools.unittest_utils.mockup import ImageDummy
|
||||
from model_bakery import baker
|
||||
|
@ -46,15 +46,42 @@ ITEM_FORM_DEFAULTS = {
|
|||
ITEM_FORM_DEFAULTS = tuple(ITEM_FORM_DEFAULTS.items())
|
||||
|
||||
|
||||
class AdminAnonymousTests(TestCase):
|
||||
class AdminAnonymousTests(HtmlAssertionMixin, TestCase):
|
||||
def test_login(self):
|
||||
response = self.client.get('/admin/inventory/itemmodel/add/', HTTP_ACCEPT_LANGUAGE='en')
|
||||
# HTTP -> HTTPS redirect:
|
||||
response = self.client.get('/admin/', HTTP_ACCEPT_LANGUAGE='en')
|
||||
self.assertRedirects(
|
||||
response,
|
||||
expected_url='/admin/login/?next=/admin/inventory/itemmodel/add/'
|
||||
expected_url='https://testserver/admin/',
|
||||
status_code=301, # Permanent redirect
|
||||
fetch_redirect_response=False
|
||||
)
|
||||
|
||||
response = self.client.get(
|
||||
path='/admin/inventory/itemmodel/add/',
|
||||
secure=True,
|
||||
HTTP_ACCEPT_LANGUAGE='en'
|
||||
)
|
||||
self.assertRedirects(
|
||||
response,
|
||||
expected_url='/admin/login/?next=/admin/inventory/itemmodel/add/',
|
||||
fetch_redirect_response=False
|
||||
)
|
||||
with mock.patch.object(CsrfTokenNode, 'render', return_value='MockedCsrfTokenNode'):
|
||||
response = self.client.get(
|
||||
path='/admin/login/',
|
||||
secure=True,
|
||||
HTTP_ACCEPT_LANGUAGE='en'
|
||||
)
|
||||
self.assert_html_parts(response, parts=(
|
||||
f'<title>Log in | PyInventory v{__version__}</title>',
|
||||
'<label class="required" for="id_username">Username:</label>',
|
||||
'<label class="required" for="id_password">Password:</label>',
|
||||
))
|
||||
assert_html_response_snapshot(response, validate=False)
|
||||
|
||||
|
||||
@override_settings(SECURE_SSL_REDIRECT=False)
|
||||
class AdminTestCase(HtmlAssertionMixin, TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>
|
||||
Log in | PyInventory v0.12.0
|
||||
</title>
|
||||
<link href="/static/admin/css/base.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="/static/admin/css/nav_sidebar.css" rel="stylesheet" type="text/css"/>
|
||||
<script defer="" src="/static/admin/js/nav_sidebar.js">
|
||||
</script>
|
||||
<link href="/static/admin/css/login.css" rel="stylesheet" type="text/css"/>
|
||||
<style>
|
||||
.form-row {display: none;}
|
||||
</style>
|
||||
<meta content="notranslate" name="google"/>
|
||||
<meta content="noindex,nofollow" name="robots">
|
||||
<link href="/static/inventory.css" rel="stylesheet" type="text/css"/>
|
||||
<meta content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0" name="viewport"/>
|
||||
<link href="/static/admin/css/responsive.css" rel="stylesheet" type="text/css"/>
|
||||
<meta content="NONE,NOARCHIVE" name="robots"/>
|
||||
</meta>
|
||||
</head>
|
||||
<body class="login" data-admin-utc-offset="3600">
|
||||
<!-- Container -->
|
||||
<div id="container">
|
||||
<!-- Header -->
|
||||
<div id="header">
|
||||
<div id="branding">
|
||||
</div>
|
||||
</div>
|
||||
<!-- END Header -->
|
||||
<div class="main shifted" id="main">
|
||||
<div class="content">
|
||||
<!-- Content -->
|
||||
<div class="colM" id="content">
|
||||
<script>
|
||||
document.write('<fo'+'rm act'+'ion="/admin/login/" met'+'hod="po'+'st" id="lo'+'gin-fo'+'rm">');
|
||||
</script>
|
||||
MockedCsrfTokenNode
|
||||
<div class="form-row">
|
||||
<p class="required">
|
||||
<label class="required" for="id_username">
|
||||
Username:
|
||||
</label>
|
||||
<input autocapitalize="none" autocomplete="username" autofocus="" id="id_username" maxlength="150" name="username" required="" type="text"/>
|
||||
</p>
|
||||
<p class="required">
|
||||
<label class="required" for="id_password">
|
||||
Password:
|
||||
</label>
|
||||
<input autocomplete="current-password" id="id_password" name="password" required="" type="password"/>
|
||||
</p>
|
||||
</div>
|
||||
<div class="submit-row">
|
||||
<noscript>
|
||||
Please enable JavaScript ;)
|
||||
</noscript>
|
||||
<label>
|
||||
</label>
|
||||
<script>
|
||||
document.write('<in'+'put type="sub'+'mit" val'+'ue="Log in">');
|
||||
</script>
|
||||
</div>
|
||||
<script>
|
||||
'use strict';
|
||||
document.write('</fo'+'rm>');
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
for (const object of document.querySelectorAll('.form-row')) {
|
||||
object.style.display = "block";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<br class="clear"/>
|
||||
</div>
|
||||
<!-- END Content -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END Container -->
|
||||
</body>
|
||||
</html>
|
|
@ -3,7 +3,7 @@ from unittest import mock
|
|||
from bx_django_utils.test_utils.html_assertion import HtmlAssertionMixin
|
||||
from django.contrib.auth.models import User
|
||||
from django.template.defaulttags import CsrfTokenNode, NowNode
|
||||
from django.test import TestCase
|
||||
from django.test import TestCase, override_settings
|
||||
from django_tools.unittest_utils.mockup import ImageDummy
|
||||
from model_bakery import baker
|
||||
|
||||
|
@ -15,13 +15,19 @@ from inventory_project.tests.temp_utils import assert_html_response_snapshot
|
|||
|
||||
class AdminAnonymousTests(TestCase):
|
||||
def test_login(self):
|
||||
response = self.client.get('/admin/inventory/memomodel/add/', HTTP_ACCEPT_LANGUAGE='en')
|
||||
response = self.client.get(
|
||||
'/admin/inventory/memomodel/add/',
|
||||
secure=True,
|
||||
HTTP_ACCEPT_LANGUAGE='en'
|
||||
)
|
||||
self.assertRedirects(
|
||||
response,
|
||||
expected_url='/admin/login/?next=/admin/inventory/memomodel/add/'
|
||||
expected_url='/admin/login/?next=/admin/inventory/memomodel/add/',
|
||||
fetch_redirect_response=False,
|
||||
)
|
||||
|
||||
|
||||
@override_settings(SECURE_SSL_REDIRECT=False)
|
||||
class AdminTestCase(HtmlAssertionMixin, TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
|
|
Ładowanie…
Reference in New Issue