Skip to content

Commit

Permalink
Merge pull request #234 from italia/dev
Browse files Browse the repository at this point in the history
BREAKING CHANGE: [federation entity configuration] jwks divided in jwks_fed and jwks_core
  • Loading branch information
Giuseppe De Marco authored Apr 23, 2022
2 parents c9c9bda + 93b6e39 commit fd71876
Show file tree
Hide file tree
Showing 30 changed files with 1,557 additions and 1,364 deletions.
2 changes: 2 additions & 0 deletions examples/federation_authority/dump_data.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
./manage.py dumpdata -e admin -e spid_cie_oidc_relying_party -e spid_cie_oidc_provider -e spid_cie_oidc_relying_party_test -e auth -e contenttypes -e sessions --indent 2 > dumps/example.json
1,632 changes: 1,339 additions & 293 deletions examples/federation_authority/dumps/example.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions examples/provider/dump_data.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
./manage.py dumpdata -e admin -e spid_cie_oidc_provider -e auth -e contenttypes -e sessions --indent 2 > dumps/example.json
413 changes: 68 additions & 345 deletions examples/provider/dumps/example.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions examples/relying_party/dump_data.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/bash
./manage.py dumpdata -e admin -e spid_cie_oidc_relying_party -e auth -e contenttypes -e sessions --indent 2 > dumps/example.json
751 changes: 67 additions & 684 deletions examples/relying_party/dumps/example.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion spid_cie_oidc/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.6.9"
__version__ = "0.7.0"
4 changes: 2 additions & 2 deletions spid_cie_oidc/authority/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ def entity_statement_as_jws(self, iss: str = None, aud: list = None) -> str:
issuer = get_first_self_trust_anchor(iss)
return create_jws(
self.entity_statement_as_dict(iss, aud),
issuer.jwks[0],
issuer.jwks_fed[0],
alg=issuer.default_signature_alg,
typ="entity-statement+jwt"
)
Expand Down Expand Up @@ -263,7 +263,7 @@ def trust_mark_as_json(self):
def trust_mark_as_jws(self):
return create_jws(
self.trust_mark_as_dict,
self.issuer.jwks[0],
self.issuer.jwks_fed[0],
alg=self.issuer.default_signature_alg,
typ="trust-mark+jwt"
)
Expand Down
6 changes: 4 additions & 2 deletions spid_cie_oidc/authority/tests/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@

