Make Feign client to take truststore from custom property

I ended up handcrafting my own instance of SSLSocketFactory that I pass to my Feign client, using the below code,

/**
 * Gets the {@link SSLSocketFactory} instance for the client communication
 * using the given truststore file and password.
 * 
 * Since the instance is used as client, this is instantiated with empty
 * keystore and the truststore represented by the given truststore file.
 * 
 * 
 * @param theTrustStoreFile
 *            The complete file path of the truststore.
 * @return {@link SSLSocketFactory} instance that internally uses the given
 *         truststore.
 * @throws Exception
 *             When there is an error in the creating the
 *             {@link SSLSocketFactory} instance.
 */
public static SSLSocketFactory getClientSSLSocketFactory(File theTrustStoreFile)
        throws Exception
{
    // This supports TLSv1.2
    SSLContext sslContext = SSLContext.getInstance("TLS");

    KeyStore kStore = KeyStore.getInstance(KeyStore.getDefaultType());

    FileInputStream file = getFileInputStream(theTrustStoreFile);
    kStore.load(file, null);

    TrustManagerFactory tmf = TrustManagerFactory
            .getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(kStore);

    sslContext.init(new KeyManager[] {}, tmf.getTrustManagers(), null);

    return sslContext.getSocketFactory();
}

/**
 * Reads the file into {@link FileInputStream} instance.
 * 
 * @param file
 *            The file to be read.
 * @return {@link FileInputStream} that represents the file content/
 * @throws Exception
 *             When there is any error in reading the file.
 */
private static FileInputStream getFileInputStream(final File file) throws Exception
{
    return AccessController.doPrivileged(new PrivilegedExceptionAction<FileInputStream>()
    {
        @Override
        public FileInputStream run() throws Exception
        {
            try
            {
                if (file.exists())
                {
                    return new FileInputStream(file);
                } else
                {
                    return null;
                }
            } catch (FileNotFoundException e)
            {
                // couldn't find it, oh well.
                return null;
            }
        }
    });
}

And when I instantiate my client, I do it like,

Feign.builder().client(getClientSSLSocketFactory(trustFile),null)...

This gist contains sample code and its usage.


This is how i used FeignClient with keystore and truststore

FeignClient Configuration

@Configuration
public class TestClientConfig {

    @Bean
    public Client feignClient() {
        Client trustSSLSockets = new Client.Default(getSSLSocketFactory(), new NoopHostnameVerifier());
        return trustSSLSockets;
    }

    private SSLSocketFactory getSSLSocketFactory() {
        try {
            TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    //Do your validations
                    return true;
                }
            };
            String allPassword = "123456";
            SSLContext sslContext = SSLContextBuilder
                    .create()
                    // .loadKeyMaterial(ResourceUtils.getFile("classpath:keystore.p12"), allPassword.toCharArray(), allPassword.toCharArray())
                    .loadKeyMaterial(ResourceUtils.getFile("classpath:keystore.jks"), allPassword.toCharArray(), allPassword.toCharArray())
                    .loadTrustMaterial(ResourceUtils.getFile("classpath:truststore.jks"), allPassword.toCharArray())
                    .build();
            return sslContext.getSocketFactory();
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }
    }
}

Interface

@FeignClient(name = "Test", url = "https://localhost:8443",configuration=TestClientConfig.class)
public interface TestClient {

    @RequestMapping(method = RequestMethod.GET,value = "/hello")
    String getHello();
}