From 90c0e3494545dc228407c015663cb797d5cc7e02 Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Fri, 7 Sep 2018 15:26:32 -0400 Subject: [PATCH] Add ability to configure custom email and username claims This will help customers support active directory-based OIDC --- .../core-config-setup/config-setup-tool.html | 26 +++++++++++++++++++ oauth/oidc.py | 23 ++++++++++++++-- oauth/test/test_oidc.py | 5 +++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/config_app/js/core-config-setup/config-setup-tool.html b/config_app/js/core-config-setup/config-setup-tool.html index 9780f85de..f043fe9fc 100644 --- a/config_app/js/core-config-setup/config-setup-tool.html +++ b/config_app/js/core-config-setup/config-setup-tool.html @@ -1201,6 +1201,32 @@ + + Verified E-mail Address Claim (optional): + + + +
+ If specified, the claim in the User Information JWT that contains the verified e-mail address for the user. +
+ + + + Preferred Username Claim (optional): + + + +
+ If specified, the claim in the User Information JWT that contains the preferred username for the user. +
+ + Binding Field: diff --git a/oauth/oidc.py b/oauth/oidc.py index 892929b29..6abe6496c 100644 --- a/oauth/oidc.py +++ b/oauth/oidc.py @@ -167,13 +167,32 @@ class OIDCLoginService(OAuthService): raise OAuthLoginException('Mismatch in `sub` returned by OIDC user info endpoint') # Check if we have a verified email address. - email_address = user_info.get('email') if user_info.get('email_verified') else None + if self.config.get('VERIFIED_EMAIL_CLAIM_NAME'): + email_address = user_info.get(self.config['VERIFIED_EMAIL_CLAIM_NAME']) + else: + email_address = user_info.get('email') if user_info.get('email_verified') else None + + logger.debug('Found e-mail address `%s` for sub `%s`', email_address, user_info['sub']) if self._mailing: if email_address is None: raise OAuthLoginException('A verified email address is required to login with this service') # Check for a preferred username. - lusername = user_info.get('preferred_username') or user_info.get('sub') + if self.config.get('PREFERRED_USERNAME_CLAIM_NAME'): + lusername = user_info.get(self.config['PREFERRED_USERNAME_CLAIM_NAME']) + else: + lusername = user_info.get('preferred_username') + if lusername is None: + # Note: Active Directory provides `unique_name` and `upn`. + # https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-id-and-access-tokens + lusername = user_info.get('unique_name', user_info.get('upn')) + + if lusername is None: + lusername = user_info['sub'] + + if lusername.find('@') >= 0: + lusername = lusername[0:lusername.find('@')] + return decoded_id_token['sub'], lusername, email_address @property diff --git a/oauth/test/test_oidc.py b/oauth/test/test_oidc.py index 1309060e3..3ab184593 100644 --- a/oauth/test/test_oidc.py +++ b/oauth/test/test_oidc.py @@ -51,7 +51,7 @@ def email_verified(request): def userinfo_supported(request): return request.param -@pytest.fixture(params=["someusername", None]) +@pytest.fixture(params=["someusername", "foo@bar.com", None]) def preferred_username(request): return request.param @@ -334,6 +334,9 @@ def test_exchange_code_validcode(oidc_service, discovery_handler, app_config, ht assert lemail is None if preferred_username is not None: + if preferred_username.find('@') >= 0: + preferred_username = preferred_username[0:preferred_username.find('@')] + assert lusername == preferred_username else: assert lusername == lid