From 82d6172a86b29785b98747de03cf6e861ddb222d Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Tue, 6 Feb 2024 20:07:33 +0100 Subject: [PATCH 01/20] feat: added get_client_organisation_name method to retrieve the correct RP name --- spid_cie_oidc/provider/views/__init__.py | 75 +++++++++++-------- .../provider/views/authz_request_view.py | 10 ++- .../provider/views/consent_page_view.py | 4 +- 3 files changed, 52 insertions(+), 37 deletions(-) diff --git a/spid_cie_oidc/provider/views/__init__.py b/spid_cie_oidc/provider/views/__init__.py index 8ca9832d..3ef40868 100644 --- a/spid_cie_oidc/provider/views/__init__.py +++ b/spid_cie_oidc/provider/views/__init__.py @@ -32,6 +32,7 @@ OIDCFED_PROVIDER_PROFILES_ACR_4_REFRESH, OIDCFED_PROVIDER_PROFILES_ID_TOKEN_CLAIMS ) + logger = logging.getLogger(__name__) @@ -40,7 +41,7 @@ class OpBase: Baseclass with common methods for OPs """ - def redirect_response_data(self, redirect_uri:str, **kwargs) -> HttpResponseRedirect: + def redirect_response_data(self, redirect_uri: str, **kwargs) -> HttpResponseRedirect: if "?" in redirect_uri: qstring = "&" else: @@ -114,7 +115,7 @@ def validate_authz_request_object(self, req) -> TrustChain: jwks = get_jwks( rp_trust_chain.metadata['openid_relying_party'], - federation_jwks = rp_trust_chain.jwks + federation_jwks=rp_trust_chain.jwks ) jwk = self.find_jwk(header, jwks) if not jwk: @@ -178,7 +179,7 @@ def check_session(self, request) -> OidcSession: ) session_not_after = session.created + timezone.timedelta( - minutes = OIDCFED_PROVIDER_AUTH_CODE_MAX_AGE + minutes=OIDCFED_PROVIDER_AUTH_CODE_MAX_AGE ) if session_not_after < timezone.localtime(): raise ExpiredAuthCode( @@ -199,12 +200,12 @@ def check_client_assertion(self, client_id: str, client_assertion: str) -> bool: _op = self.get_issuer() _op_eid = _op.sub _op_eid_authz_endpoint = [_op.metadata['openid_provider']['authorization_endpoint']] - + try: ClientAssertion(**payload) except Exception as e: raise Exception(f"Client Assertion: json schema validation error: {e}") - + if isinstance(_aud, str): _aud = [_aud] _allowed_auds = _aud + _op_eid_authz_endpoint @@ -250,9 +251,9 @@ def get_jwt_common_data(self): } def get_access_token( - self, iss_sub:str, sub:str, authz: OidcSession, commons:dict + self, iss_sub: str, sub: str, authz: OidcSession, commons: dict ) -> dict: - + access_token = { "iss": iss_sub, "sub": sub, @@ -266,8 +267,8 @@ def get_access_token( return access_token def get_id_token_claims( - self, - authz:OidcSession + self, + authz: OidcSession ) -> dict: _provider_profile = getattr(settings, 'OIDCFED_DEFAULT_PROVIDER_PROFILE', OIDCFED_DEFAULT_PROVIDER_PROFILE) claims = {} @@ -276,21 +277,21 @@ def get_id_token_claims( return claims for claim in ( - authz.authz_request.get( - "claims", {} - ).get("id_token", {}).keys() + authz.authz_request.get( + "claims", {} + ).get("id_token", {}).keys() ): if claim in allowed_id_token_claims and authz.user.attributes.get(claim, None): claims[claim] = authz.user.attributes[claim] return claims def get_id_token( - self, - iss_sub:str, - sub:str, - authz:OidcSession, - jwt_at:str, - commons:dict + self, + iss_sub: str, + sub: str, + authz: OidcSession, + jwt_at: str, + commons: dict ) -> dict: id_token = { @@ -312,19 +313,19 @@ def get_id_token( def get_refresh_token( self, - iss_sub:str, - sub:str, - authz:OidcSession, - jwt_at:str, - commons:dict + iss_sub: str, + sub: str, + authz: OidcSession, + jwt_at: str, + commons: dict ) -> dict: # refresh token is scope offline_access and prompt == consent refresh_acrs = OIDCFED_PROVIDER_PROFILES_ACR_4_REFRESH[OIDCFED_DEFAULT_PROVIDER_PROFILE] acrs = authz.authz_request.get('acr_values', []) if ( - "offline_access" in authz.authz_request['scope'] and - 'consent' in authz.authz_request['prompt'] and - set(refresh_acrs).intersection(set(acrs)) + "offline_access" in authz.authz_request['scope'] and + 'consent' in authz.authz_request['prompt'] and + set(refresh_acrs).intersection(set(acrs)) ): refresh_token = { "sub": sub, @@ -337,8 +338,8 @@ def get_refresh_token( refresh_token.update(commons) return refresh_token - def get_iss_token_data(self, session : OidcSession, issuer: FederationEntityConfiguration): - _sub = session.pairwised_sub(provider_id = issuer.sub) + def get_iss_token_data(self, session: OidcSession, issuer: FederationEntityConfiguration): + _sub = session.pairwised_sub(provider_id=issuer.sub) iss_sub = issuer.sub commons = self.get_jwt_common_data() jwk = issuer.jwks_core[0] @@ -363,7 +364,7 @@ def get_iss_token_data(self, session : OidcSession, issuer: FederationEntityConf def get_expires_in(self, iat: int, exp: int): return timezone.timedelta( - seconds = exp - iat + seconds=exp - iat ).seconds def attributes_names_to_release(self, request, session: OidcSession) -> dict: @@ -391,6 +392,18 @@ def attributes_names_to_release(self, request, session: OidcSession) -> dict: for i in filtered_user_claims.keys() ] return dict( - i18n_user_claims = i18n_user_claims, - filtered_user_claims = filtered_user_claims + i18n_user_claims=i18n_user_claims, + filtered_user_claims=filtered_user_claims ) + + def get_client_organisation_name(self, tc): + fed_metadata = tc.metadata.get("federation_entity", {}) + name = fed_metadata.get("organization_name", "") + if not name: + op_metadata = tc.metadata.get("openid_relying_party", {}) + name = op_metadata.get("organization_name", "") + if not name: + name = op_metadata.get("client_name", "") + if not name: + name = op_metadata.get("client_id", "") + return name diff --git a/spid_cie_oidc/provider/views/authz_request_view.py b/spid_cie_oidc/provider/views/authz_request_view.py index 415b738f..b59d4cf2 100644 --- a/spid_cie_oidc/provider/views/authz_request_view.py +++ b/spid_cie_oidc/provider/views/authz_request_view.py @@ -198,10 +198,14 @@ def get(self, request, *args, **kwargs): # stores the authz request in a hidden field in the form form = self.get_login_form()() + + # context = { + # "client_organization_name": tc.metadata.get( + # "client_name", self.payload["client_id"] + # ), + context = { - "client_organization_name": tc.metadata.get( - "client_name", self.payload["client_id"] - ), + "client_organization_name": self.get_client_organisation_name(tc), "hidden_form": AuthzHiddenForm(dict(authz_request_object=req)), "form": form, "redirect_uri": self.payload["redirect_uri"], diff --git a/spid_cie_oidc/provider/views/consent_page_view.py b/spid_cie_oidc/provider/views/consent_page_view.py index 14fb0b26..56ffd843 100644 --- a/spid_cie_oidc/provider/views/consent_page_view.py +++ b/spid_cie_oidc/provider/views/consent_page_view.py @@ -56,9 +56,7 @@ def get(self, request, *args, **kwargs): context = { "form": self.get_consent_form()(), "session": session, - "client_organization_name": tc.metadata.get( - "client_name", session.client_id - ), + "client_organization_name": self.get_client_organisation_name(tc), "user_claims": sorted(set(i18n_user_claims),), "redirect_uri": session.authz_request["redirect_uri"], "state": session.authz_request["state"] From 4740ea5bccf81153f15b985d8ac46b995eb24ade Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Tue, 6 Feb 2024 20:16:55 +0100 Subject: [PATCH 02/20] chore: fix CIE organization_name --- examples/provider/dumps/example.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/provider/dumps/example.json b/examples/provider/dumps/example.json index 06242afd..fb0e7e4b 100644 --- a/examples/provider/dumps/example.json +++ b/examples/provider/dumps/example.json @@ -147,7 +147,7 @@ "metadata": { "federation_entity": { "federation_resolve_endpoint": "http://127.0.0.1:8002/oidc/op/resolve", - "organization_name": "SPID OIDC identity provider", + "organization_name": "CIE OIDC identity provider", "homepage_uri": "http://127.0.0.1:8002", "policy_uri": "http://127.0.0.1:8002/oidc/op/en/website/legal-information", "logo_uri": "http://127.0.0.1:8002/static/svg/logo-cie.svg", From 6403674dae07cf5536c82357b459b5cad261b1b6 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Wed, 7 Feb 2024 07:42:29 +0100 Subject: [PATCH 03/20] fix: updated cryptography rsa import to 42.0.2 --- spid_cie_oidc/entity/jwks.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spid_cie_oidc/entity/jwks.py b/spid_cie_oidc/entity/jwks.py index 9726d505..b65f844d 100644 --- a/spid_cie_oidc/entity/jwks.py +++ b/spid_cie_oidc/entity/jwks.py @@ -2,7 +2,7 @@ from cryptojwt.jwk.rsa import new_rsa_key from cryptography.hazmat.primitives import serialization from cryptojwt.jwk.rsa import RSAKey - +from cryptography.hazmat.primitives.asymmetric import rsa import cryptography from django.conf import settings @@ -64,9 +64,9 @@ def serialize_rsa_key(rsa_key, kind="public", hash_func="SHA-256"): cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey """ data = {} - if isinstance(rsa_key, cryptography.hazmat.backends.openssl.rsa._RSAPublicKey): + if isinstance(rsa_key, rsa.RSAPublicKey): data = {"pub_key": rsa_key} - elif isinstance(rsa_key, cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey): + elif isinstance(rsa_key, rsa.RSAPrivateKey): data = {"priv_key": rsa_key} elif isinstance(rsa_key, (str, bytes)): # pragma: no cover if kind == "private": From ab823916862cc07558afc3712e008a28a407b4c6 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Wed, 7 Feb 2024 08:02:04 +0100 Subject: [PATCH 04/20] chore: bump to 1.3.1 --- spid_cie_oidc/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spid_cie_oidc/__init__.py b/spid_cie_oidc/__init__.py index 67bc602a..9c73af26 100644 --- a/spid_cie_oidc/__init__.py +++ b/spid_cie_oidc/__init__.py @@ -1 +1 @@ -__version__ = "1.3.0" +__version__ = "1.3.1" From 22381842391ada11826e9fe6316941d0278a3faf Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Wed, 7 Feb 2024 09:59:17 +0100 Subject: [PATCH 05/20] fix: corrected proposed change --- spid_cie_oidc/provider/views/__init__.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/spid_cie_oidc/provider/views/__init__.py b/spid_cie_oidc/provider/views/__init__.py index 3ef40868..b29269af 100644 --- a/spid_cie_oidc/provider/views/__init__.py +++ b/spid_cie_oidc/provider/views/__init__.py @@ -397,13 +397,19 @@ def attributes_names_to_release(self, request, session: OidcSession) -> dict: ) def get_client_organisation_name(self, tc): - fed_metadata = tc.metadata.get("federation_entity", {}) - name = fed_metadata.get("organization_name", "") - if not name: - op_metadata = tc.metadata.get("openid_relying_party", {}) - name = op_metadata.get("organization_name", "") - if not name: - name = op_metadata.get("client_name", "") - if not name: - name = op_metadata.get("client_id", "") + global name + rp_metadata = ( + tc.metadata.get( + "federation_entity", {} + ) or + tc.metadata.get( + "openid_relying_party", {} + ) + ) + if rp_metadata: + name = ( + rp_metadata.get("organization_name", "") or + rp_metadata.get("client_name", "") or + rp_metadata.get("client_id", "") + ) return name From 0f1c63afa32e7907b6fff8176b36a3c3d545d177 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Wed, 7 Feb 2024 10:51:36 +0100 Subject: [PATCH 06/20] fix: scope issue --- spid_cie_oidc/provider/views/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/spid_cie_oidc/provider/views/__init__.py b/spid_cie_oidc/provider/views/__init__.py index b29269af..de69e1f7 100644 --- a/spid_cie_oidc/provider/views/__init__.py +++ b/spid_cie_oidc/provider/views/__init__.py @@ -397,7 +397,6 @@ def attributes_names_to_release(self, request, session: OidcSession) -> dict: ) def get_client_organisation_name(self, tc): - global name rp_metadata = ( tc.metadata.get( "federation_entity", {} From e4e61f6af9d21dece02307c2b0959c9339608ac8 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Wed, 7 Feb 2024 12:00:50 +0100 Subject: [PATCH 07/20] Update spid_cie_oidc/provider/views/consent_page_view.py Co-authored-by: Giuseppe De Marco --- spid_cie_oidc/provider/views/consent_page_view.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spid_cie_oidc/provider/views/consent_page_view.py b/spid_cie_oidc/provider/views/consent_page_view.py index 56ffd843..f639db23 100644 --- a/spid_cie_oidc/provider/views/consent_page_view.py +++ b/spid_cie_oidc/provider/views/consent_page_view.py @@ -56,7 +56,7 @@ def get(self, request, *args, **kwargs): context = { "form": self.get_consent_form()(), "session": session, - "client_organization_name": self.get_client_organisation_name(tc), + "client_organization_name": self.get_client_organization_name(tc), "user_claims": sorted(set(i18n_user_claims),), "redirect_uri": session.authz_request["redirect_uri"], "state": session.authz_request["state"] From d718b27eb896b589b22352828a90f70d2bdf8e81 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Wed, 7 Feb 2024 12:00:59 +0100 Subject: [PATCH 08/20] Update spid_cie_oidc/provider/views/__init__.py Co-authored-by: Giuseppe De Marco --- spid_cie_oidc/provider/views/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spid_cie_oidc/provider/views/__init__.py b/spid_cie_oidc/provider/views/__init__.py index de69e1f7..d154e661 100644 --- a/spid_cie_oidc/provider/views/__init__.py +++ b/spid_cie_oidc/provider/views/__init__.py @@ -396,7 +396,7 @@ def attributes_names_to_release(self, request, session: OidcSession) -> dict: filtered_user_claims=filtered_user_claims ) - def get_client_organisation_name(self, tc): + def get_client_organization_name(self, tc): rp_metadata = ( tc.metadata.get( "federation_entity", {} From b6e8a15b791cc325eb6f0049fbe456c240e82945 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Wed, 7 Feb 2024 12:01:12 +0100 Subject: [PATCH 09/20] Update spid_cie_oidc/provider/views/authz_request_view.py Co-authored-by: Giuseppe De Marco --- spid_cie_oidc/provider/views/authz_request_view.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/spid_cie_oidc/provider/views/authz_request_view.py b/spid_cie_oidc/provider/views/authz_request_view.py index b59d4cf2..91aa24b7 100644 --- a/spid_cie_oidc/provider/views/authz_request_view.py +++ b/spid_cie_oidc/provider/views/authz_request_view.py @@ -198,12 +198,6 @@ def get(self, request, *args, **kwargs): # stores the authz request in a hidden field in the form form = self.get_login_form()() - - # context = { - # "client_organization_name": tc.metadata.get( - # "client_name", self.payload["client_id"] - # ), - context = { "client_organization_name": self.get_client_organisation_name(tc), "hidden_form": AuthzHiddenForm(dict(authz_request_object=req)), From de5969c081d78862e8a888c5ae96843735f6b5dc Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Wed, 7 Feb 2024 12:11:23 +0100 Subject: [PATCH 10/20] fix: reinstated method name --- spid_cie_oidc/provider/views/authz_request_view.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spid_cie_oidc/provider/views/authz_request_view.py b/spid_cie_oidc/provider/views/authz_request_view.py index 91aa24b7..76e3df86 100644 --- a/spid_cie_oidc/provider/views/authz_request_view.py +++ b/spid_cie_oidc/provider/views/authz_request_view.py @@ -199,7 +199,7 @@ def get(self, request, *args, **kwargs): # stores the authz request in a hidden field in the form form = self.get_login_form()() context = { - "client_organization_name": self.get_client_organisation_name(tc), + "client_organization_name": self.get_client_organization_name(tc), "hidden_form": AuthzHiddenForm(dict(authz_request_object=req)), "form": form, "redirect_uri": self.payload["redirect_uri"], From 7d2e0b911a570a6c1e4efd17bc16c142b1e53ba1 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Fri, 8 Mar 2024 16:00:10 +0100 Subject: [PATCH 11/20] feat: distinction between sig and enc keys during RP and OP operations --- .../federation_authority/dumps/example.json | 24 +++++++++++++++++-- examples/relying_party/dumps/example.json | 21 ++++++++++++++++ spid_cie_oidc/entity/utils.py | 17 +++++++++++++ .../provider/views/userinfo_endpoint.py | 15 ++++++------ .../relying_party/oauth2/__init__.py | 4 ++-- spid_cie_oidc/relying_party/views/__init__.py | 3 ++- spid_cie_oidc/relying_party/views/rp_begin.py | 8 ++++--- 7 files changed, 77 insertions(+), 15 deletions(-) diff --git a/examples/federation_authority/dumps/example.json b/examples/federation_authority/dumps/example.json index 0dc488c8..9e3fb256 100644 --- a/examples/federation_authority/dumps/example.json +++ b/examples/federation_authority/dumps/example.json @@ -238,6 +238,18 @@ ], "jwks_core": [ { + "alg": "RSA-OAEP", + "use": "enc", + "kty": "RSA", + "e": "AQAB", + "n": "oP1EPjcPOtV7Zog2suguY-tCLUVWSe2DOAHqlEWeDJtuQ1sO99Ue_5-Zbdm7iUmA2JNoCKZhp3RpICxRy01PsmXVm5UhsiYvHwK4vYq8hJRgtNpci3Gwj4YzpsN1p2un1VbvtAgiSN5wXURWyaMPMDuOMhIPIleaXU0wHcmGeXEuJrVPluz2jbqYhUHkAlySsH8-3Tx9VIjYohkiaSGU43XIYgCDL3mDkt7u3Z5w009vsNu1XhVZ7SE_XhkOzcvnA82NSq04ogwZ_oAyBY8nYMIN0irxR9r8NssGR3OZxqUMwvElqpyWt2NthgvS0GkMrgirQig-rvJ5bldlBkgOWQ", "d": "caSgY0rD4zH0oSM9eZ_ajUCFUgIN54-dyFlI0M_Bwf_2jQNM1sqbO9eSm9Rgsq2eIh-jLC7ZnBK1kLdvTxRELhiQQ7FwPHZuzQeMhkBpZb_qhFJ8JjyI1DXDZPUnquMK3_xaFODNnBCOZdqO1uxozFpivT7duTvUvAgupfzlp2XWDu_b2xDed16ZtroQk2gqjcByJSDt8U3lj82n34HjcpTZNGIIV4IbJ1jbUJ554A73bmQbjRFInKHMEDmTZGoa-GVcn9YgITUPL_vNvMJgzwcNeextFFLsX-Z8WD3ku4en-guehqFt7-6ZPVLJ0nlBn7oYOpLEML-U-tBZXsBx", + "p": "z8soMD0NaVkvMqIYN1OkKPGQUNSaopYiQEgS9ynQfo-GEo7lhHbcLnhpnqXVR0MYwpvdchJwehIr5-UZIWIV7BHkNLSWy5KPCKZ5G2P7CWsbDTDk0DjL7IJpOukhMsWRpumIKoOefs8RurTtbvGhwj09eLwy4sWO7uI7u11SHdU", + "q": "xlZonE4-C1acGa15uQDSes0DXrLShT337FLCRMy-6HQODSW__xxtV87wVywvDIf39nTQxoOnvUybuAfXww9xexuzC3Q2jXznpvHE7O7lglc6Uq-tEnviVVe-RhAwEQheVPEbCIJQHfvXhDsRzbTrzw7ennM0Gd5WtaICtb54vHU", + "kid": "m1-4Lr9DqAh5-UXYvQnacFiMSrPMaXfK0cfFmCxVvI8" + }, + { + "alg": "RS256", + "use": "sig", "kty": "RSA", "kid": "2HnoFS3YnC9tjiCaivhWLVUJ3AxwGGz_98uRFaqMEEs", "n": "5s4qi1Ta-sEuKb5rJ8TzHmyGKaSu89pIXIi6w4Ekx6GL56mJDNE_MWJHsFjWXajfMdMQmZrSXAvLtXxmbhUui9Mq_IormhmEyyEJS0SyE9UKTxWzi0yd_n_C7OjFBhM-0ZyUlgl81E_sr-35P1A6b5WSYwMvRSR-P9yx_NI-XBQ48G_zdmk3CbuuzZsXZqqgj5U7OGWH-4Huosn9nH3FVkwX0OlWkgWM-J9DEWzGBjl9hfbbrMtM_obljHL2NfT6RJYER2IpdI8RCyQS3sMPt6ZHDskmuNlyMDNATCChXQJLnltwEjxcgvzjw_G9J25DwfdfVEhDF_0kCp44UMmS3Q", @@ -276,12 +288,20 @@ "jwks": { "keys": [ { - "kty": "RSA", "use": "sig", + "alg": "RS256", + "kty": "RSA", "n": "5s4qi1Ta-sEuKb5rJ8TzHmyGKaSu89pIXIi6w4Ekx6GL56mJDNE_MWJHsFjWXajfMdMQmZrSXAvLtXxmbhUui9Mq_IormhmEyyEJS0SyE9UKTxWzi0yd_n_C7OjFBhM-0ZyUlgl81E_sr-35P1A6b5WSYwMvRSR-P9yx_NI-XBQ48G_zdmk3CbuuzZsXZqqgj5U7OGWH-4Huosn9nH3FVkwX0OlWkgWM-J9DEWzGBjl9hfbbrMtM_obljHL2NfT6RJYER2IpdI8RCyQS3sMPt6ZHDskmuNlyMDNATCChXQJLnltwEjxcgvzjw_G9J25DwfdfVEhDF_0kCp44UMmS3Q", "e": "AQAB", "kid": "2HnoFS3YnC9tjiCaivhWLVUJ3AxwGGz_98uRFaqMEEs" - } + }, + { + "use": "enc", + "kty": "RSA", + "e": "AQAB", + "alg": "RSA-OAEP", + "n": "oP1EPjcPOtV7Zog2suguY-tCLUVWSe2DOAHqlEWeDJtuQ1sO99Ue_5-Zbdm7iUmA2JNoCKZhp3RpICxRy01PsmXVm5UhsiYvHwK4vYq8hJRgtNpci3Gwj4YzpsN1p2un1VbvtAgiSN5wXURWyaMPMDuOMhIPIleaXU0wHcmGeXEuJrVPluz2jbqYhUHkAlySsH8-3Tx9VIjYohkiaSGU43XIYgCDL3mDkt7u3Z5w009vsNu1XhVZ7SE_XhkOzcvnA82NSq04ogwZ_oAyBY8nYMIN0irxR9r8NssGR3OZxqUMwvElqpyWt2NthgvS0GkMrgirQig-rvJ5bldlBkgOWQ", + "kid": "m1-4Lr9DqAh5-UXYvQnacFiMSrPMaXfK0cfFmCxVvI8"} ] }, "jwks_uri": "http://127.0.0.1:8000/oidc/rp/openid_relying_party/jwks.json", diff --git a/examples/relying_party/dumps/example.json b/examples/relying_party/dumps/example.json index 53682e0c..80d62eff 100644 --- a/examples/relying_party/dumps/example.json +++ b/examples/relying_party/dumps/example.json @@ -45,6 +45,7 @@ ], "jwks_core": [ { + "use": "sig", "kty": "RSA", "n": "uXfJA-wTlTCA4FdsoE0qZfmKIgedmarrtWgQbElKbWg9RDR7Z8JVBaRLFqwyfyG1JJFm64G51cBJwLIFwWoF7nxsH9VYLm5ocjAnsR4RhlfVE0y_60wjf8skJgBRpiXQPlwH9jDGaqVE_PEBTObDO5w3XourD1F360-v5cLDLRHdFJIitdEVtqATqY5DglRDaKiBhis7a5_1bk839PDLaQhju4XJk4tvDy5-LVkMy5sP2zU6-1tJdA-VmaBZLXy9n0967FGIWmMzpafrBMOuHFcUOH56o-clDah_CITH1dq2D64K0MYhEpACO2p8AH4K8Q6YuJ1dnkVDDwZp2C84sQ", "e": "AQAB", @@ -52,6 +53,17 @@ "p": "5PA7lJEDd3vrw5hlolFzvjvRriOu1SMHXx9Y52AgpOeQ6MnE1pO8qwn33lwYTSPGYinaq4jS3FKF_U5vOZltJAGBMa4ByEvAROJVCh958rKVRWKIqVXLOi8Gk11kHbVKw6oDXAd8Qt_y_ff8k_K6jW2EbWm1K6kfTvTMzoHkqrU", "q": "z2QeMH4WtrdiWUET7JgZNX0TbcaVBgd2Gpo8JHnfnGOUsvO_euKGgqpCcxiWVXSlqffQyTgVzl4iMROP8bEaQwvueHurtziMDSy9Suumyktu3PbGgjqu_izRim8Xlg7sz8Hs2quJPII_fQ8BCoaWpg30osFZqCBarQM7CWhxR40", "kid": "YhuIJU6o15EUCyqA0LHEqJd-xVPJgoyW5wZ1o4padWs" + }, + { + "alg": "RSA-OAEP", + "use": "enc", + "kty": "RSA", + "n": "rZDx5jxztL4RL4obgFtOZCCelabRolJo_WHdvHVM0Pe5M1rCYXmcnGq5I2M7MdXrFHLa_Yl5rAzkxKyFgpB48vkmqIGNl8NX-6c95XDMQttHmp_atrPnKyJ0E2Zk1ZTomZMWnQCIXQYfcJI2x4W5Mjyh8Ip0ZDDUiqlYsADkHCThj0q6RjJRXtmK_rrt1-tcHOQbIHDVKXYACMWOzUr1YDGWgrFjPu2D2QAXmO3qxhaqIdABwim6XKuLYwzTlIeHJyeEZQiVLEY_Notu5GVQGeL8qMnW3SsqBw7rMYxKgLOcSk2-2J5_orToRNy0x1LQfMtHG3ic8KcFefV7UZeR3w", + "e": "AQAB", + "d": "Agb1P-F-bVupnNWH_5ZYh-8S7qb5I500yyjS6A9dVfvs736BGZYhQc5uoZQtrglwzgIA96uOmwW3h6Mx-469h1gTny3FE3vrmNEvIKogRRATssxMR8VWXU4Nma6gz4jp0MlgApKKPhPmkBrN925i9a_ODNeBI9dSKYP-Y4RPJb5RWBj2SwL62AwfSAYD012qUQAOw9uYP9c2gIA2sWRnNG0ufe6YTh0UDZub3B34BCoMf8Cr0cZZ4AvjVqoPBWWLZm265TDRHmJ3cS8EdMsSYCzQSaMy5B2wEwGmilO14TiNroDN1UcdoANhmXC9lzZWYx8Iz6BYH4ybk4fwGinEWQ", + "p": "7-9WcW5dg64vEAok88rZESb9ZXP6FgPMrZ2wCIDxP3XxhqQlaVANE2bSBLQYrwxCpKlIznCJOvOY2FALhBcF5GKdBhUrBhs7Iz46ACr2HKr7mQ5EiigDwMmdIJ5LGJL-RVevP2Ye4QxOWQbn3jttc9fsj2Pw3FjYaeUurs9AnUs", + "q": "uS__hm1ZVGN1FPmT6LfiM5-_xPmZwNwKRWV02e4drqa_qXQgbaMzZoSAc4duXXXgbyXc7LaJF4_fqR3Cpr1rXsXMTuJf9rb0uN4wZ9awZgmwbBx1JM2ikoQt08xvdxuH_7_0j584Ta7Go1TO2XX1QII06nr7EkVJ8HJqsE665T0", + "kid": "dlDtBxB1sKzY5hZTxJRLpvKVLeWHy5QYsFTSxETF5qM" } ], "trust_marks": [ @@ -85,11 +97,20 @@ "jwks": { "keys": [ { + "alg": "RS256", "kty": "RSA", "use": "sig", "n": "uXfJA-wTlTCA4FdsoE0qZfmKIgedmarrtWgQbElKbWg9RDR7Z8JVBaRLFqwyfyG1JJFm64G51cBJwLIFwWoF7nxsH9VYLm5ocjAnsR4RhlfVE0y_60wjf8skJgBRpiXQPlwH9jDGaqVE_PEBTObDO5w3XourD1F360-v5cLDLRHdFJIitdEVtqATqY5DglRDaKiBhis7a5_1bk839PDLaQhju4XJk4tvDy5-LVkMy5sP2zU6-1tJdA-VmaBZLXy9n0967FGIWmMzpafrBMOuHFcUOH56o-clDah_CITH1dq2D64K0MYhEpACO2p8AH4K8Q6YuJ1dnkVDDwZp2C84sQ", "e": "AQAB", "kid": "YhuIJU6o15EUCyqA0LHEqJd-xVPJgoyW5wZ1o4padWs" + }, + { + "alg": "RSA-OAEP", + "use": "enc", + "kty": "RSA", + "n": "rZDx5jxztL4RL4obgFtOZCCelabRolJo_WHdvHVM0Pe5M1rCYXmcnGq5I2M7MdXrFHLa_Yl5rAzkxKyFgpB48vkmqIGNl8NX-6c95XDMQttHmp_atrPnKyJ0E2Zk1ZTomZMWnQCIXQYfcJI2x4W5Mjyh8Ip0ZDDUiqlYsADkHCThj0q6RjJRXtmK_rrt1-tcHOQbIHDVKXYACMWOzUr1YDGWgrFjPu2D2QAXmO3qxhaqIdABwim6XKuLYwzTlIeHJyeEZQiVLEY_Notu5GVQGeL8qMnW3SsqBw7rMYxKgLOcSk2-2J5_orToRNy0x1LQfMtHG3ic8KcFefV7UZeR3w", + "e": "AQAB", + "kid": "dlDtBxB1sKzY5hZTxJRLpvKVLeWHy5QYsFTSxETF5qM" } ] }, diff --git a/spid_cie_oidc/entity/utils.py b/spid_cie_oidc/entity/utils.py index 8dd242e6..bd832fc4 100644 --- a/spid_cie_oidc/entity/utils.py +++ b/spid_cie_oidc/entity/utils.py @@ -14,6 +14,23 @@ logger = logging.getLogger(__name__) +def get_core_signing_key(entity_conf): + jwk_core_sig = entity_conf.jwks_core[0] + if len(entity_conf.jwks_core) > 1: + for jwk in entity_conf.jwks_core: + if jwk['use'] == 'sig': + jwk_core_sig = jwk + return jwk_core_sig + + +def get_rp_encryption_key(jwks_core): + jwk_core_enc = jwks_core[0] + if len(jwks_core) > 1: + for jwk in jwks_core: + if jwk['use'] == 'enc': + jwk_core_enc = jwk + return jwk_core_enc + def iat_now() -> int: return int(datetime.datetime.now().timestamp()) diff --git a/spid_cie_oidc/provider/views/userinfo_endpoint.py b/spid_cie_oidc/provider/views/userinfo_endpoint.py index f35a8b5e..02969b60 100644 --- a/spid_cie_oidc/provider/views/userinfo_endpoint.py +++ b/spid_cie_oidc/provider/views/userinfo_endpoint.py @@ -16,7 +16,7 @@ from spid_cie_oidc.entity.models import ( TrustChain ) -from spid_cie_oidc.entity.utils import get_jwks +from spid_cie_oidc.entity.utils import get_jwks, get_rp_encryption_key, get_core_signing_key from spid_cie_oidc.provider.models import IssuedToken from . import OpBase @@ -85,18 +85,19 @@ def get(self, request, *args, **kwargs): jwt[claim] = token.session.user.attributes[claim] # sign the data - jws = create_jws(jwt, issuer.jwks_core[0]) + key = get_core_signing_key(issuer) + jws = create_jws(jwt, key) #issuer.jwks_core[0]) # encrypt the data client_jwks = get_jwks( rp_tc.metadata['openid_relying_party'], federation_jwks = rp_tc.jwks ) - client_jwk = client_jwks[0] - for k in client_jwks: - if k.get('kid') and len(k["kid"]) >= 1: - client_jwk = k - break + client_jwk = get_rp_encryption_key(client_jwks) #[0] + # for k in client_jwks: + # if k.get('kid') and len(k["kid"]) >= 1: + # client_jwk = k + # break jwe = create_jwe( jws, diff --git a/spid_cie_oidc/relying_party/oauth2/__init__.py b/spid_cie_oidc/relying_party/oauth2/__init__.py index fa03535a..4f494a9e 100644 --- a/spid_cie_oidc/relying_party/oauth2/__init__.py +++ b/spid_cie_oidc/relying_party/oauth2/__init__.py @@ -6,7 +6,7 @@ from spid_cie_oidc.entity.models import FederationEntityConfiguration from spid_cie_oidc.entity.jwtse import create_jws from spid_cie_oidc.entity.settings import HTTPC_PARAMS, HTTPC_TIMEOUT -from spid_cie_oidc.entity.utils import iat_now, exp_from_now +from spid_cie_oidc.entity.utils import iat_now, exp_from_now, get_core_signing_key logger = logging.getLogger(__name__) @@ -49,7 +49,7 @@ def access_token_request( "exp": exp_from_now(), "jti": str(uuid.uuid4()), }, - jwk_dict=client_conf.jwks_core[0], + jwk_dict=get_core_signing_key(client_conf), ), ) diff --git a/spid_cie_oidc/relying_party/views/__init__.py b/spid_cie_oidc/relying_party/views/__init__.py index 5be98762..ffa2efae 100644 --- a/spid_cie_oidc/relying_party/views/__init__.py +++ b/spid_cie_oidc/relying_party/views/__init__.py @@ -13,6 +13,7 @@ from spid_cie_oidc.entity.exceptions import InvalidTrustchain from spid_cie_oidc.entity.models import TrustChain +from spid_cie_oidc.entity.utils import get_core_signing_key from spid_cie_oidc.entity.trust_chain_operations import get_or_create_trust_chain from spid_cie_oidc.relying_party.exceptions import ValidationException from spid_cie_oidc.relying_party.settings import ( @@ -146,7 +147,7 @@ def get_token_request(self, auth_token, request, token_type): "exp": exp_from_now(), "jti": str(uuid.uuid4()) }, - jwk_dict=rp_conf.jwks_core[0], + jwk_dict=get_core_signing_key(rp_conf) ) token_request_data["client_assertion"] = client_assertion diff --git a/spid_cie_oidc/relying_party/views/rp_begin.py b/spid_cie_oidc/relying_party/views/rp_begin.py index 86eb5608..3ab8ac6a 100644 --- a/spid_cie_oidc/relying_party/views/rp_begin.py +++ b/spid_cie_oidc/relying_party/views/rp_begin.py @@ -12,7 +12,7 @@ from django.views import View from spid_cie_oidc.entity.exceptions import InvalidTrustchain from spid_cie_oidc.entity.jwtse import create_jws -from spid_cie_oidc.entity.utils import get_jwks +from spid_cie_oidc.entity.utils import get_jwks, get_core_signing_key from spid_cie_oidc.entity.models import FederationEntityConfiguration from spid_cie_oidc.relying_party.settings import OIDCFED_ACR_PROFILES, RP_PROVIDER_PROFILES, \ RP_DEFAULT_PROVIDER_PROFILES @@ -25,7 +25,7 @@ ) from ..utils import ( http_dict_to_redirect_uri_path, - random_string, + random_string ) from . import SpidCieOidcRp @@ -188,7 +188,9 @@ def get(self, request, *args, **kwargs): # could be reused as a private_key_jwt # authz_data_obj["sub"] = client_conf["client_id"] - request_obj = create_jws(authz_data_obj, entity_conf.jwks_core[0]) + jwk_core_sig = get_core_signing_key(entity_conf) + + request_obj = create_jws(authz_data_obj, jwk_core_sig) authz_data["request"] = request_obj uri_path = http_dict_to_redirect_uri_path( { From 602c3a3ac8e23be2513c6882f9f44b17e38c1456 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Sat, 9 Mar 2024 12:58:13 +0100 Subject: [PATCH 12/20] fix: better function for key retrivial --- spid_cie_oidc/entity/utils.py | 19 +++++-------------- .../provider/views/userinfo_endpoint.py | 6 +++--- .../relying_party/oauth2/__init__.py | 4 ++-- spid_cie_oidc/relying_party/views/__init__.py | 4 ++-- spid_cie_oidc/relying_party/views/rp_begin.py | 4 ++-- 5 files changed, 14 insertions(+), 23 deletions(-) diff --git a/spid_cie_oidc/entity/utils.py b/spid_cie_oidc/entity/utils.py index bd832fc4..aed2743c 100644 --- a/spid_cie_oidc/entity/utils.py +++ b/spid_cie_oidc/entity/utils.py @@ -14,22 +14,13 @@ logger = logging.getLogger(__name__) -def get_core_signing_key(entity_conf): - jwk_core_sig = entity_conf.jwks_core[0] - if len(entity_conf.jwks_core) > 1: - for jwk in entity_conf.jwks_core: - if jwk['use'] == 'sig': - jwk_core_sig = jwk - return jwk_core_sig - - -def get_rp_encryption_key(jwks_core): - jwk_core_enc = jwks_core[0] +def get_key(jwks_core, use='sig'): + selected_jwk = jwks_core[0] if len(jwks_core) > 1: for jwk in jwks_core: - if jwk['use'] == 'enc': - jwk_core_enc = jwk - return jwk_core_enc + if jwk['use'] == use: + selected_jwk = jwk + return selected_jwk def iat_now() -> int: return int(datetime.datetime.now().timestamp()) diff --git a/spid_cie_oidc/provider/views/userinfo_endpoint.py b/spid_cie_oidc/provider/views/userinfo_endpoint.py index 02969b60..b9b90dd1 100644 --- a/spid_cie_oidc/provider/views/userinfo_endpoint.py +++ b/spid_cie_oidc/provider/views/userinfo_endpoint.py @@ -16,7 +16,7 @@ from spid_cie_oidc.entity.models import ( TrustChain ) -from spid_cie_oidc.entity.utils import get_jwks, get_rp_encryption_key, get_core_signing_key +from spid_cie_oidc.entity.utils import get_jwks, get_key from spid_cie_oidc.provider.models import IssuedToken from . import OpBase @@ -85,7 +85,7 @@ def get(self, request, *args, **kwargs): jwt[claim] = token.session.user.attributes[claim] # sign the data - key = get_core_signing_key(issuer) + key = get_key(issuer.jwks_core, 'sig') jws = create_jws(jwt, key) #issuer.jwks_core[0]) # encrypt the data @@ -93,7 +93,7 @@ def get(self, request, *args, **kwargs): rp_tc.metadata['openid_relying_party'], federation_jwks = rp_tc.jwks ) - client_jwk = get_rp_encryption_key(client_jwks) #[0] + client_jwk = get_key(client_jwks, 'enc') #[0] # for k in client_jwks: # if k.get('kid') and len(k["kid"]) >= 1: # client_jwk = k diff --git a/spid_cie_oidc/relying_party/oauth2/__init__.py b/spid_cie_oidc/relying_party/oauth2/__init__.py index 4f494a9e..b12f425d 100644 --- a/spid_cie_oidc/relying_party/oauth2/__init__.py +++ b/spid_cie_oidc/relying_party/oauth2/__init__.py @@ -6,7 +6,7 @@ from spid_cie_oidc.entity.models import FederationEntityConfiguration from spid_cie_oidc.entity.jwtse import create_jws from spid_cie_oidc.entity.settings import HTTPC_PARAMS, HTTPC_TIMEOUT -from spid_cie_oidc.entity.utils import iat_now, exp_from_now, get_core_signing_key +from spid_cie_oidc.entity.utils import iat_now, exp_from_now, get_key logger = logging.getLogger(__name__) @@ -49,7 +49,7 @@ def access_token_request( "exp": exp_from_now(), "jti": str(uuid.uuid4()), }, - jwk_dict=get_core_signing_key(client_conf), + jwk_dict=get_key(client_conf.jwks_core, 'sig'), ), ) diff --git a/spid_cie_oidc/relying_party/views/__init__.py b/spid_cie_oidc/relying_party/views/__init__.py index ffa2efae..65f8053a 100644 --- a/spid_cie_oidc/relying_party/views/__init__.py +++ b/spid_cie_oidc/relying_party/views/__init__.py @@ -13,7 +13,7 @@ from spid_cie_oidc.entity.exceptions import InvalidTrustchain from spid_cie_oidc.entity.models import TrustChain -from spid_cie_oidc.entity.utils import get_core_signing_key +from spid_cie_oidc.entity.utils import get_key from spid_cie_oidc.entity.trust_chain_operations import get_or_create_trust_chain from spid_cie_oidc.relying_party.exceptions import ValidationException from spid_cie_oidc.relying_party.settings import ( @@ -147,7 +147,7 @@ def get_token_request(self, auth_token, request, token_type): "exp": exp_from_now(), "jti": str(uuid.uuid4()) }, - jwk_dict=get_core_signing_key(rp_conf) + jwk_dict=get_key(rp_conf) ) token_request_data["client_assertion"] = client_assertion diff --git a/spid_cie_oidc/relying_party/views/rp_begin.py b/spid_cie_oidc/relying_party/views/rp_begin.py index 3ab8ac6a..b3bdad11 100644 --- a/spid_cie_oidc/relying_party/views/rp_begin.py +++ b/spid_cie_oidc/relying_party/views/rp_begin.py @@ -12,7 +12,7 @@ from django.views import View from spid_cie_oidc.entity.exceptions import InvalidTrustchain from spid_cie_oidc.entity.jwtse import create_jws -from spid_cie_oidc.entity.utils import get_jwks, get_core_signing_key +from spid_cie_oidc.entity.utils import get_jwks, get_key from spid_cie_oidc.entity.models import FederationEntityConfiguration from spid_cie_oidc.relying_party.settings import OIDCFED_ACR_PROFILES, RP_PROVIDER_PROFILES, \ RP_DEFAULT_PROVIDER_PROFILES @@ -188,7 +188,7 @@ def get(self, request, *args, **kwargs): # could be reused as a private_key_jwt # authz_data_obj["sub"] = client_conf["client_id"] - jwk_core_sig = get_core_signing_key(entity_conf) + jwk_core_sig = get_key(entity_conf.jwks_core, 'sig') request_obj = create_jws(authz_data_obj, jwk_core_sig) authz_data["request"] = request_obj From 1beb7da413ff49a4019a3dad7021ba03a5d20df9 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Sun, 10 Mar 2024 09:21:09 +0100 Subject: [PATCH 13/20] fix: added encryption algs to jwk validator --- spid_cie_oidc/entity/schemas/jwks.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spid_cie_oidc/entity/schemas/jwks.py b/spid_cie_oidc/entity/schemas/jwks.py index 78f0f55a..23cc6d3c 100644 --- a/spid_cie_oidc/entity/schemas/jwks.py +++ b/spid_cie_oidc/entity/schemas/jwks.py @@ -18,6 +18,11 @@ class Jwk(BaseModel): "PS256", "PS384", "PS512", + "RSA-OAEP", + "RSA-OAEP-256", + "ECDH-ES", + "ECDH-ES+A128KW", + "ECDH-ES+A256KW" ] ] use: Optional[Literal["sig", "enc"]] From 92ec01113710b8371fdc1270502af82c9c0e8f9e Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Mon, 11 Mar 2024 17:42:22 +0100 Subject: [PATCH 14/20] fix: added enum for key usage, fixed entity_type save method --- spid_cie_oidc/__init__.py | 2 +- spid_cie_oidc/entity/__init__.py | 6 ++++++ spid_cie_oidc/entity/models.py | 2 +- spid_cie_oidc/entity/utils.py | 10 +++++----- spid_cie_oidc/provider/views/userinfo_endpoint.py | 8 ++++---- spid_cie_oidc/relying_party/oauth2/__init__.py | 4 ++-- spid_cie_oidc/relying_party/views/rp_begin.py | 4 ++-- 7 files changed, 21 insertions(+), 15 deletions(-) diff --git a/spid_cie_oidc/__init__.py b/spid_cie_oidc/__init__.py index 7b1e3120..f9e47b6a 100644 --- a/spid_cie_oidc/__init__.py +++ b/spid_cie_oidc/__init__.py @@ -1 +1 @@ -__version__ = "1.3.3" +__version__ = "1.3.4" diff --git a/spid_cie_oidc/entity/__init__.py b/spid_cie_oidc/entity/__init__.py index e69de29b..7d77e5d0 100644 --- a/spid_cie_oidc/entity/__init__.py +++ b/spid_cie_oidc/entity/__init__.py @@ -0,0 +1,6 @@ +from enum import Enum + + +class KeyUsage(str, Enum): + signature = "sig" + encryption = "enc" diff --git a/spid_cie_oidc/entity/models.py b/spid_cie_oidc/entity/models.py index 5072a45f..dab1f983 100644 --- a/spid_cie_oidc/entity/models.py +++ b/spid_cie_oidc/entity/models.py @@ -263,7 +263,7 @@ def set_jwks_as_array(self): setattr(self, i, [value]) def save(self, *args, **kwargs): - self.entity_type = self.type[0] + #self.entity_type = self.type[0] self.set_jwks_as_array() super().save(*args, **kwargs) diff --git a/spid_cie_oidc/entity/utils.py b/spid_cie_oidc/entity/utils.py index aed2743c..30915b32 100644 --- a/spid_cie_oidc/entity/utils.py +++ b/spid_cie_oidc/entity/utils.py @@ -5,7 +5,7 @@ from spid_cie_oidc.entity.jwtse import unpad_jwt_head from spid_cie_oidc.entity.settings import HTTPC_PARAMS from spid_cie_oidc.entity.statements import get_http_url - +from . import KeyUsage import datetime import json @@ -14,10 +14,10 @@ logger = logging.getLogger(__name__) -def get_key(jwks_core, use='sig'): - selected_jwk = jwks_core[0] - if len(jwks_core) > 1: - for jwk in jwks_core: +def get_key(jwks, use=KeyUsage.signature): + selected_jwk = jwks[0] + if len(jwks) > 1: + for jwk in jwks: if jwk['use'] == use: selected_jwk = jwk return selected_jwk diff --git a/spid_cie_oidc/provider/views/userinfo_endpoint.py b/spid_cie_oidc/provider/views/userinfo_endpoint.py index b9b90dd1..4b295138 100644 --- a/spid_cie_oidc/provider/views/userinfo_endpoint.py +++ b/spid_cie_oidc/provider/views/userinfo_endpoint.py @@ -16,7 +16,7 @@ from spid_cie_oidc.entity.models import ( TrustChain ) -from spid_cie_oidc.entity.utils import get_jwks, get_key +from spid_cie_oidc.entity.utils import get_jwks, get_key, KeyUsage from spid_cie_oidc.provider.models import IssuedToken from . import OpBase @@ -85,15 +85,15 @@ def get(self, request, *args, **kwargs): jwt[claim] = token.session.user.attributes[claim] # sign the data - key = get_key(issuer.jwks_core, 'sig') - jws = create_jws(jwt, key) #issuer.jwks_core[0]) + key = get_key(issuer.jwks_core, KeyUsage.signature) + jws = create_jws(jwt, key) # encrypt the data client_jwks = get_jwks( rp_tc.metadata['openid_relying_party'], federation_jwks = rp_tc.jwks ) - client_jwk = get_key(client_jwks, 'enc') #[0] + client_jwk = get_key(client_jwks, KeyUsage.encryption) # for k in client_jwks: # if k.get('kid') and len(k["kid"]) >= 1: # client_jwk = k diff --git a/spid_cie_oidc/relying_party/oauth2/__init__.py b/spid_cie_oidc/relying_party/oauth2/__init__.py index b12f425d..2ed5012f 100644 --- a/spid_cie_oidc/relying_party/oauth2/__init__.py +++ b/spid_cie_oidc/relying_party/oauth2/__init__.py @@ -6,7 +6,7 @@ from spid_cie_oidc.entity.models import FederationEntityConfiguration from spid_cie_oidc.entity.jwtse import create_jws from spid_cie_oidc.entity.settings import HTTPC_PARAMS, HTTPC_TIMEOUT -from spid_cie_oidc.entity.utils import iat_now, exp_from_now, get_key +from spid_cie_oidc.entity.utils import iat_now, exp_from_now, get_key, KeyUsage logger = logging.getLogger(__name__) @@ -49,7 +49,7 @@ def access_token_request( "exp": exp_from_now(), "jti": str(uuid.uuid4()), }, - jwk_dict=get_key(client_conf.jwks_core, 'sig'), + jwk_dict=get_key(client_conf.jwks_core, KeyUsage.signature), ), ) diff --git a/spid_cie_oidc/relying_party/views/rp_begin.py b/spid_cie_oidc/relying_party/views/rp_begin.py index b3bdad11..a2c05a49 100644 --- a/spid_cie_oidc/relying_party/views/rp_begin.py +++ b/spid_cie_oidc/relying_party/views/rp_begin.py @@ -12,7 +12,7 @@ from django.views import View from spid_cie_oidc.entity.exceptions import InvalidTrustchain from spid_cie_oidc.entity.jwtse import create_jws -from spid_cie_oidc.entity.utils import get_jwks, get_key +from spid_cie_oidc.entity.utils import get_jwks, get_key, KeyUsage from spid_cie_oidc.entity.models import FederationEntityConfiguration from spid_cie_oidc.relying_party.settings import OIDCFED_ACR_PROFILES, RP_PROVIDER_PROFILES, \ RP_DEFAULT_PROVIDER_PROFILES @@ -188,7 +188,7 @@ def get(self, request, *args, **kwargs): # could be reused as a private_key_jwt # authz_data_obj["sub"] = client_conf["client_id"] - jwk_core_sig = get_key(entity_conf.jwks_core, 'sig') + jwk_core_sig = get_key(entity_conf.jwks_core, KeyUsage.signature) request_obj = create_jws(authz_data_obj, jwk_core_sig) authz_data["request"] = request_obj From 51489f9e4330aa79c817d6ea5ab80ea2d217a7f7 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Mon, 11 Mar 2024 18:22:33 +0100 Subject: [PATCH 15/20] chore: deleted unused code --- spid_cie_oidc/entity/models.py | 1 - spid_cie_oidc/provider/views/userinfo_endpoint.py | 4 ---- 2 files changed, 5 deletions(-) diff --git a/spid_cie_oidc/entity/models.py b/spid_cie_oidc/entity/models.py index dab1f983..9a289fb6 100644 --- a/spid_cie_oidc/entity/models.py +++ b/spid_cie_oidc/entity/models.py @@ -263,7 +263,6 @@ def set_jwks_as_array(self): setattr(self, i, [value]) def save(self, *args, **kwargs): - #self.entity_type = self.type[0] self.set_jwks_as_array() super().save(*args, **kwargs) diff --git a/spid_cie_oidc/provider/views/userinfo_endpoint.py b/spid_cie_oidc/provider/views/userinfo_endpoint.py index 4b295138..52d22f3d 100644 --- a/spid_cie_oidc/provider/views/userinfo_endpoint.py +++ b/spid_cie_oidc/provider/views/userinfo_endpoint.py @@ -94,10 +94,6 @@ def get(self, request, *args, **kwargs): federation_jwks = rp_tc.jwks ) client_jwk = get_key(client_jwks, KeyUsage.encryption) - # for k in client_jwks: - # if k.get('kid') and len(k["kid"]) >= 1: - # client_jwk = k - # break jwe = create_jwe( jws, From f3a41431f8a2c29056f376af085b5ca26d1d057b Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Mon, 11 Mar 2024 19:18:46 +0100 Subject: [PATCH 16/20] Update spid_cie_oidc/entity/utils.py Co-authored-by: Giuseppe De Marco --- spid_cie_oidc/entity/utils.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/spid_cie_oidc/entity/utils.py b/spid_cie_oidc/entity/utils.py index 30915b32..47adbdc3 100644 --- a/spid_cie_oidc/entity/utils.py +++ b/spid_cie_oidc/entity/utils.py @@ -16,10 +16,9 @@ def get_key(jwks, use=KeyUsage.signature): selected_jwk = jwks[0] - if len(jwks) > 1: - for jwk in jwks: - if jwk['use'] == use: - selected_jwk = jwk + for jwk in jwks: + if jwk['use'] == use: + return jwk return selected_jwk def iat_now() -> int: From cea2ba274e802d08025ad522a320e1bb1b96c63f Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Mon, 11 Mar 2024 19:18:52 +0100 Subject: [PATCH 17/20] Update spid_cie_oidc/entity/utils.py Co-authored-by: Giuseppe De Marco --- spid_cie_oidc/entity/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/spid_cie_oidc/entity/utils.py b/spid_cie_oidc/entity/utils.py index 47adbdc3..33b75b16 100644 --- a/spid_cie_oidc/entity/utils.py +++ b/spid_cie_oidc/entity/utils.py @@ -19,7 +19,6 @@ def get_key(jwks, use=KeyUsage.signature): for jwk in jwks: if jwk['use'] == use: return jwk - return selected_jwk def iat_now() -> int: return int(datetime.datetime.now().timestamp()) From 1548bd1506b16ebf6ed11f0e7819214b1a115429 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Mon, 11 Mar 2024 19:20:01 +0100 Subject: [PATCH 18/20] chore: update version --- spid_cie_oidc/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spid_cie_oidc/__init__.py b/spid_cie_oidc/__init__.py index f9e47b6a..3e8d9f94 100644 --- a/spid_cie_oidc/__init__.py +++ b/spid_cie_oidc/__init__.py @@ -1 +1 @@ -__version__ = "1.3.4" +__version__ = "1.4.0" From 215e0a63b5d6659f48f4262b63fdbabdb88c4804 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Tue, 12 Mar 2024 11:04:42 +0100 Subject: [PATCH 19/20] fix: default return for get_key --- spid_cie_oidc/entity/jwks.py | 4 ++-- spid_cie_oidc/entity/utils.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/spid_cie_oidc/entity/jwks.py b/spid_cie_oidc/entity/jwks.py index b65f844d..3efd0b69 100644 --- a/spid_cie_oidc/entity/jwks.py +++ b/spid_cie_oidc/entity/jwks.py @@ -59,9 +59,9 @@ def public_pem_from_jwk(jwk_dict: dict): def serialize_rsa_key(rsa_key, kind="public", hash_func="SHA-256"): """ rsa_key can be - cryptography.hazmat.backends.openssl.rsa._RSAPublicKey + cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey or - cryptography.hazmat.backends.openssl.rsa._RSAPrivateKey + cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey """ data = {} if isinstance(rsa_key, rsa.RSAPublicKey): diff --git a/spid_cie_oidc/entity/utils.py b/spid_cie_oidc/entity/utils.py index 33b75b16..6643c8de 100644 --- a/spid_cie_oidc/entity/utils.py +++ b/spid_cie_oidc/entity/utils.py @@ -15,11 +15,10 @@ def get_key(jwks, use=KeyUsage.signature): - selected_jwk = jwks[0] for jwk in jwks: if jwk['use'] == use: return jwk - + return jwks[0] def iat_now() -> int: return int(datetime.datetime.now().timestamp()) From 1133275144570380eeb32b0ba4f7cf9d42a661d6 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Tue, 12 Mar 2024 22:09:11 +0100 Subject: [PATCH 20/20] fix: tests --- spid_cie_oidc/entity/utils.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/spid_cie_oidc/entity/utils.py b/spid_cie_oidc/entity/utils.py index 6643c8de..73fd91d9 100644 --- a/spid_cie_oidc/entity/utils.py +++ b/spid_cie_oidc/entity/utils.py @@ -14,11 +14,15 @@ logger = logging.getLogger(__name__) -def get_key(jwks, use=KeyUsage.signature): - for jwk in jwks: - if jwk['use'] == use: - return jwk +def get_key(jwks, used=KeyUsage.signature): + # TODO change tests accordingly due 2 core keys + if len(jwks) > 1: + for jwk in jwks: + if jwk['use'] == used: + return jwk return jwks[0] + + def iat_now() -> int: return int(datetime.datetime.now().timestamp()) @@ -32,7 +36,7 @@ def datetime_from_timestamp(value) -> datetime.datetime: return make_aware(datetime.datetime.fromtimestamp(value)) -def get_jwks(metadata: dict, federation_jwks:list = []) -> dict: +def get_jwks(metadata: dict, federation_jwks: list = []) -> dict: """ get jwks or jwks_uri or signed_jwks_uri """