Skip to content

Commit 1ec3c65

Browse files
author
Ryan Baxter
authored
Use OK HttpClient directly (#788)
We no longer need the abstraction in commons and will be removing it
1 parent d30540d commit 1ec3c65

File tree

2 files changed

+78
-11
lines changed

2 files changed

+78
-11
lines changed

spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/FeignAutoConfiguration.java

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,21 @@
1717
package org.springframework.cloud.openfeign;
1818

1919
import java.lang.reflect.Method;
20+
import java.security.KeyManagementException;
21+
import java.security.NoSuchAlgorithmException;
22+
import java.security.cert.X509Certificate;
2023
import java.time.Duration;
2124
import java.util.ArrayList;
2225
import java.util.List;
2326
import java.util.concurrent.TimeUnit;
2427

28+
import javax.net.ssl.HostnameVerifier;
29+
import javax.net.ssl.SSLContext;
30+
import javax.net.ssl.SSLSession;
31+
import javax.net.ssl.SSLSocketFactory;
32+
import javax.net.ssl.TrustManager;
33+
import javax.net.ssl.X509TrustManager;
34+
2535
import com.fasterxml.jackson.databind.Module;
2636
import feign.Capability;
2737
import feign.Client;
@@ -31,6 +41,8 @@
3141
import feign.okhttp.OkHttpClient;
3242
import jakarta.annotation.PreDestroy;
3343
import okhttp3.ConnectionPool;
44+
import org.apache.commons.logging.Log;
45+
import org.apache.commons.logging.LogFactory;
3446

3547
import org.springframework.beans.factory.annotation.Autowired;
3648
import org.springframework.beans.factory.annotation.Value;
@@ -43,8 +55,6 @@
4355
import org.springframework.cloud.client.actuator.HasFeatures;
4456
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
4557
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
46-
import org.springframework.cloud.commons.httpclient.OkHttpClientConnectionPoolFactory;
47-
import org.springframework.cloud.commons.httpclient.OkHttpClientFactory;
4858
import org.springframework.cloud.openfeign.security.OAuth2AccessTokenInterceptor;
4959
import org.springframework.cloud.openfeign.support.FeignEncoderProperties;
5060
import org.springframework.cloud.openfeign.support.FeignHttpClientProperties;
@@ -81,6 +91,8 @@
8191
FeignEncoderProperties.class })
8292
public class FeignAutoConfiguration {
8393

94+
private static final Log LOG = LogFactory.getLog(FeignAutoConfiguration.class);
95+
8496
@Autowired(required = false)
8597
private List<FeignClientSpecification> configurations = new ArrayList<>();
8698

@@ -205,29 +217,52 @@ protected static class OkHttpFeignConfiguration {
205217

206218
private okhttp3.OkHttpClient okHttpClient;
207219

220+
@Bean
221+
@ConditionalOnMissingBean
222+
public okhttp3.OkHttpClient.Builder okHttpClientBuilder() {
223+
return new okhttp3.OkHttpClient.Builder();
224+
}
225+
208226
@Bean
209227
@ConditionalOnMissingBean(ConnectionPool.class)
210-
public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties,
211-
OkHttpClientConnectionPoolFactory connectionPoolFactory) {
228+
public ConnectionPool httpClientConnectionPool(FeignHttpClientProperties httpClientProperties) {
212229
int maxTotalConnections = httpClientProperties.getMaxConnections();
213230
long timeToLive = httpClientProperties.getTimeToLive();
214231
TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
215-
return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
232+
return new ConnectionPool(maxTotalConnections, timeToLive, ttlUnit);
216233
}
217234

218235
@Bean
219-
public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory, ConnectionPool connectionPool,
236+
public okhttp3.OkHttpClient client(okhttp3.OkHttpClient.Builder builder, ConnectionPool connectionPool,
220237
FeignHttpClientProperties httpClientProperties) {
221238
boolean followRedirects = httpClientProperties.isFollowRedirects();
222239
int connectTimeout = httpClientProperties.getConnectionTimeout();
223240
boolean disableSslValidation = httpClientProperties.isDisableSslValidation();
224241
Duration readTimeout = httpClientProperties.getOkHttp().getReadTimeout();
225-
this.okHttpClient = httpClientFactory.createBuilder(disableSslValidation)
226-
.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS).followRedirects(followRedirects)
227-
.readTimeout(readTimeout).connectionPool(connectionPool).build();
242+
if (disableSslValidation) {
243+
disableSsl(builder);
244+
}
245+
this.okHttpClient = builder.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
246+
.followRedirects(followRedirects).readTimeout(readTimeout).connectionPool(connectionPool).build();
228247
return this.okHttpClient;
229248
}
230249

250+
private void disableSsl(okhttp3.OkHttpClient.Builder builder) {
251+
try {
252+
X509TrustManager disabledTrustManager = new DisableValidationTrustManager();
253+
TrustManager[] trustManagers = new TrustManager[1];
254+
trustManagers[0] = disabledTrustManager;
255+
SSLContext sslContext = SSLContext.getInstance("SSL");
256+
sslContext.init(null, trustManagers, new java.security.SecureRandom());
257+
SSLSocketFactory disabledSSLSocketFactory = sslContext.getSocketFactory();
258+
builder.sslSocketFactory(disabledSSLSocketFactory, disabledTrustManager);
259+
builder.hostnameVerifier(new TrustAllHostnames());
260+
}
261+
catch (NoSuchAlgorithmException | KeyManagementException e) {
262+
LOG.warn("Error setting SSLSocketFactory in OKHttpClient", e);
263+
}
264+
}
265+
231266
@PreDestroy
232267
public void destroy() {
233268
if (this.okHttpClient != null) {
@@ -242,6 +277,38 @@ public Client feignClient(okhttp3.OkHttpClient client) {
242277
return new OkHttpClient(client);
243278
}
244279

280+
/**
281+
* A {@link X509TrustManager} that does not validate SSL certificates.
282+
*/
283+
class DisableValidationTrustManager implements X509TrustManager {
284+
285+
@Override
286+
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
287+
}
288+
289+
@Override
290+
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
291+
}
292+
293+
@Override
294+
public X509Certificate[] getAcceptedIssuers() {
295+
return new X509Certificate[0];
296+
}
297+
298+
}
299+
300+
/**
301+
* A {@link HostnameVerifier} that does not validate any hostnames.
302+
*/
303+
class TrustAllHostnames implements HostnameVerifier {
304+
305+
@Override
306+
public boolean verify(String s, SSLSession sslSession) {
307+
return true;
308+
}
309+
310+
}
311+
245312
}
246313

247314
// the following configuration is for alternate feign clients if

spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/FeignOkHttpConfigurationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import org.springframework.boot.WebApplicationType;
2929
import org.springframework.boot.builder.SpringApplicationBuilder;
3030
import org.springframework.cloud.commons.httpclient.HttpClientConfiguration;
31-
import org.springframework.cloud.commons.httpclient.OkHttpClientFactory;
3231
import org.springframework.context.ConfigurableApplicationContext;
3332
import org.springframework.util.ReflectionUtils;
3433

@@ -63,7 +62,8 @@ void tearDown() {
6362
void disableSslTest() {
6463
OkHttpClient httpClient = context.getBean(OkHttpClient.class);
6564
HostnameVerifier hostnameVerifier = (HostnameVerifier) this.getField(httpClient, "hostnameVerifier");
66-
assertThat(hostnameVerifier instanceof OkHttpClientFactory.TrustAllHostnames).isTrue();
65+
assertThat(hostnameVerifier instanceof FeignAutoConfiguration.OkHttpFeignConfiguration.TrustAllHostnames)
66+
.isTrue();
6767
}
6868

6969
@Test

0 commit comments

Comments
 (0)