This is an automated email from the ASF dual-hosted git repository. robertlazarski pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-rampart.git
commit 37dd4b399616826c54d85597c11d8953e5582eba Author: Robert Lazarski <[email protected]> AuthorDate: Thu Oct 8 18:14:51 2026 -1000 Fail rampart and rahas module init clearly when guava is missing A hand-assembled classpath without guava used to surface as a NoClassDefFoundError deep in OpenSAML. Both modules now check at init and log an ERROR naming the jars to copy, since Axis2 logs module init faults at INFO. Co-Authored-By: Claude Opus 5.5 <[email protected]> --- .../src/main/java/org/apache/rampart/Rampart.java | 3 +++ .../src/main/java/org/apache/rahas/Rahas.java | 3 +++ .../rahas/impl/util/OpenSAMLInitializer.java | 27 ++++++++++++++++++++++ .../rahas/impl/util/OpenSAMLInitializerTest.java | 19 +++++++++++++++ src/site/markdown/release-notes/2.0.0.md | 10 ++++++++ 5 files changed, 62 insertions(+) diff --git a/modules/rampart-core/src/main/java/org/apache/rampart/Rampart.java b/modules/rampart-core/src/main/java/org/apache/rampart/Rampart.java index 72f23164..750a1433 100644 --- a/modules/rampart-core/src/main/java/org/apache/rampart/Rampart.java +++ b/modules/rampart-core/src/main/java/org/apache/rampart/Rampart.java @@ -23,6 +23,7 @@ import org.apache.axis2.description.AxisModule; import org.apache.axis2.modules.Module; import org.apache.neethi.Assertion; import org.apache.neethi.Policy; +import org.apache.rahas.impl.util.OpenSAMLInitializer; import org.apache.rampart.policy.model.RampartConfig; import org.apache.ws.secpolicy.SP11Constants; import org.apache.ws.secpolicy.SP12Constants; @@ -31,6 +32,8 @@ public class Rampart implements Module /* , ModulePolicyExtension */ { public void init(ConfigurationContext configContext, AxisModule module) throws AxisFault { + // OpenSAML is used on the message path, so check its runtime dependencies here. + OpenSAMLInitializer.checkRuntimeDependencies(); } public void engageNotify(AxisDescription axisDescription) throws AxisFault { diff --git a/modules/rampart-trust/src/main/java/org/apache/rahas/Rahas.java b/modules/rampart-trust/src/main/java/org/apache/rahas/Rahas.java index 2cdd416f..0e0054bc 100644 --- a/modules/rampart-trust/src/main/java/org/apache/rahas/Rahas.java +++ b/modules/rampart-trust/src/main/java/org/apache/rahas/Rahas.java @@ -25,6 +25,7 @@ import org.apache.axis2.description.AxisModule; import org.apache.axis2.modules.Module; import org.apache.neethi.Assertion; import org.apache.neethi.Policy; +import org.apache.rahas.impl.util.OpenSAMLInitializer; import org.apache.ws.secpolicy.SP11Constants; import org.apache.ws.secpolicy.SP12Constants; import org.opensaml.core.config.InitializationException; @@ -36,6 +37,8 @@ public class Rahas implements Module { // Set up OpenSAML to use a DOM aware Axiom implementation // Axiom Parser pool is also set within the RampartSAMLBootstrap class. + OpenSAMLInitializer.checkRuntimeDependencies(); + try { RampartSAMLBootstrap.initialize(); diff --git a/modules/rampart-trust/src/main/java/org/apache/rahas/impl/util/OpenSAMLInitializer.java b/modules/rampart-trust/src/main/java/org/apache/rahas/impl/util/OpenSAMLInitializer.java index 2b30ed79..50a504d9 100644 --- a/modules/rampart-trust/src/main/java/org/apache/rahas/impl/util/OpenSAMLInitializer.java +++ b/modules/rampart-trust/src/main/java/org/apache/rahas/impl/util/OpenSAMLInitializer.java @@ -18,6 +18,7 @@ */ package org.apache.rahas.impl.util; +import org.apache.axis2.AxisFault; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.wss4j.common.saml.OpenSAMLUtil; @@ -50,6 +51,32 @@ public final class OpenSAMLInitializer { private OpenSAMLInitializer() { } + /** + * Fails module initialisation with a clear message when guava is missing. + * + * <p>OpenSAML, Shibboleth and WSS4J all need guava at runtime. Axis2 2.0.2 stopped + * bundling it, so it now ships in the Rampart distribution's lib/; an installation + * assembled by hand can easily miss it. Without this check the failure surfaces as + * a NoClassDefFoundError deep inside OpenSAML, and Axis2 logs module init faults + * only at INFO, so the reason is logged here at ERROR as well.</p> + */ + public static void checkRuntimeDependencies() throws AxisFault { + checkRuntimeDependencies(InitializationService.class.getClassLoader()); + } + + static void checkRuntimeDependencies(ClassLoader openSAMLLoader) throws AxisFault { + try { + Class.forName("com.google.common.base.Strings", false, openSAMLLoader); + } catch (ClassNotFoundException | LinkageError e) { + String message = "Google Guava is not on the classpath, but OpenSAML and WSS4J" + + " require it. Copy the guava and failureaccess jars from the Rampart" + + " distribution's lib/ directory into the Axis2 lib/ (or WEB-INF/lib)" + + " directory alongside the other Rampart dependencies."; + log.error(message); + throw new AxisFault(message, e); + } + } + /** * Initialises OpenSAML once. After the first successful call this is a single * volatile read. A failed attempt is not recorded, so the next call retries. diff --git a/modules/rampart-trust/src/test/java/org/apache/rahas/impl/util/OpenSAMLInitializerTest.java b/modules/rampart-trust/src/test/java/org/apache/rahas/impl/util/OpenSAMLInitializerTest.java index 7ae2e12c..d47adcc1 100644 --- a/modules/rampart-trust/src/test/java/org/apache/rahas/impl/util/OpenSAMLInitializerTest.java +++ b/modules/rampart-trust/src/test/java/org/apache/rahas/impl/util/OpenSAMLInitializerTest.java @@ -18,12 +18,16 @@ */ package org.apache.rahas.impl.util; +import java.net.URL; +import java.net.URLClassLoader; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import junit.framework.TestCase; +import org.apache.axis2.AxisFault; + import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.xmlsec.SecurityConfigurationSupport; import org.opensaml.xmlsec.SignatureSigningConfiguration; @@ -61,6 +65,21 @@ public class OpenSAMLInitializerTest extends TestCase { SecurityConfigurationSupport.getGlobalSignatureSigningConfiguration()); } + public void testRuntimeDependencyCheckPassesWithGuava() throws Exception { + OpenSAMLInitializer.checkRuntimeDependencies(); + } + + /** A missing guava must fail module init with a message naming the jars to add. */ + public void testRuntimeDependencyCheckFailsWithoutGuava() throws Exception { + ClassLoader withoutGuava = new URLClassLoader(new URL[0], null); + try { + OpenSAMLInitializer.checkRuntimeDependencies(withoutGuava); + fail("a classpath without guava must fail the check"); + } catch (AxisFault expected) { + assertTrue(expected.getMessage(), expected.getMessage().contains("guava")); + } + } + public void testConcurrentCallsSucceed() throws Exception { final int threadCount = 16; final CountDownLatch startGate = new CountDownLatch(1); diff --git a/src/site/markdown/release-notes/2.0.0.md b/src/site/markdown/release-notes/2.0.0.md index 206b3f61..7f102c2e 100644 --- a/src/site/markdown/release-notes/2.0.0.md +++ b/src/site/markdown/release-notes/2.0.0.md @@ -12,6 +12,16 @@ Axis2. - **Java**: OpenJDK 17 minimum; tested on OpenJDK 17, 21, and 25. - **Apache Axis2**: 2.0.1 (Jakarta-based). +## Installation Note: Guava + +OpenSAML and WSS4J require Google Guava at runtime. Axis2 2.0.2 no longer bundles +it, so the Rampart binary distribution now ships `guava`, `failureaccess` and +`jspecify` in its `lib/` directory, and `ant` copies them into Axis2 with the other +Rampart dependencies. Guava is pinned to the version Axis2 2.0.1 shipped, so +installing into 2.0.1 replaces that jar rather than adding a second copy. If you +assemble `WEB-INF/lib` by hand, include these jars: without them the rampart and +rahas modules now fail to initialise with an error naming the missing jars. + ## Current Dependency Versions This release uses the following updated dependency versions:
