This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch fix/CAMEL-25674
in repository https://gitbox.apache.org/repos/asf/camel.git

commit f0b9f12943f1d281a0416946066cc61bec4f3f88
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Nov 2 14:27:40 2026 +0100

    CAMEL-25674: camel-netty-http - hostnameVerification no longer breaks 
client certificates on a consumer
    
    HttpServerInitializerFactory set endpointIdentificationAlgorithm=HTTPS on 
the
    server engine when hostnameVerification=true. The JDK does not support host
    name verification on the server side, so every handshake in which the client
    presented a certificate failed with "Endpoint Identification Algorithm HTTPS
    is not supported on the server side", and nothing was checked otherwise.
    
    The consumer now ignores the option, as camel-netty does since CAMEL-25649 
and
    as HttpServerSharedInitializerFactory always did. The producer still 
verifies
    the host.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../camel/catalog/docs/netty-http-component.adoc   |  11 ++
 .../src/main/docs/netty-http-component.adoc        |  11 ++
 .../netty/http/HttpServerInitializerFactory.java   |   9 +-
 ...NettyHttpSSLServerHostnameVerificationTest.java | 122 +++++++++++++++++++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    |  10 ++
 5 files changed, 157 insertions(+), 6 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/netty-http-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/netty-http-component.adoc
index 2373c69dce3a..5b098510360b 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/netty-http-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/netty-http-component.adoc
@@ -175,6 +175,17 @@ invoking the route, unless the endpoint is restricted to 
the `OPTIONS` method wi
 `httpMethodRestrict`. All other HTTP methods are authenticated when 
`oauthProfile` is set.
 ====
 
+=== Verifying the host name of the server
+
+Set `hostnameVerification=true` on a producer that calls an `https` URL to 
check that the certificate of the server
+matches the host it connects to, with the same rules as an HTTPS client: a 
connection to an IP address needs a
+certificate that lists that address as a subject alternative name of its own. 
A certificate that does not match makes
+the call fail with an `SSLHandshakeException`.
+
+The option applies to the producer only. On a consumer it is ignored, because 
the JDK does not support host name
+verification on the server side of a handshake. To control which clients may 
connect to a consumer, use client
+authentication (`needClientAuth=true`) with a trust store that holds only the 
certificates you accept.
+
 === Access to Netty types
 
 This component uses the
diff --git 
a/components/camel-netty-http/src/main/docs/netty-http-component.adoc 
b/components/camel-netty-http/src/main/docs/netty-http-component.adoc
index 2373c69dce3a..5b098510360b 100644
--- a/components/camel-netty-http/src/main/docs/netty-http-component.adoc
+++ b/components/camel-netty-http/src/main/docs/netty-http-component.adoc
@@ -175,6 +175,17 @@ invoking the route, unless the endpoint is restricted to 
the `OPTIONS` method wi
 `httpMethodRestrict`. All other HTTP methods are authenticated when 
`oauthProfile` is set.
 ====
 
+=== Verifying the host name of the server
+
+Set `hostnameVerification=true` on a producer that calls an `https` URL to 
check that the certificate of the server
+matches the host it connects to, with the same rules as an HTTPS client: a 
connection to an IP address needs a
+certificate that lists that address as a subject alternative name of its own. 
A certificate that does not match makes
+the call fail with an `SSLHandshakeException`.
+
+The option applies to the producer only. On a consumer it is ignored, because 
the JDK does not support host name
+verification on the server side of a handshake. To control which clients may 
connect to a consumer, use client
+authentication (`needClientAuth=true`) with a trust store that holds only the 
certificates you accept.
+
 === Access to Netty types
 
 This component uses the
diff --git 
a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpServerInitializerFactory.java
 
b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpServerInitializerFactory.java
index f303bde010ac..e42b50a5cf44 100644
--- 
a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpServerInitializerFactory.java
+++ 
b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/HttpServerInitializerFactory.java
@@ -20,7 +20,6 @@ import java.util.List;
 
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLParameters;
 
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandler;
@@ -178,11 +177,9 @@ public class HttpServerInitializerFactory extends 
ServerInitializerFactory {
                 // REQUIRE or WANT) when needClientAuth is not enabled
                 engine.setNeedClientAuth(true);
             }
