Skip to content

Instantly share code, notes, and snippets.

@62mkv
Created October 11, 2019 08:46
Show Gist options
  • Save 62mkv/de295ffd8dae75234d091713b2a226fb to your computer and use it in GitHub Desktop.
Save 62mkv/de295ffd8dae75234d091713b2a226fb to your computer and use it in GitHub Desktop.
How to add a custom trusted certificate for making HTTP requests against external sites

Thoughts on how to add trusted store for connection to external sites that use that certificate for HTTPS

Option 1: global configuration

One can just provide the -Djavax.net.ssl.trustStore=<path/to/store> -Djavax.net.ssl.trustStorePassword=<password> options when running the Java application

However, this is not always possible (for example, when run in the cloud).

And if you want to use server.ssl.trust-store/server.ssl.trust-store-password options from Spring Boot, be aware that with those you also have to provide key-store options as well. And, basically that would be an abuse, because this configuration is specifically for server side of your application.

There's an alternative: provide custom properties, that can be overridden via environment variables, and add a bean to process those:

@ConfigurationProperties("client-ssl")
@Data
public class SslClientProperties {
    private String trustStore;
    private String trustStorePassword;
}

@Configuration
public class SslConfiguration {
    public SslConfiguration(SslClientProperties properties) {
       if (properties != null) {
         if (StringUtils.isNotBlank(properties.getTrustStore()) {
           System.setProperty("javax.net.ssl.trustStore", properties.getTrustStore());
         } 

       if (StringUtils.isNotBlank(properties.getTrustStorePassword()) {
           System.setProperty("javax.net.ssl.trustStorePassword", properties.getTrustStorePassword());
         } 
       }
    }
}

with this solution, however, one must pay attention that this configuration has to be initialized BEFORE the SSLEngine from the underlying server implementation.

Option 2. Smart configuration

When using a WebClient, we might customize specifically our WebClient by providing necessary config along the lines of:

@Configuration
public class WmsClientConfiguration {

    @Bean
    public WebClient.Builder jdaWmsBuilder() {
        return WebClient.builder()
            .clientConnector(new ReactorClientHttpConnector(builder -> builder.sslSupport(sslContextBuilder -> {
                Collection<X509Certificate> certs = getTrustedCerts();
                sslContextBuilder.trustManager(certs.toArray(new X509Certificate[certs.size()]));
            })));
    }
}

(as of how getTrustedCerts method might be implemented, see here: spring-projects/spring-boot#6493 (comment))

(WARNING: this has not been tested yet)

@WalkerWalker
Copy link

Great content. I wonder if I want to setup mutual TLS between two spring boot applications, then how should I set up the keystore on the client side? I guess using server.ssl.key-store is also an abuse because it is meant for the server side. I also tried with -Djavax.net.ssl.trustStore, Both do not work. T_T Maybe only the configuration is not enough? I don't if and how should I change the code for the client to be able to use its keystore and to provide the server its certificate.

Thank in advance for the help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment