This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 18948157d10f CAMEL-23773: camel-cxf - make ws-security optional to
avoid opensaml/shibboleth dependency (#24054)
18948157d10f is described below
commit 18948157d10fd59c0cd6209fbf3407678cd468b6
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Jun 16 17:49:39 2026 +0200
CAMEL-23773: camel-cxf - make ws-security optional to avoid
opensaml/shibboleth dependency (#24054)
Make cxf-rt-ws-security optional in camel-cxf-soap so most CXF users
avoid the 13+ transitive org.opensaml JARs hosted on the unreliable
build.shibboleth.net repository. Extract wss4j-dependent cert extraction
into WsSecurityHelper (loaded only when wss4j is on the classpath).
Exclude org.opensaml from both camel-cxf-soap and camel-cxf-spring-soap.
Remove the now-unnecessary .mvn/rrf/groupId-B_shibboleth.txt filter.
Signed-off-by: Claus Ibsen <[email protected]>
Co-authored-by: Claude <[email protected]>
---
.mvn/rrf/groupId-B_shibboleth.txt | 3 -
components/camel-cxf/camel-cxf-soap/pom.xml | 7 ++
.../component/cxf/jaxws/DefaultCxfBinding.java | 85 +++------------
.../component/cxf/jaxws/WsSecurityHelper.java | 115 +++++++++++++++++++++
components/camel-cxf/camel-cxf-spring-soap/pom.xml | 6 ++
.../ROOT/pages/camel-4x-upgrade-guide-4_21.adoc | 22 ++++
6 files changed, 167 insertions(+), 71 deletions(-)
diff --git a/.mvn/rrf/groupId-B_shibboleth.txt
b/.mvn/rrf/groupId-B_shibboleth.txt
deleted file mode 100644
index 0a644833082c..000000000000
--- a/.mvn/rrf/groupId-B_shibboleth.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-net.shibboleth
-net.shibboleth.utilities
-org.opensaml
diff --git a/components/camel-cxf/camel-cxf-soap/pom.xml
b/components/camel-cxf/camel-cxf-soap/pom.xml
index 87135ea35e78..d7b24157d9bb 100644
--- a/components/camel-cxf/camel-cxf-soap/pom.xml
+++ b/components/camel-cxf/camel-cxf-soap/pom.xml
@@ -194,6 +194,13 @@
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-ws-security</artifactId>
<version>${cxf-version}</version>
+ <optional>true</optional>
+ <exclusions>
+ <exclusion>
+ <groupId>org.opensaml</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
diff --git
a/components/camel-cxf/camel-cxf-soap/src/main/java/org/apache/camel/component/cxf/jaxws/DefaultCxfBinding.java
b/components/camel-cxf/camel-cxf-soap/src/main/java/org/apache/camel/component/cxf/jaxws/DefaultCxfBinding.java
index 591f7974c6c1..cbe2af5c8d90 100644
---
a/components/camel-cxf/camel-cxf-soap/src/main/java/org/apache/camel/component/cxf/jaxws/DefaultCxfBinding.java
+++
b/components/camel-cxf/camel-cxf-soap/src/main/java/org/apache/camel/component/cxf/jaxws/DefaultCxfBinding.java
@@ -95,9 +95,6 @@ import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.service.model.MessagePartInfo;
import org.apache.cxf.service.model.OperationInfo;
import org.apache.cxf.staxutils.StaxUtils;
-import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
-import org.apache.wss4j.dom.handler.WSHandlerConstants;
-import org.apache.wss4j.dom.handler.WSHandlerResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -389,82 +386,34 @@ public class DefaultCxfBinding implements CxfBinding,
HeaderFilterStrategyAware
}
}
+ private static final boolean WSS4J_AVAILABLE;
+ static {
+ boolean available;
+ try {
+ Class.forName("org.apache.wss4j.dom.handler.WSHandlerConstants");
+ available = true;
+ } catch (ClassNotFoundException e) {
+ available = false;
+ }
+ WSS4J_AVAILABLE = available;
+ }
+
private static void addInboundX509CertificatesToSubject(Message
cxfMessage, Subject subject) {
- if (cxfMessage == null || subject == null) {
+ if (!WSS4J_AVAILABLE || cxfMessage == null || subject == null) {
return;
}
- // If it’s read-only, don’t break the route; just skip.
if (subject.isReadOnly()) {
return;
}
- final Object recv = cxfMessage.get(WSHandlerConstants.RECV_RESULTS);
- if (recv == null) {
+ Collection<X509Certificate> certs;
+ try {
+ certs = WsSecurityHelper.extractCertificates(cxfMessage);
+ } catch (NoClassDefFoundError e) {
return;
}
- // We only need the cert objects.
- Collection<X509Certificate> certs = null;
-
- if (recv instanceof Map<?, ?> map) {
- Object v = map.get(WSSecurityEngineResult.TAG_X509_CERTIFICATES);
-
- if (v instanceof Collection<?> coll) {
- certs = new ArrayList<>();
- for (Object o : coll) {
- if (o instanceof X509Certificate cert) {
- certs.add(cert);
- } else if (o instanceof X509Certificate[] arr) {
- for (X509Certificate c : arr) {
- if (c != null) {
- certs.add(c);
- }
- }
- }
- }
- } else if (v instanceof X509Certificate[] arr) {
- certs = new ArrayList<>();
- for (X509Certificate c : arr) {
- if (c != null) {
- certs.add(c);
- }
- }
- }
-
- } else if (recv instanceof List<?> list) {
- // Typical CXF case: List<WSHandlerResult>
- if (!list.isEmpty() && list.get(0) instanceof WSHandlerResult) {
- certs = new ArrayList<>();
- for (Object hrObj : list) {
- if (!(hrObj instanceof WSHandlerResult hr)) {
- continue;
- }
- for (WSSecurityEngineResult r : hr.getResults()) {
- Object v =
r.get(WSSecurityEngineResult.TAG_X509_CERTIFICATES);
-
- if (v instanceof X509Certificate[] arr) {
- for (X509Certificate c : arr) {
- if (c != null) {
- certs.add(c);
- }
- }
- } else if (v instanceof X509Certificate cert) {
- certs.add(cert);
- } else {
- Object leaf =
r.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
- if (leaf instanceof X509Certificate cert) {
- certs.add(cert);
- }
- }
- }
- }
- if (certs.isEmpty()) {
- certs = null;
- }
- }
- }
-
if (certs == null || certs.isEmpty()) {
return;
}
diff --git
a/components/camel-cxf/camel-cxf-soap/src/main/java/org/apache/camel/component/cxf/jaxws/WsSecurityHelper.java
b/components/camel-cxf/camel-cxf-soap/src/main/java/org/apache/camel/component/cxf/jaxws/WsSecurityHelper.java
new file mode 100644
index 000000000000..8942747c743c
--- /dev/null
+++
b/components/camel-cxf/camel-cxf-soap/src/main/java/org/apache/camel/component/cxf/jaxws/WsSecurityHelper.java
@@ -0,0 +1,115 @@
+/*
+ * 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.cxf.jaxws;
+
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.message.Message;
+import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
+import org.apache.wss4j.dom.handler.WSHandlerConstants;
+import org.apache.wss4j.dom.handler.WSHandlerResult;
+
+/**
+ * Extracts X.509 certificates from WS-Security processing results. This class
is isolated so that
+ * {@link DefaultCxfBinding} does not require wss4j on the classpath — it is
only loaded when wss4j is present.
+ */
+final class WsSecurityHelper {
+
+ private WsSecurityHelper() {
+ }
+
+ static Collection<X509Certificate> extractCertificates(Message cxfMessage)
{
+ final Object recv = cxfMessage.get(WSHandlerConstants.RECV_RESULTS);
+ if (recv == null) {
+ return null;
+ }
+
+ Collection<X509Certificate> certs = null;
+
+ if (recv instanceof Map<?, ?> map) {
+ certs = extractFromMap(map);
+ } else if (recv instanceof List<?> list) {
+ certs = extractFromHandlerResults(list);
+ }
+
+ return certs;
+ }
+
+ private static Collection<X509Certificate> extractFromMap(Map<?, ?> map) {
+ Object v = map.get(WSSecurityEngineResult.TAG_X509_CERTIFICATES);
+
+ Collection<X509Certificate> certs = null;
+ if (v instanceof Collection<?> coll) {
+ certs = new ArrayList<>();
+ for (Object o : coll) {
+ if (o instanceof X509Certificate cert) {
+ certs.add(cert);
+ } else if (o instanceof X509Certificate[] arr) {
+ for (X509Certificate c : arr) {
+ if (c != null) {
+ certs.add(c);
+ }
+ }
+ }
+ }
+ } else if (v instanceof X509Certificate[] arr) {
+ certs = new ArrayList<>();
+ for (X509Certificate c : arr) {
+ if (c != null) {
+ certs.add(c);
+ }
+ }
+ }
+ return certs;
+ }
+
+ private static Collection<X509Certificate>
extractFromHandlerResults(List<?> list) {
+ if (list.isEmpty() || !(list.get(0) instanceof WSHandlerResult)) {
+ return null;
+ }
+
+ Collection<X509Certificate> certs = new ArrayList<>();
+ for (Object hrObj : list) {
+ if (!(hrObj instanceof WSHandlerResult hr)) {
+ continue;
+ }
+ for (WSSecurityEngineResult r : hr.getResults()) {
+ Object v = r.get(WSSecurityEngineResult.TAG_X509_CERTIFICATES);
+
+ if (v instanceof X509Certificate[] arr) {
+ for (X509Certificate c : arr) {
+ if (c != null) {
+ certs.add(c);
+ }
+ }
+ } else if (v instanceof X509Certificate cert) {
+ certs.add(cert);
+ } else {
+ Object leaf =
r.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
+ if (leaf instanceof X509Certificate cert) {
+ certs.add(cert);
+ }
+ }
+ }
+ }
+ return certs.isEmpty() ? null : certs;
+ }
+}
diff --git a/components/camel-cxf/camel-cxf-spring-soap/pom.xml
b/components/camel-cxf/camel-cxf-spring-soap/pom.xml
index 550f9aba5118..5b4be84a6dd3 100644
--- a/components/camel-cxf/camel-cxf-spring-soap/pom.xml
+++ b/components/camel-cxf/camel-cxf-spring-soap/pom.xml
@@ -192,6 +192,12 @@
<artifactId>cxf-rt-ws-security</artifactId>
<version>${cxf-version}</version>
<scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.opensaml</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
index 1d28db3c3884..7f6cb3af3851 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
@@ -824,6 +824,28 @@ The same pattern applies to HTTP-based bridges
(`platform-http`/`jetty`/`netty
-http`/`http` -> `cxf:`) and any other transport whose default
`HeaderFilterStrategy` filters `Camel*` headers.
+==== WS-Security dependency is now optional
+
+The `cxf-rt-ws-security` dependency in `camel-cxf-soap` is now **optional**.
Most Camel CXF users do
+not need WS-Security / SAML support, yet the dependency transitively pulled in
13+ `org.opensaml`
+JARs hosted on a third-party Maven repository (`build.shibboleth.net`) that
has proven unreliable,
+causing intermittent CI and build failures.
+
+If your project uses WS-Security features (signatures, encryption, username
tokens, SAML), you will
+need to add `cxf-rt-ws-security` explicitly to your project's POM:
+
+[source,xml]
+----
+<dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-ws-security</artifactId>
+</dependency>
+----
+
+If you also need OpenSAML (for SAML-based WS-Security), add the `org.opensaml`
dependencies
+explicitly and configure the Shibboleth Maven repository
(`https://build.shibboleth.net/nexus/content/repositories/releases`)
+in your project's POM or Maven `settings.xml`.
+
=== camel-dns - potential breaking change
The Exchange header constants in `DnsConstants` have been renamed to follow the