Projet

Général

Profil

0001-idp_oidc-discard-any-extra-scopes-at-profile-selecti.patch

Paul Marillonnet, 21 mars 2022 11:27

Télécharger (5,97 ko)

Voir les différences:

Subject: [PATCH] idp_oidc: discard any extra scopes at profile selection
 (#62900)

 .../authentic2_idp_oidc/authorization.html    | 13 +++++-
 src/authentic2_idp_oidc/views.py              | 11 +++++
 tests/idp_oidc/test_user_profiles.py          | 40 +++++++++++++++++++
 3 files changed, 62 insertions(+), 2 deletions(-)
src/authentic2_idp_oidc/templates/authentic2_idp_oidc/authorization.html
23 23
      </ul>
24 24
    {% endif %}
25 25
    {% if needs_profile_validation %}
26
     <div id="profile-validation">
27
     <p>{% trans "You may authenticate as owner of the following juridical entity management profile, which may change the aforementioned information." %}</p>
26
      <div id="profile-validation">
27
      <p>{% trans "You may authenticate as owner of the following management profile, which may change the aforementioned information." %}</p>
28
      {% if "email" in scopes %}
29
      <p>{% blocktrans with client_name=client.name %}In this case, {{ client_name }} will collect your managenement profile email address instead of your personal email address.{% endblocktrans %}</p>
30
      {% endif %}
31
      {% if "profile" in scopes %}
32
      <p>{% blocktrans with client_name=client.name %}{{ client_name }} will still collect your first name, your last name and your username.{% endblocktrans %}</p>
33
      {% endif %}
34
      {% if extra_scopes %}
35
      {% blocktrans with client_name=client.name %}Additional personal info will not be sent to {{ client_name }}.{% endblocktrans %}
36
      {% endif %}
28 37
      <div class="profile" id="profile-validation-none">
29 38
        <input type="radio" id="_none" name="profile-validation" value="" checked>
30 39
        <label for="_none">{% trans "Keep my default user profile." %}</label>
src/authentic2_idp_oidc/views.py
306 306
    if not scope:
307 307
        raise MissingParameter('scope')
308 308
    scopes = utils.scope_set(scope)
309
    extra_scopes = scopes - {'openid', 'email', 'profile'}
309 310
    if 'openid' not in scopes:
310 311
        raise InvalidScope(_('Scope must contain "openid", received "%s"') % ', '.join(sorted(scopes)))
311 312
    if not is_scopes_allowed(scopes, client):
......
405 406
                        )
406 407
                    except Profile.DoesNotExist:
407 408
                        pass
409
                if profile and extra_scopes:
410
                    logger.info(
411
                        'idp_oidc: profile of type %s chosen by user %s for client %s, discarding scopes %s',
412
                        profile.profile_type,
413
                        request.user,
414
                        client,
415
                        ' '.join(extra_scopes),
416
                    )
417
                    scopes = scopes - extra_scopes
408 418
                if 'accept' in request.POST:
409 419
                    if 'do_not_ask_again' in request.POST:
410 420
                        pk_to_deletes = []
......
441 451
                        'needs_scope_validation': needs_scope_validation,
442 452
                        'client': client,
443 453
                        'scopes': scopes - {'openid'},
454
                        'extra_scopes': extra_scopes,
444 455
                    },
445 456
                )
446 457
    if response_type == 'code':
tests/idp_oidc/test_user_profiles.py
423 423
    )
424 424
    response = app.get(authorize_url)
425 425
    assert 'do_not_ask_again' not in response.text
426

  
427

  
428
def test_scopes_minimization(app, oidc_client, profile_user, profile_settings):
429
    oidc_client.idtoken_algo = oidc_client.ALGO_HMAC
430
    oidc_client.activate_user_profiles = True
431
    oidc_client.perform_sub_profile_substitution = True
432
    oidc_client.scope = 'openid profile email custom1 custom2 custom3'
433
    oidc_client.save()
434
    redirect_uri = oidc_client.redirect_uris.split()[0]
435
    params = {
436
        'client_id': oidc_client.client_id,
437
        'scope': 'openid profile email custom1 custom2 custom3',
438
        'redirect_uri': redirect_uri,
439
        'state': 'xxx',
440
        'nonce': 'yyy',
441
        'login_hint': 'backoffice john@example.com',
442
        'response_type': 'code',
443
    }
444

  
445
    assert not OIDCCode.objects.count()
446
    assert not OIDCAuthorization.objects.count()
447

  
448
    # firt attempt with no profile: all scopes are saved
449
    authorize_url = make_url('oidc-authorize', params=params)
450
    utils.login(app, profile_user)
451
    response = app.get(authorize_url)
452
    response.form.set('profile-validation', '')
453
    response = response.form.submit('accept')
454
    assert OIDCCode.objects.get(user=profile_user).scope_set() == set(
455
        'openid profile email custom1 custom2 custom3'.split(' ')
456
    )
457
    OIDCCode.objects.get(user=profile_user).delete()
458

  
459
    # second attempt while selection profile: extra scopes are discarded
460
    authorize_url = make_url('oidc-authorize', params=params)
461
    utils.login(app, profile_user)
462
    response = app.get(authorize_url)
463
    response.form.set('profile-validation', profile_user.profiles.first().id)
464
    response = response.form.submit('accept')
465
    assert OIDCCode.objects.get(user=profile_user).scope_set() == set('openid profile email'.split(' '))
426
-