I recently encountered an issue with SAML metadata validation from a customer.
The relevant part of metadata that is failing:
<IDPSSODescriptor protocolSupportEnumeration="urn:mace:shibboleth:1.0 urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol">
<Extensions>
<shibmd:Scope regexp="false">...</shibmd:Scope>
</Extensions>
<KeyDescriptor>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
...
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
<ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding" Location="..." index="1"/>
<ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="..." index="2"/>
<SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="..."/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="..."/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="..."/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="h..."/>
<NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
</IDPSSODescriptor>
This fails with the folowing error:
cvc-complex-type.2.4.a: Invalid content was found starting with element 'NameIDFormat'. One of '{"urn:oasis:names:tc:SAML:2.0:metadata":SingleSignOnService, "urn:oasis:names:tc:SAML:2.0:metadata":NameIDMappingService, "urn:oasis:names:tc:SAML:2.0:metadata":AssertionIDRequestService, "urn:oasis:names:tc:SAML:2.0:metadata":AttributeProfile, "urn:oasis:names:tc:SAML:2.0:assertion":Attribute}' is expected.
The following is the relevant portion of saml-schema-metadata-2.0.xsd
:
<complexType name="SSODescriptorType" abstract="true">
<complexContent>
<extension base="md:RoleDescriptorType">
<sequence>
<element ref="md:ArtifactResolutionService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:SingleLogoutService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:ManageNameIDService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:NameIDFormat" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="ArtifactResolutionService" type="md:IndexedEndpointType"/>
<element name="SingleLogoutService" type="md:EndpointType"/>
<element name="ManageNameIDService" type="md:EndpointType"/>
<element name="NameIDFormat" type="anyURI"/>
<element name="IDPSSODescriptor" type="md:IDPSSODescriptorType"/>
<complexType name="IDPSSODescriptorType">
<complexContent>
<extension base="md:SSODescriptorType">
<sequence>
<element ref="md:SingleSignOnService" maxOccurs="unbounded"/>
<element ref="md:NameIDMappingService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:AssertionIDRequestService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:AttributeProfile" minOccurs="0" maxOccurs="unbounded"/>
<element ref="saml:Attribute" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="WantAuthnRequestsSigned" type="boolean" use="optional"/>
</extension>
</complexContent>
</complexType>
<element name="SingleSignOnService" type="md:EndpointType"/>
<element name="NameIDMappingService" type="md:EndpointType"/>
<element name="AssertionIDRequestService" type="md:EndpointType"/>
<element name="AttributeProfile" type="anyURI"/>
I notice that the error message only specifies elements from the IDPSSODescriptorType
and not the base SSODescriptorType
. Maybe that's by design?
Regardless, I receive no errors for ArtifactResolutionService
which also happens to be define in the base type.
In fact, if I move <element ref="md:NameIDFormat" minOccurs="0" maxOccurs="unbounded"/>
in the schema file from the base SSODescriptorType
to the IDPSSODescriptorType
, and leave everything else, the metadata file passes validation.
I'm using Java 8 with the default implementation of javax.xml.validation.*
private static String[] schemas = {
"/schema/xml.xsd",
"/schema/XMLSchema.xsd",
"/schema/xmldsig-core-schema.xsd",
"/schema/xenc-schema.xsd",
"/schema/saml-schema-assertion-2.0.xsd",
"/schema/saml-schema-metadata-2.0.xsd",
};
public boolean validateXMLSchema(Document document) {
try {
SchemaFactory factory =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(getSources().toArray(new Source[0]));
Validator validator = schema.newValidator();
validator.validate(new DOMSource(document));
return true;
} catch (SAXException e) {
log.error("Exception: " e.getMessage());
} catch (Exception ex) {
log.debug("Exception: ", ex);
}
return false;
}
At this point I'm unsure what would be causing the NameIDFormat
element to fail validation, or why the validator isn't finding it in the base type but does seem to find ArtifactResolutionService
.
CodePudding user response:
How this element is produced it is generated without its minOccurs= attribute while other elements of the same set type do have it. , so there is a malformation much as the parser error says.
<element ref="md:SingleSignOnService" maxOccurs="unbounded"/>
CodePudding user response:
I figured out what's going on. The customer metadata is indeed invalid (according to this schema).
The complexType
s in the schema are specifying sequence
s. This means the elements MUST be specified in that particular order.
According to the schema, the NameIDFormat
elements defined in the SSODescriptorType
must be specified before any of the elements defined by the IDPSSODescriptorType
. Changing the metadata to the following works:
<IDPSSODescriptor protocolSupportEnumeration="urn:mace:shibboleth:1.0 urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol">
<Extensions>
<shibmd:Scope regexp="false">...</shibmd:Scope>
</Extensions>
<KeyDescriptor>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
...
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
<ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding" Location="..." index="1"/>
<ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="..." index="2"/>
<NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
<SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="..."/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="..."/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="..."/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="h..."/>
</IDPSSODescriptor>
Now to figure out how I'm going to handle this since it's unlikely I'll be able to get the customer to fix their metadata...