Closed ealexhaywood closed 5 years ago
@ealexhaywood Can you try setting -Dio.netty.handler.ssl.noOpenSsl=true
That didn't work :( it still sends credential-less requests.
I'm fine with using an SSL context builder, but it would have been nice to somehow just use the default context provided by the JVM similar to the Apache HttpClient's [useSystemProperties()
](http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/client/HttpClientBuilder.html#useSystemProperties())
Did you at least enable the SSL?
HttpClient httpClient = HttpClient.create().secure(spec ->
spec.sslContext(SslContextBuilder.forClient().build()));
WebClient webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
Right, that was kind of my point. I didn't think I would have to set an SSL context since the JDK's native web clients URLConnection
and HttpClient
don't require you to, and was wondering if there was a non-code changing way to do this.
And that did not work unfortunately.
@rstoyanchev What do you think? ^^^ Should there be some SSL configuration enabled by default for WebClient?
We could indeed enable security by default on the WebClient
Reactor connector (we've enabled compression already).
It looks like this won't solve this particular issue; looking at Netty's codebase, it doesn't seem Netty is looking at javax.net.ssl
system properties when setting up the SSL contexts.
I meant to post back a while back to show how I configured the WebClient
for TLS for anyone else running into a similar problem, for what it's worth:
HttpClient httpClient = HttpClient.create().secure(spec ->
{
try {
String keyStoreLocation = System.getProperty("javax.net.ssl.keyStore");
String keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword");
String trustStoreLocation = System.getProperty("javax.net.ssl.trustStore");
String trustStorePassword = System.getProperty("javax.net.ssl.trustStorePassword");
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(ResourceUtils.getFile(keyStoreLocation)), keyStorePassword.toCharArray());
// Set up key manager factory to use our key store
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
// truststore
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream((ResourceUtils.getFile(trustStoreLocation))), trustStorePassword.toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustStore);
spec.sslContext(SslContextBuilder.forClient()
.keyManager(keyManagerFactory)
.trustManager(trustManagerFactory)
.build());
} catch (Exception e) {
LOGGER.warn("Unable to set SSL Context", e);
}
});
WebClient webClient = WebClient.builder()
.baseUrl(baseUrl)
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
Like I said, not a big deal at all. Just would be nice to have :)
@ealexhaywood Why do you need to do this by yourself? You can delegate that to Netty.
I did the following:
-Djavax.net.ssl.keyStore=<path>/keystore.jks
-Djavax.net.ssl.keyStorePassword=<password>
-Djavax.net.ssl.trustStore=<path>/truststore.ts
-Djavax.net.ssl.trustStorePassword=<password>
-Djavax.net.ssl.trustStoreType=JKS
-Dio.netty.handler.ssl.noOpenSsl=true
WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create()
.secure(spec -> spec.sslContext(SslContextBuilder.forClient()))))
.build()
.get()
.uri("https://localhost:8080/text")
.retrieve()
.bodyToMono(String.class)
.block()
@violetagg Did you pass those arguments as a _JAVA_OPTIONS
environment variable? Maybe it works as regular commandline argument.
In our environment there is a strong preference to use environment variables for configuration instead of arguments.
@ealexhaywood JVM options
Right, which is different from setting the _JAVA_OPTIONS
variable.
I have tried by providing solution and getting below error for https://localhost:8080
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: no cipher suites in common
And I used http://locahost:8080 and getting below,
Caused by: io.netty.handler.ssl.NotSslRecordException: not an SSL/TLS record
I have tried by providing solution and getting below error for https://localhost:8080
io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: no cipher suites in common
And I used http://locahost:8080 and getting below,
Caused by: io.netty.handler.ssl.NotSslRecordException: not an SSL/TLS record
Sorry my bad. I have set server.ssl
properties in config file which forcing to enable localhost also secure.
@ealexhaywood Why do you need to do this by yourself? You can delegate that to Netty.
I did the following:
-Djavax.net.ssl.keyStore=<path>/keystore.jks -Djavax.net.ssl.keyStorePassword=<password> -Djavax.net.ssl.trustStore=<path>/truststore.ts -Djavax.net.ssl.trustStorePassword=<password> -Djavax.net.ssl.trustStoreType=JKS -Dio.netty.handler.ssl.noOpenSsl=true
WebClient.builder() .clientConnector(new ReactorClientHttpConnector( HttpClient.create() .secure(spec -> spec.sslContext(SslContextBuilder.forClient())))) .build() .get() .uri("https://localhost:8080/text") .retrieve() .bodyToMono(String.class) .block()
Seemes like a good solution, but what should I provide in 'path' for keystore, if my app is spring boot app and it's packed in jar (or if )? How to reference my keystore with relevant path? Seems like classpath:client.jks doesn't work, because TrustStoreManager acts like
String storePropName = System.getProperty("javax.net.ssl.trustStore", jsseDefaultStore); ... new File(storePropName );
Wondering why they didn't use getResources ...
But it worked in @ealexhaywood manual setup solution, as he uses ResourceUtils.getFile
@ealexhaywood Why do you need to do this by yourself? You can delegate that to Netty.
I did the following:
-Djavax.net.ssl.keyStore=<path>/keystore.jks -Djavax.net.ssl.keyStorePassword=<password> -Djavax.net.ssl.trustStore=<path>/truststore.ts -Djavax.net.ssl.trustStorePassword=<password> -Djavax.net.ssl.trustStoreType=JKS -Dio.netty.handler.ssl.noOpenSsl=true
WebClient.builder() .clientConnector(new ReactorClientHttpConnector( HttpClient.create() .secure(spec -> spec.sslContext(SslContextBuilder.forClient())))) .build() .get() .uri("https://localhost:8080/text") .retrieve() .bodyToMono(String.class) .block()
I tried that, and trustStore gets loaded, however keyStore does not SSLContextImpl.engineInit() loads system properties if it receives null for trustManager, but it does not do so for keyManager
public WebClient getOauthWebClient() {
final SslContext sslContext = SslContextBuilder
.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.build();
final HttpClient httpClient = HttpClient.create().secure(t -> t.sslContext(sslContext));
return WebClient.builder()
.filter(oAuthErrorHandler())
.clientConnector(new ReactorClientHttpConnector(httpClient)).build();
}
getting
io.netty.handler.ssl.SslHandshakeTimeoutException: handshake timed out after 10000ms
Hi guys , I know its a bit late but this is a simplest solution:
-Djavax.net.ssl.keyStore=
SslContext sslContext = new JdkSslContext(SSLContext.getDefault(), true, ClientAuth.NONE);
return WebClient .builder() .clientConnector(new ReactorClientHttpConnector (HttpClient.create() .secure(sslContextSpec -> sslContextSpec.sslContext(sslContext)))) .filter(oauth) .baseUrl(appProperties.getServicesUrl()) .build();
Just 2 importants things to notice :
You don't need to do any manual SSLContext config anymore. I removed them all and it's perfectly working fine !
I hope it helps
Expected behavior
When I pass keystore/truststore arguments, such as
-Djavax.net.ssl.keyStore=$(KEYSTORE) -Djavax.net.ssl.keyStorePassword=$(PASSWORD) -Djavax.net.ssl.trustStore=$(TRUSTSTORE) -Djavax.net.ssl.trustStorePassword=$(TRUSTSTORE_PASSWORD) -Djavax.net.ssl.trustStoreType=$(TRUSTSTORE_TYPE)
in the_JAVA_OPTIONS
environment variable to the JVM, I expected theWebClient
to use the default JavaSSLContext
.Actual behavior
It does not use the default
SSLContext
set by the JVM, resulting inhandshake_failure
s.Steps to reproduce
Pass a similar
_JAVA_OPTIONS
variable and try to make a request to a trusted server configured for 2-way TLS.Here's how I am using the web client:
Reactor Netty version
0.8.4.RELEASE
JVM version (e.g.
java -version
)openjdk version "11" 2018-09-25 OpenJDK Runtime Environment 18.9 (build 11+28) OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)
OS version (e.g.
uname -a
)JVM ran in an official openJDK docker container --
openjdk:11-jre-slim