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

coheigea pushed a commit to branch coheigea/WSS-660
in repository https://gitbox.apache.org/repos/asf/ws-wss4j.git

commit dc2b070ce91525bf801c608efb2f0af9192d4943
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Tue Nov 3 06:42:24 2026 +0000

    WSS-660 - Only remove security providers on cleanUp that WSS4J registered
---
 .../wss4j/common/crypto/WSProviderConfig.java      | 68 +++++++++++++++-------
 .../org/apache/wss4j/dom/engine/WSSConfig.java     | 52 +++++++++++------
 .../wss4j/dom/components/crypto/WSSConfigTest.java | 38 +++++++++++-
 3 files changed, 119 insertions(+), 39 deletions(-)

diff --git 
a/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/WSProviderConfig.java
 
b/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/WSProviderConfig.java
index acdae3796..20067bd20 100644
--- 
a/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/WSProviderConfig.java
+++ 
b/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/WSProviderConfig.java
@@ -25,6 +25,8 @@ import java.security.PrivilegedAction;
 import java.security.PrivilegedExceptionAction;
 import java.security.Provider;
 import java.security.Security;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.wss4j.common.util.FIPSUtils;
 import org.apache.wss4j.common.util.Loader;
@@ -56,9 +58,12 @@ public final class WSProviderConfig {
      */
     private static boolean staticallyInitialized;
 
-    private static boolean santuarioProviderAdded;
-    private static boolean bcProviderAdded;
-    private static boolean tlProviderAdded;
+    /**
+     * The provider instances registered by this class, keyed by name. On 
cleanUp only these
+     * instances are removed, so that a provider of the same name registered 
by another copy
+     * of WSS4J (e.g. in another web application) is left alone.
+     */
+    private static final Map<String, Provider> ADDED_PROVIDERS = new 
HashMap<>();
 
     private WSProviderConfig() {
         // complete
@@ -75,10 +80,6 @@ public final class WSProviderConfig {
                         return true;
                     }
                 });
