-
-
Save NemchinovSergey/1c3ea6e641aad3011dbd970403b13f42 to your computer and use it in GitHub Desktop.
Configuring RestTemplate for Client TLS in a Spring Boot Application
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*** 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment