Skip to content

Instantly share code, notes, and snippets.

@serac
Last active March 25, 2021 16:32
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save serac/4f77e42c1ac515114a1c8e9469be25ad to your computer and use it in GitHub Desktop.
Save serac/4f77e42c1ac515114a1c8e9469be25ad to your computer and use it in GitHub Desktop.
Configuring RestTemplate for Client TLS in a Spring Boot Application
/*
* See LICENSE for licensing and NOTICE for copyright.
*/
package edu.vt.middleware.app;
import java.io.File;
import java.security.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import org.apache.http.client.HttpClient;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import org.cryptacular.bean.KeyStoreFactoryBean;
import org.cryptacular.io.ClassPathResource;
import org.cryptacular.io.FileResource;
import org.cryptacular.io.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* Application entry point.
*
* @author Marvin S. Addison
*/
@SpringBootApplication
public class Application {
/** Logger instance. */
private final Logger logger = LoggerFactory.getLogger(Application.class);
/** Application HTTP client connection pool size. */
@Value("${application.httpclient.pool.size:10}")
private int httpClientPoolSize;
/** Application HTTP client keepalive duration in seconds. */
@Value("${application.httpclient.keepalive:120}")
private int httpClientKeepAlive;
/** Application keystore path. */
@Value("${application.keystore.path}")
private String keystorePath;
/** Application keystore type. */
@Value("${application.keystore.type}")
private String keystoreType;
/** Application keystore password. */
@Value("${application.keystore.password}")
private String keystorePassword;
/** Keystore alias for application client credential. */
@Value("${application.keystore.entry.app-name}")
private String applicationKeyAlias;
public static void main(String[] args) {
LoggerFactory.getLogger(Application.class).info("Starting application");
SpringApplication.run(Application.class, args);
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(new HttpComponentsClientHttpRequestFactory(createHttpClient(applicationKeyAlias)));
}
private static Resource makeResource(final String path) {
if (path.startsWith(FILE_RESOURCE_PREFIX)) {
return new FileResource(new File(path.substring(FILE_RESOURCE_PREFIX.length())));
} else if (path.startsWith(CLASSPATH_RESOURCE_PREFIX)) {
return new ClassPathResource(path.substring(CLASSPATH_RESOURCE_PREFIX.length()));
}
// Assume a path without a known prefix is a file
return new FileResource(new File(path));
}
private HttpClient createHttpClient(final String keyAlias) {
logger.info("Creating HTTP client using keystore={} and alias={}", keystorePath, keyAlias);
final KeyStore trustStore = new KeyStoreFactoryBean(
makeResource("classpath:/truststore.jks"), "JKS", "changeit").newInstance();
final KeyStore keyStore = new KeyStoreFactoryBean(
makeResource(keystorePath), keystoreType, keystorePassword).newInstance();
final SSLContext sslContext;
try {
sslContext = SSLContexts.custom()
.loadKeyMaterial(keyStore, keystorePassword.toCharArray(), (aliases, socket) -> keyAlias)
.loadTrustMaterial(trustStore, (x509Certificates, s) -> false)
.build();
} catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | UnrecoverableKeyException e) {
throw new IllegalStateException("Error loading key or trust material", e);
}
final SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
sslContext,
new String[] { "TLSv1.2" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
final Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslSocketFactory)
.build();
final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
connectionManager.setMaxTotal(httpClientPoolSize);
connectionManager.setDefaultMaxPerRoute(httpClientPoolSize);
return HttpClients.custom()
.setSSLSocketFactory(sslSocketFactory)
.setConnectionManager(connectionManager)
.build();
}
}
*** CertificateRequest
Cert Types: RSA, DSS, ECDSA
Supported Signature Algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA
Cert Authorities:
<C=US, DC=edu, DC=vt, O=Virginia Polytechnic Institute and State University, CN=Virginia Tech Middleware CA>
*** ServerHelloDone
matching alias: somebody
*** Certificate chain
chain [0] = [
[
Version: V3
Subject: C=US, DC=edu, DC=vt, ST=Virginia, L=Blacksburg, O=Virginia Polytechnic Institute and State University, OU=Middleware-Client, OU=Middleware, SERIALNUMBER=OU812, CN=somebody
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
@serac
Copy link
Author

serac commented Dec 16, 2016

I should note that this is for http-components 4.5.2. I'm sure it will be incorrect on the next minor release :(

@apache/httpclient, we appreciate using @deprecated, but let's be reasonable.

@nullmicgo
Copy link

what is x509Certificates ??

@ArnauAregall
Copy link

@nullmicgo x509Certificates is an agrument from the lambda.

@divya07514
Copy link

Wha is applicationKeyAlias?

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