Disable TLS certificate check for WebTestClient - spring

I am using Spring WebFlux WebTestClient in integration tests. I create client using WebTestClient.bindToServer(). Tested server serves resources with HTTPS. I have following code:
WebTestClient webTestClient = WebTestClient.bindToServer()
.baseUrl("https://secured.example.com")
.build();
webTestClient.get().uri("/index.html")
.exchange()
.expectStatus().isOk();
There is no need to use valid certificate in tests. How can I configure WebTestClient to trust all certificates?
P.S. I can configure WebClient to trust everyone. But WebTestClient is more suitable for writing tests.

You can configure that with a custom ClientHttpConnector that you can provide to the WebTestClient.
// create a custom connector and customize TLS configuration there.
ReactorClientHttpConnector connector = new ReactorClientHttpConnector(options -> options...);
WebTestClient client = WebTestClient.bindToServer(connector);
This has been fixed recently in SPR-16168.

Related

Spring Gateway - multiple httpclients in Spring Gateway?

I have many filters that I use to manipulate different requests.
I'm overriding the default netty httpClient provided by Spring Gateway so I can set programatically some sslContext - mTLS in my case. This is fine, but I will also need to have a second netty httpClient so I can connect to other server with no ssl at all, or just regular tls.
I was wondering if it's possible either to set sslContext on specific filters or to decide what httpClient to use based on the filter or some other extension point that spring gateway provides.
Do you think it is possible to have multiple httpClients and decide which one to use?
I tried to create a new bean which configures a httpClient and set some sslContext like this:
#Bean
public reactor.netty.http.client.HttpClient httpClient() {
final PrivateKey privateKey = getPrivateKey();
final X509Certificate x509Certificate = getX509Certificate();
final SslContext sslContext =
SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.keyManager(privateKey, x509Certificate)
.build();
return reactor.netty.http.client.HttpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
}
While I use this httpClient to connect via mTLS it works fine, but I'd like to decide what httpClient to use based on specific filters.

How can I authenticate a Ribbon load balancer and Zuul proxy using a certificate?

I have a Spring application, that acts as an authentication proxy for two backend servers. A user will access the Spring application and be forwarded to the backend once he is successfully authenticated. To prevent unwanted access without prior authentication the backend servers require a certificate as authentication.
My Spring application uses Netflix-Ribbon as a load balancer and Netflix-Zuul as a Proxy for the users requests. How can I configure them to use the client certificate that is required for the authentication on the backend servers?
Ok, I figured it out. You can configure your own CloasableHttpClient as a #Bean and create a custom SSL context. You can provide a certificate to a server through .loadKeyMaterial(). Zuul will then use these settings.
#Configuration
public class HttpClientConfig {
#Bean
public CloseableHttpClient httpClient() throws Throwable {
String keyPassphrase = "yourCertificatePassword";
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream("Path/to/your/clientCert.pfx"), keyPassphrase.toCharArray());
SSLContext sslContext = SSLContexts.custom()
.loadKeyMaterial(keyStore, keyPassphrase.toCharArray())
.build();
return HttpClients.custom()
.setSSLContext(sslContext)
.build();
}
}

Does calling https service by Resttemplate work for all services whose certificate has been imported in the trustore of my client service?

I have a restemplate which can make call to multiple external systems over https.
I configured the resttemplate like so :
SSLContext sslContext = SSLContextBuilder
.create()
.loadTrustMaterial(key, keyPassword)
.build();
HttpClient client = HttpClients
.custom()
.setSSLContext(sslContext)
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.build();
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(
client);
httpComponentsClientHttpRequestFactory.setConnectTimeout(5000);
httpComponentsClientHttpRequestFactory.setReadTimeout(30000);
return new RestTemplate(httpComponentsClientHttpRequestFactory);
I have setup 2 mock services on 2 separate VMs with ssl enabled and I am testing this restemplate by calling those services over https. And it works.
What I want to confirm is that configuring the restemplate as shown in the above code and importing the certificates of the different services to be called in by the client truststore should work without any additional configurations right?
I am confused because in the code in this example here : https://github.com/jonashackt/spring-boot-rest-clientcertificates-docker-compose the author has used 2 different factories i.e. serverTomClientHttpRequestFactory & serverAliceClientHttpRequestFactory, however mine works with a single restemplate. can someone please shed some light on this topic?

How to specificy preconfigured webshpere-liberty SSLSocketFactory to Netty rective client used by spring-webclient

I am building a spring boot application that runs on #websphere-liberty profile. I am using a Spring webclient for outbound connections. All good except that I am not able to specify liberty SSL context to the netty httpclient used by Spring Webclient.
Any help on how how to specify pre-configured libery ssl context to Netty httpclient is greatly appreciated.
IBM documentation says that I should use SSLSocketFactory.getDefault() to get liberty SSL context. But I don't see any way to pass this to Netty HttpClient.
Ref: [https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/twlp_sec_ssl.html]
This is what I tried, but it is not pointing to the SSL context configured by #Websphere-liberty. Instead, it seems to create a new one. Because of that, the trust/keystores are not available to the netty HttpClient and I get an error saying that the peer is not trusted.
#Bean
public WebClient createWebClient() throws SSLException {
JdkSslContext jdkSslContext = new
JdkSslContext(SSLContext.getInstance("SSL"),true,
null, IdentityCipherSuiteFilter.INSTANCE,null,ClientAuth.NONE,
null,false);
ClientHttpConnector httpConnector = HttpClient.create().secure { t -> t.sslContext(jdkSslContext) }
return WebClient.builder().clientConnector(httpConnector).build();
}

How do I configure reactor-netty to use SSL?

I am trying to get familiar with Spring's Project Reactor (https://projectreactor.io/) and have built a small application to make REST calls to another service over SSL. I cannot find any way to configure the org.springframework.web.client.reactive.WebClient to make requests over SSL. There seems to be no documentation about this. I am using reactor-core 3.0.0.RC1 and reactor-netty 0.5.0.M3, and Spring Framework 5.0.0.M1. Does anyone know how to configure reactor-netty with SSL support?
Update 2017-01-04:
This was corrected in the 5.0.0.M4 release of Spring Framework with this patch.
Original Answer:
I discovered that the solution is to create a new ClientHttpConnector implementation that respects SSL.
public class ReactorClientHttpsAwareConnector implements ClientHttpConnector {
#Override
public Mono<ClientHttpResponse> connect(HttpMethod method, URI uri,
Function<? super ClientHttpRequest, Mono<Void>> requestCallback) {
return reactor.ipc.netty.http.HttpClient.create()
.request(io.netty.handler.codec.http.HttpMethod.valueOf(method.name()),
uri.toString(),
httpClientRequest -> requestCallback
.apply(new ReactorClientHttpRequest(method, uri, httpClientRequest)))
.cast(HttpInbound.class)
.otherwise(HttpException.class, exc -> Mono.just(exc.getChannel()))
.map(ReactorClientHttpResponse::new);
}
}
HttpClient.create() is required to make the client SSL-aware.

Resources