Relaxed SSL validation with RestTemplate interceptors (#1869)

* Relaxed SSL validation with RestTemplate interceptors

* Formatting

* Checkstyle

fixes #1868
This commit is contained in:
Nikola Kološnjaji
2023-03-21 15:18:19 +01:00
committed by GitHub
parent 05b3ee7113
commit 5343cb9b35
3 changed files with 76 additions and 19 deletions

View File

@@ -16,6 +16,8 @@
package org.springframework.cloud.contract.wiremock;
import java.lang.reflect.Field;
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;
@@ -29,13 +31,17 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.client.RestTemplateCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.InterceptingClientHttpRequestFactory;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.client.RestTemplate;
import static org.apache.hc.client5.http.ssl.NoopHostnameVerifier.INSTANCE;
/**
* @author Dave Syer
* @author Nikola Kološnjaji
*
*/
@Configuration(proxyBeanMethods = false)
@@ -48,11 +54,20 @@ public class WireMockRestTemplateConfiguration {
return new RestTemplateCustomizer() {
@Override
public void customize(RestTemplate restTemplate) {
if (restTemplate.getRequestFactory() instanceof HttpComponentsClientHttpRequestFactory) {
HttpComponentsClientHttpRequestFactory factory = (HttpComponentsClientHttpRequestFactory) restTemplate
.getRequestFactory();
if (restTemplate.getRequestFactory() instanceof HttpComponentsClientHttpRequestFactory factory) {
factory.setHttpClient(createSslHttpClient());
}
else if (restTemplate.getRequestFactory() instanceof InterceptingClientHttpRequestFactory) {
Field requestFactoryField = ReflectionUtils.findField(RestTemplate.class, "requestFactory");
if (requestFactoryField != null) {
requestFactoryField.setAccessible(true);
ClientHttpRequestFactory requestFactory = (ClientHttpRequestFactory) ReflectionUtils
.getField(requestFactoryField, restTemplate);
if (requestFactory instanceof HttpComponentsClientHttpRequestFactory factory) {
factory.setHttpClient(createSslHttpClient());
}
}
}
}
private HttpClient createSslHttpClient() {

View File

@@ -30,6 +30,11 @@ import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Dave Syer
* @author Nikola Kološnjaji
*
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = WiremockTestsApplication.class,
properties = "app.baseUrl=https://localhost:${wiremock.server.https-port}",
@@ -50,6 +55,20 @@ public class AutoConfigureWireMockHttpsPortApplicationTests {
assertThat(this.service.go()).isEqualTo("Hello World!");
}
@Test
public void contextLoadsWithApacheClient() throws Exception {
stubFor(get(urlEqualTo("/test"))
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
assertThat(this.service.goWithApacheClient()).isEqualTo("Hello World!");
}
@Test
public void contextLoadsWithApacheClientAndAdditonalInterceptor() throws Exception {
stubFor(get(urlEqualTo("/test"))
.willReturn(aResponse().withHeader("Content-Type", "text/plain").withBody("Hello World!")));
assertThat(this.service.goWithApacheClientAndAdditonalInterceptor()).isEqualTo("Hello World!");
}
@Test
public void portsAreFixed() {
boolean httpPortDynamic = this.wireMockProperties.getServer().isPortDynamic();

View File

@@ -22,22 +22,30 @@ import java.util.stream.Stream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* @author Dave Syer
* @author Nikola Kološnjaji
*
*/
@Configuration
@EnableAutoConfiguration
@Import({ Service.class, Controller.class })
@Import(Service.class)
public class WiremockTestsApplication {
public static void main(String[] args) {
@@ -45,24 +53,20 @@ public class WiremockTestsApplication {
}
@Bean
@Primary
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@RestController
class Controller {
private final Service service;
Controller(Service service) {
this.service = service;
@Bean
public RestTemplate apacheHttpClient(RestTemplateBuilder builder) {
return builder.requestFactory(() -> new HttpComponentsClientHttpRequestFactory()).build();
}
@RequestMapping("/")
public String home() {
return this.service.go();
@Bean
public RestTemplate apacheHttpClientWithInterceptor(RestTemplateBuilder builder) {
return builder.requestFactory(() -> new HttpComponentsClientHttpRequestFactory())
.additionalInterceptors(new BasicAuthenticationInterceptor("u", "p")).build();
}
}
@@ -77,8 +81,15 @@ class Service {
private RestTemplate restTemplate;
Service(RestTemplate restTemplate) {
private RestTemplate apacheHttpClient;
private RestTemplate apacheHttpClientWithInterceptor;
Service(RestTemplate restTemplate, @Qualifier("apacheHttpClient") RestTemplate apacheHttpClient,
@Qualifier("apacheHttpClientWithInterceptor") RestTemplate apacheHttpClientWithInterceptor) {
this.restTemplate = restTemplate;
this.apacheHttpClient = apacheHttpClient;
this.apacheHttpClientWithInterceptor = apacheHttpClientWithInterceptor;
}
public String go() {
@@ -87,6 +98,18 @@ class Service {
return this.restTemplate.getForEntity(requestUrl, String.class).getBody();
}
public String goWithApacheClient() {
String requestUrl = this.base + "/test";
log.info("Will send a request to [" + requestUrl + "]");
return this.apacheHttpClient.getForEntity(requestUrl, String.class).getBody();
}
public String goWithApacheClientAndAdditonalInterceptor() {
String requestUrl = this.base + "/test";
log.info("Will send a request to [" + requestUrl + "]");
return this.apacheHttpClientWithInterceptor.getForEntity(requestUrl, String.class).getBody();
}
public String link() {
String requestUrl = this.base + "/link";
log.info("Will send a request to [" + requestUrl + "]");