Search code examples
spring-bootclient-certificatesspring-cloud-feign

How to use p12 client certificate with spring feign client


I have a Spring Boot application that calls a remote service.

This remote web service provided me a p12 file that should authenticate my application.

How do I configure my feign client to use the p12 certificate ?


I've tried settings these properties:

-Djavax.net.ssl.keyStore=path_to_cert.p12 -Djavax.net.ssl.keyStorePassword=xxx -Djavax.net.ssl.keyStoreType=PKCS12

But it doesn't change anything, I still get this error:

sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Solution

  • I could finally manage to do it with a lot of blind trial and error.

    The problem is, by default, the feign builder builds feign clients with null SSLSocketFactory:

    org.springframework.cloud.openfeign.FeignClientsConfiguration#feignBuilder:

    @Bean
    @Scope("prototype")
    @ConditionalOnMissingBean
    public Feign.Builder feignBuilder(Retryer retryer) {
        return Feign.builder().retryer(retryer);
    }
    

    feign.Feign.Builder:

      public static class Builder {
        // ...
        private Client client = new Client.Default(null, null);
    

    So, I had to define this bean in a @Configuration:

    @Bean
    @Profile({"prod", "docker"})
    public Feign.Builder feignBuilder() {
        return Feign.builder()
            .retryer(Retryer.NEVER_RETRY)
            .client(new Client.Default(getSSLSocketFactory(), null));
    

    with this method: (can't remember source)

    SSLSocketFactory getSSLSocketFactory() {
        char[] allPassword = keyStorePassword.toCharArray();
        SSLContext sslContext = null;
        try {
            sslContext = SSLContextBuilder
                .create()
                .setKeyStoreType(keyStoreType)
                .loadKeyMaterial(ResourceUtils.getFile(keyStore), allPassword, allPassword)
                .build();
        } catch (Exception e) { /* *** */ }
        return sslContext.getSocketFactory();
    }
    

    Now, it works for me, I debugged though the feign client calls and the sslSocketFactory is correctly passed to the underlying connection.