graphql-java-kickstart/graphql-spring-webclient

Option to disable SSL verification

weijuly opened this issue · 1 comments

Is your feature request related to a problem? Please describe.
I'm trying to use this client against a local GraphQL server which has a self-signed certificate over HTTPS. I get the following error:

javax.net.ssl.SSLHandshakeException: General SSLEngine problem
	...
Caused by: javax.net.ssl.SSLHandshakeException: General SSLEngine problem
	...
	... 21 common frames omitted
Caused by: java.security.cert.CertificateException: No name matching localhost found
	...
	at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:231) ~[na:1.8.0_212]
	at sun.security.util.HostnameChecker.match(HostnameChecker.java:96) ~[na:1.8.0_212]
	at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455) ~[na:1.8.0_212]
	at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:436) ~[na:1.8.0_212]
	at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:252) ~[na:1.8.0_212]
	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136) ~[na:1.8.0_212]
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1626) ~[na:1.8.0_212]
	... 29 common frames omitted

Code that triggers this issue:

GraphQLRequest request = GraphQLRequest.builder().query("query { hello }").build();
GraphQLResponse response = graphQLWebClient.post(request).block();
System.out.println(response.get("hello", String.class));

Application configuration:

spring:
  main:
    web-application-type: NONE

graphql:
  client:
    url: https://localhost:8443/graphql

Describe the solution you'd like
To workaround this error, this line to disable hostname verification doesn't work

HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);

Describe alternatives you've considered
Tried creating a new WebClient as below:

@Bean
public WebClient webClient() throws SSLException {
    SslContext context = SslContextBuilder
            .forClient()
            .sslProvider(SslProvider.JDK)
            .trustManager(InsecureTrustManagerFactory.INSTANCE)
            .build();
    HttpClient client = HttpClient
            .create()
            .secure(sslContextSpec -> sslContextSpec.sslContext(context));
    return WebClient
            .builder()
            .clientConnector(new ReactorClientHttpConnector(client))
            .build();
}

This gives out a different error

Caused by: java.lang.IllegalArgumentException: Unable to parse url []
	at reactor.netty.http.client.UriEndpointFactory.createUriEndpoint(UriEndpointFactory.java:68) ~[reactor-netty-http-1.0.14.jar:1.0.14]
	at reactor.netty.http.client.UriEndpointFactory.createUriEndpoint(UriEndpointFactory.java:44) ~[reactor-netty-http-1.0.14.jar:1.0.14]
	at reactor.netty.http.client.HttpClientConnect$HttpClientHandler.<init>(HttpClientConnect.java:488) ~[reactor-netty-http-1.0.14.jar:1.0.14]

Additional context
I'm using Zulu JDK 8

openjdk version "1.8.0_212"
OpenJDK Runtime Environment (Zulu 8.38.0.13-CA-macosx) (build 1.8.0_212-b04)
OpenJDK 64-Bit Server VM (Zulu 8.38.0.13-CA-macosx) (build 25.212-b04, mixed mode)

Fixed it using a custom GraphQLWebClient bean, thanks to @rubal-98 !

@Bean
public GraphQLWebClient graphQLWebClient() throws SSLException {
    return GraphQLWebClient.newInstance(webClient(), new ObjectMapper());
}

private WebClient webClient() {
    return WebClient
            .builder()
            .baseUrl(url)
            .clientConnector(new ReactorClientHttpConnector(httpClient()))
            .build();
}

private HttpClient httpClient() {
    return HttpClient
            .create()
            .secure(t -> t.sslContext(noVerifySSLContext()));
}

@SneakyThrows
private SslContext noVerifySSLContext() {
    return SslContextBuilder
            .forClient()
            .trustManager(InsecureTrustManagerFactory.INSTANCE)
            .build();
}