From 63fca12502acc76bc5f01be6abb16a9de8430629 Mon Sep 17 00:00:00 2001 From: Ivan Kanakarakis Date: Wed, 10 Aug 2022 13:16:43 +0300 Subject: Include eIDAS definitation in the validator - expose saml2.xml.schema:validate Signed-off-by: Ivan Kanakarakis --- src/saml2/sigver.py | 16 +----- src/saml2/xml/schema/__init__.py | 118 ++++++++++++++++++++++----------------- 2 files changed, 68 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/saml2/sigver.py b/src/saml2/sigver.py index 79e23d4f..a5295fa5 100644 --- a/src/saml2/sigver.py +++ b/src/saml2/sigver.py @@ -65,7 +65,7 @@ from saml2.xmlenc import EncryptedKey from saml2.xmlenc import CipherData from saml2.xmlenc import CipherValue from saml2.xmlenc import EncryptedData -from saml2.xml.schema import node_to_schema +from saml2.xml.schema import validate as validate_doc_with_schema from saml2.xml.schema import XMLSchemaError @@ -1427,20 +1427,8 @@ class SecurityContext(object): if not certs: raise MissingKey(_issuer) - # validate XML with the appropriate schema try: - _schema = node_to_schema[node_name] - except KeyError as e: - error_context = { - "message": "Signature verification failed. Unknown node type.", - "issuer": _issuer, - "type": node_name, - "document": decoded_xml, - } - raise SignatureError(error_context) from e - - try: - _schema.validate(str(item)) + validate_doc_with_schema(str(item)) except XMLSchemaError as e: error_context = { "message": "Signature verification failed. Invalid document format.", diff --git a/src/saml2/xml/schema/__init__.py b/src/saml2/xml/schema/__init__.py index 5ef5a8e8..6bbac2ef 100644 --- a/src/saml2/xml/schema/__init__.py +++ b/src/saml2/xml/schema/__init__.py @@ -8,16 +8,62 @@ else: from importlib_resources import files as _resource_files from xmlschema import XMLSchema as _XMLSchema -from xmlschema.exceptions import XMLSchemaException as XMLSchemaError +from xmlschema.exceptions import XMLSchemaException as _XMLSchemaException import saml2.data.schemas as _data_schemas -def _create_xml_schema_validator(source, **kwargs): +class XMLSchemaError(Exception): + """Generic error raised when the schema does not validate with a document""" + + +def _create_xml_schema_validator(source=None, **kwargs): + schema_resources = _resource_files(_data_schemas) + path_schema_xml = str(schema_resources.joinpath("xml.xsd")) + path_schema_envelope = str(schema_resources.joinpath("envelope.xsd")) + path_schema_xenc = str(schema_resources.joinpath("xenc-schema.xsd")) + path_schema_xmldsig_core = str(schema_resources.joinpath("xmldsig-core-schema.xsd")) + path_schema_saml_assertion = str( + schema_resources.joinpath("saml-schema-assertion-2.0.xsd") + ) + path_schema_saml_metadata = str( + schema_resources.joinpath("saml-schema-metadata-2.0.xsd") + ) + path_schema_saml_protocol = str( + schema_resources.joinpath("saml-schema-protocol-2.0.xsd") + ) + path_schema_eidas_metadata_servicelist= str( + schema_resources.joinpath("eidas-schema-metadata-servicelist.xsd") + ) + path_schema_eidas_saml_extensions = str( + schema_resources.joinpath("eidas-schema-saml-extensions.xsd") + ) + path_schema_eidas_attribute_naturalperson = str( + schema_resources.joinpath("eidas-schema-attribute-naturalperson.xsd") + ) + path_schema_eidas_attribute_legalperson = str( + schema_resources.joinpath("eidas-schema-attribute-legalperson.xsd") + ) + + source = source if source else path_schema_saml_protocol + locations = { + "http://www.w3.org/XML/1998/namespace": path_schema_xml, + "http://schemas.xmlsoap.org/soap/envelope/": path_schema_envelope, + "http://www.w3.org/2001/04/xmlenc#": path_schema_xenc, + "http://www.w3.org/2000/09/xmldsig#": path_schema_xmldsig_core, + "urn:oasis:names:tc:SAML:2.0:assertion": path_schema_saml_assertion, + "urn:oasis:names:tc:SAML:2.0:metadata": path_schema_saml_metadata, + "urn:oasis:names:tc:SAML:2.0:protocol": path_schema_saml_protocol, + "http://eidas.europa.eu/metadata/servicelist": path_schema_eidas_metadata_servicelist, + "http://eidas.europa.eu/saml-extensions": path_schema_eidas_saml_extensions, + "http://eidas.europa.eu/attributes/naturalperson": path_schema_eidas_attribute_naturalperson, + "http://eidas.europa.eu/attributes/legalperson": path_schema_eidas_attribute_legalperson, + } + kwargs = { **kwargs, "validation": "strict", - "locations": _locations, + "locations": locations, "base_url": source, "allow": "sandbox", "use_fallback": False, @@ -25,54 +71,22 @@ def _create_xml_schema_validator(source, **kwargs): return _XMLSchema(source, **kwargs) -_schema_resources = _resource_files(_data_schemas) -_path_schema_xml = str(_schema_resources.joinpath("xml.xsd")) -_path_schema_envelope = str(_schema_resources.joinpath("envelope.xsd")) -_path_schema_xenc = str(_schema_resources.joinpath("xenc-schema.xsd")) -_path_schema_xmldsig_core = str(_schema_resources.joinpath("xmldsig-core-schema.xsd")) -_path_schema_saml_assertion = str( - _schema_resources.joinpath("saml-schema-assertion-2.0.xsd") -) -_path_schema_saml_metadata = str( - _schema_resources.joinpath("saml-schema-metadata-2.0.xsd") -) -_path_schema_saml_protocol = str( - _schema_resources.joinpath("saml-schema-protocol-2.0.xsd") -) - -_locations = { - "http://www.w3.org/XML/1998/namespace": _path_schema_xml, - "http://schemas.xmlsoap.org/soap/envelope/": _path_schema_envelope, - "http://www.w3.org/2001/04/xmlenc#": _path_schema_xenc, - "http://www.w3.org/2000/09/xmldsig#": _path_schema_xmldsig_core, - "urn:oasis:names:tc:SAML:2.0:assertion": _path_schema_saml_assertion, - "urn:oasis:names:tc:SAML:2.0:metadata": _path_schema_saml_metadata, - "urn:oasis:names:tc:SAML:2.0:protocol": _path_schema_saml_protocol, -} +_schema_validator_default = _create_xml_schema_validator() -schema_saml_assertion = _create_xml_schema_validator(_path_schema_saml_assertion) -schema_saml_metadata = _create_xml_schema_validator(_path_schema_saml_metadata) -schema_saml_protocol = _create_xml_schema_validator(_path_schema_saml_protocol) -node_to_schema = { - # AssertionType - "urn:oasis:names:tc:SAML:2.0:assertion:Assertion": schema_saml_assertion, - # EntitiesDescriptorType - "urn:oasis:names:tc:SAML:2.0:metadata:EntitiesDescriptor": schema_saml_metadata, - # EntityDescriptorType - "urn:oasis:names:tc:SAML:2.0:metadata:EntityDescriptor": schema_saml_metadata, - # RequestAbstractType - "urn:oasis:names:tc:SAML:2.0:protocol:AssertionIDRequest": schema_saml_protocol, - "urn:oasis:names:tc:SAML:2.0:protocol:SubjectQuery": schema_saml_protocol, - "urn:oasis:names:tc:SAML:2.0:protocol:AuthnRequest": schema_saml_protocol, - "urn:oasis:names:tc:SAML:2.0:protocol:ArtifactResolve": schema_saml_protocol, - "urn:oasis:names:tc:SAML:2.0:protocol:ManageNameIDRequest": schema_saml_protocol, - "urn:oasis:names:tc:SAML:2.0:protocol:LogoutRequest": schema_saml_protocol, - "urn:oasis:names:tc:SAML:2.0:protocol:NameIDMappingRequest": schema_saml_protocol, - # StatusResponseType - "urn:oasis:names:tc:SAML:2.0:protocol:Response": schema_saml_protocol, - "urn:oasis:names:tc:SAML:2.0:protocol:ArtifactResponse": schema_saml_protocol, - "urn:oasis:names:tc:SAML:2.0:protocol:ManageNameIDResponse": schema_saml_protocol, - "urn:oasis:names:tc:SAML:2.0:protocol:LogoutResponse": schema_saml_protocol, - "urn:oasis:names:tc:SAML:2.0:protocol:NameIDMappingResponse": schema_saml_protocol, -} +def validate(doc, validator=None): + validator = _schema_validator_default if validator is None else validator + try: + validator.validate(doc) + except _XMLSchemaException as e: + error_context = { + "doc": doc, + "error": str(e), + } + raise XMLSchemaError(error_context) from e + except Exception as e: + error_context = { + "doc": doc, + "error": str(e), + } + raise XMLSchemaError(error_context) from e -- cgit v1.2.1