This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-3.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-3.x by this push:
new 2ddb366db85 CAMEL-19502 Netty4-http SNI configuration using
SSLContextParameters (#10516)
2ddb366db85 is described below
commit 2ddb366db85562aaad9ecdce158b51ecb7934ca3
Author: Michael Hughes <[email protected]>
AuthorDate: Tue Jun 27 19:51:57 2023 +0100
CAMEL-19502 Netty4-http SNI configuration using SSLContextParameters
(#10516)
* CAMEL-19502 Netty4-http SNI configuration using SSLContextParameters
* CAMEL-19502 fix build by committing changed file
---
.../netty/http/HttpClientInitializerFactory.java | 9 +-
.../component/netty/http/NettyHttpSSLSNITest.java | 135 +++++++++++++++++++++
2 files changed, 143 insertions(+), 1 deletion(-)
diff --git
a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpClientInitializerFactory.java
b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpClientInitializerFactory.java
index 7ee0bc61211..2a0bc816f49 100644
---
a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpClientInitializerFactory.java
+++
b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpClientInitializerFactory.java
@@ -22,6 +22,7 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIServerName;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
@@ -54,6 +55,7 @@ public class HttpClientInitializerFactory extends
ClientInitializerFactory {
protected NettyHttpConfiguration configuration;
private NettyHttpProducer producer;
private SSLContext sslContext;
+ private List<SNIServerName> sniServerNames;
public HttpClientInitializerFactory() {
// default constructor needed
@@ -143,6 +145,10 @@ public class HttpClientInitializerFactory extends
ClientInitializerFactory {
// create ssl context once
if (configuration.getSslContextParameters() != null) {
answer =
configuration.getSslContextParameters().createSSLContext(producer.getContext());
+ if (answer.getSupportedSSLParameters().getServerNames() != null
+ &&
!answer.getSupportedSSLParameters().getServerNames().isEmpty()) {
+ sniServerNames =
answer.getSupportedSSLParameters().getServerNames();
+ }
} else {
if (configuration.getKeyStoreFile() == null &&
configuration.getKeyStoreResource() == null) {
LOG.debug("keystorefile is null");
@@ -192,7 +198,8 @@ public class HttpClientInitializerFactory extends
ClientInitializerFactory {
SSLEngine engine = sslContext.createSSLEngine(uri.getHost(),
uri.getPort());
engine.setUseClientMode(true);
SSLParameters sslParameters = engine.getSSLParameters();
- sslParameters.setServerNames(Arrays.asList(new
SNIHostName(uri.getHost())));
+ sslParameters
+ .setServerNames(sniServerNames != null ? sniServerNames :
Arrays.asList(new SNIHostName(uri.getHost())));
engine.setSSLParameters(sslParameters);
if (producer.getConfiguration().getSslContextParameters() == null)
{
// just set the enabledProtocols if the SslContextParameter
doesn't set
diff --git
a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSSLSNITest.java
b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSSLSNITest.java
new file mode 100644
index 00000000000..6a473bb317f
--- /dev/null
+++
b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSSLSNITest.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.netty.http;
+
+import java.util.List;
+
+import javax.net.ssl.ExtendedSSLSession;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIServerName;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.netty.NettyConstants;
+import org.apache.camel.support.jsse.KeyStoreParameters;
+import org.apache.camel.support.jsse.SSLContextClientParameters;
+import org.apache.camel.support.jsse.SSLContextParameters;
+import org.apache.camel.support.jsse.TrustManagersParameters;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.camel.test.junit5.TestSupport.isJavaVendor;
+import static org.junit.jupiter.api.Assumptions.assumeFalse;
+
+public class NettyHttpSSLSNITest extends BaseNettyTest {
+
+ @Override
+ public boolean isUseRouteBuilder() {
+ return false;
+ }
+
+ @Test
+ public void testSSLAddsDefaultServerNameIndication() throws Exception {
+ // ibm jdks dont have sun security algorithms
+ assumeFalse(isJavaVendor("ibm"));
+
+ getMockEndpoint("mock:output").expectedBodiesReceived("localhost");
+
+ context.getRegistry().bind("customSSLContextParameters",
createSSLContextParameters(null));
+ context.addRoutes(nettyServerThatRespondsWithSNI());
+ context.addRoutes(new RouteBuilder() {
+ public void configure() {
+ from("direct:in")
+ .setHeader(Exchange.HTTP_METHOD, constant("GET"))
+
.to("netty-http:https://localhost:{{port}}?sslContextParameters=#customSSLContextParameters")
+ .to("mock:output");
+ }
+ });
+ context.start();
+ template.sendBody("direct:in", null);
+
+ MockEndpoint.assertIsSatisfied(context);
+ }
+
+ @Test
+ public void testSSLAddsCustomServerNameIndication() throws Exception {
+ // ibm jdks dont have sun security algorithms
+ assumeFalse(isJavaVendor("ibm"));
+
+ String customSNI = "custom.host.name";
+
+ getMockEndpoint("mock:output").expectedBodiesReceived(customSNI);
+
+ SSLContextClientParameters customClientParameters = new
SSLContextClientParameters();
+ customClientParameters.setSniHostName(customSNI);
+
+ context.getRegistry().bind("customSSLContextParameters",
createSSLContextParameters(customClientParameters));
+ context.addRoutes(nettyServerThatRespondsWithSNI());
+ context.addRoutes(new RouteBuilder() {
+ public void configure() {
+ from("direct:in")
+ .setHeader(Exchange.HTTP_METHOD, constant("GET"))
+
.to("netty-http:https://localhost:{{port}}?sslContextParameters=#customSSLContextParameters")
+ .to("mock:output");
+ }
+ });
+ context.start();
+ template.sendBody("direct:in", null);
+
+ MockEndpoint.assertIsSatisfied(context);
+ }
+
+ private SSLContextParameters
createSSLContextParameters(SSLContextClientParameters clientParameters) {
+ SSLContextParameters sslContextParameters = new SSLContextParameters();
+
+ sslContextParameters.setClientParameters(clientParameters);
+
+ KeyStoreParameters trustStoreParameters = new KeyStoreParameters();
+ trustStoreParameters.setResource("jsse/localhost.p12");
+ trustStoreParameters.setPassword("changeit");
+
+ TrustManagersParameters trustManagersParameters = new
TrustManagersParameters();
+ trustManagersParameters.setKeyStore(trustStoreParameters);
+
+ sslContextParameters.setTrustManagers(trustManagersParameters);
+
+ return sslContextParameters;
+ }
+
+ private RouteBuilder nettyServerThatRespondsWithSNI() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+
from("netty-http:https://localhost:{{port}}?ssl=true&passphrase=changeit&keyStoreResource=jsse/localhost.p12&trustStoreResource=jsse/localhost.p12")
+ .process(exchange -> {
+ ExtendedSSLSession extendedSSLSession
+ =
exchange.getIn().getHeader(NettyConstants.NETTY_SSL_SESSION,
ExtendedSSLSession.class);
+ if (extendedSSLSession != null) {
+ List<SNIServerName> serverNames =
extendedSSLSession.getRequestedServerNames();
+ if (serverNames.size() == 1) {
+
exchange.getMessage().setBody(((SNIHostName)
serverNames.get(0)).getAsciiName());
+ } else {
+ exchange.getMessage().setBody("SNI is
missing or incorrect");
+ }
+ } else {
+ exchange.getMessage().setBody("Cannot
determine success without ExtendedSSLSession");
+ }
+ });
+ }
+ };
+ }
+}