From 74b052f55ead3f711c9b346d1dc7564d6023d5a1 Mon Sep 17 00:00:00 2001 From: Johan Lundberg Date: Fri, 9 Dec 2022 11:11:08 +0100 Subject: add ability to get required subject id as a RequestedAttribute dict --- src/saml2/mdstore.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/saml2/mdstore.py b/src/saml2/mdstore.py index b2bae0a7..7519a20e 100644 --- a/src/saml2/mdstore.py +++ b/src/saml2/mdstore.py @@ -418,6 +418,17 @@ class MetaData: """ raise NotImplementedError + def subject_id_requirement(self, entity_id): + """ + Returns what subject identifier the SP requires if any + + :param entity_id: The entity id of the SP + :type entity_id: str + :return: RequestedAttribute dict or None + :rtype: Optional[dict] + """ + raise NotImplementedError + def dumps(self): return json.dumps(list(self.items()), indent=2) @@ -1290,6 +1301,32 @@ class MetadataStore(MetaData): if entity_id in _md: return _md.attribute_requirement(entity_id, index) + def subject_id_requirement(self, entity_id): + try: + entity_attributes = self.entity_attributes(entity_id) + except KeyError: + return None + + if "urn:oasis:names:tc:SAML:profiles:subject-id:req" in entity_attributes: + subject_id_req = entity_attributes["urn:oasis:names:tc:SAML:profiles:subject-id:req"][0] + if subject_id_req == "any" or subject_id_req == "pairwise-id": + return { + "__class__": "urn:oasis:names:tc:SAML:2.0:metadata&RequestedAttribute", + "name": "urn:oasis:names:tc:SAML:attribute:pairwise-id", + "name_format": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri", + "friendly_name": "pairwise-id", + "is_required": "true", + } + elif subject_id_req == "subject-id": + return { + "__class__": "urn:oasis:names:tc:SAML:2.0:metadata&RequestedAttribute", + "name": "urn:oasis:names:tc:SAML:attribute:subject-id", + "name_format": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri", + "friendly_name": "subject-id", + "is_required": "true", + } + return None + def keys(self): res = [] for _md in self.metadata.values(): -- cgit v1.2.1 From 5eb48c3f6c82889c6a3f8b950ac9848600dc5380 Mon Sep 17 00:00:00 2001 From: Johan Lundberg Date: Fri, 9 Dec 2022 11:11:53 +0100 Subject: add requested subject id to SPs requested attributes --- src/saml2/assertion.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/saml2/assertion.py b/src/saml2/assertion.py index 53f917be..4df0cf3c 100644 --- a/src/saml2/assertion.py +++ b/src/saml2/assertion.py @@ -556,11 +556,16 @@ class Policy: metadata_store = metadata or self.metadata_store spec = metadata_store.attribute_requirement(sp_entity_id) or {} if metadata_store else {} + required_attributes = spec.get("required", []) + optional_attributes = spec.get("optional", []) + required_subject_id = metadata_store.subject_id_requirement(sp_entity_id) if metadata_store else None + if required_subject_id: + required_attributes.append(required_subject_id) return self.filter( ava, sp_entity_id, - required=spec.get("required"), - optional=spec.get("optional"), + required=required_attributes or None, + optional=optional_attributes or None, ) def conditions(self, sp_entity_id): -- cgit v1.2.1 From 8185902f9f5db8f85bcc6f3362ebdee2ae595ba4 Mon Sep 17 00:00:00 2001 From: Johan Lundberg Date: Fri, 9 Dec 2022 11:12:19 +0100 Subject: add test for requested subject id --- tests/entity_esi_and_coco_sp.xml | 5 ++++- tests/test_30_mdstore.py | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/entity_esi_and_coco_sp.xml b/tests/entity_esi_and_coco_sp.xml index a076535b..f4e0ccbb 100644 --- a/tests/entity_esi_and_coco_sp.xml +++ b/tests/entity_esi_and_coco_sp.xml @@ -7,6 +7,9 @@ https://myacademicid.org/entity-categories/esi http://www.geant.net/uri/dataprotection-code-of-conduct/v1 + + any + @@ -65,7 +68,7 @@ wHyaxzYldWmVC5omkgZeAdCGpJ316GQF8Zwg/yDOUzm4cvGeIESf1Q6ZxBwI6zGE - + esi-coco-SP ESI and COCO SP diff --git a/tests/test_30_mdstore.py b/tests/test_30_mdstore.py index 1c67a701..013a6062 100644 --- a/tests/test_30_mdstore.py +++ b/tests/test_30_mdstore.py @@ -189,6 +189,12 @@ METADATACONF = { "metadata": [(full_path("empty_metadata_file.xml"),)], } ], + "17": [ + { + "class": "saml2.mdstore.MetaDataFile", + "metadata": [(full_path("entity_esi_and_coco_sp.xml"),)], + } + ], } @@ -654,6 +660,17 @@ def test_registration_info_no_policy(): assert registration_info["registration_policy"] == {} +def test_subject_id_requirement(): + mds = MetadataStore(ATTRCONV, sec_config, disable_ssl_certificate_validation=True) + mds.imp(METADATACONF["17"]) + required_subject_id = mds.subject_id_requirement(entity_id="https://esi-coco.example.edu/saml2/metadata/") + assert required_subject_id["__class__"] == "urn:oasis:names:tc:SAML:2.0:metadata&RequestedAttribute" + assert required_subject_id["name"] == "urn:oasis:names:tc:SAML:attribute:pairwise-id" + assert required_subject_id["name_format"] == "urn:oasis:names:tc:SAML:2.0:attrname-format:uri" + assert required_subject_id["friendly_name"] == "pairwise-id" + assert required_subject_id["is_required"] == "true" + + def test_extension(): mds = MetadataStore(ATTRCONV, None) # use ordered dict to force expected entity to be last -- cgit v1.2.1 From bc8440650cafb9a7273c26f2489720f95cb89ada Mon Sep 17 00:00:00 2001 From: Johan Lundberg Date: Fri, 9 Dec 2022 11:12:30 +0100 Subject: cleanup --- tests/entity_personalized_sp.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/entity_personalized_sp.xml b/tests/entity_personalized_sp.xml index a6bfb46b..aa48693a 100644 --- a/tests/entity_personalized_sp.xml +++ b/tests/entity_personalized_sp.xml @@ -64,7 +64,6 @@ wHyaxzYldWmVC5omkgZeAdCGpJ316GQF8Zwg/yDOUzm4cvGeIESf1Q6ZxBwI6zGE - personalized-SP refeds personalized access SP -- cgit v1.2.1 From 5bd9ec44e7fbfd7017ac9762b2e97d1e31db9368 Mon Sep 17 00:00:00 2001 From: Johan Lundberg Date: Fri, 9 Dec 2022 11:38:15 +0100 Subject: do not add a duplicate attribute request for subject id --- src/saml2/assertion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/saml2/assertion.py b/src/saml2/assertion.py index 4df0cf3c..46733f93 100644 --- a/src/saml2/assertion.py +++ b/src/saml2/assertion.py @@ -559,7 +559,7 @@ class Policy: required_attributes = spec.get("required", []) optional_attributes = spec.get("optional", []) required_subject_id = metadata_store.subject_id_requirement(sp_entity_id) if metadata_store else None - if required_subject_id: + if required_subject_id and required_subject_id not in required_attributes: required_attributes.append(required_subject_id) return self.filter( ava, -- cgit v1.2.1