Upgrade to HttpClient5 5.4

Closes gh-42675
This commit is contained in:
Moritz Halbritter 2024-10-16 15:05:39 +02:00
parent dc78bd468c
commit d1976a48dc
7 changed files with 119 additions and 136 deletions

View File

@ -575,7 +575,7 @@ bom {
] ]
} }
} }
library("HttpClient5", "5.3.1") { library("HttpClient5", "5.4") {
group("org.apache.httpcomponents.client5") { group("org.apache.httpcomponents.client5") {
modules = [ modules = [
"httpclient5", "httpclient5",

View File

@ -38,8 +38,8 @@ import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder; import org.apache.hc.client5.http.ssl.TlsSocketStrategy;
import org.apache.hc.core5.http.io.SocketConfig; import org.apache.hc.core5.http.io.SocketConfig;
import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.http.ssl.TLS; import org.apache.hc.core5.http.ssl.TLS;
@ -992,7 +992,7 @@ public class TestRestTemplate {
ENABLE_REDIRECTS, ENABLE_REDIRECTS,
/** /**
* Use a {@link SSLConnectionSocketFactory} that trusts self-signed certificates. * Use a {@link TlsSocketStrategy} that trusts self-signed certificates.
*/ */
SSL SSL
@ -1038,7 +1038,7 @@ public class TestRestTemplate {
throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException { throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException {
PoolingHttpClientConnectionManagerBuilder builder = PoolingHttpClientConnectionManagerBuilder.create(); PoolingHttpClientConnectionManagerBuilder builder = PoolingHttpClientConnectionManagerBuilder.create();
if (ssl) { if (ssl) {
builder.setSSLSocketFactory(createSocketFactory()); builder.setTlsSocketStrategy(createTlsSocketStrategy());
} }
if (readTimeout != null) { if (readTimeout != null) {
SocketConfig socketConfig = SocketConfig.custom() SocketConfig socketConfig = SocketConfig.custom()
@ -1049,14 +1049,12 @@ public class TestRestTemplate {
return builder.build(); return builder.build();
} }
private SSLConnectionSocketFactory createSocketFactory() private TlsSocketStrategy createTlsSocketStrategy()
throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException { throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()) SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
.build(); .build();
return SSLConnectionSocketFactoryBuilder.create() return new DefaultClientTlsStrategy(sslContext, new String[] { TLS.V_1_3.getId(), TLS.V_1_2.getId() }, null,
.setSslContext(sslContext) null, null);
.setTlsVersions(TLS.V_1_3, TLS.V_1_2)
.build();
} }
@Override @Override

View File

@ -18,9 +18,8 @@ package org.springframework.boot.buildpack.platform.docker.transport;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.Proxy;
import java.net.Socket; import java.net.Socket;
import java.net.UnknownHostException;
import com.sun.jna.Platform; import com.sun.jna.Platform;
import org.apache.hc.client5.http.DnsResolver; import org.apache.hc.client5.http.DnsResolver;
@ -30,12 +29,11 @@ import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; 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.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.io.DefaultHttpClientConnectionOperator;
import org.apache.hc.client5.http.io.DetachedSocketFactory;
import org.apache.hc.client5.http.io.HttpClientConnectionManager; import org.apache.hc.client5.http.io.HttpClientConnectionManager;
import org.apache.hc.client5.http.routing.HttpRoutePlanner; import org.apache.hc.client5.http.routing.HttpRoutePlanner;
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.config.Registry;
import org.apache.hc.core5.http.config.RegistryBuilder;
import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.util.TimeValue; import org.apache.hc.core5.util.TimeValue;
@ -48,6 +46,7 @@ import org.springframework.boot.buildpack.platform.socket.UnixDomainSocket;
* *
* @author Phillip Webb * @author Phillip Webb
* @author Scott Frederick * @author Scott Frederick
* @author Moritz Halbritter
*/ */
final class LocalHttpClientTransport extends HttpClientTransport { final class LocalHttpClientTransport extends HttpClientTransport {
@ -62,9 +61,9 @@ final class LocalHttpClientTransport extends HttpClientTransport {
} }
static LocalHttpClientTransport create(ResolvedDockerHost dockerHost) { static LocalHttpClientTransport create(ResolvedDockerHost dockerHost) {
HttpClientBuilder builder = HttpClients.custom(); HttpClientBuilder builder = HttpClients.custom()
builder.setConnectionManager(new LocalConnectionManager(dockerHost.getAddress())); .setConnectionManager(new LocalConnectionManager(dockerHost))
builder.setRoutePlanner(new LocalRoutePlanner()); .setRoutePlanner(new LocalRoutePlanner());
HttpHost host = new HttpHost(DOCKER_SCHEME, dockerHost.getAddress()); HttpHost host = new HttpHost(DOCKER_SCHEME, dockerHost.getAddress());
return new LocalHttpClientTransport(builder.build(), host); return new LocalHttpClientTransport(builder.build(), host);
} }
@ -78,15 +77,34 @@ final class LocalHttpClientTransport extends HttpClientTransport {
.setValidateAfterInactivity(TimeValue.NEG_ONE_MILLISECOND) .setValidateAfterInactivity(TimeValue.NEG_ONE_MILLISECOND)
.build(); .build();
LocalConnectionManager(String host) { LocalConnectionManager(ResolvedDockerHost dockerHost) {
super(getRegistry(host), null, null, new LocalDnsResolver()); super(new DefaultHttpClientConnectionOperator(new LocalDetachedSocketFactory(dockerHost), null,
new LocalDnsResolver(), (name) -> null), null);
setConnectionConfig(CONNECTION_CONFIG); setConnectionConfig(CONNECTION_CONFIG);
} }
private static Registry<ConnectionSocketFactory> getRegistry(String host) { }
RegistryBuilder<ConnectionSocketFactory> builder = RegistryBuilder.create();
builder.register(DOCKER_SCHEME, new LocalConnectionSocketFactory(host)); /**
return builder.build(); * {@link DetachedSocketFactory} for local Docker.
*/
static class LocalDetachedSocketFactory implements DetachedSocketFactory {
private static final String NPIPE_PREFIX = "npipe://";
private final ResolvedDockerHost dockerHost;
LocalDetachedSocketFactory(ResolvedDockerHost dockerHost) {
this.dockerHost = dockerHost;
}
@Override
public Socket create(Proxy proxy) throws IOException {
String address = this.dockerHost.getAddress();
if (address.startsWith(NPIPE_PREFIX)) {
return NamedPipeSocket.get(address.substring(NPIPE_PREFIX.length()));
}
return (!Platform.isWindows()) ? UnixDomainSocket.get(address) : NamedPipeSocket.get(address);
} }
} }
@ -99,48 +117,17 @@ final class LocalHttpClientTransport extends HttpClientTransport {
private static final InetAddress LOOPBACK = InetAddress.getLoopbackAddress(); private static final InetAddress LOOPBACK = InetAddress.getLoopbackAddress();
@Override @Override
public InetAddress[] resolve(String host) throws UnknownHostException { public InetAddress[] resolve(String host) {
return new InetAddress[] { LOOPBACK }; return new InetAddress[] { LOOPBACK };
} }
@Override @Override
public String resolveCanonicalHostname(String host) throws UnknownHostException { public String resolveCanonicalHostname(String host) {
return LOOPBACK.getCanonicalHostName(); return LOOPBACK.getCanonicalHostName();
} }
} }
/**
* {@link ConnectionSocketFactory} that connects to the local Docker domain socket or
* named pipe.
*/
private static class LocalConnectionSocketFactory implements ConnectionSocketFactory {
private static final String NPIPE_PREFIX = "npipe://";
private final String host;
LocalConnectionSocketFactory(String host) {
this.host = host;
}
@Override
public Socket createSocket(HttpContext context) throws IOException {
if (this.host.startsWith(NPIPE_PREFIX)) {
return NamedPipeSocket.get(this.host.substring(NPIPE_PREFIX.length()));
}
return (!Platform.isWindows()) ? UnixDomainSocket.get(this.host) : NamedPipeSocket.get(this.host);
}
@Override
public Socket connectSocket(TimeValue connectTimeout, Socket socket, HttpHost host,
InetSocketAddress remoteAddress, InetSocketAddress localAddress, HttpContext context)
throws IOException {
return socket;
}
}
/** /**
* {@link HttpRoutePlanner} for local Docker. * {@link HttpRoutePlanner} for local Docker.
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2023 the original author or authors. * Copyright 2012-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,8 +25,8 @@ 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.HttpClientBuilder;
import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory; import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; import org.apache.hc.client5.http.ssl.TlsSocketStrategy;
import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.io.SocketConfig; import org.apache.hc.core5.http.io.SocketConfig;
import org.apache.hc.core5.util.Timeout; import org.apache.hc.core5.util.Timeout;
@ -74,7 +74,7 @@ final class RemoteHttpClientTransport extends HttpClientTransport {
.create() .create()
.setDefaultSocketConfig(socketConfig); .setDefaultSocketConfig(socketConfig);
if (host.isSecure()) { if (host.isSecure()) {
connectionManagerBuilder.setSSLSocketFactory(getSecureConnectionSocketFactory(host, sslContextFactory)); connectionManagerBuilder.setTlsSocketStrategy(getTlsSocketStrategy(host, sslContextFactory));
} }
HttpClientBuilder builder = HttpClients.custom(); HttpClientBuilder builder = HttpClients.custom();
builder.setConnectionManager(connectionManagerBuilder.build()); builder.setConnectionManager(connectionManagerBuilder.build());
@ -83,13 +83,12 @@ final class RemoteHttpClientTransport extends HttpClientTransport {
return new RemoteHttpClientTransport(builder.build(), httpHost); return new RemoteHttpClientTransport(builder.build(), httpHost);
} }
private static LayeredConnectionSocketFactory getSecureConnectionSocketFactory(DockerHost host, private static TlsSocketStrategy getTlsSocketStrategy(DockerHost host, SslContextFactory sslContextFactory) {
SslContextFactory sslContextFactory) {
String directory = host.getCertificatePath(); String directory = host.getCertificatePath();
Assert.hasText(directory, Assert.hasText(directory,
() -> "Docker host TLS verification requires trust material location to be specified with certificate path"); () -> "Docker host TLS verification requires trust material location to be specified with certificate path");
SSLContext sslContext = sslContextFactory.forDirectory(directory); SSLContext sslContext = sslContextFactory.forDirectory(directory);
return new SSLConnectionSocketFactory(sslContext); return new DefaultClientTlsStrategy(sslContext);
} }
} }

View File

@ -36,8 +36,8 @@ 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.HttpClientBuilder;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
import org.apache.hc.client5.http.ssl.DefaultHostnameVerifier; import org.apache.hc.client5.http.ssl.DefaultHostnameVerifier;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.http.io.SocketConfig; import org.apache.hc.core5.http.io.SocketConfig;
import org.eclipse.jetty.client.transport.HttpClientTransportDynamic; import org.eclipse.jetty.client.transport.HttpClientTransportDynamic;
import org.eclipse.jetty.io.ClientConnector; import org.eclipse.jetty.io.ClientConnector;
@ -209,9 +209,8 @@ public final class ClientHttpRequestFactories {
} }
if (sslBundle != null) { if (sslBundle != null) {
SslOptions options = sslBundle.getOptions(); SslOptions options = sslBundle.getOptions();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslBundle.createSslContext(), connectionManagerBuilder.setTlsSocketStrategy(new DefaultClientTlsStrategy(sslBundle.createSslContext(),
options.getEnabledProtocols(), options.getCiphers(), new DefaultHostnameVerifier()); options.getEnabledProtocols(), options.getCiphers(), null, new DefaultHostnameVerifier()));
connectionManagerBuilder.setSSLSocketFactory(socketFactory);
} }
PoolingHttpClientConnectionManager connectionManager = connectionManagerBuilder.useSystemProperties() PoolingHttpClientConnectionManager connectionManager = connectionManagerBuilder.useSystemProperties()
.build(); .build();

View File

@ -33,6 +33,7 @@ import java.util.concurrent.atomic.AtomicReference;
import javax.naming.InitialContext; import javax.naming.InitialContext;
import javax.naming.NamingException; import javax.naming.NamingException;
import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSession;
@ -64,7 +65,8 @@ import org.apache.coyote.http11.Http11Nio2Protocol;
import org.apache.hc.client5.http.HttpHostConnectException; import org.apache.hc.client5.http.HttpHostConnectException;
import org.apache.hc.client5.http.classic.HttpClient; import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
import org.apache.hc.client5.http.ssl.TlsSocketStrategy;
import org.apache.hc.core5.http.HttpResponse; import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.NoHttpResponseException; import org.apache.hc.core5.http.NoHttpResponseException;
import org.apache.hc.core5.ssl.SSLContextBuilder; import org.apache.hc.core5.ssl.SSLContextBuilder;
@ -670,12 +672,12 @@ class TomcatServletWebServerFactoryTests extends AbstractServletWebServerFactory
this.webServer = factory.getWebServer(); this.webServer = factory.getWebServer();
this.webServer.start(); this.webServer.start();
RememberingHostnameVerifier verifier = new RememberingHostnameVerifier(); RememberingHostnameVerifier verifier = new RememberingHostnameVerifier();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build(), verifier); TlsSocketStrategy tlsSocketStrategy = new DefaultClientTlsStrategy(sslContext, verifier);
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory); HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(tlsSocketStrategy);
assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test"); assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test");
assertThat(verifier.getLastPrincipal()).isEqualTo("CN=1"); assertThat(verifier.getLastPrincipal()).isEqualTo("CN=1");
requestFactory = createHttpComponentsRequestFactory(socketFactory); requestFactory = createHttpComponentsRequestFactory(tlsSocketStrategy);
bundles.updateBundle("test", createPemSslBundle("classpath:org/springframework/boot/web/embedded/tomcat/2.crt", bundles.updateBundle("test", createPemSslBundle("classpath:org/springframework/boot/web/embedded/tomcat/2.crt",
"classpath:org/springframework/boot/web/embedded/tomcat/2.key")); "classpath:org/springframework/boot/web/embedded/tomcat/2.key"));
assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test"); assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test");
@ -690,9 +692,8 @@ class TomcatServletWebServerFactoryTests extends AbstractServletWebServerFactory
factory.setSsl(getSsl(null, "password", "src/test/resources/test.jks")); factory.setSsl(getSsl(null, "password", "src/test/resources/test.jks"));
this.webServer = factory.getWebServer(); this.webServer = factory.getWebServer();
this.webServer.start(); this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build()); createTrustSelfSignedTlsSocketStrategy());
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory);
assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test"); assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test");
} }

View File

@ -29,7 +29,9 @@ import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
@ -89,7 +91,8 @@ import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
import org.apache.hc.client5.http.ssl.TlsSocketStrategy;
import org.apache.hc.core5.http.HttpResponse; import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.io.HttpClientResponseHandler; import org.apache.hc.core5.http.io.HttpClientResponseHandler;
import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.protocol.HttpContext;
@ -260,7 +263,7 @@ public abstract class AbstractServletWebServerFactoryTests {
} }
@Test @Test
void stopServlet() throws Exception { void stopServlet() {
AbstractServletWebServerFactory factory = getFactory(); AbstractServletWebServerFactory factory = getFactory();
this.webServer = factory.getWebServer(exampleServletRegistration()); this.webServer = factory.getWebServer(exampleServletRegistration());
this.webServer.start(); this.webServer.start();
@ -443,9 +446,8 @@ public abstract class AbstractServletWebServerFactoryTests {
factory.setSsl(ssl); factory.setSsl(ssl);
this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello")); this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello"));
this.webServer.start(); this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build()); createTrustSelfSignedTlsSocketStrategy());
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory);
assertThatExceptionOfType(SSLException.class) assertThatExceptionOfType(SSLException.class)
.isThrownBy(() -> getResponse(getLocalUrl("https", "/hello"), requestFactory)); .isThrownBy(() -> getResponse(getLocalUrl("https", "/hello"), requestFactory));
} }
@ -456,9 +458,8 @@ public abstract class AbstractServletWebServerFactoryTests {
factory.setSsl(getSsl(null, "password", "src/test/resources/test.jks")); factory.setSsl(getSsl(null, "password", "src/test/resources/test.jks"));
this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello")); this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello"));
this.webServer.start(); this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build()); createTrustSelfSignedTlsSocketStrategy());
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory);
assertThat(getResponse(getLocalUrl("https", "/hello"), requestFactory)).contains("scheme=https"); assertThat(getResponse(getLocalUrl("https", "/hello"), requestFactory)).contains("scheme=https");
} }
@ -474,7 +475,7 @@ public abstract class AbstractServletWebServerFactoryTests {
TrustStrategy trustStrategy = new SerialNumberValidatingTrustSelfSignedStrategy("14ca9ba6abe2a70d"); TrustStrategy trustStrategy = new SerialNumberValidatingTrustSelfSignedStrategy("14ca9ba6abe2a70d");
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, trustStrategy).build(); SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, trustStrategy).build();
PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
.setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext)) .setTlsSocketStrategy(new DefaultClientTlsStrategy(sslContext))
.build(); .build();
HttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build(); HttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();
String response = getResponse(getLocalUrl("https", "/hello"), String response = getResponse(getLocalUrl("https", "/hello"),
@ -504,10 +505,8 @@ public abstract class AbstractServletWebServerFactoryTests {
factory.setSsl(getSsl(null, "password", "src/test/resources/test.jks")); factory.setSsl(getSsl(null, "password", "src/test/resources/test.jks"));
this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello")); this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello"));
this.webServer.start(); this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build());
PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
.setSSLSocketFactory(socketFactory) .setTlsSocketStrategy(createTrustSelfSignedTlsSocketStrategy())
.build(); .build();
HttpClient httpClient = this.httpClientBuilder.get().setConnectionManager(connectionManager).build(); HttpClient httpClient = this.httpClientBuilder.get().setConnectionManager(connectionManager).build();
ClientHttpResponse response = getClientResponse(getLocalUrl("https", "/hello"), HttpMethod.GET, ClientHttpResponse response = getClientResponse(getLocalUrl("https", "/hello"), HttpMethod.GET,
@ -522,10 +521,8 @@ public abstract class AbstractServletWebServerFactoryTests {
factory.setSsl(getSsl(null, "password", "src/test/resources/test.jks")); factory.setSsl(getSsl(null, "password", "src/test/resources/test.jks"));
this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello")); this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello"));
this.webServer.start(); this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build());
PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
.setSSLSocketFactory(socketFactory) .setTlsSocketStrategy(createTrustSelfSignedTlsSocketStrategy())
.build(); .build();
HttpClient httpClient = this.httpClientBuilder.get().setConnectionManager(connectionManager).build(); HttpClient httpClient = this.httpClientBuilder.get().setConnectionManager(connectionManager).build();
ClientHttpResponse response = getClientResponse(getLocalUrl("https", "/hello"), HttpMethod.GET, ClientHttpResponse response = getClientResponse(getLocalUrl("https", "/hello"), HttpMethod.GET,
@ -539,9 +536,8 @@ public abstract class AbstractServletWebServerFactoryTests {
factory.setSsl(getSsl(null, "password", keyStore)); factory.setSsl(getSsl(null, "password", keyStore));
this.webServer = factory.getWebServer(); this.webServer = factory.getWebServer();
this.webServer.start(); this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build()); createTrustSelfSignedTlsSocketStrategy());
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory);
assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test"); assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test");
} }
@ -554,11 +550,11 @@ public abstract class AbstractServletWebServerFactoryTests {
this.webServer.start(); this.webServer.start();
KeyStore keyStore = KeyStore.getInstance("pkcs12"); KeyStore keyStore = KeyStore.getInstance("pkcs12");
loadStore(keyStore, new FileSystemResource("src/test/resources/test.p12")); loadStore(keyStore, new FileSystemResource("src/test/resources/test.p12"));
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()) .loadKeyMaterial(keyStore, "secret".toCharArray())
.loadKeyMaterial(keyStore, "secret".toCharArray()) .build();
.build()); HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory); new DefaultClientTlsStrategy(sslContext));
assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test"); assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test");
} }
@ -571,11 +567,11 @@ public abstract class AbstractServletWebServerFactoryTests {
this.webServer.start(); this.webServer.start();
KeyStore keyStore = KeyStore.getInstance("pkcs12"); KeyStore keyStore = KeyStore.getInstance("pkcs12");
loadStore(keyStore, new FileSystemResource("src/test/resources/test.p12")); loadStore(keyStore, new FileSystemResource("src/test/resources/test.p12"));
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()) .loadKeyMaterial(keyStore, "secret".toCharArray())
.loadKeyMaterial(keyStore, "secret".toCharArray()) .build();
.build()); HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory); new DefaultClientTlsStrategy(sslContext));
assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test"); assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test");
} }
@ -590,11 +586,11 @@ public abstract class AbstractServletWebServerFactoryTests {
this.webServer.start(); this.webServer.start();
KeyStore keyStore = KeyStore.getInstance("pkcs12"); KeyStore keyStore = KeyStore.getInstance("pkcs12");
loadStore(keyStore, new FileSystemResource("src/test/resources/test.p12")); loadStore(keyStore, new FileSystemResource("src/test/resources/test.p12"));
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()) .loadKeyMaterial(keyStore, "secret".toCharArray())
.loadKeyMaterial(keyStore, "secret".toCharArray()) .build();
.build()); HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory); new DefaultClientTlsStrategy(sslContext));
assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test"); assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test");
} }
@ -609,11 +605,11 @@ public abstract class AbstractServletWebServerFactoryTests {
this.webServer.start(); this.webServer.start();
KeyStore keyStore = KeyStore.getInstance("pkcs12"); KeyStore keyStore = KeyStore.getInstance("pkcs12");
loadStore(keyStore, new FileSystemResource("src/test/resources/test.p12")); loadStore(keyStore, new FileSystemResource("src/test/resources/test.p12"));
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()) .loadKeyMaterial(keyStore, "secret".toCharArray())
.loadKeyMaterial(keyStore, "secret".toCharArray()) .build();
.build()); HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory); new DefaultClientTlsStrategy(sslContext));
assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test"); assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test");
} }
@ -627,11 +623,11 @@ public abstract class AbstractServletWebServerFactoryTests {
this.webServer.start(); this.webServer.start();
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
loadStore(keyStore, new FileSystemResource("src/test/resources/test.jks")); loadStore(keyStore, new FileSystemResource("src/test/resources/test.jks"));
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()) .loadKeyMaterial(keyStore, "password".toCharArray())
.loadKeyMaterial(keyStore, "password".toCharArray()) .build();
.build()); HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory); new DefaultClientTlsStrategy(sslContext));
assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test"); assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test");
} }
@ -642,9 +638,8 @@ public abstract class AbstractServletWebServerFactoryTests {
factory.setSsl(getSsl(ClientAuth.NEED, "password", "classpath:test.jks")); factory.setSsl(getSsl(ClientAuth.NEED, "password", "classpath:test.jks"));
this.webServer = factory.getWebServer(); this.webServer = factory.getWebServer();
this.webServer.start(); this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build()); createTrustSelfSignedTlsSocketStrategy());
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory);
String localUrl = getLocalUrl("https", "/test.txt"); String localUrl = getLocalUrl("https", "/test.txt");
assertThatIOException().isThrownBy(() -> getResponse(localUrl, requestFactory)); assertThatIOException().isThrownBy(() -> getResponse(localUrl, requestFactory));
} }
@ -659,11 +654,11 @@ public abstract class AbstractServletWebServerFactoryTests {
this.webServer.start(); this.webServer.start();
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
loadStore(keyStore, new FileSystemResource("src/test/resources/test.jks")); loadStore(keyStore, new FileSystemResource("src/test/resources/test.jks"));
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy())
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()) .loadKeyMaterial(keyStore, "password".toCharArray())
.loadKeyMaterial(keyStore, "password".toCharArray()) .build();
.build()); HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory); new DefaultClientTlsStrategy(sslContext));
assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test"); assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test");
} }
@ -674,9 +669,8 @@ public abstract class AbstractServletWebServerFactoryTests {
factory.setSsl(getSsl(ClientAuth.WANT, "password", "classpath:test.jks")); factory.setSsl(getSsl(ClientAuth.WANT, "password", "classpath:test.jks"));
this.webServer = factory.getWebServer(); this.webServer = factory.getWebServer();
this.webServer.start(); this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build()); createTrustSelfSignedTlsSocketStrategy());
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory);
assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test"); assertThat(getResponse(getLocalUrl("https", "/test.txt"), requestFactory)).isEqualTo("test");
} }
@ -772,16 +766,15 @@ public abstract class AbstractServletWebServerFactoryTests {
factory.setSsl(getSsl(null, "password", "src/test/resources/restricted.jks", null, protocols, ciphers)); factory.setSsl(getSsl(null, "password", "src/test/resources/restricted.jks", null, protocols, ciphers));
this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello")); this.webServer = factory.getWebServer(new ServletRegistrationBean<>(new ExampleServlet(true, false), "/hello"));
this.webServer.start(); this.webServer.start();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory( HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(
new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build()); createTrustSelfSignedTlsSocketStrategy());
HttpComponentsClientHttpRequestFactory requestFactory = createHttpComponentsRequestFactory(socketFactory);
assertThat(getResponse(getLocalUrl("https", "/hello"), requestFactory)).contains("scheme=https"); assertThat(getResponse(getLocalUrl("https", "/hello"), requestFactory)).contains("scheme=https");
} }
protected HttpComponentsClientHttpRequestFactory createHttpComponentsRequestFactory( protected HttpComponentsClientHttpRequestFactory createHttpComponentsRequestFactory(
SSLConnectionSocketFactory socketFactory) { TlsSocketStrategy tlsSocketStrategy) {
PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
.setSSLSocketFactory(socketFactory) .setTlsSocketStrategy(tlsSocketStrategy)
.build(); .build();
HttpClient httpClient = this.httpClientBuilder.get().setConnectionManager(connectionManager).build(); HttpClient httpClient = this.httpClientBuilder.get().setConnectionManager(connectionManager).build();
return new HttpComponentsClientHttpRequestFactory(httpClient); return new HttpComponentsClientHttpRequestFactory(httpClient);
@ -1635,6 +1628,12 @@ public abstract class AbstractServletWebServerFactoryTests {
protected abstract String startedLogMessage(); protected abstract String startedLogMessage();
protected TlsSocketStrategy createTrustSelfSignedTlsSocketStrategy()
throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
return new DefaultClientTlsStrategy(sslContext);
}
private final class TestGzipInputStreamFactory implements InputStreamFactory { private final class TestGzipInputStreamFactory implements InputStreamFactory {
private final AtomicBoolean requested = new AtomicBoolean(); private final AtomicBoolean requested = new AtomicBoolean();