Projet

Général

Profil

0001-idp_oidc-fix-profile-suffix-during-sub-generation-62.patch

Paul Marillonnet, 16 mars 2022 12:13

Télécharger (5,66 ko)

Voir les différences:

Subject: [PATCH] idp_oidc: fix profile suffix during sub generation (#62702)

 src/authentic2_idp_oidc/apps.py      |  4 +--
 src/authentic2_idp_oidc/utils.py     |  7 ++--
 tests/idp_oidc/test_user_profiles.py | 48 +++++++++++++++++++++++++++-
 3 files changed, 54 insertions(+), 5 deletions(-)
src/authentic2_idp_oidc/apps.py
88 88
        sub = smart_bytes(view.kwargs[lookup_url_kwarg])
89 89
        decrypted = utils.reverse_pairwise_sub(client, sub)
90 90
        if decrypted:
91
            view.kwargs[lookup_url_kwarg] = uuid.UUID(bytes=decrypted.split(b'#')[0]).hex
91
            view.kwargs[lookup_url_kwarg] = uuid.UUID(bytes=decrypted).hex
92 92

  
93 93
    def a2_hook_api_modify_serializer_after_validation(self, view, serializer):
94 94
        import uuid
......
111 111
        for u in serializer.validated_data['known_uuids']:
112 112
            decrypted = utils.reverse_pairwise_sub(client, smart_bytes(u))
113 113
            if decrypted:
114
                new_known_uuid = uuid.UUID(bytes=decrypted.split(b'#')[0]).hex
114
                new_known_uuid = uuid.UUID(bytes=decrypted).hex
115 115
                new_known_uuids.append(new_known_uuid)
116 116
                uuid_map[new_known_uuid] = u
117 117
            else:
src/authentic2_idp_oidc/utils.py
175 175
        sector_identifier,
176 176
    ]
177 177
    if profile and client.perform_sub_profile_substitution:
178
        cipher_args[1] += b'#%s' % str(profile.id).encode()
178
        # add user-chosen profile identifier information
179
        cipher_args[1] += b'#profile-id:%s' % str(profile.id).encode()
179 180
    return crypto.aes_base64url_deterministic_encrypt(*cipher_args).decode('utf-8')
180 181

  
181 182

  
182 183
def reverse_pairwise_sub(client, sub):
183 184
    sector_identifier = client.get_sector_identifier()
184 185
    try:
185
        return crypto.aes_base64url_deterministic_decrypt(
186
        reversed_id = crypto.aes_base64url_deterministic_decrypt(
186 187
            settings.SECRET_KEY.encode('utf-8'), sub, sector_identifier
187 188
        )
189
        # strip any suffix from original 16-byte-long uuid
190
        return reversed_id[:16]
188 191
    except crypto.DecryptionError:
189 192
        return None
190 193

  
tests/idp_oidc/test_user_profiles.py
17 17
import base64
18 18
import json
19 19
import urllib.parse
20
from uuid import UUID
20 21

  
21 22
import pytest
22 23
from django.contrib.auth import get_user_model
......
29 30
from authentic2.custom_user.models import Profile, ProfileType
30 31
from authentic2.utils.misc import make_url
31 32
from authentic2_idp_oidc.models import OIDCAccessToken, OIDCCode
32
from authentic2_idp_oidc.utils import get_jwkset, make_sub
33
from authentic2_idp_oidc.utils import get_jwkset, make_pairwise_sub, make_sub, reverse_pairwise_sub
33 34

  
34 35
from .. import utils
35 36
from .conftest import client_authentication_headers
......
334 335
    claims = json.loads(jwt.claims)
335 336
    assert claims['sub'] != make_sub(oidc_client, profile_user)
336 337
    assert claims['sub'] == make_sub(oidc_client, profile_user, profile=profile_user.profiles.first())
338

  
339

  
340
def test_full_sub_reversibility(app, oidc_client, profile_settings):
341
    from django.utils.encoding import smart_bytes
342

  
343
    oidc_client.idtoken_algo = oidc_client.ALGO_EC
344
    oidc_client.activate_user_profiles = True
345
    oidc_client.perform_sub_profile_substitution = True
346
    oidc_client.identifier_policy = oidc_client.POLICY_PAIRWISE_REVERSIBLE
347
    oidc_client.save()
348
    profile_type_manager = ProfileType.objects.create(
349
        name='One Manager Type',
350
        slug='one-manager-type',
351
    )
352
    # first with no profiles
353
    for i in range(10):
354
        user = User.objects.create(
355
            first_name='john-%s' % i,
356
            last_name='doe',
357
            email='john.doe.%s@example.org' % i,
358
        )
359
        sub = make_pairwise_sub(oidc_client, user, profile=None)
360
        uuid = reverse_pairwise_sub(oidc_client, smart_bytes(sub))
361
        assert uuid == UUID(user.uuid).bytes
362

  
363
    # then adding user profile information
364
    for i in range(100):
365
        user = User.objects.create(
366
            first_name='john-%s' % i,
367
            last_name='doe',
368
            email='john.doe.%s@example.org' % i,
369
        )
370
        profile = Profile.objects.create(
371
            user=user,
372
            profile_type=profile_type_manager,
373
            identifier='manager %s' % i,
374
            email='manager-%s@example.org' % i,
375
        )
376
        sub_with_profile = make_pairwise_sub(oidc_client, user, profile=profile)
377
        sub_without_profile = make_pairwise_sub(oidc_client, user, profile=None)
378
        uuid_with_profile = reverse_pairwise_sub(oidc_client, smart_bytes(sub_with_profile))
379
        uuid_without_profile = reverse_pairwise_sub(oidc_client, smart_bytes(sub_without_profile))
380
        assert sub_with_profile != sub_without_profile
381
        assert uuid_with_profile == uuid_without_profile
382
        assert uuid_with_profile == UUID(user.uuid).bytes
337
-