Fixed method name screw-up.
This commit is contained in:
parent
dc67e73afd
commit
63e20151f9
|
@ -1,4 +1,4 @@
|
|||
from oic.oauth2.exception import FailedAuthentication
|
||||
from oic.exception import FailedAuthentication
|
||||
from oic.oic import OpenIDSchema
|
||||
from oic.utils.http_util import Response
|
||||
|
||||
|
|
|
@ -132,7 +132,8 @@ class OpenIDConnect(Social):
|
|||
session.setService(self.opKey)
|
||||
acr_value = session.getAcrValue(client.authorization_endpoint)
|
||||
try:
|
||||
acr_values = client.provider_info[self.srv_discovery_url]["acr_values"].split()
|
||||
acr_values = client.provider_info[
|
||||
self.srv_discovery_url]["acr_values_supported"].split()
|
||||
session.setAcrvalues(acr_values)
|
||||
except:
|
||||
pass
|
||||
|
|
|
@ -139,7 +139,8 @@ class OpenIDConnect(object):
|
|||
session.setClient(client)
|
||||
acr_value = session.getAcrValue(client.authorization_endpoint)
|
||||
try:
|
||||
acr_values = client.provider_info[self.srv_discovery_url]["acr_values"].split()
|
||||
acr_values = client.provider_info[
|
||||
self.srv_discovery_url]["acr_values_supported"].split()
|
||||
session.setAcrvalues(acr_values)
|
||||
except:
|
||||
pass
|
||||
|
|
|
@ -64,3 +64,7 @@ class NotForMe(PyoidcError):
|
|||
class UnSupported(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class MessageException(PyoidcError):
|
||||
pass
|
||||
|
|
@ -13,7 +13,7 @@ import logging
|
|||
|
||||
from oic.utils.keyio import KeyJar
|
||||
from oic.utils.time_util import utc_time_sans_frac
|
||||
from oic.oauth2.exception import UnSupported
|
||||
from oic.exception import UnSupported
|
||||
|
||||
DEF_SIGN_ALG = "HS256"
|
||||
|
||||
|
|
|
@ -0,0 +1,639 @@
|
|||
import logging
|
||||
import urllib
|
||||
import urlparse
|
||||
from oic.oic import OIDCONF_PATTERN
|
||||
from oic.oic.message import ProviderConfigurationResponse
|
||||
import requests
|
||||
from oic.utils.keyio import KeyJar
|
||||
from oic.utils.time_util import utc_time_sans_frac
|
||||
from oic.oic.provider import secret
|
||||
from oic.oic.provider import RegistrationEndpoint
|
||||
from oic.oic.provider import Endpoint
|
||||
|
||||
from oic import oauth2
|
||||
from oic.oauth2 import provider
|
||||
from oic.oauth2 import VerificationError
|
||||
from oic.oauth2 import rndstr
|
||||
from oic.oauth2 import ErrorResponse
|
||||
from oic.oauth2 import UnSupported
|
||||
from oic.oauth2 import Message
|
||||
from oic.oauth2 import message
|
||||
from oic.oauth2 import SINGLE_REQUIRED_STRING
|
||||
from oic.oauth2 import OPTIONAL_LIST_OF_SP_SEP_STRINGS
|
||||
from oic.oauth2 import REQUIRED_LIST_OF_STRINGS
|
||||
from oic.oauth2 import OPTIONAL_LIST_OF_STRINGS
|
||||
from oic.oauth2 import SINGLE_OPTIONAL_STRING
|
||||
from oic.oauth2 import SINGLE_OPTIONAL_INT
|
||||
from oic.exception import UnknownAssertionType, PyoidcError
|
||||
|
||||
from oic.utils.authn.client import AuthnFailure
|
||||
from oic.utils.http_util import Unauthorized, NoContent
|
||||
from oic.utils.http_util import Response
|
||||
from oic.utils.http_util import BadRequest
|
||||
from oic.utils.http_util import Forbidden
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
__author__ = 'roland'
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
class InvalidRedirectUri(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class MissingPage(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ModificationForbidden(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class RegistrationRequest(Message):
|
||||
c_param = {
|
||||
"redirect_uris": REQUIRED_LIST_OF_STRINGS,
|
||||
"client_name": SINGLE_OPTIONAL_STRING,
|
||||
"client_uri": SINGLE_OPTIONAL_STRING,
|
||||
"logo_uri": SINGLE_OPTIONAL_STRING,
|
||||
"contacts": OPTIONAL_LIST_OF_STRINGS,
|
||||
"tos_uri": SINGLE_OPTIONAL_STRING,
|
||||
"policy_uri": SINGLE_OPTIONAL_STRING,
|
||||
"token_endpoint_auth_method": SINGLE_OPTIONAL_STRING,
|
||||
"scope": OPTIONAL_LIST_OF_SP_SEP_STRINGS,
|
||||
"grant_types": OPTIONAL_LIST_OF_STRINGS,
|
||||
"response_types": OPTIONAL_LIST_OF_STRINGS,
|
||||
"jwks_uri": SINGLE_OPTIONAL_STRING,
|
||||
"software_id": SINGLE_OPTIONAL_STRING,
|
||||
"software_version": SINGLE_OPTIONAL_STRING,
|
||||
}
|
||||
|
||||
def verify(self, **kwargs):
|
||||
if "initiate_login_uri" in self:
|
||||
assert self["initiate_login_uri"].startswith("https:")
|
||||
|
||||
if "redirect_uris" in self:
|
||||
for uri in self["redirect_uris"]:
|
||||
if urlparse.urlparse(uri).fragment:
|
||||
raise InvalidRedirectUri(
|
||||
"redirect_uri contains fragment: %s" % uri)
|
||||
|
||||
for uri in ["client_uri", "logo_uri", "tos_uri", "policy_uri"]:
|
||||
if uri in self:
|
||||
try:
|
||||
resp = requests.request("GET", self[uri],
|
||||
allow_redirects=True)
|
||||
except requests.ConnectionError:
|
||||
raise MissingPage(self[uri])
|
||||
|
||||
if not resp.status_code in [200, 201]:
|
||||
raise MissingPage(self[uri])
|
||||
|
||||
if "grant_types" in self and "response_types" in self:
|
||||
for typ in self["grant_types"]:
|
||||
if typ == "authorization_code":
|
||||
try:
|
||||
assert "code" in self["response_types"]
|
||||
except AssertionError:
|
||||
self["response_types"].append("code")
|
||||
elif typ == "implicit":
|
||||
try:
|
||||
assert "token" in self["response_types"]
|
||||
except AssertionError:
|
||||
self["response_types"].append("token")
|
||||
|
||||
return super(RegistrationRequest, self).verify(**kwargs)
|
||||
|
||||
|
||||
class ClientInfoResponse(RegistrationRequest):
|
||||
c_param = RegistrationRequest.c_param.copy()
|
||||
c_param.update({
|
||||
"client_id": SINGLE_REQUIRED_STRING,
|
||||
"client_secret": SINGLE_OPTIONAL_STRING,
|
||||
"client_id_issued_at": SINGLE_OPTIONAL_INT,
|
||||
"client_secret_expires_at": SINGLE_OPTIONAL_INT,
|
||||
"registration_access_token": SINGLE_REQUIRED_STRING,
|
||||
"registration_client_uri": SINGLE_REQUIRED_STRING
|
||||
})
|
||||
|
||||
|
||||
class ClientRegistrationError(ErrorResponse):
|
||||
c_param = ErrorResponse.c_param.copy()
|
||||
c_param.update({"state": SINGLE_OPTIONAL_STRING})
|
||||
c_allowed_values = ErrorResponse.c_allowed_values.copy()
|
||||
c_allowed_values.update({"error": ["invalid_redirect_uri",
|
||||
"invalid_client_metadata",
|
||||
"invalid_client_id"]})
|
||||
|
||||
|
||||
class ClientUpdateRequest(RegistrationRequest):
|
||||
c_param = RegistrationRequest.c_param.copy()
|
||||
c_param.update({
|
||||
"client_id": SINGLE_REQUIRED_STRING,
|
||||
"client_secret": SINGLE_OPTIONAL_STRING,
|
||||
})
|
||||
|
||||
|
||||
MSG = {
|
||||
"RegistrationRequest": RegistrationRequest,
|
||||
"ClientInfoResponse": ClientInfoResponse,
|
||||
"ClientRegistrationError": ClientRegistrationError,
|
||||
"ClientUpdateRequest": ClientUpdateRequest
|
||||
}
|
||||
|
||||
|
||||
def factory(msgtype):
|
||||
try:
|
||||
return MSG[msgtype]
|
||||
except KeyError:
|
||||
return message.factory(msgtype)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
class ClientInfoEndpoint(Endpoint):
|
||||
etype = "clientinfo"
|
||||
|
||||
|
||||
class Provider(provider.Provider):
|
||||
def __init__(self, name, sdb, cdb, authn_broker, authz, client_authn,
|
||||
symkey="", urlmap=None, iv=0, default_scope="",
|
||||
ca_bundle=None, seed="", client_authn_methods=None,
|
||||
authn_at_registration="", client_info_url="",
|
||||
secret_lifetime=86400):
|
||||
provider.Provider.__init__(self, name, sdb, cdb, authn_broker, authz,
|
||||
client_authn, symkey, urlmap, iv,
|
||||
default_scope, ca_bundle)
|
||||
|
||||
self.endp.extend([RegistrationEndpoint, ClientInfoEndpoint])
|
||||
|
||||
# dictionary of client authentication methods
|
||||
self.client_authn_methods = client_authn_methods
|
||||
if authn_at_registration:
|
||||
assert authn_at_registration in client_authn_methods
|
||||
self.authn_at_registration = authn_at_registration
|
||||
self.seed = seed
|
||||
self.client_info_url = client_info_url
|
||||
self.secret_lifetime = secret_lifetime
|
||||
|
||||
# @staticmethod
|
||||
# def _uris_to_dict(uris):
|
||||
# ruri = {}
|
||||
# for uri in uris:
|
||||
# base, query = urllib.splitquery(uri)
|
||||
# if query:
|
||||
# try:
|
||||
# ruri[base].append(urlparse.parse_qs(query))
|
||||
# except KeyError:
|
||||
# ruri[base] = [urlparse.parse_qs(query)]
|
||||
# else:
|
||||
# ruri[base] = [""]
|
||||
# return ruri
|
||||
#
|
||||
# @staticmethod
|
||||
# def _dict_to_uris(spec):
|
||||
# _uri = []
|
||||
# for url, qlist in spec.items():
|
||||
# for query in qlist:
|
||||
# if query:
|
||||
# _uri.append("%s?%s" % (url, query))
|
||||
# else:
|
||||
# _uri.append(url)
|
||||
# return _uri
|
||||
|
||||
@staticmethod
|
||||
def _uris_to_tuples(uris):
|
||||
tup = []
|
||||
for uri in uris:
|
||||
base, query = urllib.splitquery(uri)
|
||||
if query:
|
||||
tup.append((base, query))
|
||||
else:
|
||||
tup.append((base,""))
|
||||
return tup
|
||||
|
||||
@staticmethod
|
||||
def _tuples_to_uris(items):
|
||||
_uri = []
|
||||
for url, query in items:
|
||||
if query:
|
||||
_uri.append("%s?%s" % (url, query))
|
||||
else:
|
||||
_uri.append(url)
|
||||
return _uri
|
||||
|
||||
def create_new_client(self, request):
|
||||
"""
|
||||
|
||||
:param request: The Client registration request
|
||||
:return: The client_id
|
||||
"""
|
||||
|
||||
_cinfo = request.to_dict()
|
||||
|
||||
# create new id and secret
|
||||
_id = rndstr(12)
|
||||
while _id in self.cdb:
|
||||
_id = rndstr(12)
|
||||
|
||||
_cinfo["client_id"] = _id
|
||||
_cinfo["client_secret"] = secret(self.seed, _id)
|
||||
_cinfo["client_id_issued_at"] = utc_time_sans_frac()
|
||||
_cinfo["client_secret_expires_at"] = utc_time_sans_frac() + \
|
||||
self.secret_lifetime
|
||||
|
||||
# If I support client info endpoint
|
||||
if ClientInfoEndpoint in self.endp:
|
||||
_cinfo["registration_access_token"] = rndstr(32)
|
||||
_cinfo["registration_client_uri"] = "%s%s?client_id=%s" % (
|
||||
self.client_info_url, ClientInfoEndpoint.etype, _id)
|
||||
|
||||
if "redirect_uris" in request:
|
||||
_cinfo["redirect_uris"] = self._uris_to_tuples(
|
||||
request["redirect_uris"])
|
||||
|
||||
self.cdb[_id] = _cinfo
|
||||
|
||||
return _id
|
||||
|
||||
def client_info(self, client_id):
|
||||
_cinfo = self.cdb[client_id].copy()
|
||||
try:
|
||||
_cinfo["redirect_uris"] = self._tuples_to_uris(
|
||||
_cinfo["redirect_uris"])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
msg = ClientInfoResponse(**_cinfo)
|
||||
return Response(msg.to_json(), content="application/json")
|
||||
|
||||
def client_info_update(self, client_id, request):
|
||||
_cinfo = self.cdb[client_id].copy()
|
||||
try:
|
||||
_cinfo["redirect_uris"] = self._tuples_to_uris(
|
||||
_cinfo["redirect_uris"])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
for key, value in request.items():
|
||||
if key in ["client_secret", "client_id"]:
|
||||
# assure it's the same
|
||||
try:
|
||||
assert value == _cinfo[key]
|
||||
except AssertionError:
|
||||
raise ModificationForbidden("Not allowed to change")
|
||||
else:
|
||||
_cinfo[key] = value
|
||||
|
||||
for key in _cinfo.keys():
|
||||
if key in ["client_id_issued_at", "client_secret_expires_at",
|
||||
"registration_access_token","registration_client_uri"]:
|
||||
continue
|
||||
if key not in request:
|
||||
del _cinfo[key]
|
||||
|
||||
if "redirect_uris" in request:
|
||||
_cinfo["redirect_uris"] = self._uris_to_tuples(
|
||||
request["redirect_uris"])
|
||||
|
||||
self.cdb[client_id] = _cinfo
|
||||
|
||||
def verify_client(self, environ, areq, authn_method, client_id=""):
|
||||
"""
|
||||
|
||||
:param areq: The request
|
||||
:param authn_method: client authentication method
|
||||
:return:
|
||||
"""
|
||||
|
||||
if not client_id:
|
||||
client_id = self.get_client_id(areq, environ["HTTP_AUTHORIZATION"])
|
||||
|
||||
try:
|
||||
method = self.client_authn_methods[authn_method]
|
||||
except KeyError:
|
||||
raise UnSupported()
|
||||
return method(self).verify(environ, client_id=client_id)
|
||||
|
||||
def registration_endpoint(self, request, environ, **kwargs):
|
||||
"""
|
||||
|
||||
:param request: The request
|
||||
:param authn: Client authentication information
|
||||
:param kwargs: extra keyword arguments
|
||||
:return: A Response instance
|
||||
"""
|
||||
|
||||
_request = RegistrationRequest().deserialize(request, "json")
|
||||
try:
|
||||
_request.verify()
|
||||
except InvalidRedirectUri, err:
|
||||
msg = ClientRegistrationError(error="invalid_redirect_uri",
|
||||
error_description="%s" % err)
|
||||
return BadRequest(msg.to_json(), content="application/json")
|
||||
except (MissingPage, VerificationError), err:
|
||||
msg = ClientRegistrationError(error="invalid_client_metadata",
|
||||
error_description="%s" % err)
|
||||
return BadRequest(msg.to_json(), content="application/json")
|
||||
|
||||
# authenticated client
|
||||
if self.authn_at_registration:
|
||||
try:
|
||||
_ = self.verify_client(environ, _request,
|
||||
self.authn_at_registration)
|
||||
except (AuthnFailure, UnknownAssertionType):
|
||||
return Unauthorized()
|
||||
|
||||
client_id = self.create_new_client(_request)
|
||||
|
||||
return self.client_info(client_id)
|
||||
|
||||
def client_info_endpoint(self, request, environ,
|
||||
method="GET", query="", **kwargs):
|
||||
"""
|
||||
Operations on this endpoint are switched through the use of different
|
||||
HTTP methods
|
||||
|
||||
:param request: The request
|
||||
:param authn: Client authentication information
|
||||
:param method: HTTP method used for the request
|
||||
:param query: The query part of the URL used, this is where the
|
||||
client_id is supposed to reside.
|
||||
:param kwargs: extra keyword arguments
|
||||
:return: A Response instance
|
||||
"""
|
||||
|
||||
_query = urlparse.parse_qs(query)
|
||||
try:
|
||||
_id = _query["client_id"][0]
|
||||
except KeyError:
|
||||
return BadRequest("Missing query component")
|
||||
|
||||
try:
|
||||
assert _id in self.cdb
|
||||
except AssertionError:
|
||||
return Unauthorized()
|
||||
|
||||
# authenticated client
|
||||
try:
|
||||
_ = self.verify_client(environ, request, "bearer_header",
|
||||
client_id=_id)
|
||||
except (AuthnFailure, UnknownAssertionType):
|
||||
return Unauthorized()
|
||||
|
||||
if method == "GET":
|
||||
return self.client_info(_id)
|
||||
elif method == "PUT":
|
||||
try:
|
||||
_request = ClientUpdateRequest().from_json(request)
|
||||
except ValueError:
|
||||
return BadRequest()
|
||||
|
||||
try:
|
||||
_request.verify()
|
||||
except InvalidRedirectUri, err:
|
||||
msg = ClientRegistrationError(error="invalid_redirect_uri",
|
||||
error_description="%s" % err)
|
||||
return BadRequest(msg.to_json(), content="application/json")
|
||||
except (MissingPage, VerificationError), err:
|
||||
msg = ClientRegistrationError(error="invalid_client_metadata",
|
||||
error_description="%s" % err)
|
||||
return BadRequest(msg.to_json(), content="application/json")
|
||||
|
||||
try:
|
||||
self.client_info_update(_id, _request)
|
||||
return self.client_info(_id)
|
||||
except ModificationForbidden:
|
||||
return Forbidden()
|
||||
elif method == "DELETE":
|
||||
try:
|
||||
del self.cdb[_id]
|
||||
except KeyError:
|
||||
return Unauthorized()
|
||||
else:
|
||||
return NoContent()
|
||||
|
||||
def providerinfo_endpoint(self):
|
||||
pass
|
||||
|
||||
|
||||
RESPONSE2ERROR = {
|
||||
"ClientInfoResponse": [ClientRegistrationError],
|
||||
"ClientUpdateRequest": [ClientRegistrationError]
|
||||
}
|
||||
|
||||
|
||||
class Client(oauth2.Client):
|
||||
def __init__(self, client_id=None, ca_certs=None,
|
||||
client_authn_method=None, keyjar=None):
|
||||
oauth2.Client.__init__(self, client_id=client_id, ca_certs=ca_certs,
|
||||
client_authn_method=client_authn_method,
|
||||
keyjar=keyjar)
|
||||
self.allow = {}
|
||||
self.request2endpoint.update({
|
||||
"RegistrationRequest": "registration_endpoint",
|
||||
"ClientUpdateRequest": "clientinfo_endpoint"
|
||||
})
|
||||
self.registration_response = None
|
||||
|
||||
def construct_RegistrationRequest(self, request=RegistrationRequest,
|
||||
request_args=None, extra_args=None,
|
||||
**kwargs):
|
||||
|
||||
if request_args is None:
|
||||
request_args = {}
|
||||
|
||||
return self.construct_request(request, request_args, extra_args)
|
||||
|
||||
def do_client_registration(self, request=RegistrationRequest,
|
||||
body_type="", method="GET",
|
||||
request_args=None, extra_args=None,
|
||||
http_args=None,
|
||||
response_cls=ClientInfoResponse,
|
||||
**kwargs):
|
||||
|
||||
url, body, ht_args, csi = self.request_info(request, method,
|
||||
request_args, extra_args,
|
||||
**kwargs)
|
||||
|
||||
if http_args is None:
|
||||
http_args = ht_args
|
||||
else:
|
||||
http_args.update(http_args)
|
||||
|
||||
resp = self.request_and_return(url, response_cls, method, body,
|
||||
body_type, http_args=http_args)
|
||||
|
||||
return resp
|
||||
|
||||
def do_client_read_request(self, request=ClientUpdateRequest,
|
||||
body_type="", method="GET",
|
||||
request_args=None, extra_args=None,
|
||||
http_args=None,
|
||||
response_cls=ClientInfoResponse,
|
||||
**kwargs):
|
||||
|
||||
url, body, ht_args, csi = self.request_info(request, method,
|
||||
request_args, extra_args,
|
||||
**kwargs)
|
||||
|
||||
if http_args is None:
|
||||
http_args = ht_args
|
||||
else:
|
||||
http_args.update(http_args)
|
||||
|
||||
resp = self.request_and_return(url, response_cls, method, body,
|
||||
body_type, http_args=http_args)
|
||||
|
||||
return resp
|
||||
|
||||
def do_client_update_request(self, request=ClientUpdateRequest,
|
||||
body_type="", method="PUT",
|
||||
request_args=None, extra_args=None,
|
||||
http_args=None,
|
||||
response_cls=ClientInfoResponse,
|
||||
**kwargs):
|
||||
|
||||
url, body, ht_args, csi = self.request_info(request, method,
|
||||
request_args, extra_args,
|
||||
**kwargs)
|
||||
|
||||
if http_args is None:
|
||||
http_args = ht_args
|
||||
else:
|
||||
http_args.update(http_args)
|
||||
|
||||
resp = self.request_and_return(url, response_cls, method, body,
|
||||
body_type, http_args=http_args)
|
||||
|
||||
return resp
|
||||
|
||||
def do_client_delete_request(self, request=ClientUpdateRequest,
|
||||
body_type="", method="DELETE",
|
||||
request_args=None, extra_args=None,
|
||||
http_args=None,
|
||||
response_cls=ClientInfoResponse,
|
||||
**kwargs):
|
||||
|
||||
url, body, ht_args, csi = self.request_info(request, method,
|
||||
request_args, extra_args,
|
||||
**kwargs)
|
||||
|
||||
if http_args is None:
|
||||
http_args = ht_args
|
||||
else:
|
||||
http_args.update(http_args)
|
||||
|
||||
resp = self.request_and_return(url, response_cls, method, body,
|
||||
body_type, http_args=http_args)
|
||||
|
||||
return resp
|
||||
|
||||
def handle_provider_config(self, pcr, issuer, keys=True, endpoints=True):
|
||||
"""
|
||||
Deal with Provider Config Response
|
||||
:param pcr: The ProviderConfigResponse instance
|
||||
:param issuer: The one I thought should be the issuer of the config
|
||||
:param keys: Should I deal with keys
|
||||
:param endpoints: Should I deal with endpoints, that is store them
|
||||
as attributes in self.
|
||||
"""
|
||||
|
||||
if "issuer" in pcr:
|
||||
_pcr_issuer = pcr["issuer"]
|
||||
if pcr["issuer"].endswith("/"):
|
||||
if issuer.endswith("/"):
|
||||
_issuer = issuer
|
||||
else:
|
||||
_issuer = issuer + "/"
|
||||
else:
|
||||
if issuer.endswith("/"):
|
||||
_issuer = issuer[:-1]
|
||||
else:
|
||||
_issuer = issuer
|
||||
|
||||
try:
|
||||
_ = self.allow["issuer_mismatch"]
|
||||
except KeyError:
|
||||
try:
|
||||
assert _issuer == _pcr_issuer
|
||||
except AssertionError:
|
||||
raise PyoidcError(
|
||||
"provider info issuer mismatch '%s' != '%s'" % (
|
||||
_issuer, _pcr_issuer))
|
||||
|
||||
self.provider_info[_pcr_issuer] = pcr
|
||||
else:
|
||||
_pcr_issuer = issuer
|
||||
|
||||
if endpoints:
|
||||
for key, val in pcr.items():
|
||||
if key.endswith("_endpoint"):
|
||||
setattr(self, key, val)
|
||||
|
||||
if keys:
|
||||
if self.keyjar is None:
|
||||
self.keyjar = KeyJar()
|
||||
|
||||
self.keyjar.load_keys(pcr, _pcr_issuer)
|
||||
|
||||
def provider_config(self, issuer, keys=True, endpoints=True,
|
||||
response_cls=ProviderConfigurationResponse,
|
||||
serv_pattern=OIDCONF_PATTERN):
|
||||
if issuer.endswith("/"):
|
||||
_issuer = issuer[:-1]
|
||||
else:
|
||||
_issuer = issuer
|
||||
|
||||
url = serv_pattern % _issuer
|
||||
|
||||
pcr = None
|
||||
r = self.http_request(url)
|
||||
if r.status_code == 200:
|
||||
pcr = response_cls().from_json(r.text)
|
||||
elif r.status_code == 302:
|
||||
while r.status_code == 302:
|
||||
r = self.http_request(r.headers["location"])
|
||||
if r.status_code == 200:
|
||||
pcr = response_cls().from_json(r.text)
|
||||
break
|
||||
|
||||
if pcr is None:
|
||||
raise PyoidcError("Trying '%s', status %s" % (url, r.status_code))
|
||||
|
||||
self.handle_provider_config(pcr, issuer, keys, endpoints)
|
||||
|
||||
return pcr
|
||||
|
||||
def store_registration_info(self, reginfo):
|
||||
self.registration_response = reginfo
|
||||
self.client_secret = reginfo["client_secret"]
|
||||
self.client_id = reginfo["client_id"]
|
||||
self.redirect_uris = reginfo["redirect_uris"]
|
||||
|
||||
def handle_registration_info(self, response):
|
||||
if response.status_code == 200:
|
||||
resp = ClientInfoResponse().deserialize(response.text, "json")
|
||||
self.store_registration_info(resp)
|
||||
else:
|
||||
err = ErrorResponse().deserialize(response.text, "json")
|
||||
raise PyoidcError("Registration failed: %s" % err.get_json())
|
||||
|
||||
return resp
|
||||
|
||||
def register(self, url, **kwargs):
|
||||
"""
|
||||
Register the client at an OP
|
||||
|
||||
:param url: The OPs registration endpoint
|
||||
:param kwargs: parameters to the registration request
|
||||
:return:
|
||||
"""
|
||||
req = self.construct_RegistrationRequest(**kwargs)
|
||||
|
||||
headers = {"content-type": "application/json"}
|
||||
|
||||
rsp = self.http_request(url, "POST", data=req.to_json(),
|
||||
headers=headers)
|
||||
|
||||
return self.handle_registration_info(rsp)
|
|
@ -8,15 +8,12 @@ import jwkest
|
|||
from jwkest.jwe import JWE
|
||||
from jwkest.jwk import keyitems2keyreps
|
||||
from jwkest.jws import JWS
|
||||
from oic.oauth2.exception import PyoidcError
|
||||
from oic.exception import PyoidcError
|
||||
from oic.exception import MessageException
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MessageException(PyoidcError):
|
||||
pass
|
||||
|
||||
|
||||
class MissingRequiredAttribute(MessageException):
|
||||
def __init__(self, attr):
|
||||
Exception.__init__(self)
|
||||
|
@ -652,7 +649,8 @@ class Message(object):
|
|||
def from_jwe(self, msg, keys):
|
||||
krs = keyitems2keyreps(keys)
|
||||
jwe = JWE()
|
||||
return self.from_json(jwe.decrypt(msg, krs))
|
||||
_res = jwe.decrypt(msg, krs)
|
||||
return self.from_json(_res[0])
|
||||
|
||||
# =============================================================================
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import traceback
|
|||
import sys
|
||||
import urllib
|
||||
import urlparse
|
||||
from oic.utils.sdb import AccessCodeUsed
|
||||
|
||||
__author__ = 'rohe0002'
|
||||
|
||||
|
@ -10,11 +11,12 @@ import base64
|
|||
import logging
|
||||
import os
|
||||
|
||||
from oic.oauth2.exception import MissingParameter, URIError
|
||||
from oic.oauth2.exception import RedirectURIError
|
||||
from oic.oauth2.exception import ParameterError
|
||||
from oic.oauth2.exception import FailedAuthentication
|
||||
from oic.oauth2.exception import UnknownClient
|
||||
from oic.exception import MissingParameter
|
||||
from oic.exception import URIError
|
||||
from oic.exception import RedirectURIError
|
||||
from oic.exception import ParameterError
|
||||
from oic.exception import FailedAuthentication
|
||||
from oic.exception import UnknownClient
|
||||
|
||||
from oic.oauth2.message import AccessTokenResponse
|
||||
from oic.oauth2.message import ErrorResponse
|
||||
|
@ -28,7 +30,8 @@ from oic.oauth2.message import MissingRequiredAttribute
|
|||
from oic.oauth2.message import TokenErrorResponse
|
||||
from oic.oauth2.message import AccessTokenRequest
|
||||
|
||||
from oic.utils.http_util import BadRequest, CookieDealer
|
||||
from oic.utils.http_util import BadRequest
|
||||
from oic.utils.http_util import CookieDealer
|
||||
from oic.utils.http_util import make_cookie
|
||||
from oic.utils.http_util import Redirect
|
||||
from oic.utils.http_util import Response
|
||||
|
@ -82,7 +85,7 @@ def token_response(**kwargs):
|
|||
_areq = kwargs["areq"]
|
||||
_scode = kwargs["scode"]
|
||||
_sdb = kwargs["sdb"]
|
||||
_dic = _sdb.update_to_token(_scode, issue_refresh=False)
|
||||
_dic = _sdb.upgrade_to_token(_scode, issue_refresh=False)
|
||||
|
||||
aresp = AccessTokenResponse(**by_schema(AccessTokenResponse, **_dic))
|
||||
if "state" in _areq:
|
||||
|
@ -217,10 +220,10 @@ class Provider(object):
|
|||
def authn_reply(self, areq, aresp, bsid, **kwargs):
|
||||
"""
|
||||
|
||||
:param areq:
|
||||
:param aresp:
|
||||
:param bsid:
|
||||
:param kwargs:
|
||||
:param areq: Authorization Request
|
||||
:param aresp: Authorization Response
|
||||
:param bsid: Session id
|
||||
:param kwargs: Additional keyword args
|
||||
:return:
|
||||
"""
|
||||
if "redirect_uri" in areq:
|
||||
|
@ -253,7 +256,8 @@ class Provider(object):
|
|||
return self.response_type_map[_rtype](areq=areq, scode=scode,
|
||||
sdb=self.sdb)
|
||||
|
||||
def input(self, query="", post=None):
|
||||
@staticmethod
|
||||
def input(query="", post=None):
|
||||
# Support GET and POST
|
||||
if query:
|
||||
return query
|
||||
|
@ -262,18 +266,21 @@ class Provider(object):
|
|||
else:
|
||||
raise MissingParameter("No input")
|
||||
|
||||
def _error_response(self, error, descr=None):
|
||||
@staticmethod
|
||||
def _error_response(error, descr=None):
|
||||
logger.error("%s" % error)
|
||||
response = ErrorResponse(error=error, error_description=descr)
|
||||
return Response(response.to_json(), content="application/json",
|
||||
status="400 Bad Request")
|
||||
|
||||
def _error(self, error, descr=None):
|
||||
@staticmethod
|
||||
def _error(error, descr=None):
|
||||
response = ErrorResponse(error=error, error_description=descr)
|
||||
return Response(response.to_json(), content="application/json",
|
||||
status="400 Bad Request")
|
||||
|
||||
def _authz_error(self, error, descr=None):
|
||||
@staticmethod
|
||||
def _authz_error(error, descr=None):
|
||||
|
||||
response = AuthorizationErrorResponse(error=error)
|
||||
if descr:
|
||||
|
@ -282,7 +289,8 @@ class Provider(object):
|
|||
return Response(response.to_json(), content="application/json",
|
||||
status="400 Bad Request")
|
||||
|
||||
def _redirect_authz_error(self, error, redirect_uri, descr=None):
|
||||
@staticmethod
|
||||
def _redirect_authz_error(error, redirect_uri, descr=None):
|
||||
err = ErrorResponse(error=error)
|
||||
if descr:
|
||||
err["error_description"] = descr
|
||||
|
@ -451,26 +459,26 @@ class Provider(object):
|
|||
except KeyError:
|
||||
oidc_req = None
|
||||
|
||||
sinfo = self.sdb.create_authz_session(user, areq, oidreq=oidc_req)
|
||||
skey = self.sdb.create_authz_session(user, areq, oidreq=oidc_req)
|
||||
|
||||
# Now about the authorization step.
|
||||
try:
|
||||
permissions = self.authz.permissions(cookie)
|
||||
if not permissions:
|
||||
return self.authz(user, sinfo)
|
||||
return self.authz(user, skey)
|
||||
except (ToOld, TamperAllert):
|
||||
return self.authz(user, areq, sinfo)
|
||||
return self.authz(user, areq, skey)
|
||||
|
||||
return self.authz_part2(user, areq, sinfo, permissions, _authn)
|
||||
return self.authz_part2(user, areq, skey, permissions, _authn)
|
||||
|
||||
def authz_part2(self, user, areq, sinfo, permission=None, authn=None,
|
||||
def authz_part2(self, user, areq, skey, permission=None, authn=None,
|
||||
**kwargs):
|
||||
"""
|
||||
After the authentication this is where you should end up
|
||||
|
||||
:param user:
|
||||
:param areq: The Authorization Request
|
||||
:param sinfo: Session information
|
||||
:param skey: Session key
|
||||
:param permission: A permission specification
|
||||
:param authn: The Authentication Method used
|
||||
:param kwargs: possible other parameters
|
||||
|
@ -479,7 +487,7 @@ class Provider(object):
|
|||
_log_debug = logger.debug
|
||||
_log_debug("- in authenticated() -")
|
||||
|
||||
sinfo["auz"] = permission
|
||||
self.sdb.update(skey, "auz", permission)
|
||||
|
||||
_log_debug("response type: %s" % areq["response_type"])
|
||||
|
||||
|
@ -504,7 +512,7 @@ class Provider(object):
|
|||
except KeyError:
|
||||
pass
|
||||
|
||||
_log_debug("_dic: %s" % sinfo)
|
||||
_log_debug("_dic: %s" % self.sdb[skey])
|
||||
|
||||
rtype = set(areq["response_type"][:])
|
||||
if "code" in areq["response_type"]:
|
||||
|
@ -512,19 +520,20 @@ class Provider(object):
|
|||
# scode = self.sdb.duplicate(_sinfo)
|
||||
# _sinfo = self.sdb[scode]
|
||||
|
||||
_code = aresp["code"] = self.sdb.get_token(sinfo)
|
||||
_code = aresp["code"] = self.sdb.get_token(skey)
|
||||
rtype.remove("code")
|
||||
else:
|
||||
sinfo["code"] = None
|
||||
_code = None
|
||||
_code = self.sdb[skey]["code"]
|
||||
self.sdb.update(skey, "code", None)
|
||||
|
||||
if "token" in rtype:
|
||||
_dic = self.sdb.upgrade_to_token(sinfo, issue_refresh=False)
|
||||
|
||||
self.sdb.upgrade_to_token(skey, issue_refresh=False,
|
||||
access_grant=_code)
|
||||
atr = AccessTokenResponse(**aresp.to_dict())
|
||||
aresp = atr
|
||||
_log_debug("_dic: %s" % _dic)
|
||||
for key, val in _dic.items():
|
||||
_cont = self.sdb[skey]
|
||||
_log_debug("_dic: %s" % _cont)
|
||||
for key, val in _cont.items():
|
||||
if key in aresp.parameters() and val is not None:
|
||||
aresp[key] = val
|
||||
|
||||
|
@ -538,7 +547,7 @@ class Provider(object):
|
|||
except (RedirectURIError, ParameterError), err:
|
||||
return BadRequest("%s" % err)
|
||||
|
||||
self.sdb.store_session(sinfo)
|
||||
#self.sdb.store_session(skey)
|
||||
|
||||
# so everything went well should set a SSO cookie
|
||||
headers = [authn.create_cookie(user, typ="sso", ttl=self.sso_ttl)]
|
||||
|
@ -577,7 +586,14 @@ class Provider(object):
|
|||
|
||||
LOG_DEBUG("AccessTokenRequest: %s" % areq)
|
||||
|
||||
assert areq["grant_type"] == "authorization_code"
|
||||
try:
|
||||
assert areq["grant_type"] == "authorization_code"
|
||||
except AssertionError:
|
||||
err = TokenErrorResponse(error="invalid_request",
|
||||
error_description="Wrong grant type")
|
||||
return Response(err.to_json(), content="application/json",
|
||||
status="401 Unauthorized")
|
||||
|
||||
|
||||
# assert that the code is valid
|
||||
_info = _sdb[areq["code"]]
|
||||
|
@ -591,7 +607,14 @@ class Provider(object):
|
|||
if "redirect_uri" in _info:
|
||||
assert areq["redirect_uri"] == _info["redirect_uri"]
|
||||
|
||||
_tinfo = _sdb.update_to_token(areq["code"])
|
||||
try:
|
||||
_tinfo = _sdb.upgrade_to_token(areq["code"])
|
||||
except AccessCodeUsed:
|
||||
err = TokenErrorResponse(error="invalid_grant",
|
||||
error_description="Access grant used")
|
||||
return Response(err.to_json(), content="application/json",
|
||||
status="401 Unauthorized")
|
||||
|
||||
|
||||
LOG_DEBUG("_tinfo: %s" % _tinfo)
|
||||
|
||||
|
|
|
@ -39,7 +39,9 @@ from oic.oauth2 import HTTP_ARGS
|
|||
from oic.oauth2 import rndstr
|
||||
from oic.oauth2.consumer import ConfigurationError
|
||||
|
||||
from oic.oauth2.exception import AccessDenied, PyoidcError, MissingParameter
|
||||
from oic.exception import AccessDenied
|
||||
from oic.exception import PyoidcError
|
||||
from oic.exception import MissingParameter
|
||||
|
||||
from oic.utils import time_util
|
||||
|
||||
|
@ -904,10 +906,14 @@ class Client(oauth2.Client):
|
|||
self.behaviour[_pref] = None
|
||||
continue
|
||||
|
||||
for val in vals:
|
||||
if val in _pvals:
|
||||
self.behaviour[_pref] = val
|
||||
break
|
||||
if isinstance(vals, basestring):
|
||||
if vals in _pvals:
|
||||
self.behaviour[_pref] = vals
|
||||
else:
|
||||
for val in vals:
|
||||
if val in _pvals:
|
||||
self.behaviour[_pref] = val
|
||||
break
|
||||
|
||||
if _pref not in self.behaviour:
|
||||
raise ConfigurationError(
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
import logging
|
||||
from oic.oauth2.exception import PyoidcError
|
||||
|
||||
__author__ = 'rohe0002'
|
||||
|
||||
|
@ -9,12 +8,12 @@ import os.path
|
|||
|
||||
from hashlib import md5
|
||||
|
||||
from oic.exception import PyoidcError
|
||||
from oic.utils import http_util
|
||||
|
||||
from oic.oic import Client
|
||||
from oic.oic import ENDPOINTS
|
||||
|
||||
|
||||
from oic.oic.message import Claims, ClaimsRequest
|
||||
from oic.oic.message import AuthorizationRequest
|
||||
from oic.oic.message import AuthorizationResponse
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import time
|
||||
from urlparse import urlparse
|
||||
from oic.oauth2.exception import InvalidRequest, PyoidcError
|
||||
|
||||
__author__ = 'rohe0002'
|
||||
|
||||
|
@ -11,6 +10,8 @@ import logging
|
|||
from oic.oauth2 import message, MissingRequiredValue
|
||||
from oic.oauth2 import MissingRequiredAttribute
|
||||
from oic.oauth2 import VerificationError
|
||||
from oic.exception import InvalidRequest
|
||||
from oic.exception import PyoidcError
|
||||
from oic.oauth2.message import Message, REQUIRED_LIST_OF_SP_SEP_STRINGS
|
||||
from oic.oauth2.message import SINGLE_OPTIONAL_STRING
|
||||
from oic.oauth2.message import OPTIONAL_LIST_OF_STRINGS
|
||||
|
|
|
@ -14,7 +14,6 @@ from oic.utils.keyio import key_export
|
|||
from requests import ConnectionError
|
||||
|
||||
from oic.oauth2.message import by_schema
|
||||
from oic.oauth2.message import MessageException
|
||||
from oic.oic.message import RefreshAccessTokenRequest
|
||||
from oic.oic.message import AuthorizationRequest, Claims
|
||||
from oic.oic.message import IdToken
|
||||
|
@ -58,7 +57,7 @@ from oic.oauth2 import rndstr
|
|||
|
||||
from oic.oic import Server
|
||||
|
||||
from oic.oauth2.exception import *
|
||||
from oic.exception import *
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -106,7 +105,7 @@ def code_token_response(**kwargs):
|
|||
|
||||
aresp["code"] = _scode
|
||||
|
||||
_dic = _sdb.update_to_token(_scode, issue_refresh=False)
|
||||
_dic = _sdb.upgrade_to_token(_scode, issue_refresh=False)
|
||||
for prop in AccessTokenResponse.c_param.keys():
|
||||
try:
|
||||
aresp[prop] = _dic[prop]
|
||||
|
@ -441,13 +440,32 @@ class Provider(AProvider):
|
|||
return Response("", headers=[authn.delete_cookie()])
|
||||
|
||||
def verify_endpoint(self, request="", cookie=None, **kwargs):
|
||||
_req = urlparse.parse_qs(request)
|
||||
try:
|
||||
areq = urlparse.parse_qs(_req["query"][0])
|
||||
except KeyError:
|
||||
return BadRequest()
|
||||
"""
|
||||
|
||||
:param request:
|
||||
:param cookie:
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
logger.debug("verify request: %s" % request)
|
||||
|
||||
_req = urlparse.parse_qs(request)
|
||||
if "query" in _req:
|
||||
try:
|
||||
# TODO FIX THIS !!! Why query ?
|
||||
areq = urlparse.parse_qs(_req["query"][0])
|
||||
except KeyError:
|
||||
return BadRequest()
|
||||
else:
|
||||
areq = _req
|
||||
|
||||
logger.debug("REQ: %s" % areq)
|
||||
try:
|
||||
authn, acr = self.pick_auth(areq, "exact")
|
||||
except Exception, err:
|
||||
logger.exception("%s", err)
|
||||
raise
|
||||
|
||||
authn, acr = self.pick_auth(areq, "exact")
|
||||
kwargs["cookie"] = cookie
|
||||
return authn.verify(_req, **kwargs)
|
||||
|
||||
|
@ -665,7 +683,7 @@ class Provider(AProvider):
|
|||
_log_debug("All checks OK")
|
||||
|
||||
try:
|
||||
_tinfo = _sdb.update_to_token(_access_code)
|
||||
_tinfo = _sdb.upgrade_to_token(_access_code)
|
||||
except Exception, err:
|
||||
logger.error("%s" % err)
|
||||
# Should revoke the token issued to this access code
|
||||
|
@ -1348,7 +1366,7 @@ class Provider(AProvider):
|
|||
_code = None
|
||||
|
||||
if "token" in rtype:
|
||||
_dic = self.sdb.update_to_token(issue_refresh=False, key=sid)
|
||||
_dic = self.sdb.upgrade_to_token(issue_refresh=False, key=sid)
|
||||
|
||||
_log_debug("_dic: %s" % _dic)
|
||||
for key, val in _dic.items():
|
||||
|
|
|
@ -2,8 +2,8 @@ import logging
|
|||
from jwkest import Invalid
|
||||
from jwkest import MissingKey
|
||||
from jwkest.jws import alg2keytype
|
||||
from oic.oauth2.exception import UnknownAssertionType
|
||||
from oic.oauth2.exception import NotForMe
|
||||
from oic.exception import UnknownAssertionType
|
||||
from oic.exception import NotForMe
|
||||
from oic.oauth2 import rndstr, VREQUIRED
|
||||
from oic.oauth2 import SINGLE_OPTIONAL_STRING
|
||||
from oic.oic import REQUEST2ENDPOINT
|
||||
|
@ -61,7 +61,13 @@ class ClientSecretBasic(ClientAuthnMethod):
|
|||
Section 3.2.1 of OAuth 2.0 [RFC6749] using HTTP Basic authentication scheme.
|
||||
"""
|
||||
def construct(self, cis, request_args=None, http_args=None, **kwargs):
|
||||
# Basic HTTP Authentication
|
||||
"""
|
||||
:param cis: Request class instance
|
||||
:param request_args: Request arguments
|
||||
:param http_args: HTTP arguments
|
||||
:return: dictionary of HTTP arguments
|
||||
"""
|
||||
|
||||
if http_args is None:
|
||||
http_args = {}
|
||||
|
||||
|
@ -89,7 +95,10 @@ class ClientSecretBasic(ClientAuthnMethod):
|
|||
pass
|
||||
|
||||
if not cis.c_param["client_id"][VREQUIRED]:
|
||||
del cis["client_id"]
|
||||
try:
|
||||
del cis["client_id"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return http_args
|
||||
|
||||
|
@ -179,6 +188,20 @@ class BearerHeader(ClientAuthnMethod):
|
|||
|
||||
return http_args
|
||||
|
||||
def verify(self, environ, **kwargs):
|
||||
try:
|
||||
cred = environ["HTTP_AUTHORIZATION"]
|
||||
except KeyError:
|
||||
raise AuthnFailure("missing authorization info")
|
||||
|
||||
try:
|
||||
assert cred.startswith("Bearer ")
|
||||
except AssertionError:
|
||||
raise AuthnFailure("Wrong type of authorization token")
|
||||
|
||||
label, token = cred.split(" ")
|
||||
return token
|
||||
|
||||
|
||||
class BearerBody(ClientAuthnMethod):
|
||||
def construct(self, cis, request_args=None, http_args=None, **kwargs):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from oic.oauth2 import rndstr
|
||||
from oic.oauth2.exception import UnsupportedMethod
|
||||
from oic.exception import UnsupportedMethod
|
||||
from oic.utils.aes import encrypt
|
||||
from oic.utils.aes import decrypt
|
||||
|
||||
|
@ -58,6 +58,18 @@ class Created(Response):
|
|||
_status = "201 Created"
|
||||
|
||||
|
||||
class Accepted(Response):
|
||||
_status = "202 Accepted"
|
||||
|
||||
|
||||
class NonAuthoritativeInformation(Response):
|
||||
_status = "203 Non Authoritative Information"
|
||||
|
||||
|
||||
class NoContent(Response):
|
||||
_status = "204 No Content"
|
||||
|
||||
|
||||
class Redirect(Response):
|
||||
_template = '<html>\n<head><title>Redirecting to %s</title></head>\n' \
|
||||
'<body>\nYou are being redirected to <a href="%s">%s</a>\n' \
|
||||
|
@ -103,6 +115,10 @@ class NotFound(Response):
|
|||
_status = '404 NOT FOUND'
|
||||
|
||||
|
||||
class NotSupported(Response):
|
||||
_status = '405 Not Support'
|
||||
|
||||
|
||||
class NotAcceptable(Response):
|
||||
_status = '406 Not Acceptable'
|
||||
|
||||
|
@ -118,19 +134,23 @@ class InvalidCookieSign(Exception):
|
|||
R2C = {
|
||||
200: Response,
|
||||
201: Created,
|
||||
202: Accepted,
|
||||
203: NonAuthoritativeInformation,
|
||||
204: NoContent,
|
||||
302: Redirect,
|
||||
303: SeeOther,
|
||||
400: BadRequest,
|
||||
401: Unauthorized,
|
||||
403: Forbidden,
|
||||
404: NotFound,
|
||||
405: NotSupported,
|
||||
406: NotAcceptable,
|
||||
500: ServiceError,
|
||||
}
|
||||
|
||||
|
||||
def factory(code, message):
|
||||
return R2C[code](message)
|
||||
def factory(code, message, **kwargs):
|
||||
return R2C[code](message, **kwargs)
|
||||
|
||||
|
||||
def extract(environ, empty=False, err=False):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import json
|
||||
import time
|
||||
from Crypto.PublicKey import RSA
|
||||
from oic.exception import MessageException
|
||||
|
||||
__author__ = 'rohe0002'
|
||||
|
||||
|
@ -489,7 +490,11 @@ class KeyJar(object):
|
|||
"""
|
||||
|
||||
logger.debug("loading keys for issuer: %s" % issuer)
|
||||
logger.debug("pcr: %s" % pcr)
|
||||
try:
|
||||
logger.debug("pcr: %s" % pcr)
|
||||
except MessageException:
|
||||
pass
|
||||
|
||||
if issuer not in self.issuer_keys:
|
||||
self.issuer_keys[issuer] = []
|
||||
elif replace:
|
||||
|
|
|
@ -26,6 +26,10 @@ class WrongTokenType(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class AccessCodeUsed(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def pairwise_id(sub, sector_identifier, seed):
|
||||
return hashlib.sha256("%s%s%s" % (sub, sector_identifier, seed)).hexdigest()
|
||||
|
||||
|
@ -245,8 +249,14 @@ class SessionDB(object):
|
|||
self.uid2sid[sub] = sid
|
||||
return sid
|
||||
|
||||
def update_to_token(self, token=None, issue_refresh=True, id_token="",
|
||||
oidreq=None, key=None):
|
||||
def get_token(self, key):
|
||||
if self._db[key]["oauth_state"] == "authz":
|
||||
return self._db[key]["code"]
|
||||
elif self._db[key]["oauth_state"] == "token":
|
||||
return self._db[key]["access_token"]
|
||||
|
||||
def upgrade_to_token(self, token=None, issue_refresh=True, id_token="",
|
||||
oidreq=None, key=None, access_grant=""):
|
||||
"""
|
||||
|
||||
:param token: The access grant
|
||||
|
@ -257,7 +267,11 @@ class SessionDB(object):
|
|||
:return: The session information as a dictionary
|
||||
"""
|
||||
if token:
|
||||
(typ, key) = self.token.type_and_key(token)
|
||||
try:
|
||||
(typ, key) = self.token.type_and_key(token)
|
||||
except (ValueError, TypeError):
|
||||
(typ, key) = self.token.type_and_key(access_grant)
|
||||
token = access_grant
|
||||
|
||||
if typ != "A": # not a access grant
|
||||
raise WrongTokenType("Not a grant token")
|
||||
|
@ -265,7 +279,7 @@ class SessionDB(object):
|
|||
dic = self._db[key]
|
||||
|
||||
if dic["code_used"]:
|
||||
raise Exception("Access code already used!!")
|
||||
raise AccessCodeUsed()
|
||||
_at = self.token("T", token)
|
||||
dic["code_used"] = True
|
||||
else:
|
||||
|
|
|
@ -54,34 +54,6 @@ class StateLess(object):
|
|||
#return _cont.to_jwe(self.keys, self.enc, self.alg)
|
||||
return _cont
|
||||
|
||||
#def update_to_token(self, token=None, issue_refresh=True, **kwargs):
|
||||
# """
|
||||
#
|
||||
# :param token: The access grant
|
||||
# :param issue_refresh: If a refresh token should be issued
|
||||
# :return: A new token
|
||||
# """
|
||||
# if token in self.used_grants:
|
||||
# raise Exception("Grant already used")
|
||||
#
|
||||
# _cont = Content().from_jwe(token, self.keys)
|
||||
#
|
||||
# try:
|
||||
# assert _cont["typ"] == "code"
|
||||
# except AssertionError:
|
||||
# raise Exception("Not a access grant")
|
||||
#
|
||||
# self.used_grants.append(token)
|
||||
#
|
||||
# _cont["typ"] = "access"
|
||||
# _cont["val"] = epoch_in_a_while(self.validity["access"])
|
||||
# if issue_refresh:
|
||||
# _c = Content(sub=_cont["sub"], aud=_cont["aud"], typ="refresh",
|
||||
# val=epoch_in_a_while(self.validity["refresh"]))
|
||||
# _cont["ref"] = _c.to_jwe(self.keys, self.enc, self.alg)
|
||||
#
|
||||
# return _cont.to_jwe(self.keys, self.enc, self.alg)
|
||||
|
||||
def upgrade_to_token(self, cont, issue_refresh=False):
|
||||
cont["typ"] = "access"
|
||||
cont["val"] = epoch_in_a_while(self.validity["access"])
|
||||
|
|
|
@ -62,7 +62,7 @@ class MyFakeOAuth2Server(Server):
|
|||
if "code" in req["response_type"]:
|
||||
if "token" in req["response_type"]:
|
||||
grant = _info["code"]
|
||||
_dict = self.sdb.update_to_token(grant)
|
||||
_dict = self.sdb.upgrade_to_token(grant)
|
||||
_dict["oauth_state"]="authz",
|
||||
|
||||
_dict = by_schema(AuthorizationResponse(), **_dict)
|
||||
|
@ -77,7 +77,7 @@ class MyFakeOAuth2Server(Server):
|
|||
params = AccessTokenResponse.c_param.keys()
|
||||
|
||||
_dict = dict([(k,v) for k,
|
||||
v in self.sdb.update_to_token(grant).items() if k in
|
||||
v in self.sdb.upgrade_to_token(grant).items() if k in
|
||||
params])
|
||||
try:
|
||||
del _dict["refresh_token"]
|
||||
|
|
|
@ -103,7 +103,7 @@ class MyFakeOICServer(Server):
|
|||
if "code" in req["response_type"]:
|
||||
if "token" in req["response_type"]:
|
||||
grant = _info["code"]
|
||||
_dict = self.sdb.update_to_token(grant)
|
||||
_dict = self.sdb.upgrade_to_token(grant)
|
||||
_dict["oauth_state"] = "authz",
|
||||
|
||||
_dict = by_schema(AuthorizationResponse(), **_dict)
|
||||
|
@ -118,7 +118,7 @@ class MyFakeOICServer(Server):
|
|||
params = AccessTokenResponse.c_param.keys()
|
||||
|
||||
_dict = dict([(k, v) for k, v in
|
||||
self.sdb.update_to_token(grant).items() if k in
|
||||
self.sdb.upgrade_to_token(grant).items() if k in
|
||||
params])
|
||||
try:
|
||||
del _dict["refresh_token"]
|
||||
|
@ -148,7 +148,7 @@ class MyFakeOICServer(Server):
|
|||
_info = self.sdb.refresh_token(req["refresh_token"])
|
||||
elif "grant_type=authorization_code":
|
||||
req = self.parse_token_request(body=data)
|
||||
_info = self.sdb.update_to_token(req["code"])
|
||||
_info = self.sdb.upgrade_to_token(req["code"])
|
||||
else:
|
||||
response = TokenErrorResponse(error="unsupported_grant_type")
|
||||
return response, ""
|
||||
|
@ -179,7 +179,10 @@ class MyFakeOICServer(Server):
|
|||
return response
|
||||
|
||||
def registration_endpoint(self, data):
|
||||
req = self.parse_registration_request(data)
|
||||
try:
|
||||
req = self.parse_registration_request(data, "json")
|
||||
except ValueError:
|
||||
req = self.parse_registration_request(data)
|
||||
|
||||
client_secret = rndstr()
|
||||
expires = utc_time_sans_frac() + self.registration_expires_in
|
||||
|
|
|
@ -959,4 +959,4 @@ def test_bearer_body_get_token():
|
|||
assert cis["access_token"] == "token1"
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_server_parse_jwt_request()
|
||||
test_client_secret_basic()
|
|
@ -1,10 +1,9 @@
|
|||
from mako.lookup import TemplateLookup
|
||||
from mako.runtime import UNDEFINED
|
||||
from oic.oauth2 import rndstr
|
||||
from oic.utils.authn.authn_context import AuthnBroker
|
||||
from oic.utils.authn.client import verify_client
|
||||
from oic.utils.authn.user import UserAuthnMethod
|
||||
from oic.utils.authz import AuthzHandling, Implicit
|
||||
from oic.utils.authz import Implicit
|
||||
from oic.utils.http_util import Response
|
||||
|
||||
from oic.oauth2.message import AuthorizationRequest
|
||||
|
@ -270,4 +269,4 @@ def test_token_endpoint_unauth():
|
|||
assert _eq(atr.keys(), ['error_description', 'error'])
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_provider_authenticated()
|
||||
test_provider_authenticated_token()
|
|
@ -548,6 +548,7 @@ def test_client_register():
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
t = TestOICConsumer()
|
||||
t.setup_class()
|
||||
t.test_begin()
|
||||
#t = TestOICConsumer()
|
||||
#t.setup_class()
|
||||
#t.test_begin()
|
||||
test_client_register()
|
|
@ -6,7 +6,7 @@ from oic.utils.authn.user import UserAuthnMethod
|
|||
from oic.utils.authz import AuthzHandling
|
||||
from oic.utils.userinfo import UserInfo
|
||||
|
||||
from oic.oauth2.exception import RedirectURIError
|
||||
from oic.exception import RedirectURIError
|
||||
|
||||
from oic.utils.keyio import KeyBundle
|
||||
from oic.utils.keyio import KeyJar
|
||||
|
@ -680,4 +680,4 @@ def test_registered_redirect_uri_with_query_component():
|
|||
assert resp is None
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_userinfo_endpoint()
|
||||
test_token_endpoint()
|
|
@ -166,11 +166,11 @@ def test_create_authz_session_with_sector_id():
|
|||
assert info_2["sub"] != user_id1
|
||||
|
||||
|
||||
def test_update_to_token():
|
||||
def test_upgrade_to_token():
|
||||
sdb = SessionDB()
|
||||
sid = sdb.create_authz_session("user_id", AREQ)
|
||||
grant = sdb[sid]["code"]
|
||||
_dict = sdb.update_to_token(grant)
|
||||
_dict = sdb.upgrade_to_token(grant)
|
||||
|
||||
print _dict.keys()
|
||||
assert _eq(_dict.keys(), ['code', 'authzreq', 'token_type', 'local_sub',
|
||||
|
@ -180,15 +180,15 @@ def test_update_to_token():
|
|||
'redirect_uri', 'code_used', 'scope',
|
||||
'access_token_scope'])
|
||||
|
||||
raises(Exception, 'sdb.update_to_token(grant)')
|
||||
raises(Exception, 'sdb.upgrade_to_token(grant)')
|
||||
|
||||
raises(Exception, 'sdb.update_to_token(_dict["access_token"]')
|
||||
raises(Exception, 'sdb.upgrade_to_token(_dict["access_token"]')
|
||||
|
||||
sdb = SessionDB()
|
||||
sid = sdb.create_authz_session("another_user_id", AREQ)
|
||||
grant = sdb[sid]["code"]
|
||||
|
||||
_dict = sdb.update_to_token(grant, id_token="id_token", oidreq=OIDR)
|
||||
_dict = sdb.upgrade_to_token(grant, id_token="id_token", oidreq=OIDR)
|
||||
print _dict.keys()
|
||||
assert _eq(_dict.keys(), ['code', 'authzreq', 'id_token', 'token_type',
|
||||
'local_sub', 'client_id', 'oauth_state',
|
||||
|
@ -200,14 +200,14 @@ def test_update_to_token():
|
|||
assert _dict["id_token"] == "id_token"
|
||||
assert _dict["oidreq"].type() == "OpenIDRequest"
|
||||
_ = _dict["access_token"]
|
||||
raises(Exception, 'sdb.update_to_token(token)')
|
||||
raises(Exception, 'sdb.upgrade_to_token(token)')
|
||||
|
||||
|
||||
def test_refresh_token():
|
||||
sdb = SessionDB()
|
||||
sid = sdb.create_authz_session("user_id", AREQ)
|
||||
grant = sdb[sid]["code"]
|
||||
_dict = sdb.update_to_token(grant)
|
||||
_dict = sdb.upgrade_to_token(grant)
|
||||
dict1 = _dict.copy()
|
||||
|
||||
rtoken = _dict["refresh_token"]
|
||||
|
@ -228,7 +228,7 @@ def test_is_valid():
|
|||
|
||||
assert sdb.is_valid(grant)
|
||||
|
||||
_dict = sdb.update_to_token(grant)
|
||||
_dict = sdb.upgrade_to_token(grant)
|
||||
assert sdb.is_valid(grant) is False
|
||||
token1 = _dict["access_token"]
|
||||
assert sdb.is_valid(token1)
|
||||
|
@ -268,7 +268,7 @@ def test_revoke_token():
|
|||
sid = sdb.create_authz_session("user_id", AREQ)
|
||||
|
||||
grant = sdb[sid]["code"]
|
||||
_dict = sdb.update_to_token(grant)
|
||||
_dict = sdb.upgrade_to_token(grant)
|
||||
|
||||
token = _dict["access_token"]
|
||||
rtoken = _dict["refresh_token"]
|
||||
|
|
|
@ -12,7 +12,7 @@ def test_access_code():
|
|||
st = StateLess(keys, enc_alg="A128KW", enc_method="A128CBC-HS256")
|
||||
con = st.create_authz_session("subject",
|
||||
{"redirect_uri": "https://example.com"})
|
||||
tok = st.encrypt(con)
|
||||
tok = st.get_token(con)
|
||||
|
||||
_info = st[tok]
|
||||
print _info
|
||||
|
|
|
@ -0,0 +1,324 @@
|
|||
from mako.lookup import TemplateLookup
|
||||
from oic.utils.http_util import Response, NoContent, Unauthorized
|
||||
from oic.utils.authn.authn_context import AuthnBroker
|
||||
from oic.utils.authn.client import verify_client
|
||||
from oic.utils.authn.client import BearerHeader
|
||||
from oic.utils.authn.client import ClientSecretPost
|
||||
from oic.utils.authn.client import ClientSecretBasic
|
||||
from oic.utils.authn.user import UserAuthnMethod
|
||||
from oic.utils.authz import Implicit
|
||||
|
||||
from oic.utils import sdb
|
||||
from oic.oauth2.dynreg import Provider
|
||||
from oic.oauth2.dynreg import RegistrationRequest
|
||||
from oic.oauth2.dynreg import ClientInfoResponse
|
||||
from oic.oauth2.dynreg import ClientRegistrationError
|
||||
|
||||
CLIENT_CONFIG = {
|
||||
"client_id": "client1",
|
||||
"ca_certs": "/usr/local/etc/oic/ca_certs.txt",
|
||||
}
|
||||
|
||||
CONSUMER_CONFIG = {
|
||||
"authz_page": "/authz",
|
||||
"flow_type": "code",
|
||||
#"password": args.passwd,
|
||||
"scope": [],
|
||||
"response_type": "code",
|
||||
#"expire_in": 600,
|
||||
}
|
||||
|
||||
SERVER_INFO = {
|
||||
"version": "3.0",
|
||||
"issuer": "https://connect-op.heroku.com",
|
||||
"authorization_endpoint": "http://localhost:8088/authorization",
|
||||
"token_endpoint": "http://localhost:8088/token",
|
||||
#"userinfo_endpoint":"http://localhost:8088/user_info",
|
||||
#"check_id_endpoint":"http://localhost:8088/id_token",
|
||||
#"registration_endpoint":"https://connect-op.heroku.com/connect/client",
|
||||
#"scopes_supported":["openid","profile","email","address","PPID"],
|
||||
"flows_supported": ["code", "token", "code token"],
|
||||
#"identifiers_supported":["public","ppid"],
|
||||
#"x509_url":"https://connect-op.heroku.com/cert.pem"
|
||||
}
|
||||
|
||||
CDB = {
|
||||
"a1b2c3": {
|
||||
"password": "hemligt",
|
||||
"client_secret": "drickyoughurt"
|
||||
},
|
||||
"client1": {
|
||||
"client_secret": "hemlighet",
|
||||
"redirect_uris": [("http://localhost:8087/authz", None)]
|
||||
}
|
||||
}
|
||||
|
||||
PASSWD = {"user": "password"}
|
||||
|
||||
ROOT = '../oc3/'
|
||||
tl = TemplateLookup(directories=[ROOT + 'templates', ROOT + 'htdocs'],
|
||||
module_directory=ROOT + 'modules',
|
||||
input_encoding='utf-8', output_encoding='utf-8')
|
||||
|
||||
|
||||
class DummyAuthn(UserAuthnMethod):
|
||||
def __init__(self, srv, user):
|
||||
UserAuthnMethod.__init__(self, srv)
|
||||
self.user = user
|
||||
|
||||
def authenticated_as(self, cookie=None, **kwargs):
|
||||
return {"uid": self.user}
|
||||
|
||||
|
||||
AUTHN_BROKER = AuthnBroker()
|
||||
AUTHN_BROKER.add("UNDEFINED", DummyAuthn(None, "username"))
|
||||
|
||||
# dealing with authorization
|
||||
AUTHZ = Implicit()
|
||||
|
||||
|
||||
def content_type(headers):
|
||||
for key, val in headers:
|
||||
if key == "Content-type":
|
||||
if val == "application/json":
|
||||
return "json"
|
||||
|
||||
|
||||
def _eq(l1, l2):
|
||||
return set(l1) == set(l2)
|
||||
|
||||
|
||||
def test_provider_init():
|
||||
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
|
||||
verify_client, client_info_url="https://example.com/as")
|
||||
|
||||
assert provider
|
||||
|
||||
|
||||
def test_client_registration():
|
||||
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
|
||||
verify_client,
|
||||
client_info_url="https://example.com/as/")
|
||||
|
||||
request = RegistrationRequest(client_name="myself",
|
||||
redirect_uris=["https://example.com/rp"])
|
||||
|
||||
resp = provider.registration_endpoint(request.to_json(), {})
|
||||
|
||||
assert isinstance(resp, Response)
|
||||
|
||||
_resp = ClientInfoResponse().from_json(resp.message)
|
||||
|
||||
assert "client_id" in _resp
|
||||
|
||||
|
||||
def test_client_registration_uri_error():
|
||||
args = {
|
||||
"redirect_uris": ["https://client.example.org/callback",
|
||||
"https://client.example.org/callback2"],
|
||||
"client_name": "My Example Client",
|
||||
"client_name#ja-Jpan-JP":
|
||||
"\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u540D",
|
||||
"token_endpoint_auth_method": "client_secret_basic",
|
||||
"scope": "read write dolphin",
|
||||
"logo_uri": "https://client.example.org/logo.png",
|
||||
"jwks_uri": "https://client.example.org/my_public_keys.jwks"
|
||||
}
|
||||
|
||||
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
|
||||
verify_client,
|
||||
client_info_url="https://example.com/as/")
|
||||
|
||||
request = RegistrationRequest(**args)
|
||||
|
||||
resp = provider.registration_endpoint(request.to_json(), {})
|
||||
|
||||
assert isinstance(resp, Response)
|
||||
|
||||
_resp = ClientRegistrationError().from_json(resp.message)
|
||||
|
||||
assert "error" in _resp
|
||||
assert _resp["error"] == "invalid_client_metadata"
|
||||
|
||||
|
||||
def test_client_registration_2():
|
||||
args = {
|
||||
"redirect_uris": ["https://client.example.org/callback",
|
||||
"https://client.example.org/callback2"],
|
||||
"client_name": "My Example Client",
|
||||
"client_name#ja-Jpan-JP":
|
||||
"\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u540D",
|
||||
"token_endpoint_auth_method": "client_secret_basic",
|
||||
"scope": "read write dolphin",
|
||||
}
|
||||
|
||||
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
|
||||
verify_client,
|
||||
client_info_url="https://example.com/as/",
|
||||
client_authn_methods={
|
||||
"client_secret_post": ClientSecretPost,
|
||||
"client_secret_basic": ClientSecretBasic,
|
||||
"bearer_header": BearerHeader})
|
||||
|
||||
request = RegistrationRequest(**args)
|
||||
|
||||
resp = provider.registration_endpoint(request.to_json(), {})
|
||||
|
||||
assert isinstance(resp, Response)
|
||||
|
||||
_resp = ClientInfoResponse().from_json(resp.message)
|
||||
|
||||
assert "client_name#ja-Jpan-JP" in _resp.keys()
|
||||
assert "client_name" in _resp.keys()
|
||||
|
||||
|
||||
def test_client_user_info_get():
|
||||
args = {
|
||||
"redirect_uris": ["https://client.example.org/callback",
|
||||
"https://client.example.org/callback2"],
|
||||
"client_name": "My Example Client",
|
||||
"client_name#ja-Jpan-JP":
|
||||
"\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u540D",
|
||||
"token_endpoint_auth_method": "client_secret_basic",
|
||||
"scope": "read write dolphin",
|
||||
}
|
||||
|
||||
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
|
||||
verify_client,
|
||||
client_info_url="https://example.com/as/",
|
||||
client_authn_methods={
|
||||
"client_secret_post": ClientSecretPost,
|
||||
"client_secret_basic": ClientSecretBasic,
|
||||
"bearer_header": BearerHeader})
|
||||
|
||||
request = RegistrationRequest(**args)
|
||||
|
||||
resp = provider.registration_endpoint(request.to_json(),
|
||||
environ={})
|
||||
|
||||
assert isinstance(resp, Response)
|
||||
|
||||
_resp = ClientInfoResponse().from_json(resp.message)
|
||||
|
||||
assert "client_name#ja-Jpan-JP" in _resp.keys()
|
||||
assert "client_name" in _resp.keys()
|
||||
|
||||
resp = provider.client_info_endpoint(
|
||||
"",
|
||||
environ={"HTTP_AUTHORIZATION": "Bearer %s" % (
|
||||
_resp["registration_access_token"],)},
|
||||
query="client_id=%s" % _resp["client_id"])
|
||||
|
||||
_resp_cir = ClientInfoResponse().from_json(resp.message)
|
||||
|
||||
assert _resp == _resp_cir
|
||||
|
||||
|
||||
def test_client_registration_update():
|
||||
args = {
|
||||
"redirect_uris": ["https://client.example.org/callback",
|
||||
"https://client.example.org/callback2"],
|
||||
"client_name": "My Example Client",
|
||||
"client_name#ja-Jpan-JP":
|
||||
"\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u540D",
|
||||
"token_endpoint_auth_method": "client_secret_basic",
|
||||
"scope": "read write dolphin",
|
||||
}
|
||||
|
||||
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
|
||||
verify_client,
|
||||
client_info_url="https://example.com/as/",
|
||||
client_authn_methods={
|
||||
"client_secret_post": ClientSecretPost,
|
||||
"client_secret_basic": ClientSecretBasic,
|
||||
"bearer_header": BearerHeader})
|
||||
|
||||
request = RegistrationRequest(**args)
|
||||
|
||||
resp = provider.registration_endpoint(request.to_json(),
|
||||
environ={})
|
||||
|
||||
assert isinstance(resp, Response)
|
||||
|
||||
_resp = ClientInfoResponse().from_json(resp.message)
|
||||
|
||||
assert "client_name#ja-Jpan-JP" in _resp.keys()
|
||||
assert "client_name" in _resp.keys()
|
||||
|
||||
update = {
|
||||
"client_id": _resp["client_id"],
|
||||
"client_secret": _resp["client_secret"],
|
||||
"redirect_uris": ["https://client.example.org/callback",
|
||||
"https://client.example.org/alt"],
|
||||
"scope": "read write dolphin",
|
||||
"grant_types": ["authorization_code", "refresh_token"],
|
||||
"token_endpoint_auth_method": "client_secret_basic",
|
||||
"jwks_uri": "https://client.example.org/my_public_keys.jwks",
|
||||
"client_name": "My New Example",
|
||||
"client_name#fr": "Mon Nouvel Exemple",
|
||||
}
|
||||
|
||||
update_req = RegistrationRequest(**update)
|
||||
|
||||
resp = provider.client_info_endpoint(
|
||||
update_req.to_json(),
|
||||
environ={"HTTP_AUTHORIZATION": "Bearer %s" % (
|
||||
_resp["registration_access_token"],)},
|
||||
method="PUT",
|
||||
query="client_id=%s" % _resp["client_id"])
|
||||
|
||||
_resp_up = ClientInfoResponse().from_json(resp.message)
|
||||
|
||||
print _resp_up
|
||||
|
||||
|
||||
def test_client_registration_delete():
|
||||
args = {
|
||||
"redirect_uris": ["https://client.example.org/callback",
|
||||
"https://client.example.org/callback2"],
|
||||
"client_name": "My Example Client",
|
||||
"client_name#ja-Jpan-JP":
|
||||
"\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u540D",
|
||||
"token_endpoint_auth_method": "client_secret_basic",
|
||||
"scope": "read write dolphin",
|
||||
}
|
||||
|
||||
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
|
||||
verify_client,
|
||||
client_info_url="https://example.com/as/",
|
||||
client_authn_methods={
|
||||
"client_secret_post": ClientSecretPost,
|
||||
"client_secret_basic": ClientSecretBasic,
|
||||
"bearer_header": BearerHeader})
|
||||
|
||||
request = RegistrationRequest(**args)
|
||||
|
||||
resp = provider.registration_endpoint(request.to_json(),
|
||||
environ={})
|
||||
|
||||
assert isinstance(resp, Response)
|
||||
|
||||
_resp = ClientInfoResponse().from_json(resp.message)
|
||||
|
||||
resp = provider.client_info_endpoint(
|
||||
"",
|
||||
environ={"HTTP_AUTHORIZATION": "Bearer %s" % (
|
||||
_resp["registration_access_token"],)},
|
||||
method="DELETE",
|
||||
query="client_id=%s" % _resp["client_id"])
|
||||
|
||||
assert isinstance(resp, NoContent)
|
||||
|
||||
# A read should fail
|
||||
|
||||
resp = provider.client_info_endpoint(
|
||||
"",
|
||||
environ={"HTTP_AUTHORIZATION": "Bearer %s" % (
|
||||
_resp["registration_access_token"],)},
|
||||
query="client_id=%s" % _resp["client_id"])
|
||||
|
||||
assert isinstance(resp, Unauthorized)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
test_client_registration_delete()
|
Reference in New Issue