rp_conf = {
"sub": rp_onboarding_data["sub"],
"jwks" : [RP_METADATA_JWK1],
"jwks_fed" : [RP_METADATA_JWK1],
"jwks_core" : [RP_METADATA_JWK1],
"metadata": {
"openid_relying_party": {
"application_type": "web",
Expand Down Expand Up @@ -61,7 +62,8 @@
"trust_marks": [],
"authority_hints": ["http://testserver/"],
"is_active": True,
"jwks": [INTERMEDIARY_JWK1]
"jwks_core": [INTERMEDIARY_JWK1],
"jwks_fed": [INTERMEDIARY_JWK1]
}
intermediary_onboarding_data = dict(
name="intermediary-test",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def test_fetch_endpoint(self):
url = reverse("oidcfed_fetch")
c = Client()
res = c.get(url, data={"sub": self.rp.sub})
data = verify_jws(res.content.decode(), self.ta_conf.jwks[0])
data = verify_jws(res.content.decode(), self.ta_conf.jwks_fed[0])
self.assertTrue(data["jwks"])

def test_list_endpoint(self):
Expand Down Expand Up @@ -253,7 +253,7 @@ def test_resolve_endpoint(self, mocked):
}
)
self.assertTrue(res.status_code == 200)
verify_jws(res.content.decode(), self.ta_conf.jwks[0])
verify_jws(res.content.decode(), self.ta_conf.jwks_fed[0])

def test_trust_mark_status_endpoint(self):
url = reverse("oidcfed_trust_mark_status")
Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/authority/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ def resolve_entity_statement(request, format: str = "jose"):
return JsonResponse(res, safe=False)
else:
return HttpResponse(
create_jws(res, iss.jwks[0]),
create_jws(res, iss.jwks_fed[0]),
content_type="application/jose",
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Generated by Django 4.0.3 on 2022-04-23 14:48

from django.db import migrations, models
import spid_cie_oidc.entity.models


class Migration(migrations.Migration):

dependencies = [
('spid_cie_oidc_entity', '0016_alter_trustchain_unique_together_and_more'),
]

operations = [
migrations.RemoveField(
model_name='federationentityconfiguration',
name='jwks',
),
migrations.AddField(
model_name='federationentityconfiguration',
name='jwks_core',
field=models.JSONField(default=spid_cie_oidc.entity.models.FederationEntityConfiguration._create_jwks, help_text='a list of private keys for Core ops'),
),
migrations.AddField(
model_name='federationentityconfiguration',
name='jwks_fed',
field=models.JSONField(default=spid_cie_oidc.entity.models.FederationEntityConfiguration._create_jwks, help_text='a list of private keys for Federation ops'),
),
]
29 changes: 17 additions & 12 deletions spid_cie_oidc/entity/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,16 @@ def _create_jwks():
help_text=_("only required if this Entity is an intermediary or leaf."),
default=list,
)
jwks = models.JSONField(
jwks_fed = models.JSONField(
blank=False,
null=False,
help_text=_("a list of private keys"),
help_text=_("a list of private keys for Federation ops"),
default=_create_jwks,
)
jwks_core = models.JSONField(
blank=False,
null=False,
help_text=_("a list of private keys for Core ops"),
default=_create_jwks,
)
trust_marks = models.JSONField(
Expand Down Expand Up @@ -162,7 +168,7 @@ def get_active_conf(cls):
@property
def public_jwks(self):
res = []
for i in self.jwks:
for i in self.jwks_fed:
skey = serialize_rsa_key(key_from_jwk_dict(i).public_key())
skey["kid"] = i["kid"]
res.append(skey)
Expand All @@ -171,7 +177,7 @@ def public_jwks(self):
@property
def pems_as_dict(self):
res = {}
for i in self.jwks:
for i in self.jwks_fed:
res[i["kid"]] = {
"private": private_pem_from_jwk(i),
"public": public_pem_from_jwk(i),
Expand All @@ -184,7 +190,7 @@ def pems_as_json(self):

@property
def kids(self) -> list:
return [i["kid"] for i in self.jwks]
return [i["kid"] for i in self.jwks_fed]

@property
def type(self) -> list:
Expand Down Expand Up @@ -230,7 +236,7 @@ def entity_configuration_as_json(self):
def entity_configuration_as_jws(self, **kwargs):
return create_jws(
self.entity_configuration_as_dict,
self.jwks[0],
self.jwks_fed[0],
alg=self.default_signature_alg,
typ="entity-statement+jwt",
**kwargs,
Expand All @@ -242,22 +248,21 @@ def save(self, *args, **kwargs):

if self.entity_type in ENTITY_TYPE_LEAFS:
valid_kids = set()
for jwk in self.jwks:
for jwk in self.jwks_fed:
valid_kids.add(jwk.get("kid", None))

for entity,metadata in self.metadata.items():
for oidc_jwk in metadata['jwks']['keys']:
if oidc_jwk['kid'] not in valid_kids:
logger.warning(
f"Found a public jwk in {entity} that haven't a valid "
f"jwk {oidc_jwk['kid']} in {self.jwks}."
f"jwk {oidc_jwk['kid']} in {self.jwks_fed}."
)




def __str__(self):
return "{} [{}]".format(self.sub, "active" if self.is_active else "--")
return "{} [{}]".format(
self.sub, "active" if self.is_active else "--"
)


class FetchedEntityStatement(TimeStampedModel):
Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/entity/tests/jwks_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
{
"kty": "EC",
"kid": "enc-ec256-0",
"kid": "enc-ec256-1",
"use": "enc",
"crv": "P-256",
"x": "QI31cvWP4GwnWIi-Z0IYHauQ4nPCk8Vf1BHoPazGqEc",
Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/entity/tests/op_metadata_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"userinfo_endpoint": "https://idserver.servizicie.interno.gov.it/op/userinfo",
"introspection_endpoint": "https://idserver.servizicie.interno.gov.it/op/introspect",
"revocation_endpoint": "https://idserver.servizicie.interno.gov.it/op/revoke",
"jwks_uri": "https://registry.cie.gov.it/.well-known/jwks.json",
"jwks_uri": "https://idserver.servizicie.interno.gov.it/.well-known/jwks.json",
"subject_types_supported": ["pairwise"],
"token_endpoint_auth_signing_alg_values_supported" : ["ES256"],
"id_token_encryption_alg_values_supported": ["RSA-OAEP"],
Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/entity/tests/test_01_entity_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@ def test_entity_configuration(self):
wk_url = reverse("entity_configuration")
c = Client()
res = c.get(wk_url)
verify_jws(res.content.decode(), self.ta_conf.jwks[0])
verify_jws(res.content.decode(), self.ta_conf.jwks_fed[0])
4 changes: 1 addition & 3 deletions spid_cie_oidc/entity/trust_chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,13 @@ def __init__(

self.tree_of_trust = OrderedDict()
self.trust_path = [] # list of valid subjects up to trust anchor

self.max_authority_hints = max_authority_hints

# dynamically valued
self.max_path_len = 0
self.final_metadata: dict = {}

self.verified_trust_marks = []

self.exp = 0

def apply_metadata_policy(self) -> dict:
Expand Down
3 changes: 2 additions & 1 deletion spid_cie_oidc/provider/tests/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"default_exp": 2880,
"default_signature_alg": "RS256",
"authority_hints": ["http://op-test/oidc/op/"],
"jwks": [op_conf_priv_jwk],
"jwks_fed": [op_conf_priv_jwk],
"jwks_core": [op_conf_priv_jwk],
"trust_marks": [],
"trust_marks_issuers": {},
"entity_type": "openid_provider",
Expand Down
1 change: 0 additions & 1 deletion spid_cie_oidc/provider/tests/test_03_refresh_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ class RefreshTokenTest(TestCase):

def setUp(self):
self.op_local_conf = deepcopy(op_conf)
self.op_local_conf["jwks"] = [op_conf_priv_jwk]
FederationEntityConfiguration.objects.create(**self.op_local_conf)
self.ta_fes = FetchedEntityStatement.objects.create(
sub=TA_SUB,
Expand Down
11 changes: 8 additions & 3 deletions spid_cie_oidc/provider/tests/test_04_userinfo_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ class UserInfoEndpointTest(TestCase):
def setUp(self):
self.RP_SUB = rp_onboarding_data["sub"]
self.op_local_conf = deepcopy(op_conf)
self.op_local_conf["jwks"] = [op_conf_priv_jwk]
FederationEntityConfiguration.objects.create(**self.op_local_conf)
self.ta_fes = FetchedEntityStatement.objects.create(
sub=TA_SUB,
Expand All @@ -39,10 +38,16 @@ def setUp(self):

def define_db(self):
session = OidcSession.objects.create(
user=User.objects.create(username = "username", attributes = {"email" : "test@test.it"}),
user=User.objects.create(
username = "username", attributes = {"email" : "test@test.it"}
),
user_uid="",
nonce="",
authz_request={"scope": "openid", "nonce": "123", "claims":{"userinfo":{"email": None}}},
authz_request={
"scope": "openid", "nonce": "123", "claims":{
"userinfo":{"email": None}
}
},
client_id=self.RP_SUB,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def setUp(self):
"iat": iat_now(),
"jti": "jti",
}
self.ca_jws = create_jws(CLIENT_ASSERTION, rp_conf["jwks"][0])
self.ca_jws = create_jws(CLIENT_ASSERTION, rp_conf["jwks_core"][0])
token = {
"iss": self.RP_SUB,
"sub": op_conf["sub"],
Expand All @@ -64,7 +64,6 @@ def setUp(self):
)
IssuedToken.objects.create(**iss_token_data)
self.op_local_conf = deepcopy(op_conf)
self.op_local_conf["jwks"] = [op_conf_priv_jwk]
FederationEntityConfiguration.objects.create(**self.op_local_conf)
self.ta_fes = FetchedEntityStatement.objects.create(
sub=TA_SUB,
Expand Down
1 change: 0 additions & 1 deletion spid_cie_oidc/provider/tests/test_08_token_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ class RefreshTokenTest(TestCase):

def setUp(self):
self.op_local_conf = deepcopy(op_conf)
self.op_local_conf["jwks"] = [op_conf_priv_jwk]
FederationEntityConfiguration.objects.create(**self.op_local_conf)
self.ta_fes = FetchedEntityStatement.objects.create(
sub=TA_SUB,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ def setUp(self):
iat=datetime_from_timestamp(iat_now()),
)
self.op_local_conf = deepcopy(op_conf)
self.op_local_conf["jwks"] = [op_conf_priv_jwk]
CLIENT_ASSERTION = {
"iss": RP_SUB,
"sub": RP_SUB,
Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/provider/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ def get_iss_token_data(self, session : OidcSession, issuer: FederationEntityConf
_sub = session.pairwised_sub()
iss_sub = issuer.sub
commons = self.get_jwt_common_data()
jwk = issuer.jwks[0]
jwk = issuer.jwks_core[0]

access_token = self.get_access_token(iss_sub, _sub, session, commons)
jwt_at = create_jws(access_token, jwk, typ="at+jwt")
Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/provider/views/userinfo_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def get(self, request, *args, **kwargs):
jwt[claim] = token.session.user.attributes[claim]

# sign the data
jws = create_jws(jwt, issuer.jwks[0])
jws = create_jws(jwt, issuer.jwks_core[0])

# encrypt the data
jwe = encrypt_dict(jws, rp_tc.metadata['openid_relying_party']["jwks"]["keys"][0])
Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/relying_party/oauth2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def access_token_request(
"exp": exp_from_now(),
"jti": str(uuid.uuid4()),
},
jwk_dict=client_conf.jwks[0],
jwk_dict=client_conf.jwks_core[0],
),
)

Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/relying_party/oidc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def get_userinfo(
jwe = authz_userinfo.content.decode()
header = unpad_jwt_head(jwe)
# header["kid"] kid di rp
rp_jwk = self.get_jwk(header["kid"], self.rp_conf.jwks)
rp_jwk = self.get_jwk(header["kid"], self.rp_conf.jwks_core)
jws = decrypt_jwe(jwe, rp_jwk)

header = unpad_jwt_head(jws)
Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/relying_party/tests/test_04_rp_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def setUp(self):
self.rp_config["sub"] = self.rp_config["metadata"]["openid_relying_party"]["client_id"]
FederationEntityConfiguration.objects.create(**self.rp_config)
rp_conf_saved = FederationEntityConfiguration.objects.all().first()
rp_conf_saved.metadata["openid_relying_party"]["jwks"]["keys"][0]["kid"] = rp_conf_saved.jwks[0]["kid"]
rp_conf_saved.metadata["openid_relying_party"]["jwks"]["keys"][0]["kid"] = rp_conf_saved.jwks_core[0]["kid"]
rp_conf_saved.save()
self.op_conf = FederationEntityConfiguration.objects.create(**op_conf)

Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/relying_party/views/rp_begin.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ def get(self, request, *args, **kwargs):
authz_data_obj["iss"] = client_conf["client_id"]
authz_data_obj["sub"] = client_conf["client_id"]

request_obj = create_jws(authz_data_obj, entity_conf.jwks[0])
request_obj = create_jws(authz_data_obj, entity_conf.jwks_core[0])
authz_data["request"] = request_obj
uri_path = http_dict_to_redirect_uri_path(
{
Expand Down
2 changes: 1 addition & 1 deletion spid_cie_oidc/relying_party/views/rp_initiated_logout.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def oidc_rpinitiated_logout(request):
"exp": exp_from_now(),
"jti": str(uuid.uuid4()),
},
jwk_dict=rp_conf.jwks[0],
jwk_dict=rp_conf.jwks_core[0],
)

auth_token.logged_out = timezone.localtime()
Expand Down

0 comments on commit fd71876

Please sign in to comment.