Understanding Functional and Non-Functional Requirements in System Design
February 25, 2025
Vertical Scaling Strategies
February 9, 2025
How the Internet of Things (IoT) is Revolutionizing Industries
January 29, 2025
The Role of AI in Architectural Decisions: Shaping the Future of Solution Design
January 12, 2025
Building a Modern Reactive Rate Limiter in Java 21 with Reactor API
December 12, 2024
Spring Boot WebFlux comes with
WebClient
which we use to make HTTP or
HTTPS
calls.
There are situations where might have disable SSL verification while making HTTPS calls, especially when dealing with
self-signed certificates
or while working in
testing environments
, or sometimes when we want to get rid of all type of exceptions related to SSL like handshake or pkix exception (please don’t do it if you are doing it). So, let’s see how we can disable SSL check in WebClient.
Let’s jump into the code.
Please make sure you have the following dependency in the pom.xml file.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
Next, create a @Configuration class for WebClient.
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.List;
import javax.net.ssl.SSLException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpHeaders;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import io.netty.channel.ChannelOption;
import io.netty.channel.unix.UnixChannelOption;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import io.netty.resolver.DefaultAddressResolverGroup;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;
@Configuration
public class WebClientConfiguration {
private static final String CONNECTION_PROVIDER_NAME = "customConnectionProvider";
private static final int MAX_CONNECTIONS = 10;
private static final int ACQUIRE_TIMEOUT = 60;
private static final int CONNECT_TIMEOUT_MILLIS = 6000;
private static final int READ_WRITE_TIMEOUT_SECONDS = 60;
private static final int TIMEOUT_SECONDS = 60;
private static final int MAX_PENDING_ACQUIRES = 5;
private static final Iterable<String> allowedCiphers = List.of("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384");
@Primary
@Bean(name = "webclientwithnossl")
WebClient.Builder webClientBuilderStage() throws SSLException {
ConnectionProvider connectionProvider = buildConnectionProvider();
SslContext sslContext = buildSslContext();
HttpClient httpClient = buildHttpClient(connectionProvider, sslContext);
return buildWebClient(httpClient);
private ConnectionProvider buildConnectionProvider() {
return ConnectionProvider.builder(CONNECTION_PROVIDER_NAME)
.maxConnections(MAX_CONNECTIONS)
.maxLifeTime(Duration.ofSeconds(TIMEOUT_SECONDS))
.pendingAcquireTimeout(Duration.ofMillis(ACQUIRE_TIMEOUT))
.pendingAcquireMaxCount(MAX_PENDING_ACQUIRES)
.maxIdleTime(Duration.ofSeconds(ACQUIRE_TIMEOUT))
.lifo()
.build();
private SslContext buildSslContext() throws SSLException {
return SslContextBuilder.forClient()
.protocols("SSLv3","TLSv1","TLSv1.1","TLSv1.2")
.ciphers(allowedCiphers)
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
private HttpClient buildHttpClient(ConnectionProvider connectionProvider, SslContext sslContext) {
return HttpClient.create(connectionProvider)
.compress(true)
.followRedirect(true)
.resolver(DefaultAddressResolverGroup.INSTANCE)
.secure(t -> t.sslContext(sslContext).handshakeTimeout(Duration.ofSeconds(TIMEOUT_SECONDS)))
.keepAlive(true)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, CONNECT_TIMEOUT_MILLIS)
.doOnConnected(connection -> {
connection.addHandlerLast(new ReadTimeoutHandler(READ_WRITE_TIMEOUT_SECONDS));
connection.addHandlerLast(new WriteTimeoutHandler(READ_WRITE_TIMEOUT_SECONDS));
.option(UnixChannelOption.SO_KEEPALIVE, true);
private WebClient.Builder buildWebClient(HttpClient httpClient) {
return WebClient.builder()
.defaultHeader(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.toString())
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(16 * 1024 * 1024))
.clientConnector(new ReactorClientHttpConnector(httpClient));
Please note 3 important things in the above class
1. The list of allowed ciphers.
private static final Iterable<String> allowedCiphers = List.of("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384");
These are the cipher suites that are allowed for TLS (Transport Layer Security) connections. Each string in the list represents a specific cipher suite, which is a combination of cryptographic algorithms used to secure network communications. For example, “TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384” represents a cipher suite that uses the ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) key exchange, RSA authentication, AES-256 for encryption, and GCM (Galois/Counter Mode) for message authentication. There are a lot of material on internet on these cipher suites, you can have a look at it if you need more details.
2. The SSLContext object creation
private SslContext buildSslContext() throws SSLException {
return SslContextBuilder.forClient()
.protocols("SSLv3","TLSv1","TLSv1.1","TLSv1.2")
.ciphers(allowedCiphers)
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
To disable SSL verification, InsecureTrustManagerFactory has been used in the SSL context builder. This will basically do the trick we need.
So, do you need the allowed ciphers in the first place or the protocols (“SSLv3″,”TLSv1″,”TLSv1.1″,”TLSv1.2”) mentioned in SSL builder? The answer is yes because in certain environment setup, you will still get SSLException if you don’t use it. However, you can still use the below code with allowed ciphers and protocols and it might work for you.
private SslContext buildSslContext() throws SSLException {
return SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
3. In order to use this SslContext object, you have to use HttpClient from netty.
private HttpClient buildHttpClient(ConnectionProvider connectionProvider, SslContext sslContext) {
return HttpClient.create(connectionProvider)
// .....
// .....
.secure(t -> t.sslContext(sslContext).handshakeTimeout(Duration.ofSeconds(TIMEOUT_SECONDS)))
// .....
Finally, use the custom WebClient in your service or controller:
@Autowired
@Qualifier("webclientwithnossl")
private WebClient.Builder webClientBuilder;
// Use webClientBuilder to create WebClient instances
That’s it.
Hope you like it.
Have a nice day ahead.