Updates to use apache client5

This commit is contained in:
spencergibb
2022-10-11 11:46:16 -04:00
parent e68a8cf2f0
commit 9018c78c4d
12 changed files with 197 additions and 47 deletions

View File

@@ -72,8 +72,8 @@
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -25,8 +25,11 @@ import java.util.Map;
import javax.net.ssl.SSLContext;
import org.apache.commons.logging.Log;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.hc.client5.http.classic.HttpClient;
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.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder;
import org.springframework.cloud.configuration.SSLContextFactory;
import org.springframework.http.HttpHeaders;
@@ -85,7 +88,12 @@ public class ConfigClientRequestTemplateFactory {
try {
SSLContextFactory factory = new SSLContextFactory(client.getTls());
SSLContext sslContext = factory.createSSLContext();
HttpClient httpClient = HttpClients.custom().setSSLContext(sslContext).build();
SSLConnectionSocketFactoryBuilder sslConnectionSocketFactoryBuilder = SSLConnectionSocketFactoryBuilder
.create();
sslConnectionSocketFactoryBuilder.setSslContext(sslContext);
PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder
.create().setSSLSocketFactory(sslConnectionSocketFactoryBuilder.build()).build();
HttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();
HttpComponentsClientHttpRequestFactory result = new HttpComponentsClientHttpRequestFactory(httpClient);
result.setReadTimeout(client.getRequestReadTimeout());

View File

@@ -72,6 +72,10 @@
<artifactId>spring-credhub-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>

View File

@@ -35,7 +35,7 @@ import org.apache.http.impl.client.HttpClientBuilder;
import org.eclipse.jgit.transport.http.HttpConnection;
import org.eclipse.jgit.transport.http.apache.HttpClientConnection;
import org.springframework.cloud.config.server.support.HttpClientSupport;
import org.springframework.cloud.config.server.support.HttpClient4Support;
import org.springframework.util.StringUtils;
import static java.util.stream.Collectors.toMap;
@@ -83,7 +83,7 @@ public class HttpClientConfigurableHttpConnectionFactory implements Configurable
private void addHttpClient(JGitEnvironmentProperties properties) throws GeneralSecurityException {
if (properties.getUri() != null && properties.getUri().startsWith("http")) {
this.httpClientBuildersByUri.put(properties.getUri(), HttpClientSupport.builder(properties));
this.httpClientBuildersByUri.put(properties.getUri(), HttpClient4Support.builder(properties));
}
}

View File

@@ -18,7 +18,7 @@ package org.springframework.cloud.config.server.environment;
import java.security.GeneralSecurityException;
import org.apache.http.client.HttpClient;
import org.apache.hc.client5.http.classic.HttpClient;
import org.springframework.cloud.config.server.support.HttpClientSupport;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;

View File

@@ -16,9 +16,9 @@
package org.springframework.cloud.config.server.proxy;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
/**
* @author Dylan Roberts
@@ -32,7 +32,7 @@ public class ProxyHostCredentialsProvider extends BasicCredentialsProvider {
if (proxy != null && proxy.connectionInformationProvided() && proxy.authenticationProvided()) {
AuthScope authscope = new AuthScope(proxy.getHost(), proxy.getPort());
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(proxy.getUsername(),
proxy.getPassword());
proxy.getPassword().toCharArray());
setCredentials(authscope, credentials);
}
}

View File

@@ -16,10 +16,9 @@
package org.springframework.cloud.config.server.proxy;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.impl.conn.DefaultRoutePlanner;
import org.apache.http.protocol.HttpContext;
import org.apache.hc.client5.http.impl.routing.DefaultRoutePlanner;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.protocol.HttpContext;
/**
* @author Dylan Roberts
@@ -33,11 +32,11 @@ public class SchemeBasedRoutePlanner extends DefaultRoutePlanner {
public SchemeBasedRoutePlanner(ProxyHostProperties httpsProxy, ProxyHostProperties httpProxy) {
super(null);
this.httpsProxy = buildProxy(httpsProxy, "https");
this.defaultSchemeProxy = buildProxy(httpProxy, HttpHost.DEFAULT_SCHEME_NAME);
this.defaultSchemeProxy = buildProxy(httpProxy, HttpHost.DEFAULT_SCHEME.getId());
}
@Override
protected HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) {
protected HttpHost determineProxy(HttpHost target, HttpContext context) {
return "https".equals(target.getSchemeName()) ? determineProxy(this.httpsProxy, this.defaultSchemeProxy)
: determineProxy(this.defaultSchemeProxy, this.httpsProxy);
}
@@ -50,7 +49,7 @@ public class SchemeBasedRoutePlanner extends DefaultRoutePlanner {
if (properties == null || !properties.connectionInformationProvided()) {
return null;
}
return new HttpHost(properties.getHost(), properties.getPort(), scheme);
return new HttpHost(scheme, properties.getHost(), properties.getPort());
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright 2018-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.config.server.support;
import java.net.ProxySelector;
import java.security.GeneralSecurityException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.SystemDefaultCredentialsProvider;
import org.apache.http.impl.conn.DefaultRoutePlanner;
import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.cloud.config.server.proxy.ProxyHostProperties;
import org.springframework.util.CollectionUtils;
/**
* @author Dylan Roberts
*/
public final class HttpClient4Support {
private HttpClient4Support() {
throw new IllegalStateException("Can't instantiate a utility class");
}
public static HttpClientBuilder builder(HttpEnvironmentRepositoryProperties environmentProperties)
throws GeneralSecurityException {
SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
HttpClientBuilder httpClientBuilder = HttpClients.custom();
if (environmentProperties.isSkipSslValidation()) {
sslContextBuilder.loadTrustMaterial(null, (certificate, authType) -> true);
httpClientBuilder.setSSLHostnameVerifier(new NoopHostnameVerifier());
}
if (!CollectionUtils.isEmpty(environmentProperties.getProxy())) {
ProxyHostProperties httpsProxy = environmentProperties.getProxy()
.get(ProxyHostProperties.ProxyForScheme.HTTPS);
ProxyHostProperties httpProxy = environmentProperties.getProxy()
.get(ProxyHostProperties.ProxyForScheme.HTTP);
httpClientBuilder.setRoutePlanner(new SchemeBasedRoutePlanner4(httpsProxy, httpProxy));
httpClientBuilder.setDefaultCredentialsProvider(new ProxyHostCredentialsProvider4(httpProxy, httpsProxy));
}
else {
httpClientBuilder.setRoutePlanner(new SystemDefaultRoutePlanner(ProxySelector.getDefault()));
httpClientBuilder.setDefaultCredentialsProvider(new SystemDefaultCredentialsProvider());
}
/*
* According to https://git.eclipse.org/c/jgit/jgit.git/commit/?id=
* e17bfc96f293744cc5c0cef306e100f53d63bb3d jGit does its own redirect handling
* and disables HttpClient's redirect handing.
*/
httpClientBuilder.disableRedirectHandling();
int timeout = environmentProperties.getTimeout() * 1000;
return httpClientBuilder.setSSLContext(sslContextBuilder.build()).setDefaultRequestConfig(
RequestConfig.custom().setSocketTimeout(timeout).setConnectTimeout(timeout).build());
}
static class SchemeBasedRoutePlanner4 extends DefaultRoutePlanner {
private final HttpHost httpsProxy;
private final HttpHost defaultSchemeProxy;
SchemeBasedRoutePlanner4(ProxyHostProperties httpsProxy, ProxyHostProperties httpProxy) {
super(null);
this.httpsProxy = buildProxy(httpsProxy, "https");
this.defaultSchemeProxy = buildProxy(httpProxy, HttpHost.DEFAULT_SCHEME_NAME);
}
@Override
protected HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) {
return "https".equals(target.getSchemeName()) ? determineProxy(this.httpsProxy, this.defaultSchemeProxy)
: determineProxy(this.defaultSchemeProxy, this.httpsProxy);
}
private HttpHost determineProxy(HttpHost proxy, HttpHost fallbackProxy) {
return proxy != null ? proxy : fallbackProxy;
}
private HttpHost buildProxy(ProxyHostProperties properties, String scheme) {
if (properties == null || !properties.connectionInformationProvided()) {
return null;
}
return new HttpHost(properties.getHost(), properties.getPort(), scheme);
}
}
static class ProxyHostCredentialsProvider4 extends BasicCredentialsProvider {
ProxyHostCredentialsProvider4(ProxyHostProperties... proxyHostProperties) {
for (ProxyHostProperties proxy : proxyHostProperties) {
if (proxy != null && proxy.connectionInformationProvided() && proxy.authenticationProvided()) {
AuthScope authscope = new AuthScope(proxy.getHost(), proxy.getPort());
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(proxy.getUsername(),
proxy.getPassword());
setCredentials(authscope, credentials);
}
}
}
}
}

View File

@@ -18,14 +18,19 @@ package org.springframework.cloud.config.server.support;
import java.net.ProxySelector;
import java.security.GeneralSecurityException;
import java.util.concurrent.TimeUnit;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.SystemDefaultCredentialsProvider;
import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.auth.SystemDefaultCredentialsProvider;
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.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner;
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder;
import org.apache.hc.core5.http.io.SocketConfig;
import org.apache.hc.core5.ssl.SSLContextBuilder;
import org.springframework.cloud.config.server.proxy.ProxyHostCredentialsProvider;
import org.springframework.cloud.config.server.proxy.ProxyHostProperties;
@@ -43,12 +48,16 @@ public final class HttpClientSupport {
public static HttpClientBuilder builder(HttpEnvironmentRepositoryProperties environmentProperties)
throws GeneralSecurityException {
SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
HttpClientBuilder httpClientBuilder = HttpClients.custom();
PoolingHttpClientConnectionManagerBuilder connectionManagerBuilder = PoolingHttpClientConnectionManagerBuilder
.create();
if (environmentProperties.isSkipSslValidation()) {
SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
sslContextBuilder.loadTrustMaterial(null, (certificate, authType) -> true);
httpClientBuilder.setSSLHostnameVerifier(new NoopHostnameVerifier());
SSLConnectionSocketFactory sslConnectionSocketFactory = SSLConnectionSocketFactoryBuilder.create()
.setSslContext(sslContextBuilder.build()).setHostnameVerifier(new NoopHostnameVerifier()).build();
connectionManagerBuilder.setSSLSocketFactory(sslConnectionSocketFactory);
}
if (!CollectionUtils.isEmpty(environmentProperties.getProxy())) {
@@ -73,8 +82,10 @@ public final class HttpClientSupport {
httpClientBuilder.disableRedirectHandling();
int timeout = environmentProperties.getTimeout() * 1000;
return httpClientBuilder.setSSLContext(sslContextBuilder.build()).setDefaultRequestConfig(
RequestConfig.custom().setSocketTimeout(timeout).setConnectTimeout(timeout).build());
connectionManagerBuilder
.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(timeout, TimeUnit.MILLISECONDS).build());
return httpClientBuilder.setConnectionManager(connectionManagerBuilder.build()).setDefaultRequestConfig(
RequestConfig.custom().setConnectTimeout(timeout, TimeUnit.MILLISECONDS).build());
}
}

View File

@@ -29,7 +29,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.http.client.HttpClient;
import org.apache.hc.client5.http.classic.HttpClient;
import org.eclipse.jgit.transport.HttpTransport;
import org.eclipse.jgit.transport.http.HttpConnection;
import org.eclipse.jgit.transport.http.HttpConnectionFactory;

View File

@@ -16,9 +16,8 @@
package org.springframework.cloud.config.server.proxy;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.protocol.HttpContext;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -36,7 +35,7 @@ class SchemeBasedRoutePlannerTest {
SchemeBasedRoutePlanner planner = new SchemeBasedRoutePlanner(SECURED_PROXY_PROPERTIES,
UNSECURED_PROXY_PROPERTIES);
final HttpHost result = planner.determineProxy(target("https"), anyRequest(), anyContext());
final HttpHost result = planner.determineProxy(target("https"), anyContext());
assertThat(result.getSchemeName()).isEqualTo("https");
assertThat(result.getHostName()).isEqualTo(SECURED_PROXY_PROPERTIES.getHost());
@@ -47,7 +46,7 @@ class SchemeBasedRoutePlannerTest {
void determineProxy_should_return_https_proxy_when_target_scheme_name_is_http_and_no_http_proxy_specified() {
SchemeBasedRoutePlanner planner = new SchemeBasedRoutePlanner(SECURED_PROXY_PROPERTIES, null);
final HttpHost result = planner.determineProxy(target("http"), anyRequest(), anyContext());
final HttpHost result = planner.determineProxy(target("http"), anyContext());
assertThat(result.getSchemeName()).isEqualTo("https");
assertThat(result.getHostName()).isEqualTo(SECURED_PROXY_PROPERTIES.getHost());
@@ -59,7 +58,7 @@ class SchemeBasedRoutePlannerTest {
SchemeBasedRoutePlanner planner = new SchemeBasedRoutePlanner(SECURED_PROXY_PROPERTIES,
UNSECURED_PROXY_PROPERTIES);
final HttpHost result = planner.determineProxy(target("http"), anyRequest(), anyContext());
final HttpHost result = planner.determineProxy(target("http"), anyContext());
assertThat(result.getSchemeName()).isEqualTo("http");
assertThat(result.getHostName()).isEqualTo(UNSECURED_PROXY_PROPERTIES.getHost());
@@ -70,7 +69,7 @@ class SchemeBasedRoutePlannerTest {
void determineProxy_should_return_http_proxy_when_target_scheme_name_is_https_and_https_proxy_provided() {
SchemeBasedRoutePlanner planner = new SchemeBasedRoutePlanner(null, UNSECURED_PROXY_PROPERTIES);
final HttpHost result = planner.determineProxy(target("https"), anyRequest(), anyContext());
final HttpHost result = planner.determineProxy(target("https"), anyContext());
assertThat(result.getSchemeName()).isEqualTo("http");
assertThat(result.getHostName()).isEqualTo(UNSECURED_PROXY_PROPERTIES.getHost());
@@ -82,7 +81,7 @@ class SchemeBasedRoutePlannerTest {
SchemeBasedRoutePlanner planner = new SchemeBasedRoutePlanner(buildProxyProperties("", 777),
buildProxyProperties("host", 0));
final HttpHost result = planner.determineProxy(target("https"), anyRequest(), anyContext());
final HttpHost result = planner.determineProxy(target("https"), anyContext());
assertThat(result).isNull();
}
@@ -93,10 +92,6 @@ class SchemeBasedRoutePlannerTest {
return host;
}
private HttpRequest anyRequest() {
return mock(HttpRequest.class);
}
private HttpContext anyContext() {
return mock(HttpContext.class);
}

View File

@@ -49,9 +49,9 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static com.github.tomakehurst.wiremock.client.WireMock.verify;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
@SpringBootTest(classes = HttpClientSupportTest.TestConfiguration.class,
@SpringBootTest(classes = HttpClient4SupportTest.TestConfiguration.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HttpClientSupportTest {
public class HttpClient4SupportTest {
@LocalServerPort
private String localServerPort;
@@ -60,7 +60,7 @@ public class HttpClientSupportTest {
public void setsTimeout() throws GeneralSecurityException, IOException {
JGitEnvironmentProperties properties = new JGitEnvironmentProperties();
properties.setTimeout(1);
CloseableHttpClient httpClient = HttpClientSupport.builder(properties).build();
CloseableHttpClient httpClient = HttpClient4Support.builder(properties).build();
Assertions.assertThatThrownBy(() -> {
httpClient.execute(new HttpGet(String.format("http://127.0.0.1:%s/test/endpoint", this.localServerPort)));
@@ -89,7 +89,7 @@ public class HttpClientSupportTest {
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
try {
httpClient = HttpClientSupport.builder(properties).build();
httpClient = HttpClient4Support.builder(properties).build();
response = httpClient
.execute(new HttpGet("https://localhost:" + wireMockServer.httpsPort() + "/test/proxy"));
}