/* * 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(); } }