Search code examples
javaspringspring-securityspring-saml

Spring SAML handshake failure - Failed to validate untrusted credential against trusted key


I'm using Spring Security SAML extension for integrating with the ACA healthcare (aka Obamacare) website. It uses IDP Initiated SSO. The SAML handshake fails with the following output

org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider] Single certificate was present, treating as end-entity certificate
org.opensaml.xml.security.keyinfo.BasicProviderKeyInfoCredentialResolver] Credentials successfully extracted from child {http://www.w3.org/2000/09/xmldsig#}X509Data by provider org.opensaml.xml.security.keyinfo.provider.InlineX509DataProvider
org.opensaml.xml.security.keyinfo.BasicProviderKeyInfoCredentialResolver] A total of 1 credentials were resolved
org.opensaml.xml.security.credential.criteria.EvaluableCredentialCriteriaRegistry] Registry could not locate evaluable criteria for criteria class org.opensaml.xml.security.keyinfo.KeyInfoCriteria
org.opensaml.xml.signature.SignatureValidator] Attempting to validate signature using key from supplied credential
org.opensaml.xml.signature.SignatureValidator] Creating XMLSignature object
org.opensaml.xml.signature.SignatureValidator] Validating signature with signature algorithm URI: http://www.w3.org/2000/09/xmldsig#rsa-sha1
org.opensaml.xml.signature.SignatureValidator] Validation credential key algorithm 'RSA', key instance class 'sun.security.rsa.RSAPublicKeyImpl'
org.opensaml.xml.signature.SignatureValidator] Signature validated with key from supplied credential
org.opensaml.xml.signature.impl.BaseSignatureTrustEngine] Signature validation using candidate credential was successful
org.opensaml.xml.signature.impl.BaseSignatureTrustEngine] Successfully verified signature using KeyInfo-derived credential
org.opensaml.xml.signature.impl.BaseSignatureTrustEngine] Attempting to establish trust of KeyInfo-derived credential
org.opensaml.xml.security.trust.ExplicitKeyTrustEvaluator] Failed to validate untrusted credential against trusted key
org.opensaml.xml.signature.impl.BaseSignatureTrustEngine] Failed to establish trust of KeyInfo-derived credential
org.opensaml.xml.signature.impl.BaseSignatureTrustEngine] Failed to verify signature and/or establish trust using any KeyInfo-derived credentials
org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine] Attempting to verify signature using trusted credentials
org.opensaml.xml.signature.SignatureValidator] Attempting to validate signature using key from supplied credential
org.opensaml.xml.signature.SignatureValidator] Creating XMLSignature object
org.opensaml.xml.signature.SignatureValidator] Validating signature with signature algorithm URI: http://www.w3.org/2000/09/xmldsig#rsa-sha1
org.opensaml.xml.signature.SignatureValidator] Validation credential key algorithm 'RSA', key instance class 'sun.security.rsa.RSAPublicKeyImpl'
org.apache.xml.security.signature.XMLSignature] Signature verification failed.
org.opensaml.xml.signature.SignatureValidator] Signature did not validate against the credential's key
org.opensaml.xml.signature.impl.BaseSignatureTrustEngine] Signature validation using candidate validation credential failed
org.opensaml.xml.validation.ValidationException: Signature did not validate against the credential's key
    at org.opensaml.xml.signature.SignatureValidator.validate(SignatureValidator.java:79)

My securityContext has the following:

    <bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager">
    <constructor-arg>
        <list>
            <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:${MC_METADATA}</value>
                        </constructor-arg>
                        <property name="parserPool" ref="parserPool" />
                    </bean>
                </constructor-arg>
                <constructor-arg>
                    <map>
                        <entry key="${MC_ALIAS_1}">
                            <bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
                                <property name="local" value="true" />
                                <property name="alias" value="${MC_ALIAS_1}" />
                                <property name="securityProfile" value="metaiop" />
                                <property name="requireArtifactResolveSigned" value="false" />
                                <property name="requireLogoutRequestSigned" value="false" />
                                <property name="requireLogoutResponseSigned" value="false" />
                                <property name="idpDiscoveryEnabled" value="false" />
                            </bean>
                        </entry>

                    </map>
                </constructor-arg>
            </bean>
        </list>
    </constructor-arg>
    <property name="defaultExtendedMetadata">
        <bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
            <property name="local" value="true" />
            <property name="alias" value="${MC_ALIAS_1}" />
            <property name="securityProfile" value="metaiop" />
            <property name="requireArtifactResolveSigned" value="false" />
            <property name="requireLogoutRequestSigned" value="false" />
            <property name="requireLogoutResponseSigned" value="false" />
            <property name="idpDiscoveryEnabled" value="false" />
        </bean>
    </property>
    <property name="hostedSPName" value="${MC_ALIAS_1}" />
</bean>

The incoming SAML contains X509Certificate and I have copied it to my metadata file under signing. I also tried adding 'metadataTrustCheck' as false but still the same error. Communication happens over HTTPS and my test server (receiving the SAML) uses self-signed certs.

Any ideas as to what may be missing/wrong?


Solution

  • Generally, adding a certificate into IDP's metadata will make it trusted by Spring SAML, so your approach is correct. One of the following could be causing the problem you're facing:

    • the ${MC_ALIAS_1} metadata might be your IDP metadata, but you're currently importing it as if it was SP metadata - are you using metadata generator, or is this really your pre-configured SP metadata?
    • you have imported the certificate you found in the IDP's message into your SP metadata, while it needs to be imported into IDP metadata in order to be trusted

    Posting the SAML message you're receiving and your complete configuration xml, not just a snippet, would make troubleshooting easier.