summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Kanakarakis <ivan.kanak@gmail.com>2022-08-10 13:16:43 +0300
committerIvan Kanakarakis <ivan.kanak@gmail.com>2022-08-10 13:16:50 +0300
commit63fca12502acc76bc5f01be6abb16a9de8430629 (patch)
tree9255a1ef0e44482cece1724fc4ffa899e60fccf3
parent14c649a9f3f68f5d95cd0b9c53e011bfd6ed8485 (diff)
downloadpysaml2-63fca12502acc76bc5f01be6abb16a9de8430629.tar.gz
Include eIDAS definitation in the validator - expose saml2.xml.schema:validate
Signed-off-by: Ivan Kanakarakis <ivan.kanak@gmail.com>
-rw-r--r--src/saml2/sigver.py16
-rw-r--r--src/saml2/xml/schema/__init__.py118
2 files changed, 68 insertions, 66 deletions
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