From b71e85314e729c2dccbc25d1d986e8cb187af996 Mon Sep 17 00:00:00 2001 From: Serghei MIHAI Date: Tue, 10 Feb 2015 11:07:32 +0100 Subject: [PATCH] Client building refactored --- ckanext/ozwillo_pyoidc/conf.py | 40 +++---- ckanext/ozwillo_pyoidc/oidc.py | 191 +++++++++++-------------------- ckanext/ozwillo_pyoidc/plugin.py | 7 +- 3 files changed, 82 insertions(+), 156 deletions(-) diff --git a/ckanext/ozwillo_pyoidc/conf.py b/ckanext/ozwillo_pyoidc/conf.py index 37486bd..e30d8e3 100644 --- a/ckanext/ozwillo_pyoidc/conf.py +++ b/ckanext/ozwillo_pyoidc/conf.py @@ -21,34 +21,20 @@ ME = { "response_types": ["code"] } -BEHAVIOUR = { - "response_type": "code", - "scope": ["openid", "profile", "email", "address", "phone"], -} - ACR_VALUES = ["SAML"] -# The keys in this dictionary are the OPs short userfriendly name -# not the issuer (iss) name. - -CLIENTS = { - # The ones that support webfinger, OP discovery and client registration - # This is the default, any client that is not listed here is expected to - # support dynamic discovery and registration. - # Supports OP information lookup but not client registration - "ozwillo": { - "srv_discovery_url": "https://accounts.ozwillo-preprod.eu/", - "client_registration": { - "client_id": None, - "client_secret": None, - "redirect_uris": [], - }, - "behaviour": { - "response_type": "code", - "scope": ["openid", "profile", "email"] - }, - "allow": { - "issuer_mismatch": True - } +CLIENT = { + "srv_discovery_url": "https://accounts.ozwillo-preprod.eu/", + "client_registration": { + "client_id": None, + "client_secret": None, + "redirect_uris": [], + }, + "behaviour": { + "response_type": "code", + "scope": ["openid", "profile", "email"] + }, + "allow": { + "issuer_mismatch": True } } diff --git a/ckanext/ozwillo_pyoidc/oidc.py b/ckanext/ozwillo_pyoidc/oidc.py index aa8c961..3d908af 100755 --- a/ckanext/ozwillo_pyoidc/oidc.py +++ b/ckanext/ozwillo_pyoidc/oidc.py @@ -1,4 +1,3 @@ -from oic.utils.http_util import Redirect from oic.exception import MissingAttribute from oic import oic from oic.oauth2 import rndstr, ErrorResponse @@ -7,12 +6,11 @@ from oic.oic import RegistrationResponse from oic.oic import AuthorizationRequest from oic.utils.authn.client import CLIENT_AUTHN_METHOD -__author__ = 'roland' - import logging logger = logging.getLogger(__name__) +import conf class OIDCError(Exception): pass @@ -107,129 +105,70 @@ class Client(oic.Client): return userinfo - -class OIDCClients(object): - def __init__(self, config): - """ - - :param config: Imported configuration module - :return: - """ - self.client = {} - self.client_cls = Client - self.config = config - - for key, val in config.CLIENTS.items(): - if key == "": - continue - else: - self.client[key] = self.create_client(**val) - - def create_client(self, userid="", **kwargs): - """ - Do an instantiation of a client instance - - :param userid: An identifier of the user - :param: Keyword arguments - Keys are ["srv_discovery_url", "client_info", "client_registration", - "provider_info"] - :return: client instance - """ - - _key_set = set(kwargs.keys()) - args = {} - for param in ["verify_ssl"]: - try: - args[param] = kwargs[param] - except KeyError: - pass - else: - _key_set.discard(param) - - client = self.client_cls(client_authn_method=CLIENT_AUTHN_METHOD, - behaviour=kwargs["behaviour"], verify_ssl=self.config.VERIFY_SSL, **args) - - # The behaviour parameter is not significant for the election process - _key_set.discard("behaviour") - for param in ["allow"]: - try: - setattr(client, param, kwargs[param]) - except KeyError: - pass - else: - _key_set.discard(param) - - if _key_set == set(["client_info"]): # Everything dynamic - # There has to be a userid - if not userid: - raise MissingAttribute("Missing userid specification") - - # Find the service that provides information about the OP - issuer = client.wf.discovery_query(userid) - # Gather OP information - _ = client.provider_config(issuer) - # register the client - _ = client.register(client.provider_info["registration_endpoint"], - **kwargs["client_info"]) - elif _key_set == set(["client_info", "srv_discovery_url"]): - # Ship the webfinger part - # Gather OP information - _ = client.provider_config(kwargs["srv_discovery_url"]) - # register the client - _ = client.register(client.provider_info["registration_endpoint"], - **kwargs["client_info"]) - elif _key_set == set(["provider_info", "client_info"]): - client.handle_provider_config( - ProviderConfigurationResponse(**kwargs["provider_info"]), - kwargs["provider_info"]["issuer"]) - _ = client.register(client.provider_info["registration_endpoint"], - **kwargs["client_info"]) - elif _key_set == set(["provider_info", "client_registration"]): - client.handle_provider_config( - ProviderConfigurationResponse(**kwargs["provider_info"]), - kwargs["provider_info"]["issuer"]) - client.store_registration_info(RegistrationResponse( - **kwargs["client_registration"])) - elif _key_set == set(["srv_discovery_url", "client_registration"]): - _ = client.provider_config(kwargs["srv_discovery_url"]) - client.store_registration_info(RegistrationResponse( - **kwargs["client_registration"])) - else: - raise Exception("Configuration error ?") - - return client - - def dynamic_client(self, userid): - client = self.client_cls(client_authn_method=CLIENT_AUTHN_METHOD, - verify_ssl=self.config.VERIFY_SSL) - - issuer = client.wf.discovery_query(userid) - if issuer in self.client: - return self.client[issuer] - else: - # Gather OP information - _pcr = client.provider_config(issuer) - # register the client - _ = client.register(_pcr["registration_endpoint"], - **self.config.CLIENTS[""]["client_info"]) - try: - client.behaviour.update(**self.config.CLIENTS[""]["behaviour"]) - except KeyError: - pass - - self.client[issuer] = client - return client - - def __getitem__(self, item): - """ - Given a service or user identifier return a suitable client - :param item: - :return: - """ +def create_client(**kwargs): + """ + kwargs = config.CLIENT.iteritems + """ + _key_set = set(kwargs.keys()) + args = {} + for param in ["verify_ssl"]: try: - return self.client[item] + args[param] = kwargs[param] except KeyError: - return self.dynamic_client(item) + pass + else: + _key_set.discard(param) - def keys(self): - return self.client.keys() + client = Client(client_authn_method=CLIENT_AUTHN_METHOD, + behaviour=kwargs["behaviour"], + verify_ssl=conf.VERIFY_SSL, **args) + + # The behaviour parameter is not significant for the election process + _key_set.discard("behaviour") + for param in ["allow"]: + try: + setattr(client, param, kwargs[param]) + except KeyError: + pass + else: + _key_set.discard(param) + + if _key_set == set(["client_info"]): # Everything dynamic + # There has to be a userid + if not userid: + raise MissingAttribute("Missing userid specification") + + # Find the service that provides information about the OP + issuer = client.wf.discovery_query(userid) + # Gather OP information + _ = client.provider_config(issuer) + # register the client + _ = client.register(client.provider_info["registration_endpoint"], + **kwargs["client_info"]) + elif _key_set == set(["client_info", "srv_discovery_url"]): + # Ship the webfinger part + # Gather OP information + _ = client.provider_config(kwargs["srv_discovery_url"]) + # register the client + _ = client.register(client.provider_info["registration_endpoint"], + **kwargs["client_info"]) + elif _key_set == set(["provider_info", "client_info"]): + client.handle_provider_config( + ProviderConfigurationResponse(**kwargs["provider_info"]), + kwargs["provider_info"]["issuer"]) + _ = client.register(client.provider_info["registration_endpoint"], + **kwargs["client_info"]) + elif _key_set == set(["provider_info", "client_registration"]): + client.handle_provider_config( + ProviderConfigurationResponse(**kwargs["provider_info"]), + kwargs["provider_info"]["issuer"]) + client.store_registration_info(RegistrationResponse( + **kwargs["client_registration"])) + elif _key_set == set(["srv_discovery_url", "client_registration"]): + _ = client.provider_config(kwargs["srv_discovery_url"]) + client.store_registration_info(RegistrationResponse( + **kwargs["client_registration"])) + else: + raise Exception("Configuration error ?") + + return client diff --git a/ckanext/ozwillo_pyoidc/plugin.py b/ckanext/ozwillo_pyoidc/plugin.py index afab907..8b2a8d8 100755 --- a/ckanext/ozwillo_pyoidc/plugin.py +++ b/ckanext/ozwillo_pyoidc/plugin.py @@ -9,7 +9,8 @@ import ckan.lib.base as base from pylons import config, request -from oidc import OIDCClients +import conf +from oidc import create_client plugin_config_prefix = 'ckanext.ozwillo_pyoidc.' @@ -51,7 +52,7 @@ class OzwilloPyoidcPlugin(plugins.SingletonPlugin): global CLIENT if 'organization_id' in session: g = model.Group.get(session['organization_id']) - conf.CLIENTS['ozwillo']['client_registration'].update({ + conf.CLIENT['client_registration'].update({ 'client_id': g._extras['client_id'].value, 'client_secret': g._extras['client_secret'].value, 'redirect_uris': [toolkit.url_for(host=request.host, @@ -61,7 +62,7 @@ class OzwilloPyoidcPlugin(plugins.SingletonPlugin): qualified=True)] }) log.info('registration info for organization "%s" set' % g.name) - CLIENT = OIDCClients(conf)['ozwillo'] + CLIENT = create_client(**conf.CLIENT) url, ht_args = CLIENT.create_authn_request(session, conf.ACR_VALUES) if ht_args: toolkit.request.headers.update(ht_args)