From 00a142b5609b04689d6d53a0a941a84d950a150c Mon Sep 17 00:00:00 2001 From: jansupol Date: Thu, 21 Apr 2022 16:00:37 +0200 Subject: [PATCH 1/2] Support null PROXY_USERNAME Support SSL Hostname verification Update request host and port in SSL Context Correct order of TLS handler vs Proxy handler Co-authored-by: olotenko --- .../connector/NettyClientProperties.java | 2 + .../netty/connector/NettyConnector.java | 37 ++++++++++++++----- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java index 17e55a937a..84b8da56fb 100644 --- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java +++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java @@ -53,4 +53,6 @@ public class NettyClientProperties { *

*/ public static final String MAX_CONNECTIONS = "jersey.config.client.maxConnections"; + + public static final String ENABLE_SSL_HOSTNAME_VERIFICATION = "jersey.config.client.tls.enableHostnameVerification"; } diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java index 056ef31802..e2d4d35514 100644 --- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java +++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java @@ -32,6 +32,9 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; + import javax.ws.rs.ProcessingException; import javax.ws.rs.client.Client; import javax.ws.rs.core.Configuration; @@ -60,6 +63,7 @@ import io.netty.handler.proxy.HttpProxyHandler; import io.netty.handler.ssl.ClientAuth; import io.netty.handler.ssl.JdkSslContext; +import io.netty.handler.ssl.SslHandler; import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.handler.timeout.IdleState; import io.netty.handler.timeout.IdleStateEvent; @@ -216,15 +220,9 @@ protected CompletableFuture execute(final ClientRequest jerseyRe protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); - // Enable HTTPS if necessary. - if ("https".equals(requestUri.getScheme())) { - // making client authentication optional for now; it could be extracted to configurable property - JdkSslContext jdkSslContext = new JdkSslContext(client.getSslContext(), true, ClientAuth.NONE); - p.addLast(jdkSslContext.newHandler(ch.alloc())); - } + Configuration config = jerseyRequest.getConfiguration(); // http proxy - Configuration config = jerseyRequest.getConfiguration(); final Object proxyUri = config.getProperties().get(ClientProperties.PROXY_URI); if (proxyUri != null) { final URI u = getProxyUri(proxyUri); @@ -234,9 +232,28 @@ protected void initChannel(SocketChannel ch) throws Exception { final String password = ClientProperties.getValue( config.getProperties(), ClientProperties.PROXY_PASSWORD, String.class); - p.addLast(new HttpProxyHandler(new InetSocketAddress(u.getHost(), - u.getPort() == -1 ? 8080 : u.getPort()), - userName, password)); + InetSocketAddress proxyAddr = new InetSocketAddress(u.getHost(), + u.getPort() == -1 ? 8080 : u.getPort()); + p.addLast(userName == null ? new HttpProxyHandler(proxyAddr) + : new HttpProxyHandler(proxyAddr, userName, password)); + } + + // Enable HTTPS if necessary. + if ("https".equals(requestUri.getScheme())) { + // making client authentication optional for now; it could be extracted to configurable property + JdkSslContext jdkSslContext = new JdkSslContext(client.getSslContext(), true, ClientAuth.NONE); + int port = requestUri.getPort(); + SslHandler sslHandler = jdkSslContext.newHandler(ch.alloc(), requestUri.getHost(), + port <= 0 ? 443 : port, executorService); + if (ClientProperties.getValue(config.getProperties(), + NettyClientProperties.ENABLE_SSL_HOSTNAME_VERIFICATION, true)) { + SSLEngine sslEngine = sslHandler.engine(); + SSLParameters sslParameters = sslEngine.getSSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + sslEngine.setSSLParameters(sslParameters); + } + + p.addLast(sslHandler); } p.addLast(new HttpClientCodec()); From 422068af87b6cb9d81f97db39e8bb516b5a84562 Mon Sep 17 00:00:00 2001 From: jansupol Date: Thu, 21 Apr 2022 16:36:07 +0200 Subject: [PATCH 2/2] Add javadoc to Netty ENABLE_SSL_HOSTNAME_VERIFICATION configuration property Signed-off-by: jansupol --- .../netty/connector/NettyClientProperties.java | 15 ++++++++++++++- .../jersey/netty/connector/NettyConnector.java | 15 +++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java index 84b8da56fb..bf34699708 100644 --- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java +++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -54,5 +54,18 @@ public class NettyClientProperties { */ public static final String MAX_CONNECTIONS = "jersey.config.client.maxConnections"; + /** + *

+ * Sets the endpoint identification algorithm to HTTPS. + *

+ *

+ * The default value is {@code true} (for HTTPS uri scheme). + *

+ *

+ * The name of the configuration property is {@value}. + *

+ * @since 2.35 + * @see javax.net.ssl.SSLParameters#setEndpointIdentificationAlgorithm(String) + */ public static final String ENABLE_SSL_HOSTNAME_VERIFICATION = "jersey.config.client.tls.enableHostnameVerification"; } diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java index e2d4d35514..c97ea2e16c 100644 --- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java +++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -61,7 +61,9 @@ import io.netty.handler.codec.http.HttpUtil; import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.proxy.HttpProxyHandler; +import io.netty.handler.ssl.ApplicationProtocolConfig; import io.netty.handler.ssl.ClientAuth; +import io.netty.handler.ssl.IdentityCipherSuiteFilter; import io.netty.handler.ssl.JdkSslContext; import io.netty.handler.ssl.SslHandler; import io.netty.handler.stream.ChunkedWriteHandler; @@ -241,7 +243,16 @@ protected void initChannel(SocketChannel ch) throws Exception { // Enable HTTPS if necessary. if ("https".equals(requestUri.getScheme())) { // making client authentication optional for now; it could be extracted to configurable property - JdkSslContext jdkSslContext = new JdkSslContext(client.getSslContext(), true, ClientAuth.NONE); + JdkSslContext jdkSslContext = new JdkSslContext( + client.getSslContext(), + true, + (Iterable) null, + IdentityCipherSuiteFilter.INSTANCE, + (ApplicationProtocolConfig) null, + ClientAuth.NONE, + (String[]) null, /* enable default protocols */ + false /* true if the first write request shouldn't be encrypted */ + ); int port = requestUri.getPort(); SslHandler sslHandler = jdkSslContext.newHandler(ch.alloc(), requestUri.getHost(), port <= 0 ? 443 : port, executorService);