Add support for defining custom query parameters for OIDC endpoints
Fixes https://jira.coreos.com/browse/QUAY-886
This commit is contained in:
parent
b4849997e7
commit
3cd314874f
2 changed files with 50 additions and 4 deletions
|
@ -2,6 +2,7 @@ import time
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import urlparse
|
import urlparse
|
||||||
|
import urllib
|
||||||
|
|
||||||
import jwt
|
import jwt
|
||||||
|
|
||||||
|
@ -65,13 +66,35 @@ class OIDCLoginService(OAuthService):
|
||||||
return list(set(login_scopes) & set(supported_scopes))
|
return list(set(login_scopes) & set(supported_scopes))
|
||||||
|
|
||||||
def authorize_endpoint(self):
|
def authorize_endpoint(self):
|
||||||
return self._oidc_config().get('authorization_endpoint', '') + '?response_type=code&'
|
return self._get_endpoint('authorization_endpoint', response_type='code')
|
||||||
|
|
||||||
def token_endpoint(self):
|
def token_endpoint(self):
|
||||||
return self._oidc_config().get('token_endpoint')
|
return self._get_endpoint('token_endpoint')
|
||||||
|
|
||||||
def user_endpoint(self):
|
def user_endpoint(self):
|
||||||
return self._oidc_config().get('userinfo_endpoint')
|
return self._get_endpoint('userinfo_endpoint')
|
||||||
|
|
||||||
|
def _get_endpoint(self, endpoint_key, **kwargs):
|
||||||
|
""" Returns the OIDC endpoint with the given key found in the OIDC discovery
|
||||||
|
document, with the given kwargs added as query parameters. Additionally,
|
||||||
|
any defined parameters found in the OIDC configuration block are also
|
||||||
|
added.
|
||||||
|
"""
|
||||||
|
endpoint = self._oidc_config().get(endpoint_key, '')
|
||||||
|
if not endpoint:
|
||||||
|
return None
|
||||||
|
|
||||||
|
(scheme, netloc, path, query, fragment) = urlparse.urlsplit(endpoint)
|
||||||
|
|
||||||
|
# Add the query parameters from the kwargs and the config.
|
||||||
|
custom_parameters = self.config.get('OIDC_ENDPOINT_CUSTOM_PARAMS', {}).get(endpoint_key, {})
|
||||||
|
|
||||||
|
query_params = urlparse.parse_qs(query, keep_blank_values=True)
|
||||||
|
query_params.update(kwargs)
|
||||||
|
query_params.update(custom_parameters)
|
||||||
|
|
||||||
|
updated_query = urllib.urlencode(query_params)
|
||||||
|
return urlparse.urlunsplit((scheme, netloc, path, updated_query, fragment))
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
return bool(self.get_login_scopes())
|
return bool(self.get_login_scopes())
|
||||||
|
|
|
@ -79,6 +79,20 @@ def app_config(http_client, mailing_feature):
|
||||||
'DEBUGGING': True,
|
'DEBUGGING': True,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'OIDCWITHPARAMS_LOGIN_CONFIG': {
|
||||||
|
'CLIENT_ID': 'foo',
|
||||||
|
'CLIENT_SECRET': 'bar',
|
||||||
|
'SERVICE_NAME': 'Some Other Service',
|
||||||
|
'SERVICE_ICON': 'http://some/icon',
|
||||||
|
'OIDC_SERVER': 'http://fakeoidc',
|
||||||
|
'DEBUGGING': True,
|
||||||
|
'OIDC_ENDPOINT_CUSTOM_PARAMS': {
|
||||||
|
'authorization_endpoint': {
|
||||||
|
'some': 'param',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
'HTTPCLIENT': http_client,
|
'HTTPCLIENT': http_client,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +104,10 @@ def oidc_service(app_config):
|
||||||
def another_oidc_service(app_config):
|
def another_oidc_service(app_config):
|
||||||
return OIDCLoginService(app_config, 'ANOTHEROIDC_LOGIN_CONFIG')
|
return OIDCLoginService(app_config, 'ANOTHEROIDC_LOGIN_CONFIG')
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def oidc_withparams_service(app_config):
|
||||||
|
return OIDCLoginService(app_config, 'OIDCWITHPARAMS_LOGIN_CONFIG')
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def discovery_content(userinfo_supported):
|
def discovery_content(userinfo_supported):
|
||||||
return {
|
return {
|
||||||
|
@ -218,13 +236,18 @@ def test_basic_config(oidc_service):
|
||||||
|
|
||||||
def test_discovery(oidc_service, http_client, discovery_content, discovery_handler):
|
def test_discovery(oidc_service, http_client, discovery_content, discovery_handler):
|
||||||
with HTTMock(discovery_handler):
|
with HTTMock(discovery_handler):
|
||||||
auth = discovery_content['authorization_endpoint'] + '?response_type=code&'
|
auth = discovery_content['authorization_endpoint'] + '?response_type=code'
|
||||||
assert oidc_service.authorize_endpoint() == auth
|
assert oidc_service.authorize_endpoint() == auth
|
||||||
|
|
||||||
assert oidc_service.token_endpoint() == discovery_content['token_endpoint']
|
assert oidc_service.token_endpoint() == discovery_content['token_endpoint']
|
||||||
assert oidc_service.user_endpoint() == discovery_content['userinfo_endpoint']
|
assert oidc_service.user_endpoint() == discovery_content['userinfo_endpoint']
|
||||||
assert set(oidc_service.get_login_scopes()) == set(discovery_content['scopes_supported'])
|
assert set(oidc_service.get_login_scopes()) == set(discovery_content['scopes_supported'])
|
||||||
|
|
||||||
|
def test_discovery_with_params(oidc_withparams_service, http_client, discovery_content, discovery_handler):
|
||||||
|
with HTTMock(discovery_handler):
|
||||||
|
auth = discovery_content['authorization_endpoint'] + '?response_type=code&some=param'
|
||||||
|
assert 'some=param' in oidc_withparams_service.authorize_endpoint()
|
||||||
|
|
||||||
def test_filtered_discovery(another_oidc_service, http_client, discovery_content, discovery_handler):
|
def test_filtered_discovery(another_oidc_service, http_client, discovery_content, discovery_handler):
|
||||||
with HTTMock(discovery_handler):
|
with HTTMock(discovery_handler):
|
||||||
assert another_oidc_service.get_login_scopes() == ['openid']
|
assert another_oidc_service.get_login_scopes() == ['openid']
|
||||||
|
|
Reference in a new issue