mirror of
https://github.com/inventree/InvenTree.git
synced 2025-10-24 01:47:39 +00:00
Fixes for SITE_URL validity checks (#10619)
* [docker] Allow HTTPS port to be specified for Caddy proxy * Fix naming collision for INVENTREE_WEB_PORT * Push InvenTree version first * Adjust Caddyfile - Change backup server * Fix docstring * Tweak for site URL check: - Ignore port if SITE_LAX_PROTOCOL_CHECK is set - Invert logic for readability * Additional checks for port mismatch * Adjust middleware checks - Allow for less strict checking of CSRF_TRUSTED_ORIGINS * Slight refactor
This commit is contained in:
@@ -239,13 +239,29 @@ class InvenTreeHostSettingsMiddleware(MiddlewareMixin):
|
||||
accessed_scheme = request._current_scheme_host
|
||||
referer = urlsplit(accessed_scheme)
|
||||
|
||||
# Ensure that the settings are set correctly with the current request
|
||||
matches = (
|
||||
(accessed_scheme and not accessed_scheme.startswith(settings.SITE_URL))
|
||||
if not settings.SITE_LAX_PROTOCOL_CHECK
|
||||
else not is_same_domain(referer.netloc, urlsplit(settings.SITE_URL).netloc)
|
||||
site_url = urlsplit(settings.SITE_URL)
|
||||
|
||||
# Check if the accessed URL matches the SITE_URL setting
|
||||
site_url_match = (
|
||||
(
|
||||
# Exact match on domain
|
||||
is_same_domain(referer.netloc, site_url.netloc)
|
||||
and referer.scheme == site_url.scheme
|
||||
)
|
||||
or (
|
||||
# Lax protocol match, accessed URL starts with SITE_URL
|
||||
settings.SITE_LAX_PROTOCOL_CHECK
|
||||
and accessed_scheme.startswith(settings.SITE_URL)
|
||||
)
|
||||
or (
|
||||
# Lax protocol match, same domain
|
||||
settings.SITE_LAX_PROTOCOL_CHECK
|
||||
and referer.hostname == site_url.hostname
|
||||
)
|
||||
)
|
||||
if matches:
|
||||
|
||||
if not site_url_match:
|
||||
# The accessed URL does not match the SITE_URL setting
|
||||
if (
|
||||
isinstance(settings.CSRF_TRUSTED_ORIGINS, list)
|
||||
and len(settings.CSRF_TRUSTED_ORIGINS) > 1
|
||||
@@ -263,17 +279,31 @@ class InvenTreeHostSettingsMiddleware(MiddlewareMixin):
|
||||
request, 'config_error.html', {'error_message': msg}, status=500
|
||||
)
|
||||
|
||||
# Check trusted origins
|
||||
if not any(
|
||||
is_same_domain(referer.netloc, host)
|
||||
for host in [
|
||||
urlsplit(origin).netloc.lstrip('*')
|
||||
trusted_origins_match = (
|
||||
# Matching domain found in allowed origins
|
||||
any(
|
||||
is_same_domain(referer.netloc, host)
|
||||
for host in [
|
||||
urlsplit(origin).netloc.lstrip('*')
|
||||
for origin in settings.CSRF_TRUSTED_ORIGINS
|
||||
]
|
||||
)
|
||||
) or (
|
||||
# Lax protocol match allowed
|
||||
settings.SITE_LAX_PROTOCOL_CHECK
|
||||
and any(
|
||||
referer.hostname == urlsplit(origin).hostname
|
||||
for origin in settings.CSRF_TRUSTED_ORIGINS
|
||||
]
|
||||
):
|
||||
)
|
||||
)
|
||||
|
||||
# Check trusted origins
|
||||
if not trusted_origins_match:
|
||||
msg = f'INVE-E7: The used path `{accessed_scheme}` is not in the TRUSTED_ORIGINS'
|
||||
logger.error(msg)
|
||||
return render(
|
||||
request, 'config_error.html', {'error_message': msg}, status=500
|
||||
)
|
||||
|
||||
# All checks passed
|
||||
return None
|
||||
|
||||
@@ -112,6 +112,15 @@ class MiddlewareTests(InvenTreeTestCase):
|
||||
|
||||
def test_site_lax_protocol(self):
|
||||
"""Test that the site URL check is correctly working with/without lax protocol check."""
|
||||
# Test that a completely different host fails
|
||||
with self.settings(
|
||||
SITE_URL='https://testserver', CSRF_TRUSTED_ORIGINS=['https://testserver']
|
||||
):
|
||||
response = self.client.get(
|
||||
reverse('web'), HTTP_HOST='otherhost.example.com'
|
||||
)
|
||||
self.assertContains(response, 'INVE-E7: The visited path', status_code=500)
|
||||
|
||||
# Simple setup with proxy
|
||||
with self.settings(
|
||||
SITE_URL='https://testserver', CSRF_TRUSTED_ORIGINS=['https://testserver']
|
||||
@@ -128,6 +137,24 @@ class MiddlewareTests(InvenTreeTestCase):
|
||||
response = self.client.get(reverse('web'))
|
||||
self.assertContains(response, 'INVE-E7: The visited path', status_code=500)
|
||||
|
||||
def test_site_url_port(self):
|
||||
"""URL checks with different ports."""
|
||||
with self.settings(
|
||||
SITE_URL='https://testserver:8000',
|
||||
CSRF_TRUSTED_ORIGINS=['https://testserver:8000'],
|
||||
):
|
||||
response = self.client.get(reverse('web'), HTTP_HOST='testserver:8008')
|
||||
self.do_positive_test(response)
|
||||
|
||||
# Try again with strict protocol check
|
||||
with self.settings(
|
||||
SITE_URL='https://testserver:8000',
|
||||
CSRF_TRUSTED_ORIGINS=['https://testserver:8000'],
|
||||
SITE_LAX_PROTOCOL_CHECK=False,
|
||||
):
|
||||
response = self.client.get(reverse('web'), HTTP_HOST='testserver:8008')
|
||||
self.assertContains(response, 'INVE-E7: The visited path', status_code=500)
|
||||
|
||||
def test_site_url_checks_multi(self):
|
||||
"""Test that the site URL check is correctly working in a multi-site setup."""
|
||||
# multi-site setup with trusted origins
|
||||
@@ -149,7 +176,7 @@ class MiddlewareTests(InvenTreeTestCase):
|
||||
)
|
||||
self.do_positive_test(response)
|
||||
|
||||
# A non-trsuted origin must still fail in multi - origin setup
|
||||
# A non-trusted origin must still fail in multi - origin setup
|
||||
response = self.client.get(
|
||||
'https://not-my-testserver.example.com/web/',
|
||||
SERVER_NAME='not-my-testserver.example.com',
|
||||
|
||||
Reference in New Issue
Block a user