From 54f8e88849bf64a58c173608ebbf18586bff6d61 Mon Sep 17 00:00:00 2001 From: Glauco <37829079+rglauco@users.noreply.github.com> Date: Wed, 13 Mar 2024 11:36:38 +0100 Subject: [PATCH] Cie Integration (#311) * feat: added get_client_organisation_name method to retrieve the correct RP name * chore: fix CIE organization_name * fix: updated cryptography rsa import to 42.0.2 * chore: bump to 1.3.1 * fix: corrected proposed change * fix: scope issue * Update spid_cie_oidc/provider/views/consent_page_view.py Co-authored-by: Giuseppe De Marco * Update spid_cie_oidc/provider/views/__init__.py Co-authored-by: Giuseppe De Marco * Update spid_cie_oidc/provider/views/authz_request_view.py Co-authored-by: Giuseppe De Marco * fix: reinstated method name * feat: distinction between sig and enc keys during RP and OP operations * fix: better function for key retrivial * fix: added encryption algs to jwk validator * fix: added enum for key usage, fixed entity_type save method * chore: deleted unused code * Update spid_cie_oidc/entity/utils.py Co-authored-by: Giuseppe De Marco * Update spid_cie_oidc/entity/utils.py Co-authored-by: Giuseppe De Marco * chore: update version * fix: default return for get_key * fix: tests --------- Co-authored-by: Giuseppe De Marco --- .../federation_authority/dumps/example.json | 24 +++++++++++++++++-- examples/relying_party/dumps/example.json | 21 ++++++++++++++++ spid_cie_oidc/__init__.py | 2 +- spid_cie_oidc/entity/__init__.py | 6 +++++ spid_cie_oidc/entity/jwks.py | 4 ++-- spid_cie_oidc/entity/models.py | 1 - spid_cie_oidc/entity/schemas/jwks.py | 5 ++++ spid_cie_oidc/entity/utils.py | 13 ++++++++-- .../provider/views/userinfo_endpoint.py | 11 ++++----- .../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 ++++--- 12 files changed, 81 insertions(+), 21 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/__init__.py b/spid_cie_oidc/__init__.py index 7b1e3120..3e8d9f94 100644 --- a/spid_cie_oidc/__init__.py +++ b/spid_cie_oidc/__init__.py @@ -1 +1 @@ -__version__ = "1.3.3" +__version__ = "1.4.0" 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/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/models.py b/spid_cie_oidc/entity/models.py index 5072a45f..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/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"]] diff --git a/spid_cie_oidc/entity/utils.py b/spid_cie_oidc/entity/utils.py index 8dd242e6..73fd91d9 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,6 +14,15 @@ logger = logging.getLogger(__name__) +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()) @@ -27,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 """ diff --git a/spid_cie_oidc/provider/views/userinfo_endpoint.py b/spid_cie_oidc/provider/views/userinfo_endpoint.py index f35a8b5e..52d22f3d 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_key, KeyUsage from spid_cie_oidc.provider.models import IssuedToken from . import OpBase @@ -85,18 +85,15 @@ 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_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 = client_jwks[0] - for k in client_jwks: - if k.get('kid') and len(k["kid"]) >= 1: - client_jwk = k - break + client_jwk = get_key(client_jwks, KeyUsage.encryption) 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..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 +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=client_conf.jwks_core[0], + jwk_dict=get_key(client_conf.jwks_core, KeyUsage.signature), ), ) diff --git a/spid_cie_oidc/relying_party/views/__init__.py b/spid_cie_oidc/relying_party/views/__init__.py index 5be98762..65f8053a 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_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_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..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 +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 @@ -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_key(entity_conf.jwks_core, KeyUsage.signature) + + request_obj = create_jws(authz_data_obj, jwk_core_sig) authz_data["request"] = request_obj uri_path = http_dict_to_redirect_uri_path( {