diff --git a/src/pyff/constants.py b/src/pyff/constants.py index 083ec32f..5ec86106 100644 --- a/src/pyff/constants.py +++ b/src/pyff/constants.py @@ -36,6 +36,7 @@ xsi="http://www.w3.org/2001/XMLSchema-instance", ser="http://eidas.europa.eu/metadata/servicelist", eidas="http://eidas.europa.eu/saml-extensions", + ti="http://seamlessaccess.org/NS/trust-info", ) #: These are the attribute aliases pyFF knows about. These are used to build URI paths, populate the index diff --git a/src/pyff/samlmd.py b/src/pyff/samlmd.py index 0b07a236..6ba7d864 100644 --- a/src/pyff/samlmd.py +++ b/src/pyff/samlmd.py @@ -4,7 +4,8 @@ from distutils.util import strtobool from io import BytesIO from itertools import chain -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Optional, Union, Tuple +from xmlrpc.client import boolean from lxml import etree from lxml.builder import ElementMaker @@ -760,7 +761,6 @@ def entity_display_name(entity: Element, langs=None) -> str: return entity.get('entityID').strip() - def sub_domains(e): lst = [] domains = entity_domains(e) @@ -777,6 +777,43 @@ def entity_scopes(e): return None return [s.text for s in elt] +def entity_trust_resolve_trusted_entities(elt:Element) -> Tuple[set, bool]: + return set([e['entityID'] for e in elt.findall(elt['select'])]), elt['include'].lower() not in ['false','off','0'] + +def entity_trust_profile_trusted_entities(elt:Element) -> set: + t = set([e.text for e in elt.findall('.//{%s}TrustedEntity' % NS['ti'])]) + for e in elt.findall('.//{%s}TrustedEntities'% NS['ti']): + s,inc = entity_trust_resolve_trusted_entities(e) + if inc: + t.update(s) + else: + t.difference_update(s) + return t + +def entity_trust_profile(e:Element) -> dict: + return dict( + name = e['name'], + strict = e['strict'], + display_name_langs=lang_dict(e.findall('.//{%s}DisplayName', NS['ti']), lambda e: e.text), + trusted_entities=[ + dict(include=elt['include'].lower() not in ['false','off','0'], match=elt['match'], value=elt.text) + for elt in e.findall('.//{%s}TrustedEntity' % NS['ti']) + ] + ) + +def entity_trust_info(e: Element) -> dict: + elt = e.findall('.//{%s}SPSSODescriptor/{%s}Extensions/{%s}/TrustInfo' % (NS['md'], NS['md'],NS['ti'])) + if elt is None or len(elt) != 1: + return None + elt = elt[0] + d = dict( + metadata_source=[e.text for e in elt.findall('.//{%s}MetadataSource' % NS['ti'])], + trust_profile=[entity_trust_profile(e) for e in elt.findall('.//{%s}TrustProfile' % NS['ti'])], + ) + fallback_handler = [e.text for e in elt.findall('.//{%s}FallbackHandler' % NS['ti'])] + if len(fallback_handler) == 1: + d['fallback_handler'] = fallback_handler[0] + return d def discojson(e, langs=None, fallback_to_favicon=False, icon_store=None): if e is None: @@ -832,6 +869,8 @@ def discojson(e, langs=None, fallback_to_favicon=False, icon_store=None): if geo: d['geo'] = geo + d['trust_info'] = entity_trust_info(e) + return d diff --git a/src/pyff/test/data/metadata/swamid-2.0-test.xml b/src/pyff/test/data/metadata/swamid-2.0-test.xml index 499dfe4c..21b3b560 100644 --- a/src/pyff/test/data/metadata/swamid-2.0-test.xml +++ b/src/pyff/test/data/metadata/swamid-2.0-test.xml @@ -1,6 +1,19 @@ - + + + + + + http://rr.aai.switch.ch/ + + + + + https://idp.nordu.net/idp/shibboleth + + + @@ -11550,6 +11563,12 @@ GImnaeS4 + + + https://idp.nordu.net/idp/shibboleth + http://refeds.org/category/research-and-scholarship + + http://www.swamid.se/category/sfs-1993-1153