-            if (consumer.getConfiguration().isHostnameVerification()) {
-                SSLParameters sslParams = engine.getSSLParameters();
-                sslParams.setEndpointIdentificationAlgorithm("HTTPS");
-                engine.setSSLParameters(sslParams);
-            }
+            // hostnameVerification is not applied: the JDK does not support 
host name verification on the server side
+            // of a handshake, and rejects every client certificate with 
"Endpoint Identification Algorithm HTTPS is not
+            // supported on the server side" when asked to 
(HttpServerSharedInitializerFactory does not apply it either)
             if (consumer.getConfiguration().getSslContextParameters() == null) 
{
                 // just set the enabledProtocols if the SslContextParameter 
doesn't set
                 
engine.setEnabledProtocols(consumer.getConfiguration().getEnabledProtocols().split(","));
diff --git 
a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSSLServerHostnameVerificationTest.java
 
b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSSLServerHostnameVerificationTest.java
new file mode 100644
index 000000000000..96c3fb18b874
--- /dev/null
+++ 
b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSSLServerHostnameVerificationTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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 org.apache.camel.BindToRegistry;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.support.jsse.KeyManagersParameters;
+import org.apache.camel.support.jsse.KeyStoreParameters;
+import org.apache.camel.support.jsse.SSLContextParameters;
+import org.apache.camel.support.jsse.TrustManagersParameters;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * A consumer that asks for client certificates completes the handshake when 
{@code hostnameVerification=true}.
+ * <p/>
+ * The JDK does not support host name verification on the server side of a 
handshake: when the option was passed to the
+ * server engine, it rejected every client certificate with
+ * {@code Endpoint Identification Algorithm HTTPS is not supported on the 
server side}.
+ */
+@DisabledIfSystemProperty(named = "java.vendor", matches = ".*ibm.*")
+public class NettyHttpSSLServerHostnameVerificationTest extends 
BaseNettyTestSupport {
+
+    @BindToRegistry("clientCertParameters")
+    public SSLContextParameters loadClientCertParameters() {
+        SSLContextParameters answer = loadTrustOnlyParameters();
+        KeyManagersParameters kmp = new KeyManagersParameters();
+        kmp.setKeyPassword("changeit");
+        kmp.setKeyStore(localhostKeyStore());
+        answer.setKeyManagers(kmp);
+        return answer;
+    }
+
+    @BindToRegistry("trustOnlyParameters")
+    public SSLContextParameters loadTrustOnlyParameters() {
+        TrustManagersParameters tmp = new TrustManagersParameters();
+        tmp.setKeyStore(localhostKeyStore());
+
+        SSLContextParameters answer = new SSLContextParameters();
+        answer.setTrustManagers(tmp);
+        return answer;
+    }
+
+    private static KeyStoreParameters localhostKeyStore() {
+        KeyStoreParameters ksp = new KeyStoreParameters();
+        ksp.setResource("jsse/localhost.p12");
+        ksp.setPassword("changeit");
+        return ksp;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                
from("netty-http:https://localhost:{{port}}/hello?sslContextParameters=#clientCertParameters";
+                     + "&needClientAuth=true&hostnameVerification=true")
+                        .transform().constant("Bye World");
+            }
+        };
+    }
+
+    @Test
+    public void testClientCertificateAccepted() {
+        String out = template.requestBody(
+                
"netty-http:https://localhost:{{port}}/hello?sslContextParameters=#clientCertParameters";,
+                "Hello World", String.class);
+
+        assertEquals("Bye World", out);
+    }
+
+    /**
+     * The consumer still requires a client certificate, so the handshake in 
the test above did not pass because the
+     * client authentication was dropped.
+     */
+    @Test
+    public void testNoClientCertificateRejected() {
+        assertThrows(CamelExecutionException.class,
+                () -> template.requestBody(
+                        
"netty-http:https://localhost:{{port}}/hello?sslContextParameters=#trustOnlyParameters";,
+                        "Hello World", String.class));
+    }
+
+    /**
+     * The option still applies to the producer: localhost.p12 lists only 
DNS:localhost as subject alternative name, so
+     * it does not match 127.0.0.1.
+     */
+    @Test
+    public void testProducerRejectsCertificateNotMatchingTheHost() {
+        CamelExecutionException e = assertThrows(CamelExecutionException.class,
+                () -> template.requestBody(
+                        
"netty-http:https://127.0.0.1:{{port}}/hello?sslContextParameters=#clientCertParameters";
+                                           + "&hostnameVerification=true",
+                        "Hello World", String.class));
+
+        Throwable cause = e;
+        while (cause.getCause() != null) {
+            cause = cause.getCause();
+        }
+        assertTrue(cause.getMessage() != null && 
cause.getMessage().contains("127.0.0.1"),
+                "the host name check should have rejected the certificate, but 
got: " + cause.getMessage());
+    }
+}
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index 9becf9752ee5..65b45954c254 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -2786,6 +2786,16 @@ anything there - the JDK does not support host name 
verification on the server s
 client certificate with `Endpoint Identification Algorithm HTTPS is not 
supported on the server side` - so a consumer
 that asks for client certificates and had the option set now completes the 
handshake instead of failing it.
 
+=== camel-netty-http - hostnameVerification is ignored on a consumer
+
+A `netty-http` consumer no longer passes `hostnameVerification=true` to its 
TLS engine, as `netty` consumers already
+do not (see above). The JDK does not support host name verification on the 
server side of a handshake: a client that
+presented a certificate failed the handshake with
+`Endpoint Identification Algorithm HTTPS is not supported on the server side`, 
and a client that presented none was not
+checked at all. A consumer with `needClientAuth=true` and the option set now 
accepts trusted client certificates
+instead of rejecting all of them. Consumers that share a server through 
`nettySharedHttpServer` never applied the
+option, and are unchanged. The option still verifies the host on a 
`netty-http` producer.
+
 === camel-alibaba-oss - a listed object that cannot be got is skipped
 
 When the consumer lists the bucket, a failure to get one of the listed objects 
(for example access denied, or an

Reply via email to