Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using ssl certificate with feign

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

like image 670
A. Boudoux Avatar asked Apr 26 '26 04:04

A. Boudoux


2 Answers

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();
}
like image 182
M Aqib Naeem Avatar answered Apr 27 '26 18:04

M Aqib Naeem


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

like image 35
meridbt Avatar answered Apr 27 '26 17:04

meridbt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!