From d7861ec0db438a1548222e45411c32165bc012c8 Mon Sep 17 00:00:00 2001 From: Roland Hedberg Date: Thu, 6 Nov 2014 12:17:11 +0100 Subject: [PATCH 1/8] Ensure variable is defined Fix proposed by J.Maennel --- oidc_example/op2/server.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/oidc_example/op2/server.py b/oidc_example/op2/server.py index 1544836..dd2d4aa 100755 --- a/oidc_example/op2/server.py +++ b/oidc_example/op2/server.py @@ -398,6 +398,12 @@ if __name__ == '__main__': PASSWORD_END_POINT_INDEX) URLS.append((r'^' + end_point, make_auth_verify(authn.verify))) + # Ensure javascript_login_authn to be defined + try: + javascript_login_authn + except NameError: + javascript_login_authn = None + if "JavascriptLogin" == authkey: if not javascript_login_authn: end_points = config.AUTHENTICATION[ From 71e47d7fad2e540599079eacdb0d738b6715365d Mon Sep 17 00:00:00 2001 From: Roland Hedberg Date: Thu, 6 Nov 2014 12:18:28 +0100 Subject: [PATCH 2/8] Ensure variable is defined. Added ACR values to logout url Fix proposed by J.Maennel --- oidc_example/rp3/rp.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/oidc_example/rp3/rp.py b/oidc_example/rp3/rp.py index f549c7d..04de53d 100755 --- a/oidc_example/rp3/rp.py +++ b/oidc_example/rp3/rp.py @@ -161,7 +161,12 @@ def application(environ, start_response): logout_url += "&" + urllib.urlencode({ "id_token_hint": id_token_as_signed_jwt(client, _idtoken, "HS256")}) + # Also append the ACR values + logout_url += "&" + urllib.urlencode({"acr_values": ACR_VALUES}, + True) + LOGGER.debug("Logout URL: %s" % str(logout_url)) + LOGGER.debug("Logging out from session: %s" % str(session)) clear_session(session) resp = Redirect(str(logout_url)) return resp(environ, start_response) From f3a5066cffc88d197c3e6ae749c0198856ceb8bf Mon Sep 17 00:00:00 2001 From: Roland Hedberg Date: Thu, 6 Nov 2014 12:20:10 +0100 Subject: [PATCH 3/8] Interesting to know which HTTP method that failed. --- src/oic/oauth2/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/oic/oauth2/__init__.py b/src/oic/oauth2/__init__.py index 3747b48..9f17737 100644 --- a/src/oic/oauth2/__init__.py +++ b/src/oic/oauth2/__init__.py @@ -371,8 +371,9 @@ class PBase(object): try: r = requests.request(method, url, **_kwargs) except Exception as err: - logger.error("http_request failed: %s, url: %s, htargs: %s" % ( - err, url, _kwargs)) + logger.error( + "http_request failed: %s, url: %s, htargs: %s, method: %s" % ( + err, url, _kwargs, method)) raise try: From f768bf7cabb679759a88c88641a95963c1524406 Mon Sep 17 00:00:00 2001 From: Roland Hedberg Date: Thu, 6 Nov 2014 12:21:23 +0100 Subject: [PATCH 4/8] Refactored. Added support for encrypting request JWT. --- src/oic/oic/__init__.py | 51 +++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/src/oic/oic/__init__.py b/src/oic/oic/__init__.py index af1fc43..5cd22ce 100644 --- a/src/oic/oic/__init__.py +++ b/src/oic/oic/__init__.py @@ -1,3 +1,4 @@ +from jwkest.jwe import JWE from oic.utils.keyio import KeyJar __author__ = 'rohe0002' @@ -50,7 +51,8 @@ from oic.utils.webfinger import OIC_ISSUER from oic.utils.webfinger import WebFinger from jwkest import jws -from jwkest.jws import alg2keytype, JWS +from jwkest import jwe +from jwkest.jws import JWS logger = logging.getLogger(__name__) @@ -302,6 +304,32 @@ class Client(oauth2.Client): return None + def request_object_encryption(self, msg, **kwargs): + try: + encalg = self.behaviour["request_object_encryption_alg"] + except KeyError: + return msg + else: + encenc = self.behaviour["request_object_encryption_enc"] + _jwe = JWE(msg, alg=encalg, enc=encenc) + _kty = jwe.alg2keytype(encalg) + + try: + _kid = kwargs["enc_kid"] + except KeyError: + try: + _kid = self.kid["enc"][_kty] + except KeyError: + _kid = "" + + if _kid: + _jwe["keys"] = self.keyjar.get_encrypt_key(_kty, kid=_kid) + _jwe["kid"] = _kid + else: + _jwe["keys"] = self.keyjar.get_signing_key(_kty) + + return _jwe.encrypt(self.keyjar) + def construct_AuthorizationRequest(self, request=AuthorizationRequest, request_args=None, extra_args=None, request_param=None, **kwargs): @@ -323,7 +351,9 @@ class Client(oauth2.Client): if "request_method" in kwargs: if kwargs["request_method"] == "file": request_param = "request_uri" - del kwargs["request_method"] + else: + request_param = "request" + del kwargs["request_method"] areq = oauth2.Client.construct_AuthorizationRequest(self, request, request_args, @@ -331,12 +361,16 @@ class Client(oauth2.Client): **kwargs) if request_param: - alg = self.behaviour["request_object_signing_alg"] - if "algorithm" not in kwargs: - kwargs["algorithm"] = alg + try: + alg = self.behaviour["request_object_signing_alg"] + except KeyError: + alg = None + else: + if "algorithm" not in kwargs: + kwargs["algorithm"] = alg if "keys" not in kwargs and alg: - _kty = alg2keytype(alg) + _kty = jws.alg2keytype(alg) try: kwargs["keys"] = self.keyjar.get_signing_key( _kty, kid=self.kid["sig"][_kty]) @@ -345,6 +379,9 @@ class Client(oauth2.Client): _req = make_openid_request(areq, **kwargs) + # Should the request be encrypted + _req = self.request_object_encryption(_req, **kwargs) + if request_param == "request": areq["request"] = _req else: @@ -711,7 +748,7 @@ class Client(oauth2.Client): return _schema().from_json(txt=resp.text) else: algo = self.client_prefs["userinfo_signed_response_alg"] - _kty = alg2keytype(algo) + _kty = jws.alg2keytype(algo) # Keys of the OP ? try: keys = self.keyjar.get_signing_key(_kty, self.kid["sig"][_kty]) From f6dc157eff7d8075a649284ce571eff6dbe783c2 Mon Sep 17 00:00:00 2001 From: Roland Hedberg Date: Thu, 6 Nov 2014 12:23:07 +0100 Subject: [PATCH 5/8] Class variable should be defined in __init__ --- src/oic/oic/consumer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/oic/oic/consumer.py b/src/oic/oic/consumer.py index eca1acf..954f758 100644 --- a/src/oic/oic/consumer.py +++ b/src/oic/oic/consumer.py @@ -158,6 +158,7 @@ class Consumer(Client): self.seed = "" self.nonce = "" self.request_filename = "" + self.request_uri = "" self.user_info = None self.registration_expires_at = 0 self.secret_type = "Bearer" From 6ed39b6e9c437ee76fd5bd9b89cbe7b097b3d5d3 Mon Sep 17 00:00:00 2001 From: Roland Hedberg Date: Thu, 6 Nov 2014 12:24:26 +0100 Subject: [PATCH 6/8] Logout acr support, more debug logging. Proposed by M. Jeckelmann --- src/oic/oic/provider.py | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/oic/oic/provider.py b/src/oic/oic/provider.py index 6263e0e..2e52870 100644 --- a/src/oic/oic/provider.py +++ b/src/oic/oic/provider.py @@ -403,13 +403,20 @@ class Provider(AProvider): if not comparision_type: comparision_type = "exact" + if not isinstance(areq["acr_values"], list): + areq["acr_values"] = [areq["acr_values"]] + for acr in areq["acr_values"]: res = self.authn_broker.pick(acr, comparision_type) + logger.debug("Picked AuthN broker for ACR %s: %s" % ( + str(acr), str(res))) if res: #Return the best guess by pick. return res[0] - except KeyError: - pass + except KeyError as exc: + logger.debug( + "An error occured while picking the authN broker: %s" % str( + exc)) # return the best I have return None, None @@ -422,8 +429,10 @@ class Provider(AProvider): client_info = self.cdb[self.sdb.getClient_id(uid)] if redirect_uri in client_info["post_logout_redirect_uris"]: return redirect_uri - except: - pass + except Exception as exc: + logger.debug( + "An error occurred while verifying redir URI: %s" % str(exc)) + return None def is_session_revoked(self, request="", cookie=None): @@ -460,7 +469,8 @@ class Provider(AProvider): esr = EndSessionRequest().from_urlencoded(request) redirect_uri = self.verify_post_logout_redirect_uri(esr, cookie) if not redirect_uri: - return self._error_response("Not allowed!") + return self._error_response( + "Not allowed (Post logout redirect URI verification failed)!") authn, acr = self.pick_auth(esr) @@ -474,7 +484,8 @@ class Provider(AProvider): try: uid = identity["uid"] except KeyError: - return self._error_response("Not allowed!") + return self._error_response( + "Not allowed (UID could not be retrieved)!") #if self.sdb.get_verified_logout(uid): # return self.let_user_verify_logout(uid, esr, cookie, redirect_uri) @@ -1335,11 +1346,19 @@ class Provider(AProvider): :param pcr_class: :return: ProviderConfigurationResponse instance """ + _scopes = SCOPE2CLAIMS.keys() + _scopes.append("openid") + + _claims = [] + for _cl in SCOPE2CLAIMS.values(): + _claims.extend(_cl) + _claims = list(set(_claims)) + _provider_info = pcr_class( token_endpoint_auth_methods_supported=[ "client_secret_post", "client_secret_basic", "client_secret_jwt", "private_key_jwt"], - scopes_supported=["openid"], + scopes_supported=_scopes, response_types_supported=["code", "token", "id_token", "code token", "code id_token", "token id_token", @@ -1350,7 +1369,7 @@ class Provider(AProvider): "authorization_code", "implicit", "urn:ietf:params:oauth:grant-type:jwt-bearer"], claim_types_supported=["normal", "aggregated", "distributed"], - claims_supported=SCOPE2CLAIMS.keys(), + claims_supported=_claims, claims_parameter_supported="true", request_parameter_supported="true", request_uri_parameter_supported="true", From 4845fac868ece2b0fc5086f0f24181fae170f02f Mon Sep 17 00:00:00 2001 From: Roland Hedberg Date: Thu, 6 Nov 2014 12:25:50 +0100 Subject: [PATCH 7/8] Added verfication_endpoints parameter ro LDAPAuthn __init__ Proposed by M. Jeckelmann --- src/oic/utils/authn/ldapc.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/oic/utils/authn/ldapc.py b/src/oic/utils/authn/ldapc.py index 7516143..0e14aa0 100644 --- a/src/oic/utils/authn/ldapc.py +++ b/src/oic/utils/authn/ldapc.py @@ -10,7 +10,8 @@ SCOPE_MAP = { class LDAPAuthn(UsernamePasswordMako): def __init__(self, srv, ldapsrv, return_to, pattern, mako_template, - template_lookup, ldap_user="", ldap_pwd=""): + template_lookup, ldap_user="", ldap_pwd="", + verification_endpoints=["verify"]): """ :param srv: The server instance :param ldapsrv: Which LDAP server to us @@ -25,8 +26,9 @@ class LDAPAuthn(UsernamePasswordMako): that as. "" is a anonymous user :param ldap_pwd: The password for the ldap_user """ - UsernamePasswordMako.__init__(self, srv, mako_template, template_lookup, - None, return_to) + UsernamePasswordMako.__init__( + self, srv, mako_template, template_lookup, None, return_to, + verification_endpoints=verification_endpoints) self.ldap = ldap.initialize(ldapsrv) self.ldap.protocol_version = 3 From 85cba0acebd80a5f935425ff83da8593d2acb325 Mon Sep 17 00:00:00 2001 From: Roland Hedberg Date: Thu, 6 Nov 2014 12:26:22 +0100 Subject: [PATCH 8/8] Added a __delitem__ method Proposed by M. Jeckelmann --- src/oic/utils/sdb.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/oic/utils/sdb.py b/src/oic/utils/sdb.py index a5ff2c6..55d8ecf 100644 --- a/src/oic/utils/sdb.py +++ b/src/oic/utils/sdb.py @@ -147,7 +147,7 @@ class SessionDB(object): try: sid = self.token.get_key(item) except Exception: - raise KeyError + raise KeyError("item '%s' could not be found" % str(item)) return self._db[sid] def __setitem__(self, key, value): @@ -157,6 +157,13 @@ class SessionDB(object): self._db[key] = value + def __delitem__(self, key): + """ + Actually delete the pointed session from this SessionDB instance + :param key: session identifier + """ + del self._db[key] + def keys(self): return self._db.keys()