Merge pull request #3246 from quay/joseph.schorr/QUAY-1079/oidc-improvements
OIDC improvements
This commit is contained in:
commit
54aca8206b
4 changed files with 60 additions and 12 deletions
|
@ -1201,6 +1201,32 @@
|
|||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Verified E-mail Address Claim (optional):</td>
|
||||
<td>
|
||||
<span class="config-string-field"
|
||||
binding="config[provider].VERIFIED_EMAIL_CLAIM_NAME"
|
||||
placeholder="User information JWT claim that contains the verified e-mail"
|
||||
is-optional="true">
|
||||
</span>
|
||||
<div class="help-text">
|
||||
If specified, the claim in the User Information JWT that contains the verified e-mail address for the user.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Preferred Username Claim (optional):</td>
|
||||
<td>
|
||||
<span class="config-string-field"
|
||||
binding="config[provider].PREFERRED_USERNAME_CLAIM_NAME"
|
||||
placeholder="User information JWT claim that contains the preferred username"
|
||||
is-optional="true">
|
||||
</span>
|
||||
<div class="help-text">
|
||||
If specified, the claim in the User Information JWT that contains the preferred username for the user.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="config.AUTHENTICATION_TYPE != 'Database' && config.AUTHENTICATION_TYPE != 'AppToken'">
|
||||
<td>Binding Field:</td>
|
||||
<td>
|
||||
|
|
|
@ -182,12 +182,12 @@ def _register_service(login_service):
|
|||
@oauthlogin_csrf_protect
|
||||
def callback_func():
|
||||
# Check for a callback error.
|
||||
error = request.args.get('error', None)
|
||||
error = request.values.get('error', None)
|
||||
if error:
|
||||
return _render_ologin_error(login_service.service_name(), error)
|
||||
|
||||
# Exchange the OAuth code for login information.
|
||||
code = request.args.get('code')
|
||||
code = request.values.get('code')
|
||||
try:
|
||||
lid, lusername, lemail = login_service.exchange_code_for_login(app.config, client, code, '')
|
||||
except OAuthLoginException as ole:
|
||||
|
@ -217,12 +217,12 @@ def _register_service(login_service):
|
|||
@oauthlogin_csrf_protect
|
||||
def attach_func():
|
||||
# Check for a callback error.
|
||||
error = request.args.get('error', None)
|
||||
error = request.values.get('error', None)
|
||||
if error:
|
||||
return _render_ologin_error(login_service.service_name(), error)
|
||||
|
||||
# Exchange the OAuth code for login information.
|
||||
code = request.args.get('code')
|
||||
code = request.values.get('code')
|
||||
try:
|
||||
lid, lusername, _ = login_service.exchange_code_for_login(app.config, client, code, '/attach')
|
||||
except OAuthLoginException as ole:
|
||||
|
@ -258,12 +258,12 @@ def _register_service(login_service):
|
|||
@oauthlogin_csrf_protect
|
||||
def cli_token_func():
|
||||
# Check for a callback error.
|
||||
error = request.args.get('error', None)
|
||||
error = request.values.get('error', None)
|
||||
if error:
|
||||
return _render_ologin_error(login_service.service_name(), error)
|
||||
|
||||
# Exchange the OAuth code for the ID token.
|
||||
code = request.args.get('code')
|
||||
code = request.values.get('code')
|
||||
try:
|
||||
idtoken, _ = login_service.exchange_code_for_tokens(app.config, client, code, '/cli')
|
||||
except OAuthLoginException as ole:
|
||||
|
@ -281,17 +281,17 @@ def _register_service(login_service):
|
|||
oauthlogin.add_url_rule('/%s/callback' % login_service.service_id(),
|
||||
'%s_oauth_callback' % login_service.service_id(),
|
||||
callback_func,
|
||||
methods=['GET'])
|
||||
methods=['GET', 'POST'])
|
||||
|
||||
oauthlogin.add_url_rule('/%s/callback/attach' % login_service.service_id(),
|
||||
'%s_oauth_attach' % login_service.service_id(),
|
||||
attach_func,
|
||||
methods=['GET'])
|
||||
methods=['GET', 'POST'])
|
||||
|
||||
oauthlogin.add_url_rule('/%s/callback/cli' % login_service.service_id(),
|
||||
'%s_oauth_cli' % login_service.service_id(),
|
||||
cli_token_func,
|
||||
methods=['GET'])
|
||||
methods=['GET', 'POST'])
|
||||
|
||||
# Register the routes for each of the login services.
|
||||
for current_service in oauth_login.services:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Reference in a new issue