Projet

Général

Profil

0002-settings_loaders-compute-a-symetric-shared-secret-fo.patch

Benjamin Dauvergne, 12 novembre 2015 13:36

Télécharger (6,04 ko)

Voir les différences:

Subject: [PATCH 2/3] settings_loaders: compute a symetric 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.
 hobo/multitenant/settings_loaders.py | 27 ++++++++++++++++++------
 tests_multitenant/conftest.py        |  3 +++
 tests_multitenant/test_settings.py   | 41 ++++++++++++++++++++++++++++++++++++
 3 files changed, 65 insertions(+), 6 deletions(-)
hobo/multitenant/settings_loaders.py
35 35
class KnownServices(FileBaseSettingsLoader):
36 36
    FILENAME = 'hobo.json'
37 37

  
38
    @classmethod
39
    def shared_secret(cls, secret1, secret2):
40
        secret1 = hashlib.sha256(secret1).hexdigest()
41
        secret2 = hashlib.sha256(secret2).hexdigest()
42
        return hex(int(secret1, 16) ^ int(secret2, 16))[2:-1]
43

  
38 44
    def update_settings_from_path(self, tenant_settings, path):
39 45
        known_services = {}
40 46
        with file(path) as f:
41 47
            hobo_json = json.load(f)
42 48
        services = hobo_json.get('services')
43
        base_url, secret = [(s.get('base_url'), s.get('secret_key'))
44
                            for s in services if s.get('this')][0]
49
        this = [s for s in services if s.get('this')][0]
50
        base_url = this['base_url']
45 51
        orig = urlparse.urlparse(base_url).netloc.split(':')[0]
46
        secret = hashlib.sha1(orig+secret).hexdigest()
52
        secret = this['secret_key']
47 53

  
48 54
        for service in services:
55
            # Why refer to ourself ?
56
            if service.get('this'):
57
                continue
49 58
            service_id = service.get('service-id')
50

  
59
            # compute a symetric shared secret using XOR
60
            # secrets MUST be hexadecimal numbers of the same even length
61
            shared_secret = (self.shared_secret(secret, service['secret_key']) if 'secret_key' in
62
                             service else None)
63
            url = service.get('base_url')
64
            verif_orig = urlparse.urlparse(url).netloc.split(':')[0]
51 65
            service_data = {
52
                'url': service.get('base_url'),
66
                'url': url,
53 67
                'backoffice-menu-url': service.get('backoffice-menu-url'),
54 68
                'title': service.get('title'),
55 69
                'orig': orig,
56
                'secret': secret,
70
                'verif_orig': verif_orig,
71
                'secret': shared_secret,
57 72
                'variables': service.get('variables')
58 73
            }
59 74
            if service_id in known_services:
tests_multitenant/conftest.py
27 27
                'services': [
28 28
                    {'slug': 'test',
29 29
                     'title': 'Test',
30
                     'service-id': 'welco',
30 31
                     'this': True,
31 32
                     'secret_key': '12345',
32 33
                     'base_url': 'http://%s' % name,
......
41 42
                    },
42 43
                    {'slug': 'other',
43 44
                     'title': 'Other',
45
                     'secret_key': 'abcde',
46
                     'service-id': 'authentic',
44 47
                     'base_url': 'http://other.example.net'},
45 48
                    ]}, fd)
46 49
        t = Tenant(domain_url=name,
tests_multitenant/test_settings.py
141 141
    t2 = threading.Thread(target=g)
142 142
    t2.start()
143 143
    t2.join()
144

  
145

  
146
def test_shared_secret():
147
    from hobo.multitenant.settings_loaders import KnownServices
148

  
149
    secrets = set()
150
    for i in range(100):
151
        a = str(random.getrandbits(160))
152
        b = str(random.getrandbits(160))
153
        assert KnownServices.shared_secret(a, b) == KnownServices.shared_secret(b, a)
154
        secrets.add(KnownServices.shared_secret(a, b))
155
    # Verify minimum entropy
156
    assert len(secrets) == 100
157

  
158

  
159
def test_known_services(tenants, settings):
160
    from hobo.multitenant.settings_loaders import KnownServices
161

  
162
    settings.clear_tenants_settings()
163

  
164
    for tenant in tenants:
165
        with tenant_context(tenant):
166
            hobo_json = tenant.get_hobo_json()
167
            assert hasattr(settings, 'KNOWN_SERVICES')
168
            assert 'authentic' in settings.KNOWN_SERVICES
169
            assert 'other' in settings.KNOWN_SERVICES['authentic']
170
            assert (set(['url', 'backoffice-menu-url', 'title', 'orig', 'verif_orig', 'secret', 'variables'])
171
                    == set(settings.KNOWN_SERVICES['authentic']['other'].keys()))
172
            assert (settings.KNOWN_SERVICES['authentic']['other']['url']
173
                    == hobo_json['services'][2]['base_url'])
174
            assert (settings.KNOWN_SERVICES['authentic']['other']['variables']
175
                    == hobo_json['services'][2].get('variables'))
176
            assert (settings.KNOWN_SERVICES['authentic']['other']['title']
177
                    == hobo_json['services'][2]['title'])
178
            assert settings.KNOWN_SERVICES['authentic']['other']['orig'] == tenant.domain_url
179
            assert (settings.KNOWN_SERVICES['authentic']['other']['verif_orig'] ==
180
                    'other.example.net')
181
            key1 = hobo_json['services'][0]['secret_key']
182
            key2 = hobo_json['services'][2]['secret_key']
183
            assert (settings.KNOWN_SERVICES['authentic']['other']['secret'] ==
184
                    KnownServices.shared_secret(key1, key2))
144
-