From 89be5e16f89ed8eb120975377144677d529b86e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Sun, 11 Oct 2020 17:08:36 +0200 Subject: [PATCH] auth oidc: update user sub when linking existing user during SSO (#47544) --- src/authentic2_auth_oidc/backends.py | 9 ++++++-- tests/test_auth_oidc.py | 33 +++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/authentic2_auth_oidc/backends.py b/src/authentic2_auth_oidc/backends.py index fbafb254d..07578dec4 100644 --- a/src/authentic2_auth_oidc/backends.py +++ b/src/authentic2_auth_oidc/backends.py @@ -242,10 +242,15 @@ class OIDCBackend(ModelBackend): if not user: user = User.objects.create(ou=provider.ou) created = True - models.OIDCAccount.objects.get_or_create( + oidc_account, created = models.OIDCAccount.objects.get_or_create( provider=provider, user=user, - sub=id_token.sub) + defaults={'sub': id_token.sub}) + if not created and oidc_account.sub != id_token.sub: + logger.info('auth_oidc: changed user %s sub from %s to %s (issuer %s)', + user, oidc_account.sub, id_token.sub, id_token.iss) + oidc_account.sub = id_token.sub + oidc_account.save() else: logger.warning(u'auth_oidc: cannot create user for sub %r as issuer %r does not' u' allow it', id_token.sub, id_token.iss) diff --git a/tests/test_auth_oidc.py b/tests/test_auth_oidc.py index 08dd25823..3c83e9eb7 100644 --- a/tests/test_auth_oidc.py +++ b/tests/test_auth_oidc.py @@ -614,7 +614,6 @@ def test_show_on_login_page(app, oidc_provider): def test_strategy_find_uuid(app, caplog, code, oidc_provider, oidc_provider_jwkset, simple_user): - # no mapping please OIDCClaimMapping.objects.all().delete() oidc_provider.strategy = oidc_provider.STRATEGY_FIND_UUID @@ -658,6 +657,38 @@ def test_strategy_find_uuid(app, caplog, code, oidc_provider, oidc_provider_jwks assert response.location.startswith('https://server.example.com/logout?') +def test_strategy_create(app, caplog, code, oidc_provider, oidc_provider_jwkset): + oidc_provider.ou.email_is_unique = True + oidc_provider.ou.save() + + User = get_user_model() + User.objects.all().delete() + + response = app.get('/').maybe_follow() + assert oidc_provider.name in response.text + response = response.click(oidc_provider.name) + location = urlparse.urlparse(response.location) + query = check_simple_qs(urlparse.parse_qs(location.query)) + nonce = app.session['auth_oidc'][query['state']]['request']['nonce'] + + # sub=john.doe + with utils.check_log(caplog, 'auth_oidc: created user'): + with oidc_provider_mock(oidc_provider, oidc_provider_jwkset, code, nonce=nonce): + response = app.get(login_callback_url(oidc_provider), params={'code': code, 'state': query['state']}) + assert User.objects.count() == 1 + + # second time + with oidc_provider_mock(oidc_provider, oidc_provider_jwkset, code, nonce=nonce): + response = app.get(login_callback_url(oidc_provider), params={'code': code, 'state': query['state']}) + assert User.objects.count() == 1 + + # different sub, same user + with utils.check_log(caplog, 'auth_oidc: changed user'): + with oidc_provider_mock(oidc_provider, oidc_provider_jwkset, code, sub='other', nonce=nonce): + response = app.get(login_callback_url(oidc_provider), params={'code': code, 'state': query['state']}) + assert User.objects.count() == 1 + + def test_register_issuer(db, app, caplog, oidc_provider_jwkset): config_dir = os.path.dirname(__file__) config_file = os.path.join(config_dir, 'openid_configuration.json')