abeauchamp
abeauchamp

Reputation: 845

SAML Java Sping Boot - PKIX path construction failed for untrusted credential

Running into this issue setting up SAML 2.0 in Java Spring Boot using latest libraries.

I followed this guide: https://www.programcreek.com/java-api-examples/?code=choonchernlim%2Fspring-security-adfs-saml2%2Fspring-security-adfs-saml2-master

Here's some relevant code, but let me know if anything else will help:

    @Bean
    public KeyManager keyManager()
    {
        return new JKSKeyManager(keyStoreResource, keystorePassword, ImmutableMap.of(keystoreKeyAlias, keystorePrivateKeyPassword), keystoreKeyAlias);
    }

    @Bean
    public SAMLDiscovery samlIDPDiscovery()
    {
        return new SAMLDiscovery();
    }

    @Bean
    public MetadataDisplayFilter metadataDisplayFilter()
    {
        return new MetadataDisplayFilter();
    }

    @Bean
    public TLSProtocolConfigurer tlsProtocolConfigurer()
    {
        TLSProtocolConfigurer t = new TLSProtocolConfigurer();
        //t.setSslHostnameVerification("allowAll");
        return t;
    }

    // Configure TLSProtocolConfigurer
    @Bean
    public ProtocolSocketFactory protocolSocketFactory()
    {
        //return new TLSProtocolSocketFactory(keyManager(), null, "defaultAndLocalhost");
        return new TLSProtocolSocketFactory(keyManager(), null, "default");
    }

    @Bean
    public Protocol protocol()
    {
        return new Protocol("https", protocolSocketFactory(), 443);
    }

    @Bean
    public MethodInvokingFactoryBean socketFactoryInitialization()
    {
        MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
        methodInvokingFactoryBean.setTargetClass(Protocol.class);
        methodInvokingFactoryBean.setTargetMethod("registerProtocol");
        methodInvokingFactoryBean.setArguments(new Object[] { "https", protocol() });
        return methodInvokingFactoryBean;
    }

    @Bean
    public CachingMetadataManager metadata() throws MetadataProviderException
    {
        HTTPMetadataProvider httpMetadataProvider = new HTTPMetadataProvider(new Timer(true), httpClient(), idpUrl);
        httpMetadataProvider.setParserPool(parserPool());

        //ExtendedMetadata em = new ExtendedMetadata(); //Attempt to explicitly add cert alias to extended metadata
        //em.setAlias(keystoreCertAlias);
        //em.setSigningKey("*.product.company.com");

        ExtendedMetadataDelegate extendedMetadataDelegate = new ExtendedMetadataDelegate(httpMetadataProvider);//, em);

        extendedMetadataDelegate.setMetadataTrustCheck(false);

        return new CachingMetadataManager(ImmutableList.<MetadataProvider>of(extendedMetadataDelegate));
    }

Here's the error:

2020-05-27 17:02:27.552 ERROR 41402 --- [           main] o.s.s.s.t.MetadataCredentialResolver     : PKIX path construction failed for untrusted credential: [subjectName='CN=*.product.company.com,O=Company,L=Location,ST=state,C=US']: unable to find valid certification path to requested target
2020-05-27 17:02:27.556  INFO 41402 --- [           main] o.a.c.httpclient.HttpMethodDirector      : I/O exception (javax.net.ssl.SSLPeerUnverifiedException) caught when processing request: SSL peer failed hostname validation for name: null
2020-05-27 17:02:27.557  INFO 41402 --- [           main] o.a.c.httpclient.HttpMethodDirector      : Retrying request
...

