summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerghei Mihai <smihai@entrouvert.com>2015-10-09 11:34:57 (GMT)
committerBenjamin Dauvergne <bdauvergne@entrouvert.com>2016-01-26 02:11:42 (GMT)
commitf36985e2425f360f13f21da40f92206f92caaf80 (patch)
tree16762e79c8d7722ea10baf02fa94fb6c63dec830
parent4359db0c35461f67b053e8e057ca4a337aeb945f (diff)
downloadhobo-f36985e2425f360f13f21da40f92206f92caaf80.zip
hobo-f36985e2425f360f13f21da40f92206f92caaf80.tar.gz
hobo-f36985e2425f360f13f21da40f92206f92caaf80.tar.bz2
settings_loaders: compute a symmetric shared secret for services (#8580)
Secret is computed by appying xor to the SHA-256 hash of each service secret, making it insensible to the ordering of the two secrets. Tests of the basic properties of the shared_secret() function are added.
-rw-r--r--hobo/multitenant/settings_loaders.py24
-rw-r--r--tests_multitenant/conftest.py3
-rw-r--r--tests_multitenant/test_settings.py41
3 files changed, 62 insertions, 6 deletions
diff --git a/hobo/multitenant/settings_loaders.py b/hobo/multitenant/settings_loaders.py
index 16ba54a..c77ddc4 100644
--- a/hobo/multitenant/settings_loaders.py
+++ b/hobo/multitenant/settings_loaders.py
@@ -35,27 +35,39 @@ class FileBaseSettingsLoader(object):
class KnownServices(FileBaseSettingsLoader):
FILENAME = 'hobo.json'
+ @classmethod
+ def shared_secret(cls, secret1, secret2):
+ secret1 = hashlib.sha256(secret1).hexdigest()
+ secret2 = hashlib.sha256(secret2).hexdigest()
+ return hex(int(secret1, 16) ^ int(secret2, 16))[2:-1]
+
def update_settings_from_path(self, tenant_settings, path):
known_services = {}
with file(path) as f:
hobo_json = json.load(f)
services = hobo_json.get('services')
- base_url, secret = [(s.get('base_url'), s.get('secret_key'))
- for s in services if s.get('this')][0]
+ this = [s for s in services if s.get('this')][0]
+ base_url = this['base_url']
orig = urlparse.urlparse(base_url).netloc.split(':')[0]
- secret = hashlib.sha1(orig+secret).hexdigest()
+ secret = this['secret_key']
for service in services:
service_id = service.get('service-id')
-
+ url = service.get('base_url')
+ verif_orig = urlparse.urlparse(url).netloc.split(':')[0]
service_data = {
- 'url': service.get('base_url'),
+ 'url': url,
'backoffice-menu-url': service.get('backoffice-menu-url'),
'title': service.get('title'),
'orig': orig,
- 'secret': secret,
+ 'verif_orig': verif_orig,
'variables': service.get('variables')
}
+ # compute a symmetric shared secret using XOR
+ # secrets MUST be hexadecimal numbers of the same even length
+ if not service.get('this'):
+ service_data['secret'] = (self.shared_secret(secret, service['secret_key']) if
+ 'secret_key' in service else None)
if service_id in known_services:
known_services[service_id][service.get('slug')] = service_data
else:
diff --git a/tests_multitenant/conftest.py b/tests_multitenant/conftest.py
index 49adcbb..c90f2c9 100644
--- a/tests_multitenant/conftest.py
+++ b/tests_multitenant/conftest.py
@@ -27,6 +27,7 @@ def tenants(db, request, settings):
'services': [
{'slug': 'test',
'title': 'Test',
+ 'service-id': 'welco',
'this': True,
'secret_key': '12345',
'base_url': 'http://%s' % name,
@@ -41,6 +42,8 @@ def tenants(db, request, settings):
},
{'slug': 'other',
'title': 'Other',
+ 'secret_key': 'abcde',
+ 'service-id': 'authentic',
'base_url': 'http://other.example.net'},
]}, fd)
t = Tenant(domain_url=name,
diff --git a/tests_multitenant/test_settings.py b/tests_multitenant/test_settings.py
index cb62e90..aac0928 100644
--- a/tests_multitenant/test_settings.py
+++ b/tests_multitenant/test_settings.py
@@ -141,3 +141,44 @@ def test_cache(tenants, client):
t2 = threading.Thread(target=g)
t2.start()
t2.join()
+
+
+def test_shared_secret():
+ from hobo.multitenant.settings_loaders import KnownServices
+
+ secrets = set()
+ for i 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.clear_tenants_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']
+ assert (set(['url', 'backoffice-menu-url', 'title', 'orig', 'verif_orig', 'secret', 'variables'])
+ == set(settings.KNOWN_SERVICES['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))