262 lines
11 KiB
Python
262 lines
11 KiB
Python
# hobo - portal to configure and deploy applications
|
|
# Copyright (C) 2015-2016 Entr'ouvert
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
# under the terms of the GNU Affero General Public License as published
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import datetime
|
|
import json
|
|
import os
|
|
import random
|
|
|
|
import django.conf
|
|
import django.db
|
|
import pytest
|
|
from tenant_schemas.utils import tenant_context
|
|
|
|
from . import utilities
|
|
|
|
|
|
def test_tenant_middleware(tenants, client, settings):
|
|
settings.ALLOWED_HOSTS.append('invalid.example.net')
|
|
settings.SETTINGS_MODULE = 'fake.settings'
|
|
res = client.get('/', SERVER_NAME='invalid.example.net')
|
|
assert res.status_code == 404
|
|
for tenant in tenants:
|
|
settings.ALLOWED_HOSTS.append(tenant.domain_url)
|
|
res = client.get('/', SERVER_NAME=tenant.domain_url)
|
|
assert res.status_code != 404
|
|
assert res.wsgi_request.tenant.schema_name == tenant.schema_name
|
|
|
|
|
|
def test_tenant_json_settings(tenants, settings):
|
|
with utilities.patch_default_settings(
|
|
settings, TENANT_SETTINGS_LOADERS=('hobo.multitenant.settings_loaders.SettingsJSON',)
|
|
):
|
|
# check the setting is not defined
|
|
with pytest.raises(AttributeError):
|
|
settings.HOBO_TEST_VARIABLE # noqa pylint: disable=pointless-statement
|
|
assert django.conf.settings.UPDATE_ME == {'x': 1}
|
|
assert django.conf.settings.EXTEND_ME == [1]
|
|
|
|
# check that for each tenant it contains the tenant domain
|
|
# it's set by the tenants fixture in conftest.py
|
|
for tenant in tenants:
|
|
with tenant_context(tenant):
|
|
assert django.conf.settings.HOBO_TEST_VARIABLE == tenant.domain_url
|
|
assert django.conf.settings.UPDATE_ME == {'x': 1, 'y': 2}
|
|
assert django.conf.settings.EXTEND_ME == [1, 2]
|
|
|
|
# check it's no longer defined after going back to the public schema
|
|
with pytest.raises(AttributeError):
|
|
settings.HOBO_TEST_VARIABLE # noqa pylint: disable=pointless-statement
|
|
assert django.conf.settings.UPDATE_ME == {'x': 1}
|
|
assert django.conf.settings.EXTEND_ME == [1]
|
|
|
|
|
|
def test_tenant_template_vars(tenants, settings, client):
|
|
with utilities.patch_default_settings(
|
|
settings, TENANT_SETTINGS_LOADERS=('hobo.multitenant.settings_loaders.TemplateVars',)
|
|
):
|
|
# check the setting is not defined
|
|
with pytest.raises(AttributeError):
|
|
django.conf.settings.TEMPLATE_VARS # noqa pylint: disable=pointless-statement
|
|
|
|
for tenant in tenants:
|
|
with tenant_context(tenant):
|
|
# check it's defined when moving into the schema
|
|
assert django.conf.settings.TEMPLATE_VARS
|
|
assert django.conf.settings.TEMPLATE_VARS['hobo_test_variable'] is True
|
|
assert django.conf.settings.TEMPLATE_VARS['test_url'] == tenant.get_base_url()
|
|
assert django.conf.settings.TEMPLATE_VARS['other_url'] == 'http://other.example.net'
|
|
assert django.conf.settings.TEMPLATE_VARS['site_title'] == 'Test'
|
|
assert django.conf.settings.TEMPLATE_VARS['other_variable'] == 'bar'
|
|
assert (
|
|
django.conf.settings.TEMPLATE_VARS['portal_agent_url']
|
|
== 'http://portal-agent.example.net'
|
|
)
|
|
assert (
|
|
django.conf.settings.TEMPLATE_VARS['portal_user_url'] == 'http://portal-user.example.net'
|
|
)
|
|
|
|
# check it's no longer defined after going back to the public schema
|
|
with pytest.raises(AttributeError):
|
|
django.conf.settings.TEMPLATE_VARS # noqa pylint: disable=pointless-statement
|
|
|
|
|
|
def test_tenant_settings_vars(tenants, settings, client):
|
|
with utilities.patch_default_settings(
|
|
settings, TENANT_SETTINGS_LOADERS=('hobo.multitenant.settings_loaders.SettingsVars',)
|
|
):
|
|
# check the setting is not defined
|
|
with pytest.raises(AttributeError):
|
|
django.conf.settings.LOCAL1 # noqa pylint: disable=pointless-statement
|
|
with pytest.raises(AttributeError):
|
|
django.conf.settings.LOCAL2 # noqa pylint: disable=pointless-statement
|
|
with pytest.raises(AttributeError):
|
|
django.conf.settings.LOCAL3 # noqa pylint: disable=pointless-statement
|
|
|
|
for tenant in tenants:
|
|
with tenant_context(tenant):
|
|
# check it's defined when moving into the schema
|
|
assert django.conf.settings.GLOBAL1 is True
|
|
assert django.conf.settings.GLOBAL2 == [1, 2, 3, 2, 3, 4]
|
|
assert django.conf.settings.GLOBAL3 == {'x': 1, 'y': 2, 'z': 1}
|
|
assert django.conf.settings.OVERRIDE1 is True
|
|
assert django.conf.settings.OVERRIDE2 == [1, 2, 3, tenant.domain_url, 7, 8]
|
|
assert django.conf.settings.OVERRIDE3 == {'a': tenant.domain_url, 'b': 2, 'z': 1}
|
|
assert django.conf.settings.LOCAL1 is False
|
|
assert django.conf.settings.LOCAL2 == [tenant.domain_url, 7, 8]
|
|
assert django.conf.settings.LOCAL3 == {'a': tenant.domain_url, 'b': 2}
|
|
|
|
|
|
def test_tenant_cors_settings(tenants, settings, client):
|
|
with utilities.patch_default_settings(
|
|
settings, TENANT_SETTINGS_LOADERS=('hobo.multitenant.settings_loaders.CORSSettings',)
|
|
):
|
|
# check the setting is not defined
|
|
with pytest.raises(AttributeError):
|
|
settings.CORS_ORIGIN_WHITELIST # noqa pylint: disable=pointless-statement
|
|
|
|
for tenant in tenants:
|
|
with tenant_context(tenant):
|
|
# check it's defined when moving into the schema
|
|
assert django.conf.settings.CORS_ORIGIN_WHITELIST
|
|
assert tenant.get_base_url() in django.conf.settings.CORS_ORIGIN_WHITELIST
|
|
assert 'http://other.example.net' in django.conf.settings.CORS_ORIGIN_WHITELIST
|
|
|
|
with pytest.raises(AttributeError):
|
|
django.conf.settings.CORS_ORIGIN_WHITELIST # noqa pylint: disable=pointless-statement
|
|
|
|
|
|
def test_tenant_theme_settings(tenants, settings, client):
|
|
with utilities.patch_default_settings(
|
|
settings,
|
|
TENANT_SETTINGS_LOADERS=(
|
|
'hobo.multitenant.settings_loaders.TemplateVars',
|
|
'hobo.multitenant.settings_loaders.ThemeSettings',
|
|
),
|
|
):
|
|
old_value = os.environ['DJANGO_SETTINGS_MODULE']
|
|
os.environ['DJANGO_SETTINGS_MODULE'] = 'fake.settings'
|
|
with tenant_context(tenants[0]):
|
|
# check it's defined when moving into the schema
|
|
assert django.conf.settings.TEMPLATE_VARS
|
|
assert django.conf.settings.TEMPLATE_VARS['theme'] == 'publik'
|
|
assert django.conf.settings.HELLO == 'world'
|
|
os.environ['DJANGO_SETTINGS_MODULE'] = old_value
|
|
|
|
|
|
def test_shared_secret():
|
|
from hobo.multitenant.settings_loaders import KnownServices
|
|
|
|
secrets = set()
|
|
for dummy in range(100):
|
|
a = str(random.getrandbits(160))
|
|
b = str(random.getrandbits(160))
|
|
assert KnownServices.shared_secret(a, b) == KnownServices.shared_secret(b, a)
|
|
secrets.add(KnownServices.shared_secret(a, b))
|
|
# Verify minimum entropy
|
|
assert len(secrets) == 100
|
|
|
|
|
|
def test_known_services(tenants, settings):
|
|
from hobo.multitenant.settings_loaders import KnownServices
|
|
|
|
settings.SETTINGS_MODULE = 'fake.settings'
|
|
|
|
for tenant in tenants:
|
|
with tenant_context(tenant):
|
|
hobo_json = tenant.get_hobo_json()
|
|
assert hasattr(settings, 'KNOWN_SERVICES')
|
|
assert 'authentic' in settings.KNOWN_SERVICES
|
|
assert 'other' in settings.KNOWN_SERVICES['authentic']
|
|
authentic_other_keys = set(settings.KNOWN_SERVICES['authentic']['other'].keys())
|
|
assert {
|
|
'url',
|
|
'backoffice-menu-url',
|
|
'title',
|
|
'orig',
|
|
'verif_orig',
|
|
'secret',
|
|
'template_name',
|
|
'variables',
|
|
'saml-sp-metadata-url',
|
|
'provisionning-url',
|
|
'secondary',
|
|
'saml-idp-metadata-url',
|
|
} == authentic_other_keys
|
|
assert (
|
|
settings.KNOWN_SERVICES['authentic']['other']['url'] == hobo_json['services'][2]['base_url']
|
|
)
|
|
assert settings.KNOWN_SERVICES['authentic']['other']['variables'] == hobo_json['services'][2].get(
|
|
'variables'
|
|
)
|
|
assert settings.KNOWN_SERVICES['authentic']['other']['title'] == hobo_json['services'][2]['title']
|
|
assert settings.KNOWN_SERVICES['authentic']['other']['orig'] == tenant.domain_url
|
|
assert settings.KNOWN_SERVICES['authentic']['other']['verif_orig'] == 'other.example.net'
|
|
key1 = hobo_json['services'][0]['secret_key']
|
|
key2 = hobo_json['services'][2]['secret_key']
|
|
assert settings.KNOWN_SERVICES['authentic']['other']['secret'] == KnownServices.shared_secret(
|
|
key1, key2
|
|
)
|
|
|
|
|
|
def test_legacy_urls_mapping(tenants, settings):
|
|
settings.SETTINGS_MODULE = 'fake.settings'
|
|
|
|
for tenant in tenants:
|
|
with tenant_context(tenant):
|
|
tenant.get_hobo_json()
|
|
assert hasattr(settings, 'LEGACY_URLS_MAPPING')
|
|
assert settings.LEGACY_URLS_MAPPING['olda2.example.net'] == 'other.example.net'
|
|
|
|
|
|
def test_unique_cookies(tenants, settings):
|
|
cookie_names = set()
|
|
for tenant in tenants:
|
|
with tenant_context(tenant):
|
|
cookie_names.add(settings.CSRF_COOKIE_NAME)
|
|
cookie_names.add(settings.SESSION_COOKIE_NAME)
|
|
|
|
assert len(cookie_names) == len(tenants) * 2
|
|
|
|
|
|
def test_tenant_json_settings_reload(tenants, settings, freezer):
|
|
with utilities.patch_default_settings(
|
|
settings, TENANT_SETTINGS_LOADERS=('hobo.multitenant.settings_loaders.SettingsJSON',)
|
|
):
|
|
# check EXTEND_ME has its base value
|
|
assert django.conf.settings.EXTEND_ME == [1]
|
|
|
|
# check EXTEND_ME is extended
|
|
for tenant in tenants:
|
|
with tenant_context(tenant):
|
|
assert django.conf.settings.EXTEND_ME == [1, 2]
|
|
|
|
# move 1 minute in the future
|
|
freezer.move_to(datetime.timedelta(seconds=60))
|
|
|
|
# update EXTEND_ME tenant value
|
|
for tenant in tenants:
|
|
with open(os.path.join(tenant.get_directory(), 'settings.json'), 'w') as fd:
|
|
json.dump({'EXTEND_ME.extend': [3]}, fd)
|
|
|
|
# move 1 minute in the future
|
|
freezer.move_to(datetime.timedelta(seconds=60))
|
|
|
|
# check EXTEND_ME is still extended from base value
|
|
for tenant in tenants:
|
|
with tenant_context(tenant):
|
|
assert django.conf.settings.EXTEND_ME == [1, 3]
|