Reputation: 371
I am new to SAML, and am integrating it into a Spring web application. I started by following the Spring SAML quick-start guide found here: http://docs.spring.io/spring-security-saml/docs/1.0.0.RELEASE/reference/html/chapter-quick-start.html
I got a this running fine. I then wanted to switch to target IDP, which is already running and successfully serving other SPs within the company.
In my securityContext.xml, I added the following to the metadata bean:
<bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
<constructor-arg>
<bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
<constructor-arg>
<value type="java.io.File">classpath:security/MyEntityId_sp.xml</value>
</constructor-arg>
<property name="parserPool" ref="parserPool"/>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
<property name="local" value="true"/>
<property name="alias" value="myAlias"/>
<property name="securityProfile" value="metaiop"/>
<property name="sslSecurityProfile" value="pkix"/>
<property name="signingKey" value="apollo"/>
<property name="encryptionKey" value="apollo"/>
<property name="requireArtifactResolveSigned" value="false"/>
<property name="requireLogoutRequestSigned" value="false"/>
<property name="requireLogoutResponseSigned" value="false"/>
<property name="idpDiscoveryEnabled" value="false"/>
</bean>
</constructor-arg>
</bean>
<bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
<constructor-arg>
<value type="java.io.File">classpath:security/IDP-MetaData.xml</value>
</constructor-arg>
<property name="parserPool" ref="parserPool"/>
</bean>
Using the Firefox SAML tracer, I can see that the interactions work fine, and the IDP redirect back to my app (the SP) after authenticating the user, with a valid SAML XML packet. This is not surprising since this IDP is already successfully being used by other SPs. However, it is redirecting to "http://localhost:8080/saml-demo/saml/SSO/alias/myAlias" which in turn throws the following error to the browser...
Authentication request failed: org.springframework.security.authentication.AuthenticationServiceException: Error determining metadata contracts
Digging into the code a bit further with the Java debugger, I found the real error is deeper in the code. It is thrown by org.springframework.security.saml.metadata.MetadataManager on line 913 when it sees the same alias for both the SP and the IDP. The real error is:
MetadataProviderException: Alias myAlias is used both for entity MyEntityId and MyEntityId
This only other change beyond what the quick start guide has is to the metadataGeneratorFilter:
<bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
<constructor-arg>
<bean class="org.springframework.security.saml.metadata.MetadataGenerator">
<property name="entityId" value="MyEntityId"/>
<property name="signMetadata" value="false"/>
</bean>
</constructor-arg>
</bean>
The IDP metadata file contains ...
<md:EntityDescriptor entityID="MyEntityId" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
<md:IDPSSODescriptor WantAuthnRequestsSigned="0" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>xxxxxx</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://auth.myidp.com/sa1234/" index="0" isDefault="1" />
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://auth.myidp.com/sa1234/" />
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://auth.myidp.com/sa1234/" />
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://auth.myidp.com/sa1234/" />
<md:ManageNameIDService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://auth.myidp.com/sa1234/" />
<md:ManageNameIDService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://auth.myidp.com/sa1234/" />
<md:ManageNameIDService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://auth.myidp.com/sa1234/" />
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://auth.myidp.com/sa1234/" />
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://auth.myidp.com/sa1234/" />
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://auth.myidp.com/sa1234/" />
</md:IDPSSODescriptor>
<md:AttributeAuthorityDescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>xxxxxx</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:AttributeService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://auth.myidp.com/sa1234/" />
</md:AttributeAuthorityDescriptor>
</md:EntityDescriptor>
Here is the contents of MyEntityId_sp.xml:
<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
ID="MyEntityId" entityID="MyEntityId">
<md:SPSSODescriptor AuthnRequestsSigned="true"
WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>xxx</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="encryption">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>xxx</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleLogoutService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://localhost:8080/saml-demo/saml/SingleLogout/alias/myAlias" />
<md:SingleLogoutService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://localhost:8080/saml-demo/saml/SingleLogout/alias/myAlias" />
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient
</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
</md:NameIDFormat>
<md:AssertionConsumerService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
Location="http://localhost:8080/saml-demo/saml/SSO/alias/myAlias"
index="0" isDefault="true" />
<md:AssertionConsumerService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8080/saml-demo/saml/SSO/alias/myAlias"
index="1" />
</md:SPSSODescriptor>
</md:EntityDescriptor>
Upvotes: 1
Views: 4291
Reputation: 371
I was able to track down the issue.
The IDP had an audience restriction that used the same ID ad the EntityID of the IDP itself. I could see this in the IDP meta data file:
<md:EntityDescriptor entityID="MyEntityId" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata">
Then using the Firefox SAML trace add on I could see the final responce from the IDP contained:
<saml:AudienceRestriction> <saml:Audience>MyEntityId</saml:Audience> </saml:AudienceRestriction>
Obviously "MyEntityID" is not what was literally used, it was a keyword for this app that made sense in the context of the files. However, this meant I needed to give my SP entity the same ID as this AudienceRestriction, or else I would get an error. However, As Andrew K. pointed out, you cannot give two entities the same entity ID.
I was not the one to set up the IDP server, so I do not have control over some of this (and the IDP metadata file was provided to me, so I just assumed there was nothign wrong with it). However, to solve this, I simply changed the entityID in the IDP metadata file. I'm new to SAML, but I don't think this will have any negative impacts for my specific implementation.
Upvotes: 2