javax.net.ssl.SSLPeerUnverifiedException: SSL peer failed hostname validation for name: null
    at org.opensaml.ws.soap.client.http.TLSProtocolSocketFactory.verifyHostname(TLSProtocolSocketFactory.java:233) ~[openws-1.5.4.jar:na]
    at org.opensaml.ws.soap.client.http.TLSProtocolSocketFactory.createSocket(TLSProtocolSocketFactory.java:186) ~[openws-1.5.4.jar:na]
    at org.springframework.security.saml.trust.httpclient.TLSProtocolSocketFactory.createSocket(TLSProtocolSocketFactory.java:97) ~[spring-security-saml2-core-1.0.10.RELEASE.jar:1.0.10.RELEASE]
    at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:707) ~[commons-httpclient-3.1.jar:na]
    at org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$HttpConnectionAdapter.open(MultiThreadedHttpConnectionManager.java:1361) ~[commons-httpclient-3.1.jar:na]
    at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:387) ~[commons-httpclient-3.1.jar:na]
    at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171) ~[commons-httpclient-3.1.jar:na]
    at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397) ~[commons-httpclient-3.1.jar:na]
    at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323) ~[commons-httpclient-3.1.jar:na]
    at org.opensaml.saml2.metadata.provider.HTTPMetadataProvider.fetchMetadata(HTTPMetadataProvider.java:250) ~[opensaml-2.6.4.jar:na]
    at org.opensaml.saml2.metadata.provider.AbstractReloadingMetadataProvider.refresh(AbstractReloadingMetadataProvider.java:255) [opensaml-2.6.4.jar:na]
    at org.opensaml.saml2.metadata.provider.AbstractReloadingMetadataProvider.doInitialization(AbstractReloadingMetadataProvider.java:236) [opensaml-2.6.4.jar:na]
    at org.opensaml.saml2.metadata.provider.AbstractMetadataProvider.initialize(AbstractMetadataProvider.java:407) [opensaml-2.6.4.jar:na]
    at org.springframework.security.saml.metadata.ExtendedMetadataDelegate.initialize(ExtendedMetadataDelegate.java:167) [spring-security-saml2-core-1.0.10.RELEASE.jar:1.0.10.RELEASE]
    at com.company.product.ProductApplication.main(ProductApplication.java:10) ~[classes/:na]

Creating the JKS keystore like so (with an attached key):

keytool -genkeypair \
 -v \
 -keystore product.jks \
 -storepass hidden \
 -alias product \
 -dname 'CN=localhost, OU=Company, O=Org, L=Loc, ST=State, C=US' \
 -keypass hidden \
 -keyalg RSA \
 -keysize 2048 \
 -sigalg SHA256withRSA

I included the cert as well: Signature trust establishment failed for SAML metadata entry The certificate provided by my IDP is contained within my keystore:

keytool -importcert \
  -file cert.pem \
  -keystore product.jks \
  -alias idp-server \
  -storepass hidden

I tried all the following tickets already:

SSL peer failed hostname validation in Spring SAML Tried to add the cert included in the passwords in KeyManager (I set the cert password to be the keystore password since the cert does not have one)

Spring Security SAML + HTTPS to another page Tried allowAll in TLSProtocolConfigurer.setSslHostnameVerification and defaultAndLocalhost in TLSProtocolSocketFactory constructor.

Spring Security SAML IdP Metadata Certificate and Signature Trust check is already disabled: extendedMetadataDelegate.setMetadataTrustCheck(false);

Signature trust establishment failed for SAML metadata entry Tried setting the alias of the cert inside the ExtendedMetadata attached to the delegate:

ExtendedMetadata em = new ExtendedMetadata();
em.setAlias(keystoreCertAlias);
em.setSigningKey("*.product.company.com"); //This is obfuscated
ExtendedMetadataDelegate extendedMetadataDelegate = new ExtendedMetadataDelegate(httpMetadataProvider, em);

My inclination is that I'm setting up the keystore incorrectly with the cert. I tried converted the PEM to crt and cer to see if it would make any difference, it did not. I can assure you this is the IDP cert and not the domain cert (FYI this is purposefully not using cacerts, but containing the cert inside the keystore to use HTTPS).

Any ideas/help is much appreciated! Thanks.

Upvotes: 0

Views: 1035

Answers (1)

abeauchamp
abeauchamp

Reputation: 845

To fix this, I dropped the tlsProtocolConfigurer bean and all beans associated to it. I'm not entirely sure why the sample included this as it works perfectly fine with HTTPS (and localhost) without it.

Note: I'm assuming the actual issue was that the tlsProtocolConfigurer wasn't finding the certificate in the keystore, but for my app, the entire bean is not necessary so it became a moot point.

Upvotes: 0

Related Questions