-
-                santuarioProviderAdded = true;
-                bcProviderAdded = false;
-                tlProviderAdded = false;
             }
             if (FIPSUtils.isFIPSEnabled()) {
                 //So far the in-JDK security provider in FIPS mode
@@ -99,7 +100,6 @@ public final class WSProviderConfig {
         if (!staticallyInitialized) {
             initializeResourceBundles();
             setXmlSecIgnoreLineBreak();
-            santuarioProviderAdded = addXMLDSigRIInternalProv;
             if (addXMLDSigRIInternalProv) {
                 AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                     public Boolean run() {
@@ -109,11 +109,12 @@ public final class WSProviderConfig {
                 });
             }
 
-            bcProviderAdded = addBCProv;
             if (addBCProv) {
                 AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                     public Boolean run() {
+                        Provider existing = Security.getProvider("BC");
                         addJceProvider("BC", 
"org.bouncycastle.jce.provider.BouncyCastleProvider");
+                        recordAddedProvider("BC", existing);
                         return true;
                     }
                 });
@@ -133,11 +134,12 @@ public final class WSProviderConfig {
                 
             }
 
-            tlProviderAdded = addTLProv;
             if (addTLProv) {
                 AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                     public Boolean run() {
+                        Provider existing = Security.getProvider("TLSP");
                         ThreadLocalSecurityProvider.install();
+                        recordAddedProvider("TLSP", existing);
                         return true;
                     }
                 });
@@ -148,18 +150,10 @@ public final class WSProviderConfig {
 
     public static synchronized void cleanUp() {
         if (staticallyInitialized) {
-            if (santuarioProviderAdded) {
-                Security.removeProvider("ApacheXMLDSig");
-                santuarioProviderAdded = false;
-            }
-            if (bcProviderAdded) {
-                Security.removeProvider("BC");
-                bcProviderAdded = false;
-            }
-            if (tlProviderAdded) {
-                Security.removeProvider("TLSP");
-                tlProviderAdded = false;
+            for (Map.Entry<String, Provider> entry : 
ADDED_PROVIDERS.entrySet()) {
+                removeJceProvider(entry.getKey(), entry.getValue());
             }
+            ADDED_PROVIDERS.clear();
 
             staticallyInitialized = false;
         }
@@ -212,8 +206,40 @@ public final class WSProviderConfig {
     }
 
     private static void addXMLDSigRIInternal() {
+        Provider existing = Security.getProvider("ApacheXMLDSig");
         Security.removeProvider("ApacheXMLDSig");
         addJceProvider("ApacheXMLDSig", SantuarioUtil.getSantuarioProvider());
+        recordAddedProvider("ApacheXMLDSig", existing);
+    }
+
+    private static void recordAddedProvider(String name, Provider previous) {
+        Provider current = Security.getProvider(name);
+        if (current != null && current != previous) {
+            ADDED_PROVIDERS.put(name, current);
+        }
+    }
+
+    /**
+     * Remove the JCE security provider registered under the given name, but 
only if it is the
+     * given provider instance. A provider of the same name registered by 
someone else, e.g. by
+     * a copy of WSS4J loaded by another web application's class loader, is 
left in place.
+     *
+     * @param name
+     *            The name of the provider
+     * @param provider
+     *            The provider instance that was registered by the caller
+     * @return true if the provider was removed
+     */
+    public static boolean removeJceProvider(String name, Provider provider) {
+        Provider current = Security.getProvider(name);
+        if (current != null && current == provider) {
+            Security.removeProvider(name);
+            return true;
+        }
+        if (current != null) {
+            LOG.debug("Not removing provider {} as it was not registered by 
this instance of WSS4J", name);
+        }
+        return false;
     }
 
     private static void initializeResourceBundles() {
diff --git 
a/ws-security-dom/src/main/java/org/apache/wss4j/dom/engine/WSSConfig.java 
b/ws-security-dom/src/main/java/org/apache/wss4j/dom/engine/WSSConfig.java
index 733c99eff..c13201bad 100644
--- a/ws-security-dom/src/main/java/org/apache/wss4j/dom/engine/WSSConfig.java
+++ b/ws-security-dom/src/main/java/org/apache/wss4j/dom/engine/WSSConfig.java
@@ -21,6 +21,7 @@ package org.apache.wss4j.dom.engine;
 
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.security.Provider;
 import java.security.Security;
 import java.util.HashMap;
 import java.util.Map;
@@ -253,6 +254,13 @@ public final class WSSConfig {
      */
     private static boolean staticallyInitialized = false;
 
+    /**
+     * The provider instances registered by this class, keyed by name. On 
cleanUp only these
+     * instances are removed, so that a provider of the same name registered 
by another copy
+     * of WSS4J (e.g. in another web application) is left alone.
+     */
+    private static final Map<String, Provider> ADDED_PROVIDERS = new 
HashMap<>();
+
     /**
      * This allows the user to specify a different time than that of the 
current System time.
      */
@@ -318,24 +326,18 @@ public final class WSSConfig {
             if (addJceProviders) {
                 AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                     public Boolean run() {
-                        Security.removeProvider("STRTransform");
-                        WSProviderConfig.appendJceProvider(
+                        replaceJceProvider(
                             "STRTransform",
                             new 
org.apache.wss4j.dom.transform.STRTransformProvider()
                         );
-
-                        
Security.removeProvider("AttachmentContentSignatureTransform");
-                        WSProviderConfig.appendJceProvider(
-                                "AttachmentContentSignatureTransform",
-                                new 
AttachmentContentSignatureTransformProvider()
+                        replaceJceProvider(
+                            "AttachmentContentSignatureTransform",
+                            new AttachmentContentSignatureTransformProvider()
                         );
-
-                        
Security.removeProvider("AttachmentCompleteSignatureTransform");
-                        WSProviderConfig.appendJceProvider(
-                                "AttachmentCompleteSignatureTransform",
-                                new 
AttachmentCompleteSignatureTransformProvider()
+                        replaceJceProvider(
+                            "AttachmentCompleteSignatureTransform",
+                            new AttachmentCompleteSignatureTransformProvider()
                         );
-
                         return true;
                     }
                 });
@@ -347,17 +349,33 @@ public final class WSSConfig {
 
     public static synchronized void cleanUp() {
         if (staticallyInitialized) {
-            if (addJceProviders) {
-                Security.removeProvider("STRTransform");
-                Security.removeProvider("AttachmentContentSignatureTransform");
-                
Security.removeProvider("AttachmentCompleteSignatureTransform");
+            for (Map.Entry<String, Provider> entry : 
ADDED_PROVIDERS.entrySet()) {
+                WSProviderConfig.removeJceProvider(entry.getKey(), 
entry.getValue());
             }
+            ADDED_PROVIDERS.clear();
             WSProviderConfig.cleanUp();
 
             staticallyInitialized = false;
         }
     }
 
+    private static void replaceJceProvider(String name, Provider provider) {
+        Provider existing = Security.getProvider(name);
+        if (existing != null
+            && existing.getClass().getClassLoader() != 
provider.getClass().getClassLoader()) {
+            LOG.warn("The security provider {} has already been registered by 
a different class loader "
+                + "and will be replaced. If WSS4J is deployed in more than one 
web application in the same "
+                + "JVM, the other application may fail to use it. Consider 
deploying WSS4J in a class loader "
+                + "shared by all applications, e.g. the container's lib 
directory.", name);
+        }
+        Security.removeProvider(name);
+        WSProviderConfig.appendJceProvider(name, provider);
+        Provider current = Security.getProvider(name);
+        if (current != null && current != existing) {
+            ADDED_PROVIDERS.put(name, current);
+        }
+    }
+
     /**
      * @return a new WSSConfig instance configured with the default values
      */
diff --git 
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/components/crypto/WSSConfigTest.java
 
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/components/crypto/WSSConfigTest.java
index d46c5f739..fb897a831 100644
--- 
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/components/crypto/WSSConfigTest.java
+++ 
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/components/crypto/WSSConfigTest.java
@@ -19,14 +19,18 @@
 
 package org.apache.wss4j.dom.components.crypto;
 
+import java.security.Provider;
 import java.security.Security;
 
+import org.apache.wss4j.common.crypto.SantuarioUtil;
 import org.apache.wss4j.common.crypto.WSProviderConfig;
 import org.apache.wss4j.dom.engine.WSSConfig;
+import 
org.apache.wss4j.dom.transform.AttachmentContentSignatureTransformProvider;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
 
 /**
  * Test loading and removing security providers via WSSConfig
@@ -78,4 +82,36 @@ public class WSSConfigTest {
 
     }
 
-}
\ No newline at end of file
+    /**
+     * WSS-660: cleanUp must not remove providers that were registered by 
someone else, e.g.
+     * by a copy of WSS4J deployed in another web application, after we 
registered ours.
+     */
+    @Test
+    public void testCleanUpLeavesForeignProviders() {
+        WSSConfig.cleanUp();
+        WSSConfig.init();
+
+        // Simulate another copy of WSS4J replacing the providers
+        Provider otherTransformProvider = new 
AttachmentContentSignatureTransformProvider();
+        Security.removeProvider("AttachmentContentSignatureTransform");
+        Security.addProvider(otherTransformProvider);
+
+        Provider otherSantuarioProvider = SantuarioUtil.getSantuarioProvider();
+        Security.removeProvider("ApacheXMLDSig");
+        Security.addProvider(otherSantuarioProvider);
+
+        try {
+            WSSConfig.cleanUp();
+
+            assertSame(otherTransformProvider, 
Security.getProvider("AttachmentContentSignatureTransform"));
+            assertSame(otherSantuarioProvider, 
Security.getProvider("ApacheXMLDSig"));
+            // The providers that were still ours are removed
+            assertNull(Security.getProvider("STRTransform"));
+            
assertNull(Security.getProvider("AttachmentCompleteSignatureTransform"));
+        } finally {
+            Security.removeProvider("AttachmentContentSignatureTransform");
+            Security.removeProvider("ApacheXMLDSig");
+        }
+    }
+
+}

Reply via email to