Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SSL peer failed hostname validation in Spring SAML

I'm trying to configure my Spring Boot project to use SAML authentication against a third party IDP. I've already achieved to make the configuration from vdenotaris work with the SSOCircle provider and now I want to switch it to the other provider.

The SAML metadata endpoint is HTTPS enabled and I've already created a keystore with both the certificate given in metadata (which is used for signing and encryption) and the one provided by the HTTP endpoint (based in this answer). Then, I save them in a cert file ($CERTIFICATE_FILE) and I use this script to generate my keystore:

keytool -delete -alias third-party -keystore $KEYSTORE_FILE -storepass $KEYSTORE_PASSWORD
keytool -import -alias third-party -file $CERTIFICATE_FILE -keystore $KEYSTORE_FILE -storepass $KEYSTORE_PASSWORD -noprompt
keytool -genkeypair -alias mycompany -keypass mycompanypass -keystore $KEYSTORE_FILE

Then, when using this keystore to retrieve the SAML metadata, I get this error:

org.opensaml.saml2.metadata.provider.MetadataProviderException: org.opensaml.saml2.metadata.provider.MetadataProviderException: Error retrieving metadata from https://third.party.provider/metadata
    at org.opensaml.saml2.metadata.provider.HTTPMetadataProvider.fetchMetadata(HTTPMetadataProvider.java:274)
    at org.opensaml.saml2.metadata.provider.AbstractReloadingMetadataProvider.refresh(AbstractReloadingMetadataProvider.java:267)
    at org.opensaml.saml2.metadata.provider.AbstractReloadingMetadataProvider.doInitialization(AbstractReloadingMetadataProvider.java:236)
    at org.opensaml.saml2.metadata.provider.AbstractMetadataProvider.initialize(AbstractMetadataProvider.java:407)
    at org.springframework.security.saml.metadata.ExtendedMetadataDelegate.initialize(ExtendedMetadataDelegate.java:167)
    at org.springframework.security.saml.metadata.MetadataManager.initializeProvider(MetadataManager.java:412)
    at org.springframework.security.saml.metadata.MetadataManager.refreshMetadata(MetadataManager.java:238)
    at org.springframework.security.saml.metadata.CachingMetadataManager.refreshMetadata(CachingMetadataManager.java:86)
    at org.springframework.security.saml.metadata.MetadataManager$RefreshTask.run(MetadataManager.java:1040)
    at java.util.TimerThread.mainLoop(Timer.java:555)
    at java.util.TimerThread.run(Timer.java:505)
Caused by: org.opensaml.saml2.metadata.provider.MetadataProviderException: Error retrieving metadata from https://third.party.provider/metadata
    at org.opensaml.saml2.metadata.provider.HTTPMetadataProvider.fetchMetadata(HTTPMetadataProvider.java:274)
    at org.opensaml.saml2.metadata.provider.AbstractReloadingMetadataProvider.refresh(AbstractReloadingMetadataProvider.java:255)
    ... 9 common frames omitted
Caused by: javax.net.ssl.SSLPeerUnverifiedException: SSL peer failed hostname validation for name: null
    at org.opensaml.ws.soap.client.http.TLSProtocolSocketFactory.verifyHostname(TLSProtocolSocketFactory.java:233)
    at org.opensaml.ws.soap.client.http.TLSProtocolSocketFactory.createSocket(TLSProtocolSocketFactory.java:186)
    at org.springframework.security.saml.trust.httpclient.TLSProtocolSocketFactory.createSocket(TLSProtocolSocketFactory.java:97)
    at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:707)
    at org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$HttpConnectionAdapter.open(MultiThreadedHttpConnectionManager.java:1361)
    at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:387)
    at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
    at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
    at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
    at org.opensaml.saml2.metadata.provider.HTTPMetadataProvider.fetchMetadata(HTTPMetadataProvider.java:250)
    ... 10 common frames omitted

These ones are the relevant parts of my configuration based in the linked project by vdenotaris:

// Setup TLS Socket Factory
@Bean
public TLSProtocolConfigurer tlsProtocolConfigurer() {
    return new TLSProtocolConfigurer();
}

@Bean
public ProtocolSocketFactory socketFactory() {
    return new TLSProtocolSocketFactory(keyManager(), null, "allowAll");
}

@Bean
public Protocol socketFactoryProtocol() {
    return new Protocol("https", socketFactory(), 443);
}

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

// Central storage of cryptographic keys
@Bean
public KeyManager keyManager() {
    DefaultResourceLoader loader = new DefaultResourceLoader();
    Resource storeFile = loader.getResource("classpath:/saml/mySamlKeystore.jks");
    String storePass = "storepass";
    Map<String, String> passwords = new HashMap<String, String>();
    passwords.put("mycompany", "mycompanypass");
    String defaultKey = "mycompany";
    return new JKSKeyManager(storeFile, storePass, passwords, defaultKey);
}

However, here I found some misconceptions. As far as I know, the TLSProtocolConfigurer creates a TLSProtocolSocketFactory itself, why is the sample project creating both beans then? According to the docs using TLSProtocolConfigurer should be enough, but how to create socketFactoryProtocol()?

I would be grateful to have some light in here.

like image 288
Xtreme Biker Avatar asked Sep 07 '25 14:09

Xtreme Biker


1 Answers

Here is my JKS key-manager bean configuration.

@Bean
public ProtocolSocketFactory socketFactory() {
return new TLSProtocolSocketFactory(keyManager(), null, "default");
}

@Bean
public KeyManager keyManager() {
DefaultResourceLoader loader = new DefaultResourceLoader();
Resource storeFile = loader.getResource("classpath:/saml/samlKeystore.jks");
String storePass = keyStorePwd;
Map<String, String> passwords = new HashMap<String, String>();
passwords.put(keyStoreAlias, keyStorePwd);
String defaultKey = keyStoreAlias;
return new JKSKeyManager(storeFile, storePass, passwords, defaultKey);

}

Solution:

Looks like the IDP has changed their Public certificate which is not available in our local keystore (samlKeystore.jks). I manually downloaded their public certificate using OpenSSL command and imported the same using keytool utility.

Get the public certificate using OpenSSL command:

openssl s_client -showcerts -connect iam-sso.google.net:443 </dev/null 2>/dev/null|openssl x509 -outform PEM >mycertfile.pem

Import it into the Keystore:

keytool -import -alias "new-public-cert" -keystore /usr/share/tomcat8/webapps/ROOT/WEB-INF/classes/saml/samlKeystore.jks
like image 171
Velu Avatar answered Sep 10 '25 04:09

Velu