From c0a41644a1ba7e893bc91b5afda806ac9159dcf9 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Tue, 21 Jun 2022 13:41:58 +0200 Subject: [PATCH] auth_oidc: check required claims only from the idtoken or the user_info endpoint not both (#66445) --- src/authentic2_auth_oidc/backends.py | 30 ++++++++++++---------- tests/test_auth_oidc.py | 38 ++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/authentic2_auth_oidc/backends.py b/src/authentic2_auth_oidc/backends.py index fa02e6f4..c96680b9 100644 --- a/src/authentic2_auth_oidc/backends.py +++ b/src/authentic2_auth_oidc/backends.py @@ -207,20 +207,22 @@ class OIDCBackend(ModelBackend): if claim_mapping.required: if '{{' in claim or '{%' in claim: logger.warning('claim \'%r\' is templated, it cannot be set as required') - elif claim_mapping.idtoken_claim and claim not in id_token: - logger.warning( - 'auth_oidc: cannot create user missing required claim %r in id_token (%r)', - claim, - id_token, - ) - return None - elif not user_info or claim not in user_info: - logger.warning( - 'auth_oidc: cannot create user missing required claim %r in user_info (%r)', - claim, - user_info, - ) - return None + elif claim_mapping.idtoken_claim: + if claim not in id_token: + logger.warning( + 'auth_oidc: cannot create user missing required claim %r in id_token (%r)', + claim, + id_token, + ) + return None + else: # claim from the user_info endpoint + if not user_info or claim not in user_info: + logger.warning( + 'auth_oidc: cannot create user missing required claim %r in user_info (%r)', + claim, + user_info, + ) + return None # find en email in mappings email = None diff --git a/tests/test_auth_oidc.py b/tests/test_auth_oidc.py index b05a4468..22325053 100644 --- a/tests/test_auth_oidc.py +++ b/tests/test_auth_oidc.py @@ -1269,3 +1269,41 @@ def test_oidc_provider_authenticator_data_migration(auth_frontend_kwargs, migrat assert second_authenticator.claim_mappings.get().pk == second_provider_claim_mapping.pk assert second_authenticator.accounts.count() == 1 assert second_authenticator.accounts.get().pk == second_provider_account.pk + + +def test_only_idtoken_claims(app, caplog, code, oidc_provider, oidc_provider_jwkset): + oidc_provider.claim_mappings.update(idtoken_claim=True) + response = app.get('/').maybe_follow() + assert oidc_provider.name in response.text + response = response.click(oidc_provider.name) + location = urllib.parse.urlparse(response.location) + query = QueryDict(location.query) + state = query['state'] + nonce = query['nonce'] + + # sub=john.doe + extra_id_token = { + 'given_name': 'John', + 'family_name': 'Doe', + 'email': 'john.doe@example.com', + } + with utils.check_log(caplog, 'missing required claim'): + with oidc_provider_mock( + oidc_provider, + oidc_provider_jwkset, + code, + nonce=nonce, + ): + response = app.get(login_callback_url(oidc_provider), params={'code': code, 'state': state}) + assert User.objects.count() == 0 + + with utils.check_log(caplog, 'auth_oidc: created user'): + with oidc_provider_mock( + oidc_provider, + oidc_provider_jwkset, + code, + nonce=nonce, + extra_id_token=extra_id_token, + ): + response = app.get(login_callback_url(oidc_provider), params={'code': code, 'state': state}) + assert User.objects.count() == 1 -- 2.35.1