Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions fix-xsq.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
diff --git a/src/saml2/sigver.py b/src/saml2/sigver.py
index cbeca41f..c3d298a9 100644
--- a/src/saml2/sigver.py
+++ b/src/saml2/sigver.py
@@ -1476,6 +1476,55 @@ class SecurityContext(object):
if not certs:
raise MissingKey(_issuer)

+ # saml-core section "5.4 XML Signature Profile" defines constrains on the
+ # xmldsig-core facilities. It explicitly dictates that enveloped signatures
+ # are the only signatures allowed. This mean that:
+ # * Assertion/RequestType/ResponseType elements must have an ID attribute
+ # * signatures must have a single Reference element
+ # * the Reference element must have a URI attribute
+ # * the URI attribute contains an anchor
+ # * the anchor points to the enclosing element's ID attribute
+ references = item.signature.signed_info.reference
+ signatures_must_have_a_single_reference_element = len(references) == 1
+ the_Reference_element_must_have_a_URI_attribute = (
+ signatures_must_have_a_single_reference_element
+ and hasattr(references[0], "uri")
+ )
+ the_URI_attribute_contains_an_anchor = (
+ the_Reference_element_must_have_a_URI_attribute
+ and references[0].uri.startswith("#")
+ and len(references[0].uri) > 1
+ )
+ the_anchor_points_to_the_enclosing_element_ID_attribute = (
+ the_URI_attribute_contains_an_anchor
+ and references[0].uri == "#{id}".format(id=item.id)
+ )
+ validators = {
+ "signatures must have a single reference element": (
+ signatures_must_have_a_single_reference_element
+ ),
+ "the Reference element must have a URI attribute": (
+ the_Reference_element_must_have_a_URI_attribute
+ ),
+ "the URI attribute contains an anchor": (
+ the_URI_attribute_contains_an_anchor
+ ),
+ "the anchor points to the enclosing element ID attribute": (
+ the_anchor_points_to_the_enclosing_element_ID_attribute
+ ),
+ }
+ if not all(validators.values()):
+ error_context = {
+ "message": "Signature failed to meet constraints on xmldsig",
+ "validators": validators,
+ "item ID": item.id,
+ "reference URI": item.signature.signed_info.reference[0].uri,
+ "issuer": _issuer,
+ "node name": node_name,
+ "xml document": decoded_xml,
+ }
+ raise SignatureError(error_context)
+
verified = False
last_pem_file = None
2 changes: 0 additions & 2 deletions pyproject.toml

This file was deleted.

50 changes: 21 additions & 29 deletions src/saml2/attribute_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def list_to_local(acs, attrlist, allow_unknown_attributes=False):
continue

try:
key, val = _func(attr)
key, val = _func(attr, allow_unknown_attributes)
except KeyError:
if allow_unknown_attributes:
key, val = acs[0].lcd_ava_from(attr)
Expand Down Expand Up @@ -295,26 +295,17 @@ def fail_safe_fro(self, statement):
return result

def ava_from(self, attribute, allow_unknown=False):
try:
attr = self._fro[attribute.name.strip().lower()]
except AttributeError:
attr = attribute.friendly_name.strip().lower()
except KeyError:
if allow_unknown:
try:
attr = attribute.name.strip().lower()
except AttributeError:
attr = attribute.friendly_name.strip().lower()
else:
raise
attr = attribute.name.strip()
if not (attr.lower() in self._fro or allow_unknown):
raise

val = []
for value in attribute.attribute_value:
if value.extension_elements:
ext = extension_elements_to_elements(value.extension_elements,
[saml])
for ex in ext:
if attr == "eduPersonTargetedID" and ex.text:
if ex.text and (attr == "urn:oid:1.3.6.1.4.1.5923.1.1.1.10" or attr.lower() == "urn:mace:dir:attribute-def:edupersontargetedid"):
val.append(ex.text.strip())
else:
cval = {}
Expand Down Expand Up @@ -428,27 +419,28 @@ def to_(self, attrvals):
"""
attributes = []
for key, value in attrvals.items():
name = self._to.get(key.lower())
if name:
if name == "urn:oid:1.3.6.1.4.1.5923.1.1.1.10":
# special case for eduPersonTargetedID
attr_value = []
for v in value:
extension_element = ExtensionElement("NameID", NAMESPACE,
attributes={'Format': NAMEID_FORMAT_PERSISTENT}, text=v)
attrval = saml.AttributeValue(extension_elements=[extension_element])
attr_value.append(attrval)
else:
attr_value = do_ava(value)
if key == "urn:oid:1.3.6.1.4.1.5923.1.1.1.10" or key.lower() == "urn:mace:dir:attribute-def:edupersontargetedid":
# special case for eduPersonTargetedID
attr_value = []
for v in value:
extension_element = ExtensionElement("NameID", NAMESPACE,
attributes={'Format': NAMEID_FORMAT_PERSISTENT}, text=v)
attrval = saml.AttributeValue(extension_elements=[extension_element])
attr_value.append(attrval)
else:
attr_value = do_ava(value)

friendlyname = self._fro.get(key.lower())
if friendlyname:
attributes.append(factory(saml.Attribute,
name=name,
name=key,
name_format=self.name_format,
friendly_name=key,
friendly_name=friendlyname,
attribute_value=attr_value))
else:
attributes.append(factory(saml.Attribute,
name=key,
attribute_value=do_ava(value)))
attribute_value=attr_value))

return attributes

Expand Down
49 changes: 49 additions & 0 deletions src/saml2/sigver.py
Original file line number Diff line number Diff line change
Expand Up @@ -1492,6 +1492,55 @@ def _check_signature(self, decoded_xml, item, node_name=NODE_NAME, origdoc=None,
if not certs:
raise MissingKey(issuer)

# saml-core section "5.4 XML Signature Profile" defines constrains on the
# xmldsig-core facilities. It explicitly dictates that enveloped signatures
# are the only signatures allowed. This mean that:
# * Assertion/RequestType/ResponseType elements must have an ID attribute
# * signatures must have a single Reference element
# * the Reference element must have a URI attribute
# * the URI attribute contains an anchor
# * the anchor points to the enclosing element's ID attribute
references = item.signature.signed_info.reference
signatures_must_have_a_single_reference_element = len(references) == 1
the_Reference_element_must_have_a_URI_attribute = (
signatures_must_have_a_single_reference_element
and hasattr(references[0], "uri")
)
the_URI_attribute_contains_an_anchor = (
the_Reference_element_must_have_a_URI_attribute
and references[0].uri.startswith("#")
and len(references[0].uri) > 1
)
the_anchor_points_to_the_enclosing_element_ID_attribute = (
the_URI_attribute_contains_an_anchor
and references[0].uri == "#{id}".format(id=item.id)
)
validators = {
"signatures must have a single reference element": (
signatures_must_have_a_single_reference_element
),
"the Reference element must have a URI attribute": (
the_Reference_element_must_have_a_URI_attribute
),
"the URI attribute contains an anchor": (
the_URI_attribute_contains_an_anchor
),
"the anchor points to the enclosing element ID attribute": (
the_anchor_points_to_the_enclosing_element_ID_attribute
),
}
if not all(validators.values()):
error_context = {
"message": "Signature failed to meet constraints on xmldsig",
"validators": validators,
"item ID": item.id,
"reference URI": item.signature.signed_info.reference[0].uri,
"issuer": _issuer,
"node name": node_name,
"xml document": decoded_xml,
}
raise SignatureError(error_context)

verified = False
last_pem_file = None

Expand Down
Loading