Skip to content

Commit 63fca12

Browse files
committed
Include eIDAS definitation in the validator - expose saml2.xml.schema:validate
Signed-off-by: Ivan Kanakarakis <[email protected]>
1 parent 14c649a commit 63fca12

File tree

2 files changed

+68
-66
lines changed

2 files changed

+68
-66
lines changed

src/saml2/sigver.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
from saml2.xmlenc import CipherData
6666
from saml2.xmlenc import CipherValue
6767
from saml2.xmlenc import EncryptedData
68-
from saml2.xml.schema import node_to_schema
68+
from saml2.xml.schema import validate as validate_doc_with_schema
6969
from saml2.xml.schema import XMLSchemaError
7070

7171

@@ -1427,20 +1427,8 @@ def _check_signature(self, decoded_xml, item, node_name=NODE_NAME, origdoc=None,
14271427
if not certs:
14281428
raise MissingKey(_issuer)
14291429

1430-
# validate XML with the appropriate schema
14311430
try:
1432-
_schema = node_to_schema[node_name]
1433-
except KeyError as e:
1434-
error_context = {
1435-
"message": "Signature verification failed. Unknown node type.",
1436-
"issuer": _issuer,
1437-
"type": node_name,
1438-
"document": decoded_xml,
1439-
}
1440-
raise SignatureError(error_context) from e
1441-
1442-
try:
1443-
_schema.validate(str(item))
1431+
validate_doc_with_schema(str(item))
14441432
except XMLSchemaError as e:
14451433
error_context = {
14461434
"message": "Signature verification failed. Invalid document format.",

src/saml2/xml/schema/__init__.py

Lines changed: 66 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -8,71 +8,85 @@
88
from importlib_resources import files as _resource_files
99

1010
from xmlschema import XMLSchema as _XMLSchema
11-
from xmlschema.exceptions import XMLSchemaException as XMLSchemaError
11+
from xmlschema.exceptions import XMLSchemaException as _XMLSchemaException
1212

1313
import saml2.data.schemas as _data_schemas
1414

1515

16-
def _create_xml_schema_validator(source, **kwargs):
16+
class XMLSchemaError(Exception):
17+
"""Generic error raised when the schema does not validate with a document"""
18+
19+
20+
def _create_xml_schema_validator(source=None, **kwargs):
21+
schema_resources = _resource_files(_data_schemas)
22+
path_schema_xml = str(schema_resources.joinpath("xml.xsd"))
23+
path_schema_envelope = str(schema_resources.joinpath("envelope.xsd"))
24+
path_schema_xenc = str(schema_resources.joinpath("xenc-schema.xsd"))
25+
path_schema_xmldsig_core = str(schema_resources.joinpath("xmldsig-core-schema.xsd"))
26+
path_schema_saml_assertion = str(
27+
schema_resources.joinpath("saml-schema-assertion-2.0.xsd")
28+
)
29+
path_schema_saml_metadata = str(
30+
schema_resources.joinpath("saml-schema-metadata-2.0.xsd")
31+
)
32+
path_schema_saml_protocol = str(
33+
schema_resources.joinpath("saml-schema-protocol-2.0.xsd")
34+
)
35+
path_schema_eidas_metadata_servicelist= str(
36+
schema_resources.joinpath("eidas-schema-metadata-servicelist.xsd")
37+
)
38+
path_schema_eidas_saml_extensions = str(
39+
schema_resources.joinpath("eidas-schema-saml-extensions.xsd")
40+
)
41+
path_schema_eidas_attribute_naturalperson = str(
42+
schema_resources.joinpath("eidas-schema-attribute-naturalperson.xsd")
43+
)
44+
path_schema_eidas_attribute_legalperson = str(
45+
schema_resources.joinpath("eidas-schema-attribute-legalperson.xsd")
46+
)
47+
48+
source = source if source else path_schema_saml_protocol
49+
locations = {
50+
"http://www.w3.org/XML/1998/namespace": path_schema_xml,
51+
"http://schemas.xmlsoap.org/soap/envelope/": path_schema_envelope,
52+
"http://www.w3.org/2001/04/xmlenc#": path_schema_xenc,
53+
"http://www.w3.org/2000/09/xmldsig#": path_schema_xmldsig_core,
54+
"urn:oasis:names:tc:SAML:2.0:assertion": path_schema_saml_assertion,
55+
"urn:oasis:names:tc:SAML:2.0:metadata": path_schema_saml_metadata,
56+
"urn:oasis:names:tc:SAML:2.0:protocol": path_schema_saml_protocol,
57+
"http://eidas.europa.eu/metadata/servicelist": path_schema_eidas_metadata_servicelist,
58+
"http://eidas.europa.eu/saml-extensions": path_schema_eidas_saml_extensions,
59+
"http://eidas.europa.eu/attributes/naturalperson": path_schema_eidas_attribute_naturalperson,
60+
"http://eidas.europa.eu/attributes/legalperson": path_schema_eidas_attribute_legalperson,
61+
}
62+
1763
kwargs = {
1864
**kwargs,
1965
"validation": "strict",
20-
"locations": _locations,
66+
"locations": locations,
2167
"base_url": source,
2268
"allow": "sandbox",
2369
"use_fallback": False,
2470
}
2571
return _XMLSchema(source, **kwargs)
2672

2773

28-
_schema_resources = _resource_files(_data_schemas)
29-
_path_schema_xml = str(_schema_resources.joinpath("xml.xsd"))
30-
_path_schema_envelope = str(_schema_resources.joinpath("envelope.xsd"))
31-
_path_schema_xenc = str(_schema_resources.joinpath("xenc-schema.xsd"))
32-
_path_schema_xmldsig_core = str(_schema_resources.joinpath("xmldsig-core-schema.xsd"))
33-
_path_schema_saml_assertion = str(
34-
_schema_resources.joinpath("saml-schema-assertion-2.0.xsd")
35-
)
36-
_path_schema_saml_metadata = str(
37-
_schema_resources.joinpath("saml-schema-metadata-2.0.xsd")
38-
)
39-
_path_schema_saml_protocol = str(
40-
_schema_resources.joinpath("saml-schema-protocol-2.0.xsd")
41-
)
42-
43-
_locations = {
44-
"http://www.w3.org/XML/1998/namespace": _path_schema_xml,
45-
"http://schemas.xmlsoap.org/soap/envelope/": _path_schema_envelope,
46-
"http://www.w3.org/2001/04/xmlenc#": _path_schema_xenc,
47-
"http://www.w3.org/2000/09/xmldsig#": _path_schema_xmldsig_core,
48-
"urn:oasis:names:tc:SAML:2.0:assertion": _path_schema_saml_assertion,
49-
"urn:oasis:names:tc:SAML:2.0:metadata": _path_schema_saml_metadata,
50-
"urn:oasis:names:tc:SAML:2.0:protocol": _path_schema_saml_protocol,
51-
}
74+
_schema_validator_default = _create_xml_schema_validator()
5275

53-
schema_saml_assertion = _create_xml_schema_validator(_path_schema_saml_assertion)
54-
schema_saml_metadata = _create_xml_schema_validator(_path_schema_saml_metadata)
55-
schema_saml_protocol = _create_xml_schema_validator(_path_schema_saml_protocol)
5676

57-
node_to_schema = {
58-
# AssertionType
59-
"urn:oasis:names:tc:SAML:2.0:assertion:Assertion": schema_saml_assertion,
60-
# EntitiesDescriptorType
61-
"urn:oasis:names:tc:SAML:2.0:metadata:EntitiesDescriptor": schema_saml_metadata,
62-
# EntityDescriptorType
63-
"urn:oasis:names:tc:SAML:2.0:metadata:EntityDescriptor": schema_saml_metadata,
64-
# RequestAbstractType
65-
"urn:oasis:names:tc:SAML:2.0:protocol:AssertionIDRequest": schema_saml_protocol,
66-
"urn:oasis:names:tc:SAML:2.0:protocol:SubjectQuery": schema_saml_protocol,
67-
"urn:oasis:names:tc:SAML:2.0:protocol:AuthnRequest": schema_saml_protocol,
68-
"urn:oasis:names:tc:SAML:2.0:protocol:ArtifactResolve": schema_saml_protocol,
69-
"urn:oasis:names:tc:SAML:2.0:protocol:ManageNameIDRequest": schema_saml_protocol,
70-
"urn:oasis:names:tc:SAML:2.0:protocol:LogoutRequest": schema_saml_protocol,
71-
"urn:oasis:names:tc:SAML:2.0:protocol:NameIDMappingRequest": schema_saml_protocol,
72-
# StatusResponseType
73-
"urn:oasis:names:tc:SAML:2.0:protocol:Response": schema_saml_protocol,
74-
"urn:oasis:names:tc:SAML:2.0:protocol:ArtifactResponse": schema_saml_protocol,
75-
"urn:oasis:names:tc:SAML:2.0:protocol:ManageNameIDResponse": schema_saml_protocol,
76-
"urn:oasis:names:tc:SAML:2.0:protocol:LogoutResponse": schema_saml_protocol,
77-
"urn:oasis:names:tc:SAML:2.0:protocol:NameIDMappingResponse": schema_saml_protocol,
78-
}
77+
def validate(doc, validator=None):
78+
validator = _schema_validator_default if validator is None else validator
79+
try:
80+
validator.validate(doc)
81+
except _XMLSchemaException as e:
82+
error_context = {
83+
"doc": doc,
84+
"error": str(e),
85+
}
86+
raise XMLSchemaError(error_context) from e
87+
except Exception as e:
88+
error_context = {
89+
"doc": doc,
90+
"error": str(e),
91+
}
92+
raise XMLSchemaError(error_context) from e

0 commit comments

Comments
 (0)