Revision b71e8531
Added by Serghei Mihai almost 11 years ago
| ckanext/ozwillo_pyoidc/conf.py | ||
|---|---|---|
|
"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
|
||
|
}
|
||
|
}
|
||
| ckanext/ozwillo_pyoidc/oidc.py | ||
|---|---|---|
|
from oic.utils.http_util import Redirect
|
||
|
from oic.exception import MissingAttribute
|
||
|
from oic import oic
|
||
|
from oic.oauth2 import rndstr, ErrorResponse
|
||
| ... | ... | |
|
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
|
||
| ... | ... | |
|
|
||
|
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]
|
||
|
def create_client(**kwargs):
|
||
|
"""
|
||
|
kwargs = config.CLIENT.iteritems
|
||
|
"""
|
||
|
_key_set = set(kwargs.keys())
|
||
|
args = {}
|
||
|
for param in ["verify_ssl"]:
|
||
|
try:
|
||
|
args[param] = kwargs[param]
|
||
|
except KeyError:
|
||
|
pass
|
||
|
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
|
||
|
_key_set.discard(param)
|
||
|
|
||
|
self.client[issuer] = client
|
||
|
return client
|
||
|
client = Client(client_authn_method=CLIENT_AUTHN_METHOD,
|
||
|
behaviour=kwargs["behaviour"],
|
||
|
verify_ssl=conf.VERIFY_SSL, **args)
|
||
|
|
||
|
def __getitem__(self, item):
|
||
|
"""
|
||
|
Given a service or user identifier return a suitable client
|
||
|
:param item:
|
||
|
:return:
|
||
|
"""
|
||
|
# The behaviour parameter is not significant for the election process
|
||
|
_key_set.discard("behaviour")
|
||
|
for param in ["allow"]:
|
||
|
try:
|
||
|
return self.client[item]
|
||
|
setattr(client, param, kwargs[param])
|
||
|
except KeyError:
|
||
|
return self.dynamic_client(item)
|
||
|
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")
|
||
|
|
||
|
def keys(self):
|
||
|
return self.client.keys()
|
||
|
# 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
|
||
| ckanext/ozwillo_pyoidc/plugin.py | ||
|---|---|---|
|
|
||
|
from pylons import config, request
|
||
|
|
||
|
from oidc import OIDCClients
|
||
|
import conf
|
||
|
from oidc import create_client
|
||
|
|
||
|
plugin_config_prefix = 'ckanext.ozwillo_pyoidc.'
|
||
|
|
||
| ... | ... | |
|
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,
|
||
| ... | ... | |
|
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)
|
||
Also available in: Unified diff
Client building refactored