From 67bd6c302ed62e11ffd855bd93cc5bb00d01cccc Mon Sep 17 00:00:00 2001 From: Maciej Mierzwa Date: Fri, 15 Dec 2023 17:47:13 +0100 Subject: [PATCH] refactor to use apache http5 library Signed-off-by: Maciej Mierzwa --- .../auth/http/saml/HTTPMetadataResolver.java | 157 ++++++++++++ .../auth/http/saml/HTTPSamlAuthenticator.java | 2 +- .../http/saml/SamlHTTPMetadataResolver.java | 33 ++- ...va => SettingsBasedSSLConfiguratorV5.java} | 45 ++-- ...> SettingsBasedSSLConfiguratorV5Test.java} | 227 +++++++++--------- 5 files changed, 313 insertions(+), 151 deletions(-) create mode 100644 src/main/java/com/amazon/dlic/auth/http/saml/HTTPMetadataResolver.java rename src/main/java/com/amazon/dlic/util/{SettingsBasedSSLConfiguratorV4.java => SettingsBasedSSLConfiguratorV5.java} (93%) rename src/test/java/org/opensearch/security/util/{SettingsBasedSSLConfiguratorV4Test.java => SettingsBasedSSLConfiguratorV5Test.java} (64%) diff --git a/src/main/java/com/amazon/dlic/auth/http/saml/HTTPMetadataResolver.java b/src/main/java/com/amazon/dlic/auth/http/saml/HTTPMetadataResolver.java new file mode 100644 index 0000000000..a8693c6689 --- /dev/null +++ b/src/main/java/com/amazon/dlic/auth/http/saml/HTTPMetadataResolver.java @@ -0,0 +1,157 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package com.amazon.dlic.auth.http.saml; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Timer; + +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.http.HttpStatus; + +import net.shibboleth.utilities.java.support.resolver.ResolverException; +import org.opensaml.saml.metadata.resolver.impl.AbstractReloadingMetadataResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HTTPMetadataResolver extends AbstractReloadingMetadataResolver { + private final Logger log = LoggerFactory.getLogger(HTTPMetadataResolver.class); + private HttpClient httpClient; + private URI metadataURI; + private String cachedMetadataETag; + private String cachedMetadataLastModified; + + public HTTPMetadataResolver(final HttpClient client, final String metadataURL) throws ResolverException { + this(null, client, metadataURL); + } + + public HTTPMetadataResolver(final Timer backgroundTaskTimer, final HttpClient client, final String metadataURL) + throws ResolverException { + super(backgroundTaskTimer); + + if (client == null) { + throw new ResolverException("HTTP client may not be null"); + } + httpClient = client; + + try { + metadataURI = new URI(metadataURL); + } catch (final URISyntaxException e) { + throw new ResolverException("Illegal URL syntax", e); + } + } + + public String getMetadataURI() { + return metadataURI.toASCIIString(); + } + + @Override + protected void doDestroy() { + if (httpClient instanceof AutoCloseable) { + try { + ((AutoCloseable) httpClient).close(); + } catch (final Exception e) { + log.error("Error closing HTTP client", e); + } + } + httpClient = null; + metadataURI = null; + cachedMetadataETag = null; + cachedMetadataLastModified = null; + + super.doDestroy(); + } + + @Override + protected String getMetadataIdentifier() { + return metadataURI.toString(); + } + + @Override + protected byte[] fetchMetadata() throws ResolverException { + final HttpGet httpGet = buildHttpGet(); + final HttpClientContext context = HttpClientContext.create(); + + try { + log.debug("{} Attempting to fetch metadata document from '{}'", getLogPrefix(), metadataURI); + return httpClient.execute(httpGet, context, response -> { + final int httpStatusCode = response.getCode(); + if (httpStatusCode == HttpStatus.SC_NOT_MODIFIED) { + log.debug("{} Metadata document from '{}' has not changed since last retrieval", getLogPrefix(), getMetadataURI()); + return null; + } + if (httpStatusCode != HttpStatus.SC_OK) { + final String errMsg = "Non-ok status code " + httpStatusCode + " returned from remote metadata source " + metadataURI; + log.error("{} " + errMsg, getLogPrefix()); + throw new HttpException(errMsg); + } + + processConditionalRetrievalHeaders(response); + try { + return getMetadataBytesFromResponse(response); + } catch (ResolverException e) { + final String errMsg = "Error retrieving metadata from " + metadataURI; + throw new HttpException(errMsg, e); + } + }); + } catch (final IOException e) { + final String errMsg = "Error retrieving metadata from " + metadataURI; + log.error("{} {}: {}", getLogPrefix(), errMsg, e.getMessage()); + throw new ResolverException(errMsg, e); + } + } + + protected HttpGet buildHttpGet() { + final HttpGet getMethod = new HttpGet(getMetadataURI()); + + if (cachedMetadataETag != null) { + getMethod.setHeader(HttpHeaders.IF_NONE_MATCH, cachedMetadataETag); + } + if (cachedMetadataLastModified != null) { + getMethod.setHeader(HttpHeaders.IF_MODIFIED_SINCE, cachedMetadataLastModified); + } + + return getMethod; + } + + protected void processConditionalRetrievalHeaders(final ClassicHttpResponse response) { + Header httpHeader = response.getFirstHeader(HttpHeaders.ETAG); + if (httpHeader != null) { + cachedMetadataETag = httpHeader.getValue(); + } + + httpHeader = response.getFirstHeader(HttpHeaders.LAST_MODIFIED); + if (httpHeader != null) { + cachedMetadataLastModified = httpHeader.getValue(); + } + } + + protected byte[] getMetadataBytesFromResponse(final ClassicHttpResponse response) throws ResolverException { + log.debug("{} Attempting to extract metadata from response to request for metadata from '{}'", getLogPrefix(), getMetadataURI()); + try { + final InputStream ins = response.getEntity().getContent(); + return inputstreamToByteArray(ins); + } catch (final IOException e) { + log.error("{} Unable to read response: {}", getLogPrefix(), e.getMessage()); + throw new ResolverException("Unable to read response", e); + } finally { + // Make sure entity has been completely consumed. + EntityUtils.consumeQuietly(response.getEntity()); + } + } +} diff --git a/src/main/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticator.java index ae3d1c9128..54b142f46c 100644 --- a/src/main/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticator.java @@ -28,7 +28,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import org.apache.commons.lang3.StringEscapeUtils; -import org.apache.http.HttpStatus; +import org.apache.hc.core5.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/com/amazon/dlic/auth/http/saml/SamlHTTPMetadataResolver.java b/src/main/java/com/amazon/dlic/auth/http/saml/SamlHTTPMetadataResolver.java index d3e5571ece..13a615fb6c 100644 --- a/src/main/java/com/amazon/dlic/auth/http/saml/SamlHTTPMetadataResolver.java +++ b/src/main/java/com/amazon/dlic/auth/http/saml/SamlHTTPMetadataResolver.java @@ -17,16 +17,21 @@ import java.security.PrivilegedExceptionAction; import java.time.Duration; -import org.apache.http.client.HttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; +import org.apache.hc.client5.http.classic.HttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; +import org.apache.hc.client5.http.socket.ConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.core5.http.URIScheme; +import org.apache.hc.core5.http.config.Registry; +import org.apache.hc.core5.http.config.RegistryBuilder; import org.opensearch.SpecialPermission; import org.opensearch.common.settings.Settings; -import com.amazon.dlic.util.SettingsBasedSSLConfiguratorV4; +import com.amazon.dlic.util.SettingsBasedSSLConfiguratorV5; import net.shibboleth.utilities.java.support.resolver.ResolverException; -import org.opensaml.saml.metadata.resolver.impl.HTTPMetadataResolver; public class SamlHTTPMetadataResolver extends HTTPMetadataResolver { @@ -38,10 +43,9 @@ public class SamlHTTPMetadataResolver extends HTTPMetadataResolver { } @Override - @SuppressWarnings("removal") protected byte[] fetchMetadata() throws ResolverException { try { - return AccessController.doPrivileged((PrivilegedExceptionAction) () -> SamlHTTPMetadataResolver.super.fetchMetadata()); + return AccessController.doPrivileged((PrivilegedExceptionAction) SamlHTTPMetadataResolver.super::fetchMetadata); } catch (PrivilegedActionException e) { if (e.getCause() instanceof ResolverException) { @@ -52,11 +56,10 @@ protected byte[] fetchMetadata() throws ResolverException { } } - private static SettingsBasedSSLConfiguratorV4.SSLConfig getSSLConfig(Settings settings, Path configPath) throws Exception { - return new SettingsBasedSSLConfiguratorV4(settings, configPath, "idp").buildSSLConfig(); + private static SettingsBasedSSLConfiguratorV5.SSLConfig getSSLConfig(Settings settings, Path configPath) throws Exception { + return new SettingsBasedSSLConfiguratorV5(settings, configPath, "idp").buildSSLConfig(); } - @SuppressWarnings("removal") private static HttpClient createHttpClient(Settings settings, Path configPath) throws Exception { try { final SecurityManager sm = System.getSecurityManager(); @@ -86,10 +89,16 @@ private static HttpClient createHttpClient0(Settings settings, Path configPath) builder.useSystemProperties(); - SettingsBasedSSLConfiguratorV4.SSLConfig sslConfig = getSSLConfig(settings, configPath); + SettingsBasedSSLConfiguratorV5.SSLConfig sslConfig = getSSLConfig(settings, configPath); if (sslConfig != null) { - builder.setSSLSocketFactory(sslConfig.toSSLConnectionSocketFactory()); + SSLConnectionSocketFactory sslConnectionSocketFactory = sslConfig.toSSLConnectionSocketFactory(); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register(URIScheme.HTTPS.id, sslConnectionSocketFactory) + .build(); + + BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); + builder.setConnectionManager(connectionManager); } return builder.build(); diff --git a/src/main/java/com/amazon/dlic/util/SettingsBasedSSLConfiguratorV4.java b/src/main/java/com/amazon/dlic/util/SettingsBasedSSLConfiguratorV5.java similarity index 93% rename from src/main/java/com/amazon/dlic/util/SettingsBasedSSLConfiguratorV4.java rename to src/main/java/com/amazon/dlic/util/SettingsBasedSSLConfiguratorV5.java index 9c273a14a4..9e49424ca8 100644 --- a/src/main/java/com/amazon/dlic/util/SettingsBasedSSLConfiguratorV4.java +++ b/src/main/java/com/amazon/dlic/util/SettingsBasedSSLConfiguratorV5.java @@ -11,7 +11,6 @@ package com.amazon.dlic.util; -import java.net.Socket; import java.nio.file.Path; import java.security.KeyManagementException; import java.security.KeyStore; @@ -25,7 +24,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.Map; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; @@ -33,14 +31,11 @@ import javax.net.ssl.X509TrustManager; import com.google.common.collect.ImmutableList; -import org.apache.http.conn.ssl.DefaultHostnameVerifier; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy; -import org.apache.http.ssl.PrivateKeyDetails; -import org.apache.http.ssl.PrivateKeyStrategy; -import org.apache.http.ssl.SSLContextBuilder; -import org.apache.http.ssl.SSLContexts; +import org.apache.hc.client5.http.ssl.DefaultHostnameVerifier; +import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.core5.ssl.SSLContextBuilder; +import org.apache.hc.core5.ssl.SSLContexts; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -51,7 +46,7 @@ import static org.opensearch.security.ssl.SecureSSLSettings.SSLSetting.SECURITY_SSL_TRANSPORT_KEYSTORE_PASSWORD; import static org.opensearch.security.ssl.SecureSSLSettings.SSLSetting.SECURITY_SSL_TRANSPORT_TRUSTSTORE_PASSWORD; -public class SettingsBasedSSLConfiguratorV4 { +public class SettingsBasedSSLConfiguratorV5 { private static final Logger log = LogManager.getLogger(SettingsBasedSSLConfigurator.class); public static final String CERT_ALIAS = "cert_alias"; @@ -95,14 +90,14 @@ public class SettingsBasedSSLConfiguratorV4 { private String effectiveKeyAlias; private List effectiveTruststoreAliases; - public SettingsBasedSSLConfiguratorV4(Settings settings, Path configPath, String settingsKeyPrefix, String clientName) { + public SettingsBasedSSLConfiguratorV5(Settings settings, Path configPath, String settingsKeyPrefix, String clientName) { this.settings = settings; this.configPath = configPath; this.settingsKeyPrefix = normalizeSettingsKeyPrefix(settingsKeyPrefix); this.clientName = clientName != null ? clientName : this.settingsKeyPrefix; } - public SettingsBasedSSLConfiguratorV4(Settings settings, Path configPath, String settingsKeyPrefix) { + public SettingsBasedSSLConfiguratorV5(Settings settings, Path configPath, String settingsKeyPrefix) { this(settings, configPath, settingsKeyPrefix, null); } @@ -203,20 +198,16 @@ private void configureWithSettings() throws SSLConfigException, NoSuchAlgorithmE if (enableSslClientAuth) { if (effectiveKeystore != null) { try { - sslContextBuilder.loadKeyMaterial(effectiveKeystore, effectiveKeyPassword, new PrivateKeyStrategy() { - - @Override - public String chooseAlias(Map aliases, Socket socket) { - if (aliases == null || aliases.isEmpty()) { - return effectiveKeyAlias; - } - - if (effectiveKeyAlias == null || effectiveKeyAlias.isEmpty()) { - return aliases.keySet().iterator().next(); - } - + sslContextBuilder.loadKeyMaterial(effectiveKeystore, effectiveKeyPassword, (aliases, socket) -> { + if (aliases == null || aliases.isEmpty()) { return effectiveKeyAlias; } + + if (effectiveKeyAlias == null || effectiveKeyAlias.isEmpty()) { + return aliases.keySet().iterator().next(); + } + + return effectiveKeyAlias; }); } catch (UnrecoverableKeyException e) { throw new RuntimeException(e); @@ -470,10 +461,6 @@ public HostnameVerifier getHostnameVerifier() { return hostnameVerifier; } - public SSLIOSessionStrategy toSSLIOSessionStrategy() { - return new SSLIOSessionStrategy(sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifier); - } - public SSLConnectionSocketFactory toSSLConnectionSocketFactory() { return new SSLConnectionSocketFactory(sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifier); } diff --git a/src/test/java/org/opensearch/security/util/SettingsBasedSSLConfiguratorV4Test.java b/src/test/java/org/opensearch/security/util/SettingsBasedSSLConfiguratorV5Test.java similarity index 64% rename from src/test/java/org/opensearch/security/util/SettingsBasedSSLConfiguratorV4Test.java rename to src/test/java/org/opensearch/security/util/SettingsBasedSSLConfiguratorV5Test.java index e1e3d979fd..ae56e7ca6e 100644 --- a/src/test/java/org/opensearch/security/util/SettingsBasedSSLConfiguratorV4Test.java +++ b/src/test/java/org/opensearch/security/util/SettingsBasedSSLConfiguratorV5Test.java @@ -22,41 +22,45 @@ import java.nio.file.Path; import java.security.GeneralSecurityException; import java.security.KeyStore; -import java.security.cert.Certificate; import java.util.Map; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLServerSocket; -import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManagerFactory; -import org.apache.http.HttpConnectionFactory; -import org.apache.http.HttpException; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.config.ConnectionConfig; -import org.apache.http.config.MessageConstraints; -import org.apache.http.entity.ContentLengthStrategy; -import org.apache.http.impl.ConnSupport; -import org.apache.http.impl.DefaultBHttpServerConnection; -import org.apache.http.impl.bootstrap.HttpServer; -import org.apache.http.impl.bootstrap.SSLServerSetupHandler; -import org.apache.http.impl.bootstrap.ServerBootstrap; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.io.HttpMessageParserFactory; -import org.apache.http.io.HttpMessageWriterFactory; -import org.apache.http.protocol.HttpContext; -import org.apache.http.protocol.HttpRequestHandler; -import org.apache.http.ssl.PrivateKeyDetails; -import org.apache.http.ssl.PrivateKeyStrategy; -import org.apache.http.ssl.SSLContextBuilder; -import org.apache.http.ssl.SSLContexts; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; +import org.apache.hc.client5.http.socket.ConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.core5.function.Callback; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.ContentLengthStrategy; +import org.apache.hc.core5.http.URIScheme; +import org.apache.hc.core5.http.config.Http1Config; +import org.apache.hc.core5.http.config.Registry; +import org.apache.hc.core5.http.config.RegistryBuilder; +import org.apache.hc.core5.http.impl.DefaultContentLengthStrategy; +import org.apache.hc.core5.http.impl.bootstrap.HttpServer; +import org.apache.hc.core5.http.impl.bootstrap.ServerBootstrap; +import org.apache.hc.core5.http.impl.io.DefaultBHttpServerConnection; +import org.apache.hc.core5.http.impl.io.DefaultHttpRequestParserFactory; +import org.apache.hc.core5.http.impl.io.DefaultHttpResponseWriterFactory; +import org.apache.hc.core5.http.io.HttpConnectionFactory; +import org.apache.hc.core5.http.io.HttpMessageParserFactory; +import org.apache.hc.core5.http.io.HttpMessageWriterFactory; +import org.apache.hc.core5.io.CloseMode; +import org.apache.hc.core5.ssl.PrivateKeyDetails; +import org.apache.hc.core5.ssl.PrivateKeyStrategy; +import org.apache.hc.core5.ssl.SSLContextBuilder; +import org.apache.hc.core5.ssl.SSLContexts; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; @@ -68,14 +72,14 @@ import org.opensearch.security.test.helper.file.FileHelper; import org.opensearch.security.test.helper.network.SocketUtils; -import com.amazon.dlic.util.SettingsBasedSSLConfiguratorV4; -import com.amazon.dlic.util.SettingsBasedSSLConfiguratorV4.SSLConfig; +import com.amazon.dlic.util.SettingsBasedSSLConfiguratorV5; +import com.amazon.dlic.util.SettingsBasedSSLConfiguratorV5.SSLConfig; import static org.hamcrest.CoreMatchers.either; import static org.hamcrest.CoreMatchers.instanceOf; import static org.opensearch.security.ssl.SecureSSLSettings.SSLSetting.SECURITY_SSL_TRANSPORT_TRUSTSTORE_PASSWORD; -public class SettingsBasedSSLConfiguratorV4Test { +public class SettingsBasedSSLConfiguratorV5Test { @Rule public ExpectedException thrown = ExpectedException.none(); @@ -102,13 +106,16 @@ public void testPemTrust() throws Exception { .build(); Path configPath = rootCaPemPath.getParent(); - SettingsBasedSSLConfiguratorV4 sbsc = new SettingsBasedSSLConfiguratorV4(settings, configPath, "prefix"); + SettingsBasedSSLConfiguratorV5 sbsc = new SettingsBasedSSLConfiguratorV5(settings, configPath, "prefix"); SSLConfig sslConfig = sbsc.buildSSLConfig(); + SSLConnectionSocketFactory sslConnectionSocketFactory = sslConfig.toSSLConnectionSocketFactory(); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register(URIScheme.HTTPS.id, sslConnectionSocketFactory) + .build(); + BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); - try ( - CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConfig.toSSLConnectionSocketFactory()).build() - ) { + try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();) { try (CloseableHttpResponse response = httpClient.execute(new HttpGet(testServer.getUri()))) { // Success @@ -138,13 +145,16 @@ public void testPemWrongTrust() throws Exception { .build(); Path configPath = rootCaPemPath.getParent(); - SettingsBasedSSLConfiguratorV4 sbsc = new SettingsBasedSSLConfiguratorV4(settings, configPath, "prefix"); + SettingsBasedSSLConfiguratorV5 sbsc = new SettingsBasedSSLConfiguratorV5(settings, configPath, "prefix"); SSLConfig sslConfig = sbsc.buildSSLConfig(); + SSLConnectionSocketFactory sslConnectionSocketFactory = sslConfig.toSSLConnectionSocketFactory(); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register(URIScheme.HTTPS.id, sslConnectionSocketFactory) + .build(); + BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); - try ( - CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConfig.toSSLConnectionSocketFactory()).build() - ) { + try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build()) { thrown.expect(SSLHandshakeException.class); @@ -180,13 +190,16 @@ public void testPemClientAuth() throws Exception { .build(); Path configPath = rootCaPemPath.getParent(); - SettingsBasedSSLConfiguratorV4 sbsc = new SettingsBasedSSLConfiguratorV4(settings, configPath, "prefix"); + SettingsBasedSSLConfiguratorV5 sbsc = new SettingsBasedSSLConfiguratorV5(settings, configPath, "prefix"); SSLConfig sslConfig = sbsc.buildSSLConfig(); + SSLConnectionSocketFactory sslConnectionSocketFactory = sslConfig.toSSLConnectionSocketFactory(); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register(URIScheme.HTTPS.id, sslConnectionSocketFactory) + .build(); + BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); - try ( - CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConfig.toSSLConnectionSocketFactory()).build() - ) { + try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build()) { try (CloseableHttpResponse response = httpClient.execute(new HttpGet(testServer.getUri()))) { // Success @@ -220,22 +233,24 @@ public void testPemClientAuthFailure() throws Exception { .build(); Path configPath = rootCaPemPath.getParent(); - SettingsBasedSSLConfiguratorV4 sbsc = new SettingsBasedSSLConfiguratorV4(settings, configPath, "prefix"); + SettingsBasedSSLConfiguratorV5 sbsc = new SettingsBasedSSLConfiguratorV5(settings, configPath, "prefix"); SSLConfig sslConfig = sbsc.buildSSLConfig(); - - try ( - CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConfig.toSSLConnectionSocketFactory()).build() - ) { + SSLConnectionSocketFactory sslConnectionSocketFactory = sslConfig.toSSLConnectionSocketFactory(); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register(URIScheme.HTTPS.id, sslConnectionSocketFactory) + .build(); + BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); + try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build()) { // Due to some race condition in Java's internal network stack, this can be one // of the following exceptions thrown.expect( either(instanceOf(SocketException.class)).or(instanceOf(SSLHandshakeException.class)).or(instanceOf(SSLException.class)) // Java - // 11: - // javax.net.ssl.SSLException: - // readHandshakeRecord + // 11: + // javax.net.ssl.SSLException: + // readHandshakeRecord ); try (CloseableHttpResponse response = httpClient.execute(new HttpGet(testServer.getUri()))) { @@ -266,13 +281,15 @@ public void testPemHostnameVerificationFailure() throws Exception { .build(); Path configPath = rootCaPemPath.getParent(); - SettingsBasedSSLConfiguratorV4 sbsc = new SettingsBasedSSLConfiguratorV4(settings, configPath, "prefix"); + SettingsBasedSSLConfiguratorV5 sbsc = new SettingsBasedSSLConfiguratorV5(settings, configPath, "prefix"); SSLConfig sslConfig = sbsc.buildSSLConfig(); - - try ( - CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConfig.toSSLConnectionSocketFactory()).build() - ) { + SSLConnectionSocketFactory sslConnectionSocketFactory = sslConfig.toSSLConnectionSocketFactory(); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register(URIScheme.HTTPS.id, sslConnectionSocketFactory) + .build(); + BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); + try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build()) { thrown.expect(SSLPeerUnverifiedException.class); @@ -304,13 +321,15 @@ public void testPemHostnameVerificationOff() throws Exception { .build(); Path configPath = rootCaPemPath.getParent(); - SettingsBasedSSLConfiguratorV4 sbsc = new SettingsBasedSSLConfiguratorV4(settings, configPath, "prefix"); + SettingsBasedSSLConfiguratorV5 sbsc = new SettingsBasedSSLConfiguratorV5(settings, configPath, "prefix"); SSLConfig sslConfig = sbsc.buildSSLConfig(); - - try ( - CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConfig.toSSLConnectionSocketFactory()).build() - ) { + SSLConnectionSocketFactory sslConnectionSocketFactory = sslConfig.toSSLConnectionSocketFactory(); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register(URIScheme.HTTPS.id, sslConnectionSocketFactory) + .build(); + BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); + try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build()) { try (CloseableHttpResponse response = httpClient.execute(new HttpGet(testServer.getUri()))) { // Success @@ -342,13 +361,15 @@ public void testJksTrust() throws Exception { .build(); Path configPath = rootCaJksPath.getParent(); - SettingsBasedSSLConfiguratorV4 sbsc = new SettingsBasedSSLConfiguratorV4(settings, configPath, "prefix"); + SettingsBasedSSLConfiguratorV5 sbsc = new SettingsBasedSSLConfiguratorV5(settings, configPath, "prefix"); SSLConfig sslConfig = sbsc.buildSSLConfig(); - - try ( - CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConfig.toSSLConnectionSocketFactory()).build() - ) { + SSLConnectionSocketFactory sslConnectionSocketFactory = sslConfig.toSSLConnectionSocketFactory(); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register(URIScheme.HTTPS.id, sslConnectionSocketFactory) + .build(); + BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); + try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build()) { try (CloseableHttpResponse response = httpClient.execute(new HttpGet(testServer.getUri()))) { // Success @@ -381,13 +402,15 @@ public void testJksWrongTrust() throws Exception { .build(); Path configPath = rootCaJksPath.getParent(); - SettingsBasedSSLConfiguratorV4 sbsc = new SettingsBasedSSLConfiguratorV4(settings, configPath, "prefix"); + SettingsBasedSSLConfiguratorV5 sbsc = new SettingsBasedSSLConfiguratorV5(settings, configPath, "prefix"); SSLConfig sslConfig = sbsc.buildSSLConfig(); - - try ( - CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConfig.toSSLConnectionSocketFactory()).build() - ) { + SSLConnectionSocketFactory sslConnectionSocketFactory = sslConfig.toSSLConnectionSocketFactory(); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register(URIScheme.HTTPS.id, sslConnectionSocketFactory) + .build(); + BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); + try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build()) { thrown.expect(SSLHandshakeException.class); @@ -417,13 +440,15 @@ public void testTrustAll() throws Exception { .build(); Path configPath = rootCaJksPath.getParent(); - SettingsBasedSSLConfiguratorV4 sbsc = new SettingsBasedSSLConfiguratorV4(settings, configPath, "prefix"); + SettingsBasedSSLConfiguratorV5 sbsc = new SettingsBasedSSLConfiguratorV5(settings, configPath, "prefix"); SSLConfig sslConfig = sbsc.buildSSLConfig(); - - try ( - CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConfig.toSSLConnectionSocketFactory()).build() - ) { + SSLConnectionSocketFactory sslConnectionSocketFactory = sslConfig.toSSLConnectionSocketFactory(); + Registry socketFactoryRegistry = RegistryBuilder.create() + .register(URIScheme.HTTPS.id, sslConnectionSocketFactory) + .build(); + BasicHttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(socketFactoryRegistry); + try (CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build()) { try (CloseableHttpResponse response = httpClient.execute(new HttpGet(testServer.getUri()))) { // Success @@ -449,21 +474,12 @@ private void createHttpServer(String trustStore, String keyStore, String passwor ServerBootstrap serverBootstrap = ServerBootstrap.bootstrap() .setListenerPort(port) - .registerHandler("test", new HttpRequestHandler() { - + .setSslContext(createSSLContext(trustStore, keyStore, password)) + .setSslSetupHandler(new Callback() { @Override - public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { - - } - }); - - serverBootstrap = serverBootstrap.setSslContext(createSSLContext(trustStore, keyStore, password)) - .setSslSetupHandler(new SSLServerSetupHandler() { - - @Override - public void initialize(SSLServerSocket socket) throws SSLException { + public void execute(SSLParameters object) { if (clientAuth) { - socket.setNeedClientAuth(true); + object.setNeedClientAuth(true); } } }) @@ -474,15 +490,14 @@ public void initialize(SSLServerSocket socket) throws SSLException { @Override public DefaultBHttpServerConnection createConnection(final Socket socket) throws IOException { final SSLTestHttpServerConnection conn = new SSLTestHttpServerConnection( - this.cconfig.getBufferSize(), - this.cconfig.getFragmentSizeHint(), - ConnSupport.createDecoder(this.cconfig), - ConnSupport.createEncoder(this.cconfig), - this.cconfig.getMessageConstraints(), - null, + "http", + Http1Config.DEFAULT, null, null, - null + DefaultContentLengthStrategy.INSTANCE, + DefaultContentLengthStrategy.INSTANCE, + DefaultHttpRequestParserFactory.INSTANCE, + DefaultHttpResponseWriterFactory.INSTANCE ); conn.bind(socket); return conn; @@ -497,7 +512,7 @@ public DefaultBHttpServerConnection createConnection(final Socket socket) throws @Override public void close() throws IOException { if (this.httpServer != null) { - this.httpServer.shutdown(0, null); + this.httpServer.close(CloseMode.IMMEDIATE); } } @@ -531,7 +546,7 @@ private SSLContext createSSLContext(String trustStorePath, String keyStorePath, sslContextBuilder.loadKeyMaterial(keyStore, password.toCharArray(), new PrivateKeyStrategy() { @Override - public String chooseAlias(Map aliases, Socket socket) { + public String chooseAlias(Map aliases, SSLParameters sslParameters) { return "node1"; } }); @@ -544,32 +559,26 @@ public String chooseAlias(Map aliases, Socket socket) static class SSLTestHttpServerConnection extends DefaultBHttpServerConnection { public SSLTestHttpServerConnection( - final int buffersize, - final int fragmentSizeHint, + final String scheme, + final Http1Config http1Config, final CharsetDecoder chardecoder, final CharsetEncoder charencoder, - final MessageConstraints constraints, final ContentLengthStrategy incomingContentStrategy, final ContentLengthStrategy outgoingContentStrategy, - final HttpMessageParserFactory requestParserFactory, - final HttpMessageWriterFactory responseWriterFactory + final HttpMessageParserFactory requestParserFactory, + final HttpMessageWriterFactory responseWriterFactory ) { super( - buffersize, - fragmentSizeHint, + scheme, + http1Config, chardecoder, charencoder, - constraints, incomingContentStrategy, outgoingContentStrategy, requestParserFactory, responseWriterFactory ); } - - public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { - return ((SSLSocket) getSocket()).getSession().getPeerCertificates(); - } } } }