I'm trying to acess a apllication secured by https, i have a p12 certificate (already imported as .cer into cacerts folder of my jdk).
I already tried this tutorial to no success: https://dzone.com/articles/ssl-based-feignclient-example-in-java-microcervice
And also i'm using part of this solution: How to use p12 client certificate with spring feign client
Debuging the ssl connection i get the following error:
javax.net.ssl|ERROR|25|http-nio-auto-1-exec-1|2021-01-26 16:56:34.789 BRT|TransportContext.java:317|Fatal (HANDSHAKE_FAILURE): Received fatal alert: handshake_failure
My current feign config class
@Bean
@ConditionalOnMissingBean
public Feign.Builder feignBuilder(Retryer retryer) {
return Feign.builder().retryer(retryer);
}
@Bean
public Feign.Builder feignBuilder() {
return Feign.builder()
.retryer(Retryer.NEVER_RETRY)
.client(new Client.Default(getSSLSocketFactory(), null));
}
private SSLSocketFactory getSSLSocketFactory() {
String keyStorePassword = "myPassword";
char[] allPassword = keyStorePassword.toCharArray();
SSLContext sslContext = null;
try {
sslContext = SSLContextBuilder
.create()
.setKeyStoreType("PKCS12")
.loadKeyMaterial(ResourceUtils.getFile("keypath"), allPassword, allPassword)
.build();
} catch (Exception e) { }
return sslContext.getSocketFactory();
}
In the debbuging section of the code i can see my certificate is there, but still my java is getting the handshake error. I'm new to ssl concept and possible did some config wrong.
One last note, when in the feign config class and set the trust store and password by System
System.setProperty("javax.net.ssl.trustStorePassword", "pass");
System.setProperty("javax.net.ssl.trustStore", "pathtocerth.p12");
The error change to this:
javax.net.ssl|ERROR|25|http-nio-auto-1-exec-1|2021-01-26 16:48:58.551 BRT|TransportContext.java:317|Fatal (CERTIFICATE_UNKNOWN): PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
In case someone is facing the same issue in 2023. I configured the Client as a Bean in Feign Configurations and set SSL Socket Factory details there.
Gradle Imports:
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:3.1.6'
implementation 'io.github.openfeign:feign-httpclient:12.3'
Client Bean in Feign Configuration:
@Bean
public Client feignClient() throws Exception {
log.info("Configuring SSL Context for Feign Client");
return new Client.Default(createSSLContext(), SSLConnectionSocketFactory.getDefaultHostnameVerifier());
}
and created SSL Socket Factory for from resource files as follow:
private SSLSocketFactory createSSLContext() throws Exception {
String trustStorePath = "classpath:cacerts"
String keyStorePath = "classpath:client-key.pfx"
log.info("Trust Store for Feign Client: " + trustStorePath);
log.info("Key Store for Feign Client: " + keyStorePath);
KeyStore keyStore = KeyStore.getInstance("PKCS12"); // PKCS12 for PFX files. Change this to 'JKS' if you are using java keystore
keyStore.load(new FileInputStream(ResourceUtils.getFile(keyStorePath)), keyStorePassword.toCharArray());
SSLContext context = SSLContextBuilder.create()
.loadTrustMaterial(ResourceUtils.getFile(trustStorePath), trustStorePassword.toCharArray())
.loadKeyMaterial(keyStore, keyStorePassword.toCharArray())
.build();
return context.getSocketFactory();
}
Hello there from 2024!
Spring Boot 3.1 introduces convenient approach of configuring SSL context using Bundles.
An elementary example for feign client:
// MyClient.java
@FeignClient(name = "my-client", url = "${my-client.url}",
configuration = MyClientConfig.class)
public interface MyClient { /* methods */ }
// MyClientConfig.java
public class MyClientConfig {
@Bean
public Client client(SslBundles sslBundles) {
SSLContext sslContext = sslBundles.getBundle("my-client").createSslContext();
return new Client.Default(sslContext.getSocketFactory(), HttpsURLConnection.getDefaultHostnameVerifier());
}
}
# application.yaml
spring:
ssl:
bundle:
jks:
my-client:
keystore:
location: /path-to-keystore/keystore.p12
password: secret
type: PKCS12
truststore:
location: /path-to-truststore/truststore.p12
password: secret
type: PKCS12
Bundles support both store-based (JKS or PKCS12) under jks node and key-based configuration under pem node
See details in this Spring blog post
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With