This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/main by this push:
new 9b224a7de6 CXF-9194: Support SNI in CXF client with Apache
HttpComponents HttpClient 4 / HttpClient 5 (#2822)
9b224a7de6 is described below
commit 9b224a7de6cba1c8edb5c5ddc43a1fc9b4755da8
Author: Andriy Redko <[email protected]>
AuthorDate: Sat Jan 24 08:13:00 2026 -0500
CXF-9194: Support SNI in CXF client with Apache HttpComponents HttpClient 4
/ HttpClient 5 (#2822)
---
.../configuration/jsse/TLSClientParameters.java | 24 +++++
.../jsse/TLSClientParametersConfig.java | 3 +
.../resources/schemas/configuration/security.xsd | 28 +++++-
.../http/asyncclient/AsyncHTTPConduit.java | 10 ++
.../http/asyncclient/hc5/AsyncHTTPConduit.java | 10 ++
.../spring/HttpConduitBeanDefinitionParser.java | 3 +
.../cxf/systest/hc5/https/sni/ClientSniServer.java | 47 +++++++++
.../cxf/systest/hc5/https/sni/ClientSniTest.java | 104 +++++++++++++++++++
.../systest/hc5/https/sni/client-sni-server.xml | 56 +++++++++++
.../cxf/systest/hc5/https/sni/client-sni.xml | 44 +++++++++
.../cxf/systest/https/sni/ClientSniServer.java | 47 +++++++++
.../cxf/systest/https/sni/ClientSniTest.java | 110 +++++++++++++++++++++
.../cxf/systest/https/sni/client-sni-server.xml | 56 +++++++++++
.../apache/cxf/systest/https/sni/client-sni.xml | 44 +++++++++
14 files changed, 581 insertions(+), 5 deletions(-)
diff --git
a/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParameters.java
b/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParameters.java
index ad1992823c..c7cebf0665 100644
---
a/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParameters.java
+++
b/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParameters.java
@@ -58,6 +58,7 @@ public class TLSClientParameters extends TLSParameterBase {
private boolean useHttpsURLConnectionDefaultHostnameVerifier;
private HostnameVerifier hostnameVerifier;
private SSLContext sslContext;
+ private List<String> serverNames;
/**
* Set custom HostnameVerifier
@@ -165,6 +166,21 @@ public class TLSClientParameters extends TLSParameterBase {
this.useHttpsURLConnectionDefaultHostnameVerifier =
useHttpsURLConnectionDefaultHostnameVerifier;
}
+ /**
+ * Sets SNI server names
+ * @param serverNames SNI server names
+ */
+ public void setServerNames(List<String> serverNames) {
+ this.serverNames = serverNames;
+ }
+
+ /**
+ * Returns SNI server names
+ */
+ public List<String> getServerNames() {
+ return serverNames;
+ }
+
public int hashCode() {
int hash = disableCNCheck ? 37 : 17;
if (sslSocketFactory != null) {
@@ -193,6 +209,9 @@ public class TLSClientParameters extends TLSParameterBase {
hash = hash(hash, certConstraints.getIssuerDNConstraints());
hash = hash(hash, certConstraints.getSubjectDNConstraints());
}
+ if (serverNames != null) {
+ hash = hash(hash, serverNames);
+ }
return hash;
}
private int hash(int i, Object o) {
@@ -253,6 +272,11 @@ public class TLSClientParameters extends TLSParameterBase {
} else {
eq &= that.certConstraints == null;
}
+ if (serverNames != null) {
+ eq &= equals(serverNames, that.serverNames);
+ } else {
+ eq &= that.serverNames == null;
+ }
return eq;
}
return false;
diff --git
a/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParametersConfig.java
b/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParametersConfig.java
index 781abcc15f..7eb060074f 100644
---
a/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParametersConfig.java
+++
b/core/src/main/java/org/apache/cxf/configuration/jsse/TLSClientParametersConfig.java
@@ -137,6 +137,9 @@ public final class TLSClientParametersConfig {
if (iparams != null && iparams.isSetTrustManagersRef() &&
!usingDefaults) {
ret.setTrustManagers(iparams.getTrustManagersRef());
}
+ if (iparams != null && iparams.isSetServerNames()) {
+ ret.setServerNames(iparams.getServerNames().getServerName());
+ }
return ret;
}
diff --git a/core/src/main/resources/schemas/configuration/security.xsd
b/core/src/main/resources/schemas/configuration/security.xsd
index 73f5e1767f..fbc28a30e7 100644
--- a/core/src/main/resources/schemas/configuration/security.xsd
+++ b/core/src/main/resources/schemas/configuration/security.xsd
@@ -436,7 +436,18 @@
<xs:enumeration value="ALL"/>
</xs:restriction>
</xs:simpleType>
-
+
+ <xs:complexType name="ServerNames">
+ <xs:annotation>
+ <xs:documentation>
+ This structure holds the list of SNI server names.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="serverName" type="xs:string" minOccurs="0"
maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
<!-- Although there are common elements of TLSClientParametersType
** and TLSServerParametersType they are listed separate so we
** can use the xs:all element.
@@ -460,7 +471,7 @@
<xs:element name="cipherSuites" type="tns:CipherSuites"
minOccurs="0">
<xs:annotation>
<xs:documentation>
- This element contains the the CipherSuites that will be
supported.
+ This element contains the CipherSuites that will be supported.
</xs:documentation>
</xs:annotation>
</xs:element>
@@ -494,6 +505,13 @@
</xs:documentation>
</xs:annotation>
</xs:element>
+ <xs:element name="serverNames" type="tns:ServerNames" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>
+ This element contains the SNI server names.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
</xs:all>
<xs:attribute name="useHttpsURLConnectionDefaultSslSocketFactory"
type="pt:ParameterizedBoolean" default="false">
<xs:annotation>
@@ -577,7 +595,7 @@
<xs:element name="cipherSuites" type="tns:CipherSuites"
minOccurs="0">
<xs:annotation>
<xs:documentation>
- This element contains the the CipherSuites that will be
supported.
+ This element contains the CipherSuites that will be supported.
</xs:documentation>
</xs:annotation>
</xs:element>
@@ -592,14 +610,14 @@
<xs:element name="excludeProtocols" type="tns:ExcludeProtocols"
minOccurs="0">
<xs:annotation>
<xs:documentation>
- This element contains the the Protocols that will be excluded
+ This element contains the Protocols that will be excluded
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="includeProtocols" type="tns:IncludeProtocols"
minOccurs="0">
<xs:annotation>
<xs:documentation>
- This element contains the the Protocols that will be included
+ This element contains the Protocols that will be included
</xs:documentation>
</xs:annotation>
</xs:element>
diff --git
a/rt/transports/http-hc/src/main/java/org/apache/cxf/transport/http/asyncclient/AsyncHTTPConduit.java
b/rt/transports/http-hc/src/main/java/org/apache/cxf/transport/http/asyncclient/AsyncHTTPConduit.java
index edf8b8cfb9..f7e4867d7e 100755
---
a/rt/transports/http-hc/src/main/java/org/apache/cxf/transport/http/asyncclient/AsyncHTTPConduit.java
+++
b/rt/transports/http-hc/src/main/java/org/apache/cxf/transport/http/asyncclient/AsyncHTTPConduit.java
@@ -39,12 +39,15 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.logging.Level;
+import java.util.stream.Collectors;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
+import javax.net.ssl.SNIHostName;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
@@ -977,6 +980,13 @@ public class AsyncHTTPConduit extends
HttpClientHTTPConduit {
if (p != null) {
sslengine.setEnabledProtocols(p);
}
+
+ final List<String> serverNames = tlsClientParameters.getServerNames();
+ if (serverNames != null && !serverNames.isEmpty()) {
+ final SSLParameters params = new SSLParameters();
+
params.setServerNames(serverNames.stream().map(SNIHostName::new).collect(Collectors.toList()));
+ sslengine.setSSLParameters(params);
+ }
}
private String[] findProtocols(String p, String[] options) {
diff --git
a/rt/transports/http-hc5/src/main/java/org/apache/cxf/transport/http/asyncclient/hc5/AsyncHTTPConduit.java
b/rt/transports/http-hc5/src/main/java/org/apache/cxf/transport/http/asyncclient/hc5/AsyncHTTPConduit.java
index c990ecf719..92a68a2956 100644
---
a/rt/transports/http-hc5/src/main/java/org/apache/cxf/transport/http/asyncclient/hc5/AsyncHTTPConduit.java
+++
b/rt/transports/http-hc5/src/main/java/org/apache/cxf/transport/http/asyncclient/hc5/AsyncHTTPConduit.java
@@ -39,11 +39,14 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.logging.Level;
+import java.util.stream.Collectors;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
+import javax.net.ssl.SNIHostName;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
@@ -982,6 +985,13 @@ public class AsyncHTTPConduit extends
HttpClientHTTPConduit {
if (p != null) {
sslengine.setEnabledProtocols(p);
}
+
+ final List<String> serverNames = tlsClientParameters.getServerNames();
+ if (serverNames != null && !serverNames.isEmpty()) {
+ final SSLParameters params = new SSLParameters();
+
params.setServerNames(serverNames.stream().map(SNIHostName::new).collect(Collectors.toList()));
+ sslengine.setSSLParameters(params);
+ }
}
@Override
diff --git
a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/spring/HttpConduitBeanDefinitionParser.java
b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/spring/HttpConduitBeanDefinitionParser.java
index f751847826..994b29a343 100644
---
a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/spring/HttpConduitBeanDefinitionParser.java
+++
b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/spring/HttpConduitBeanDefinitionParser.java
@@ -36,6 +36,7 @@ import org.apache.cxf.configuration.security.FiltersType;
import org.apache.cxf.configuration.security.KeyManagersType;
import org.apache.cxf.configuration.security.ProxyAuthorizationPolicy;
import org.apache.cxf.configuration.security.SecureRandomParameters;
+import org.apache.cxf.configuration.security.ServerNames;
import org.apache.cxf.configuration.security.TrustManagersType;
import org.apache.cxf.configuration.spring.AbstractBeanDefinitionParser;
import org.apache.cxf.transport.http.HTTPConduit;
@@ -171,6 +172,8 @@ public class HttpConduitBeanDefinitionParser
CertificateConstraintsType.class);
} else if ("certAlias".equals(ename)) {
paramsbean.addPropertyValue(ename, n.getTextContent());
+ } else if ("serverNames".equals(ename)) {
+ mapElementToJaxbProperty((Element)n, paramsbean, ename,
ServerNames.class);
}
n = n.getNextSibling();
}
diff --git
a/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/https/sni/ClientSniServer.java
b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/https/sni/ClientSniServer.java
new file mode 100644
index 0000000000..901629fae9
--- /dev/null
+++
b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/https/sni/ClientSniServer.java
@@ -0,0 +1,47 @@
+/**
+ * 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.cxf.systest.hc5.https.sni;
+
+import java.net.URL;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
+
+public class ClientSniServer extends AbstractBusTestServerBase {
+
+ public ClientSniServer() {
+
+ }
+
+ protected void run() {
+ URL busFile =
ClientSniServer.class.getResource("client-sni-server.xml");
+ Bus busLocal = new SpringBusFactory().createBus(busFile);
+ BusFactory.setDefaultBus(busLocal);
+ setBus(busLocal);
+
+ try {
+ new ClientSniServer();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git
a/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/https/sni/ClientSniTest.java
b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/https/sni/ClientSniTest.java
new file mode 100644
index 0000000000..8a390bd46c
--- /dev/null
+++
b/systests/transport-hc5/src/test/java/org/apache/cxf/systest/hc5/https/sni/ClientSniTest.java
@@ -0,0 +1,104 @@
+/**
+ * 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.cxf.systest.hc5.https.sni;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+
+import jakarta.xml.ws.BindingProvider;
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+import org.apache.hello_world.Greeter;
+import org.apache.hello_world.services.SOAPService;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized.Parameters;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * A set of tests for TLS SNI
+ */
+@RunWith(value = org.junit.runners.Parameterized.class)
+public class ClientSniTest extends AbstractBusClientServerTestBase {
+ static final String PORT = allocatePort(ClientSniServer.class);
+
+ final Boolean async;
+
+ public ClientSniTest(Boolean async) {
+ this.async = async;
+ }
+
+ @Parameters(name = "{0}")
+ public static Collection<Boolean> data() {
+ return Arrays.asList(new Boolean[] {Boolean.FALSE, Boolean.TRUE});
+ }
+
+ @BeforeClass
+ public static void startServers() throws Exception {
+ assertTrue(
+ "Server failed to launch",
+ // run the server in the same process
+ // set this to false to fork
+ launchServer(ClientSniServer.class, true)
+ );
+ }
+
+ @AfterClass
+ public static void cleanup() throws Exception {
+ stopAllServers();
+ }
+
+ // Server directly trusts the client cert
+ @org.junit.Test
+ public void testSniServerNames() throws Exception {
+ SpringBusFactory bf = new SpringBusFactory();
+ URL busFile = ClientSniTest.class.getResource("client-sni.xml");
+
+ Bus bus = bf.createBus(busFile.toString());
+ BusFactory.setDefaultBus(bus);
+ BusFactory.setThreadDefaultBus(bus);
+
+ URL url = SOAPService.WSDL_LOCATION;
+ SOAPService service = new SOAPService(url, SOAPService.SERVICE);
+ assertNotNull("Service is null", service);
+ final Greeter port = service.getHttpsPort();
+ assertNotNull("Port is null", port);
+
+ updateAddressPort(port, PORT);
+
+ // Enable Async
+ if (async) {
+
((BindingProvider)port).getRequestContext().put("use.async.http.conduit", true);
+ }
+
+ assertEquals(port.greetMe("Kitty"), "Hello Kitty");
+
+ ((java.io.Closeable)port).close();
+ bus.shutdown(true);
+ }
+}
diff --git
a/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/https/sni/client-sni-server.xml
b/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/https/sni/client-sni-server.xml
new file mode 100644
index 0000000000..378aa31a7f
--- /dev/null
+++
b/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/https/sni/client-sni-server.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:jaxws="http://cxf.apache.org/jaxws"
+ xmlns:http="http://cxf.apache.org/transports/http/configuration"
+ xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
+ xmlns:sec="http://cxf.apache.org/configuration/security"
+ xmlns:cxf="http://cxf.apache.org/core"
+ xmlns:p="http://cxf.apache.org/policy"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://cxf.apache.org/policy http://cxf.apache.org/schemas/policy.xsd
http://cxf.apache.org/transports/http/configuration
http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://cxf.apache.org/transports/http-jetty/confi [...]
+ <bean
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"/>
+ <cxf:bus>
+ <cxf:features>
+ <bean class="org.apache.cxf.ext.logging.LoggingFeature"/>
+ </cxf:features>
+ </cxf:bus>
+
+ <httpj:engine-factory id="tls-settings">
+ <httpj:engine port="${testutil.ports.ClientSniServer}">
+ <httpj:tlsServerParameters>
+ <sec:keyManagers keyPassword="password">
+ <sec:keyStore type="jks" password="password"
resource="keys/Bethal.jks"/>
+ </sec:keyManagers>
+ <sec:trustManagers>
+ <sec:keyStore type="jks" password="password"
resource="keys/Truststore.jks"/>
+ </sec:trustManagers>
+ </httpj:tlsServerParameters>
+ </httpj:engine>
+ </httpj:engine-factory>
+
+ <jaxws:endpoint xmlns:e="http://apache.org/hello_world/services"
+ xmlns:s="http://apache.org/hello_world/services"
+ id="DirectTrustServer"
+ implementor="org.apache.cxf.systest.hc5.GreeterImpl"
+
address="https://localhost:${testutil.ports.ClientSniServer}/SoapContext/HttpsPort"
+ serviceName="s:SOAPService"
+ endpointName="e:HttpsPort" depends-on="tls-settings"/>
+</beans>
\ No newline at end of file
diff --git
a/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/https/sni/client-sni.xml
b/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/https/sni/client-sni.xml
new file mode 100644
index 0000000000..cca43394e7
--- /dev/null
+++
b/systests/transport-hc5/src/test/resources/org/apache/cxf/systest/hc5/https/sni/client-sni.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:http="http://cxf.apache.org/transports/http/configuration"
+ xmlns:jaxws="http://cxf.apache.org/jaxws"
+ xmlns:cxf="http://cxf.apache.org/core"
+ xmlns:p="http://cxf.apache.org/policy"
+ xmlns:sec="http://cxf.apache.org/configuration/security"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/transports/http/configuration
http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://cxf.apache.org/configuration/security
http://cxf.apache.org/schemas/configuration/security.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://cxf.apache [...]
+
+ <cxf:bus>
+ <cxf:features>
+ <bean class="org.apache.cxf.ext.logging.LoggingFeature"/>
+ </cxf:features>
+ </cxf:bus>
+ <http:conduit name="https://localhost:.*">
+ <http:tlsClientParameters disableCNCheck="true">
+ <sec:trustManagers>
+ <sec:keyStore type="jks" password="password"
resource="keys/Truststore.jks"/>
+ </sec:trustManagers>
+ <sec:serverNames>
+ <sec:serverName>bethal</sec:serverName>
+ </sec:serverNames>
+ </http:tlsClientParameters>
+ </http:conduit>
+</beans>
\ No newline at end of file
diff --git
a/systests/transports/src/test/java/org/apache/cxf/systest/https/sni/ClientSniServer.java
b/systests/transports/src/test/java/org/apache/cxf/systest/https/sni/ClientSniServer.java
new file mode 100644
index 0000000000..b453e225fc
--- /dev/null
+++
b/systests/transports/src/test/java/org/apache/cxf/systest/https/sni/ClientSniServer.java
@@ -0,0 +1,47 @@
+/**
+ * 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.cxf.systest.https.sni;
+
+import java.net.URL;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
+
+public class ClientSniServer extends AbstractBusTestServerBase {
+
+ public ClientSniServer() {
+
+ }
+
+ protected void run() {
+ URL busFile =
ClientSniServer.class.getResource("client-sni-server.xml");
+ Bus busLocal = new SpringBusFactory().createBus(busFile);
+ BusFactory.setDefaultBus(busLocal);
+ setBus(busLocal);
+
+ try {
+ new ClientSniServer();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git
a/systests/transports/src/test/java/org/apache/cxf/systest/https/sni/ClientSniTest.java
b/systests/transports/src/test/java/org/apache/cxf/systest/https/sni/ClientSniTest.java
new file mode 100644
index 0000000000..f6d1cfb180
--- /dev/null
+++
b/systests/transports/src/test/java/org/apache/cxf/systest/https/sni/ClientSniTest.java
@@ -0,0 +1,110 @@
+/**
+ * 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.cxf.systest.https.sni;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+
+import jakarta.xml.ws.BindingProvider;
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+import org.apache.hello_world.Greeter;
+import org.apache.hello_world.services.SOAPService;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized.Parameters;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * A set of tests for TLS SNI
+ */
+@RunWith(value = org.junit.runners.Parameterized.class)
+public class ClientSniTest extends AbstractBusClientServerTestBase {
+ static final String PORT = allocatePort(ClientSniServer.class);
+
+ final String clientKey;
+ final Object clientVal;
+
+ public ClientSniTest(String ck, Object value) {
+ this.clientKey = ck;
+ this.clientVal = value;
+ }
+
+ @Parameters(name = "{0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {
+ {"force.urlconnection.http.conduit", true},
+ {"use.async.http.conduit", true},
+ {"defaultConduit", true},
+ {"org.apache.cxf.transport.http.forceVersion", "1.1"},
+ {"org.apache.cxf.transport.http.forceVersion", "2"}
+ });
+ }
+
+ @BeforeClass
+ public static void startServers() throws Exception {
+ assertTrue(
+ "Server failed to launch",
+ // run the server in the same process
+ // set this to false to fork
+ launchServer(ClientSniServer.class, true)
+ );
+ }
+
+ @AfterClass
+ public static void cleanup() throws Exception {
+ stopAllServers();
+ }
+
+ // Server directly trusts the client cert
+ @org.junit.Test
+ public void testSniServerNames() throws Exception {
+ SpringBusFactory bf = new SpringBusFactory();
+ URL busFile = ClientSniTest.class.getResource("client-sni.xml");
+
+ Bus bus = bf.createBus(busFile.toString());
+ BusFactory.setDefaultBus(bus);
+ BusFactory.setThreadDefaultBus(bus);
+
+ URL url = SOAPService.WSDL_LOCATION;
+ SOAPService service = new SOAPService(url, SOAPService.SERVICE);
+ assertNotNull("Service is null", service);
+ final Greeter port = service.getHttpsPort();
+ assertNotNull("Port is null", port);
+
+ updateAddressPort(port, PORT);
+
+ ((BindingProvider)port).getRequestContext().put(clientKey, clientVal);
+
+
+ assertEquals(port.greetMe("Kitty"), "Hello Kitty");
+
+ ((java.io.Closeable)port).close();
+ bus.shutdown(true);
+ }
+}
diff --git
a/systests/transports/src/test/resources/org/apache/cxf/systest/https/sni/client-sni-server.xml
b/systests/transports/src/test/resources/org/apache/cxf/systest/https/sni/client-sni-server.xml
new file mode 100644
index 0000000000..da1ed372fb
--- /dev/null
+++
b/systests/transports/src/test/resources/org/apache/cxf/systest/https/sni/client-sni-server.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:jaxws="http://cxf.apache.org/jaxws"
+ xmlns:http="http://cxf.apache.org/transports/http/configuration"
+ xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
+ xmlns:sec="http://cxf.apache.org/configuration/security"
+ xmlns:cxf="http://cxf.apache.org/core"
+ xmlns:p="http://cxf.apache.org/policy"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://cxf.apache.org/policy http://cxf.apache.org/schemas/policy.xsd
http://cxf.apache.org/transports/http/configuration
http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://cxf.apache.org/transports/http-jetty/confi [...]
+ <bean
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"/>
+ <cxf:bus>
+ <cxf:features>
+ <bean class="org.apache.cxf.ext.logging.LoggingFeature"/>
+ </cxf:features>
+ </cxf:bus>
+
+ <httpj:engine-factory id="tls-settings">
+ <httpj:engine port="${testutil.ports.ClientSniServer}">
+ <httpj:tlsServerParameters>
+ <sec:keyManagers keyPassword="password">
+ <sec:keyStore type="jks" password="password"
resource="keys/Bethal.jks"/>
+ </sec:keyManagers>
+ <sec:trustManagers>
+ <sec:keyStore type="jks" password="password"
resource="keys/Truststore.jks"/>
+ </sec:trustManagers>
+ </httpj:tlsServerParameters>
+ </httpj:engine>
+ </httpj:engine-factory>
+
+ <jaxws:endpoint xmlns:e="http://apache.org/hello_world/services"
+ xmlns:s="http://apache.org/hello_world/services"
+ id="DirectTrustServer"
+ implementor="org.apache.cxf.systest.http.GreeterImpl"
+
address="https://localhost:${testutil.ports.ClientSniServer}/SoapContext/HttpsPort"
+ serviceName="s:SOAPService"
+ endpointName="e:HttpsPort" depends-on="tls-settings"/>
+</beans>
\ No newline at end of file
diff --git
a/systests/transports/src/test/resources/org/apache/cxf/systest/https/sni/client-sni.xml
b/systests/transports/src/test/resources/org/apache/cxf/systest/https/sni/client-sni.xml
new file mode 100644
index 0000000000..cca43394e7
--- /dev/null
+++
b/systests/transports/src/test/resources/org/apache/cxf/systest/https/sni/client-sni.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:http="http://cxf.apache.org/transports/http/configuration"
+ xmlns:jaxws="http://cxf.apache.org/jaxws"
+ xmlns:cxf="http://cxf.apache.org/core"
+ xmlns:p="http://cxf.apache.org/policy"
+ xmlns:sec="http://cxf.apache.org/configuration/security"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/transports/http/configuration
http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://cxf.apache.org/configuration/security
http://cxf.apache.org/schemas/configuration/security.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
http://cxf.apache [...]
+
+ <cxf:bus>
+ <cxf:features>
+ <bean class="org.apache.cxf.ext.logging.LoggingFeature"/>
+ </cxf:features>
+ </cxf:bus>
+ <http:conduit name="https://localhost:.*">
+ <http:tlsClientParameters disableCNCheck="true">
+ <sec:trustManagers>
+ <sec:keyStore type="jks" password="password"
resource="keys/Truststore.jks"/>
+ </sec:trustManagers>
+ <sec:serverNames>
+ <sec:serverName>bethal</sec:serverName>
+ </sec:serverNames>
+ </http:tlsClientParameters>
+ </http:conduit>
+</beans>
\ No newline at end of file