You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by co...@apache.org on 2020/04/09 11:09:21 UTC

[ws-wss4j] 01/01: WSS-632 - Support EhCache 3+

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

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

commit 5a7db73d982005403917b1b54f815175b5654904
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Thu Apr 9 12:08:53 2020 +0100

    WSS-632 - Support EhCache 3+
---
 parent/pom.xml                                     |   4 +-
 ws-security-common/pom.xml                         |   2 +-
 .../apache/wss4j/common/cache/EHCacheExpiry.java   |  67 ++++++++
 .../wss4j/common/cache/EHCacheManagerHolder.java   | 188 ---------------------
 .../wss4j/common/cache/EHCacheReplayCache.java     | 160 +++++++-----------
 .../common/cache/EHCacheReplayCacheFactory.java    |   4 +-
 ...heReplayCacheFactory.java => EHCacheValue.java} |  24 ++-
 .../common/cache/MemoryReplayCacheFactory.java     |   4 +-
 .../wss4j/common/cache/ReplayCacheFactory.java     |   5 +-
 .../resources/messages/wss4j_errors.properties     |   1 +
 .../src/main/resources/wss4j-ehcache.xml           |  32 ++--
 .../common/cache/EHCacheManagerHolderTest.java     |  83 ---------
 .../apache/wss4j/common/cache/ReplayCacheTest.java |  23 ++-
 .../src/test/resources/test-ehcache.xml            |  16 --
 .../src/test/resources/test-ehcache2.xml           |  11 --
 ws-security-dom/pom.xml                            |   2 +-
 ws-security-stax/pom.xml                           |   2 +-
 17 files changed, 201 insertions(+), 427 deletions(-)

diff --git a/parent/pom.xml b/parent/pom.xml
index a663410..94ce362 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -35,7 +35,7 @@
         <bcprov.version>1.65</bcprov.version>
         <commons.compress.version>1.20</commons.compress.version>
         <cryptacular.version>1.2.4</cryptacular.version>
-        <ehcache.version>2.10.6</ehcache.version>
+        <ehcache.version>3.8.1</ehcache.version>
         <geronimo.javamail.version>1.8.4</geronimo.javamail.version>
         <hamcrest.version>2.2</hamcrest.version>
         <jasypt.version>1.9.3</jasypt.version>
@@ -126,7 +126,7 @@
                 <version>${xmlunit.version}</version>
             </dependency>
             <dependency>
-                <groupId>net.sf.ehcache</groupId>
+                <groupId>org.ehcache</groupId>
                 <artifactId>ehcache</artifactId>
                 <version>${ehcache.version}</version>
             </dependency>
diff --git a/ws-security-common/pom.xml b/ws-security-common/pom.xml
index 139b623..eea6674 100644
--- a/ws-security-common/pom.xml
+++ b/ws-security-common/pom.xml
@@ -196,7 +196,7 @@
             <scope>compile</scope>
         </dependency>
         <dependency>
-            <groupId>net.sf.ehcache</groupId>
+            <groupId>org.ehcache</groupId>
             <artifactId>ehcache</artifactId>
             <scope>compile</scope>
             <optional>true</optional>
diff --git a/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheExpiry.java b/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheExpiry.java
new file mode 100644
index 0000000..33e13dd
--- /dev/null
+++ b/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheExpiry.java
@@ -0,0 +1,67 @@
+/**
+ * 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.wss4j.common.cache;
+
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+import java.util.function.Supplier;
+
+import org.ehcache.expiry.ExpiryPolicy;
+
+/**
+ * A custom Expiry implementation for EhCache. It uses the supplied expiry which is part of the cache value.
+ * If it doesn't exist, it falls back to the default value (3600 seconds).
+ */
+public class EHCacheExpiry implements ExpiryPolicy<String, EHCacheValue> {
+
+    /**
+     * The default time to live (60 minutes)
+     */
+    public static final long DEFAULT_TTL = 3600L;
+
+    /**
+     * The max time to live (12 hours)
+     */
+    public static final long MAX_TTL = DEFAULT_TTL * 12L;
+
+
+    @Override
+    public Duration getExpiryForCreation(String s, EHCacheValue ehCacheValue) {
+        long parsedTTL = ehCacheValue.getExpiry();
+        if (parsedTTL <= 0 || parsedTTL > MAX_TTL) {
+            // Use default value
+            parsedTTL = DEFAULT_TTL;
+        }
+
+        return Duration.of(parsedTTL, ChronoUnit.SECONDS);
+    }
+
+    @Override
+    public Duration getExpiryForAccess(String s, Supplier<? extends EHCacheValue> supplier) {
+        return null;
+    }
+
+    @Override
+    public Duration getExpiryForUpdate(String s, Supplier<? extends EHCacheValue> supplier, EHCacheValue ehCacheValue) {
+        return null;
+    }
+
+
+}
diff --git a/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheManagerHolder.java b/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheManagerHolder.java
deleted file mode 100644
index cb9d8b4..0000000
--- a/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheManagerHolder.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/**
- * 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.wss4j.common.cache;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import net.sf.ehcache.CacheException;
-import net.sf.ehcache.CacheManager;
-import net.sf.ehcache.config.CacheConfiguration;
-import net.sf.ehcache.config.Configuration;
-import net.sf.ehcache.config.ConfigurationFactory;
-
-import org.apache.wss4j.common.util.Loader;
-
-/**
- * We need to reference count the EHCacheManager things
- */
-public final class EHCacheManagerHolder {
-    private static final org.slf4j.Logger LOG =
-        org.slf4j.LoggerFactory.getLogger(EHCacheManagerHolder.class);
-    private static final ConcurrentHashMap<String, AtomicInteger> COUNTS
-        = new ConcurrentHashMap<>(8, 0.75f, 2);
-
-    private static Method cacheManagerCreateMethodNoArg;
-    private static Method createMethodURLArg;
-    private static Method cacheManagerCreateMethodConfigurationArg;
-    static {
-        // these methods are either completely available or absent (valid assumption from ehcache 2.5.0 to 2.7.2 so far)
-        try {
-            // from 2.5.2
-            cacheManagerCreateMethodNoArg = CacheManager.class.getMethod("newInstance", (Class<?>[])null);
-            createMethodURLArg = CacheManager.class.getMethod("newInstance", URL.class);
-            cacheManagerCreateMethodConfigurationArg = CacheManager.class.getMethod("newInstance", Configuration.class);
-        } catch (NoSuchMethodException e) {
-            try {
-                // before 2.5.2
-                cacheManagerCreateMethodNoArg = CacheManager.class.getMethod("create", (Class<?>[])null);
-                createMethodURLArg = CacheManager.class.getMethod("create", URL.class);
-                cacheManagerCreateMethodConfigurationArg = CacheManager.class.getMethod("create", Configuration.class);
-            } catch (Throwable t) {
-                // ignore
-                LOG.warn(t.getMessage());
-            }
-        }
-    }
-
-    private EHCacheManagerHolder() {
-        //utility
-    }
-
-
-    public static CacheConfiguration getCacheConfiguration(String key,
-                                                           CacheManager cacheManager) {
-        CacheConfiguration cc = cacheManager.getConfiguration().getCacheConfigurations().get(key);
-        if (cc == null && key.contains("-")) {
-            cc = cacheManager.getConfiguration().getCacheConfigurations().get(
-                    key.substring(0, key.lastIndexOf('-')));
-        }
-        if (cc == null) {
-            cc = cacheManager.getConfiguration().getDefaultCacheConfiguration();
-        }
-        if (cc == null) {
-            cc = new CacheConfiguration();
-        } else {
-            cc = cc.clone();
-        }
-        cc.setName(key);
-        return cc;
-    }
-
-    public static synchronized CacheManager getCacheManager(String confName, URL configFileURL) {
-        CacheManager cacheManager = null;
-        if (configFileURL == null) {
-            //using the default
-            cacheManager = findDefaultCacheManager(confName);
-        }
-        if (cacheManager == null) {
-            if (configFileURL == null) {
-                cacheManager = createCacheManager();
-            } else {
-                cacheManager = findDefaultCacheManager(confName, configFileURL);
-            }
-        }
-        if (cacheManager != null && cacheManager.getName() != null) {
-            AtomicInteger a = COUNTS.get(cacheManager.getName());
-            if (a == null) {
-                COUNTS.putIfAbsent(cacheManager.getName(), new AtomicInteger());
-                a = COUNTS.get(cacheManager.getName());
-            }
-            a.incrementAndGet();
-            // if (a.incrementAndGet() == 1) {
-                //System.out.println("Create!! " + cacheManager.getName());
-            // }
-        } else {
-            LOG.warn("The CacheManager or CacheManager name was null");
-        }
-        return cacheManager;
-    }
-
-    private static CacheManager findDefaultCacheManager(String confName) {
-
-        String defaultConfigFile = "/wss4j-ehcache.xml";
-        URL configFileURL = null;
-        try {
-            configFileURL = Loader.getResource(defaultConfigFile);
-            if (configFileURL == null) {
-                configFileURL = new URL(defaultConfigFile);
-            }
-        } catch (IOException e) {
-            // Do nothing
-            LOG.debug(e.getMessage());
-        }
-        return findDefaultCacheManager(confName, configFileURL);
-    }
-
-    private static CacheManager findDefaultCacheManager(String confName, URL configFileURL) {
-        try {
-            Configuration conf = ConfigurationFactory.parseConfiguration(configFileURL);
-            conf.setName(confName);
-            if ("java.io.tmpdir".equals(conf.getDiskStoreConfiguration().getOriginalPath())) {
-                String path = conf.getDiskStoreConfiguration().getPath() + File.separator
-                    + confName;
-                conf.getDiskStoreConfiguration().setPath(path);
-            }
-            return createCacheManager(conf);
-        } catch (Throwable t) {
-            return null;
-        }
-    }
-
-
-    public static synchronized void releaseCacheManger(CacheManager cacheManager) {
-        AtomicInteger a = COUNTS.get(cacheManager.getName());
-        if (a == null) {
-            return;
-        }
-        if (a.decrementAndGet() == 0) {
-            //System.out.println("Shutdown!! " + cacheManager.getName());
-            cacheManager.shutdown();
-        }
-    }
-
-    static CacheManager createCacheManager() throws CacheException {
-        try {
-            return (CacheManager)cacheManagerCreateMethodNoArg.invoke(null, (Object[])null);
-        } catch (Exception e) {
-            throw new CacheException(e);
-        }
-    }
-
-    static CacheManager createCacheManager(URL url) throws CacheException {
-        try {
-            return (CacheManager)createMethodURLArg.invoke(null, new Object[]{url});
-        } catch (Exception e) {
-            throw new CacheException(e);
-        }
-    }
-
-    static CacheManager createCacheManager(Configuration conf) throws CacheException {
-        try {
-            return (CacheManager)cacheManagerCreateMethodConfigurationArg.invoke(null, new Object[]{conf});
-        } catch (Exception e) {
-            throw new CacheException(e);
-        }
-    }
-}
diff --git a/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheReplayCache.java b/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheReplayCache.java
index a17fc40..08aceaa 100644
--- a/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheReplayCache.java
+++ b/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheReplayCache.java
@@ -19,16 +19,20 @@
 
 package org.apache.wss4j.common.cache;
 
+import java.io.File;
+import java.io.IOException;
 import java.net.URL;
 import java.time.Instant;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.Random;
 
-import net.sf.ehcache.Cache;
-import net.sf.ehcache.CacheManager;
-import net.sf.ehcache.Ehcache;
-import net.sf.ehcache.Element;
-import net.sf.ehcache.Status;
-import net.sf.ehcache.config.CacheConfiguration;
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.util.Loader;
+import org.ehcache.Cache;
+import org.ehcache.CacheManager;
+import org.ehcache.Status;
+import org.ehcache.config.builders.CacheConfigurationBuilder;
+import org.ehcache.config.builders.CacheManagerBuilder;
+import org.ehcache.xml.XmlConfiguration;
 
 /**
  * An in-memory EHCache implementation of the ReplayCache interface. The default TTL is 60 minutes and the
@@ -36,64 +40,50 @@ import net.sf.ehcache.config.CacheConfiguration;
  */
 public class EHCacheReplayCache implements ReplayCache {
 
-    public static final long DEFAULT_TTL = 3600L;
-    public static final long MAX_TTL = DEFAULT_TTL * 12L;
-    protected Ehcache cache;
-    protected CacheManager cacheManager;
-    private long ttl = DEFAULT_TTL;
-
-    public EHCacheReplayCache(String key, URL configFileURL) {
-        this(key, EHCacheManagerHolder.getCacheManager("", configFileURL));
-    }
-
-    public EHCacheReplayCache(String key, CacheManager cacheManager) {
-        this.cacheManager = cacheManager;
-
-        CacheConfiguration cc = EHCacheManagerHolder.getCacheConfiguration(key, cacheManager);
-
-        Cache newCache = new RefCountCache(cc);
-        cache = cacheManager.addCacheIfAbsent(newCache);
-        synchronized (cache) {
-            if (cache.getStatus() != Status.STATUS_ALIVE) {
-                cache = cacheManager.addCacheIfAbsent(newCache);
-            }
-            if (cache instanceof RefCountCache) {
-                ((RefCountCache)cache).incrementAndGet();
-            }
+    private static final org.slf4j.Logger LOG =
+            org.slf4j.LoggerFactory.getLogger(EHCacheReplayCache.class);
+    private static final String CACHE_TEMPLATE_NAME = "wss4jCache";
+
+    private final Cache<String, EHCacheValue> cache;
+    private final CacheManager cacheManager;
+    private final String key;
+
+    public EHCacheReplayCache(String key, URL configFileURL) throws WSSecurityException {
+        this.key = key;
+        try {
+            XmlConfiguration xmlConfig = new XmlConfiguration(getConfigFileURL(configFileURL));
+            CacheConfigurationBuilder<String, EHCacheValue> configurationBuilder =
+                    xmlConfig.newCacheConfigurationBuilderFromTemplate(CACHE_TEMPLATE_NAME, String.class, EHCacheValue.class);
+            // Note, we don't require strong random values here
+            String diskKey = key + "-" + Math.abs(new Random().nextInt());
+            cacheManager = CacheManagerBuilder.newCacheManagerBuilder().withCache(key, configurationBuilder)
+                     .with(CacheManagerBuilder.persistence(new File(System.getProperty("java.io.tmpdir"), diskKey))).build();
+
+            cacheManager.init();
+            cache = cacheManager.getCache(key, String.class, EHCacheValue.class);
+        } catch (Exception ex) {
+            LOG.error("Error configuring EHCacheReplayCache", ex.getMessage());
+            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex, "replayCacheError");
         }
-
-        // Set the TimeToLive value from the CacheConfiguration
-        ttl = cc.getTimeToLiveSeconds();
     }
 
-    private static class RefCountCache extends Cache {
-        private AtomicInteger count = new AtomicInteger();
-        RefCountCache(CacheConfiguration cc) {
-            super(cc);
-        }
-        public int incrementAndGet() {
-            return count.incrementAndGet();
-        }
-        public int decrementAndGet() {
-            return count.decrementAndGet();
+    private URL getConfigFileURL(URL suppliedConfigFileURL) {
+        if (suppliedConfigFileURL == null) {
+            //using the default
+            String defaultConfigFile = "/wss4j-ehcache.xml";
+            URL configFileURL = null;
+            try {
+                configFileURL = Loader.getResource(defaultConfigFile);
+                if (configFileURL == null) {
+                    configFileURL = new URL(defaultConfigFile);
+                }
+                return configFileURL;
+            } catch (IOException e) {
+                // Do nothing
+                LOG.debug(e.getMessage());
+            }
         }
-    }
-
-
-    /**
-     * Set a new (default) TTL value in seconds
-     * @param newTtl a new (default) TTL value in seconds
-     */
-    public void setTTL(long newTtl) {
-        ttl = newTtl;
-    }
-
-    /**
-     * Get the (default) TTL value in seconds
-     * @return the (default) TTL value in seconds
-     */
-    public long getTTL() {
-        return ttl;
+        return suppliedConfigFileURL;
     }
 
     /**
@@ -101,32 +91,24 @@ public class EHCacheReplayCache implements ReplayCache {
      * @param identifier The identifier to be added
      */
     public void add(String identifier) {
-        add(identifier, Instant.now().plusSeconds(DEFAULT_TTL));
+        add(identifier, null);
     }
 
     /**
      * Add the given identifier to the cache to be cached for the given time
      * @param identifier The identifier to be added
-     * @param expiry A custom expiry time for the identifier
+     * @param expiry A custom expiry time for the identifier. Can be null in which case, the default expiry is used.
      */
     public void add(String identifier, Instant expiry) {
         if (identifier == null || "".equals(identifier)) {
             return;
         }
 
-        int parsedTTL = (int)(expiry.getEpochSecond() - Instant.now().getEpochSecond());
-        if (parsedTTL < 0 || parsedTTL > MAX_TTL) {
-            // Default to configured value
-            parsedTTL = (int)ttl;
-            if (ttl != parsedTTL) {
-                // Fall back to 60 minutes if the default TTL is set incorrectly
-                parsedTTL = 3600;
-            }
+        long ttl = 0;
+        if (expiry != null) {
+            ttl = expiry.getEpochSecond() - Instant.now().getEpochSecond();
         }
-
-        Element cacheElement = new Element(identifier, identifier, parsedTTL, parsedTTL);
-        cacheElement.resetAccessStatistics();
-        cache.put(cacheElement);
+        cache.put(identifier, new EHCacheValue(identifier, ttl));
     }
 
     /**
@@ -137,33 +119,15 @@ public class EHCacheReplayCache implements ReplayCache {
         if (cache == null) {
             return false;
         }
-        Element element = cache.get(identifier);
-        if (element != null) {
-            if (cache.isExpired(element)) {
-                cache.remove(identifier);
-                return false;
-            }
-            return true;
-        }
-        return false;
+        EHCacheValue element = cache.get(identifier);
+        return element != null;
     }
 
     @Override
     public synchronized void close() {
-        if (cacheManager != null) {
-            // this step is especially important for global shared cache manager
-            if (cache != null) {
-                synchronized (cache) {
-                    if (cache instanceof RefCountCache
-                        && ((RefCountCache)cache).decrementAndGet() == 0) {
-                        cacheManager.removeCache(cache.getName());
-                    }
-                }
-            }
-
-            EHCacheManagerHolder.releaseCacheManger(cacheManager);
-            cacheManager = null;
-            cache = null;
+        if (cacheManager.getStatus() == Status.AVAILABLE) {
+            cacheManager.removeCache(key);
+            cacheManager.close();
         }
     }
 
diff --git a/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheReplayCacheFactory.java b/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheReplayCacheFactory.java
index d9084ce..9ef0758 100644
--- a/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheReplayCacheFactory.java
+++ b/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheReplayCacheFactory.java
@@ -21,12 +21,14 @@ package org.apache.wss4j.common.cache;
 
 import java.net.URL;
 
+import org.apache.wss4j.common.ext.WSSecurityException;
+
 /**
  * A factory to return an EHCacheReplayCache instance.
  */
 public class EHCacheReplayCacheFactory extends ReplayCacheFactory {
 
-    public ReplayCache newReplayCache(String key, Object configuration) {
+    public ReplayCache newReplayCache(String key, Object configuration) throws WSSecurityException {
         URL configFileURL = getConfigFileURL(configuration);
         return new EHCacheReplayCache(key, configFileURL);
     }
diff --git a/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheReplayCacheFactory.java b/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheValue.java
similarity index 63%
copy from ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheReplayCacheFactory.java
copy to ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheValue.java
index d9084ce..352b71f 100644
--- a/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheReplayCacheFactory.java
+++ b/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheValue.java
@@ -19,16 +19,28 @@
 
 package org.apache.wss4j.common.cache;
 
-import java.net.URL;
+import java.io.Serializable;
 
 /**
- * A factory to return an EHCacheReplayCache instance.
+ * A cache value for EHCache. It contains the identifier to be cached as well as a custom expiry.
  */
-public class EHCacheReplayCacheFactory extends ReplayCacheFactory {
+public class EHCacheValue implements Serializable {
 
-    public ReplayCache newReplayCache(String key, Object configuration) {
-        URL configFileURL = getConfigFileURL(configuration);
-        return new EHCacheReplayCache(key, configFileURL);
+    private final String identifier;
+    private final long expiry;
+
+    public EHCacheValue(String identifier, long expiry) {
+        this.identifier = identifier;
+        this.expiry = expiry;
+    }
+
+    public String getIdentifier() {
+        return identifier;
     }
 
+    public long getExpiry() {
+        return expiry;
+    }
+
+
 }
diff --git a/ws-security-common/src/main/java/org/apache/wss4j/common/cache/MemoryReplayCacheFactory.java b/ws-security-common/src/main/java/org/apache/wss4j/common/cache/MemoryReplayCacheFactory.java
index 740504d..685eccd 100644
--- a/ws-security-common/src/main/java/org/apache/wss4j/common/cache/MemoryReplayCacheFactory.java
+++ b/ws-security-common/src/main/java/org/apache/wss4j/common/cache/MemoryReplayCacheFactory.java
@@ -20,12 +20,14 @@
 package org.apache.wss4j.common.cache;
 
 
+import org.apache.wss4j.common.ext.WSSecurityException;
+
 /**
  * A factory to return a MemoryReplayCache instance.
  */
 public class MemoryReplayCacheFactory extends ReplayCacheFactory {
 
-    public ReplayCache newReplayCache(String key, Object configuration) {
+    public ReplayCache newReplayCache(String key, Object configuration) throws WSSecurityException {
         return new MemoryReplayCache();
     }
 
diff --git a/ws-security-common/src/main/java/org/apache/wss4j/common/cache/ReplayCacheFactory.java b/ws-security-common/src/main/java/org/apache/wss4j/common/cache/ReplayCacheFactory.java
index 86831dc..213677a 100644
--- a/ws-security-common/src/main/java/org/apache/wss4j/common/cache/ReplayCacheFactory.java
+++ b/ws-security-common/src/main/java/org/apache/wss4j/common/cache/ReplayCacheFactory.java
@@ -22,6 +22,7 @@ package org.apache.wss4j.common.cache;
 import java.io.IOException;
 import java.net.URL;
 
+import org.apache.wss4j.common.ext.WSSecurityException;
 import org.apache.wss4j.common.util.Loader;
 
 /**
@@ -36,7 +37,7 @@ public abstract class ReplayCacheFactory {
 
     static {
         try {
-            Class<?> cacheManagerClass = Class.forName("net.sf.ehcache.CacheManager");
+            Class<?> cacheManagerClass = Class.forName("org.ehcache.CacheManager");
             if (cacheManagerClass != null) {
                 ehCacheInstalled = true;
             }
@@ -58,7 +59,7 @@ public abstract class ReplayCacheFactory {
         return new MemoryReplayCacheFactory();
     }
 
-    public abstract ReplayCache newReplayCache(String key, Object configuration);
+    public abstract ReplayCache newReplayCache(String key, Object configuration) throws WSSecurityException;
 
     protected URL getConfigFileURL(Object o) {
         if (o instanceof String) {
diff --git a/ws-security-common/src/main/resources/messages/wss4j_errors.properties b/ws-security-common/src/main/resources/messages/wss4j_errors.properties
index f51ef6f..8bd5ae0 100644
--- a/ws-security-common/src/main/resources/messages/wss4j_errors.properties
+++ b/ws-security-common/src/main/resources/messages/wss4j_errors.properties
@@ -78,6 +78,7 @@ noUserCertsFound = No certificates for user \"{0}\" were found for {1}
 noXMLSig = Cannot setup signature data structure
 parseError = Cannot parse/decode the certificate data
 proxyNotFound = Proxy file ({0}) not found.
+replayCacheError = Error configuring a ReplayCache instance
 resourceNotFound = Cannot load the resource \"{0}\"
 signatureCryptoFailure = SignatureCrypto instantiation failed
 signatureKeyStoreNotSet = Signature KeyStore is not set
diff --git a/ws-security-common/src/main/resources/wss4j-ehcache.xml b/ws-security-common/src/main/resources/wss4j-ehcache.xml
index 7afcc15..03f6d22 100644
--- a/ws-security-common/src/main/resources/wss4j-ehcache.xml
+++ b/ws-security-common/src/main/resources/wss4j-ehcache.xml
@@ -1,17 +1,19 @@
-<ehcache xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false" monitoring="autodetect" dynamicConfig="true" name="wss4jCache">
+<config
+    xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
+    xmlns='http://www.ehcache.org/v3'
+    xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">
 
-    <diskStore path="java.io.tmpdir"/>
+    <cache-template name="wss4jCache">
+        <key-type>java.lang.String</key-type>
+        <value-type>org.apache.wss4j.common.cache.EHCacheValue</value-type>
+        <expiry>
+            <class>org.apache.wss4j.common.cache.EHCacheExpiry</class>
+        </expiry>
+        <resources>
+            <heap unit="entries">5000</heap>
+            <disk unit="MB" persistent="false">10</disk>
+        </resources>
 
-    <defaultCache
-            maxEntriesLocalHeap="5000"
-            eternal="false"
-            timeToIdleSeconds="3600"
-            timeToLiveSeconds="3600"
-            overflowToDisk="true"
-            maxElementsOnDisk="10000000"
-            diskPersistent="false"
-            diskExpiryThreadIntervalSeconds="120"
-            memoryStoreEvictionPolicy="LRU"
-            />
-            
-</ehcache>
+    </cache-template>
+
+</config>
diff --git a/ws-security-common/src/test/java/org/apache/wss4j/common/cache/EHCacheManagerHolderTest.java b/ws-security-common/src/test/java/org/apache/wss4j/common/cache/EHCacheManagerHolderTest.java
deleted file mode 100644
index afaee27..0000000
--- a/ws-security-common/src/test/java/org/apache/wss4j/common/cache/EHCacheManagerHolderTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * 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.wss4j.common.cache;
-
-import net.sf.ehcache.CacheManager;
-import net.sf.ehcache.Status;
-import net.sf.ehcache.config.CacheConfiguration;
-import net.sf.ehcache.config.Configuration;
-import net.sf.ehcache.config.ConfigurationFactory;
-
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-/**
- *
- */
-public class EHCacheManagerHolderTest {
-
-    @Test
-    public void testCreateCacheManager() {
-        Configuration conf =
-            ConfigurationFactory.parseConfiguration(EHCacheManagerHolder.class.getResource("/test-ehcache.xml"));
-
-        assertNotNull(conf);
-        conf.setName("testCache");
-
-        CacheManager manager1 = EHCacheManagerHolder.createCacheManager(conf);
-        assertNotNull(manager1);
-        CacheManager manager2 = EHCacheManagerHolder.createCacheManager();
-        assertNotNull(manager2);
-
-        manager1.shutdown();
-        assertEquals(Status.STATUS_SHUTDOWN, manager1.getStatus());
-
-        assertEquals(Status.STATUS_ALIVE, manager2.getStatus());
-
-        manager2.shutdown();
-        assertEquals(Status.STATUS_SHUTDOWN, manager2.getStatus());
-
-    }
-
-    @Test
-    public void testCacheNames() {
-        CacheManager cacheManager =
-            EHCacheManagerHolder.getCacheManager("testCache2",
-                                                 EHCacheManagerHolder.class.getResource("/test-ehcache2.xml"));
-
-        String key = "org.apache.wss4j.TokenStore";
-        CacheConfiguration cacheConfig =
-            EHCacheManagerHolder.getCacheConfiguration(key, cacheManager);
-        assertEquals(3600, cacheConfig.getTimeToIdleSeconds());
-
-        key = "org.apache.wss4j.TokenStore-{http://ws.apache.org}wss4j";
-        CacheConfiguration cacheConfig2 =
-            EHCacheManagerHolder.getCacheConfiguration(key, cacheManager);
-        assertEquals(360000, cacheConfig2.getTimeToIdleSeconds());
-
-        key = "org.apache.wss4j.TokenStore-{http://ws.apache.org}wss4junknown";
-        CacheConfiguration cacheConfig3 =
-            EHCacheManagerHolder.getCacheConfiguration(key, cacheManager);
-        assertEquals(3600, cacheConfig3.getTimeToIdleSeconds());
-
-    }
-}
\ No newline at end of file
diff --git a/ws-security-common/src/test/java/org/apache/wss4j/common/cache/ReplayCacheTest.java b/ws-security-common/src/test/java/org/apache/wss4j/common/cache/ReplayCacheTest.java
index 73abcea..fb7347f 100644
--- a/ws-security-common/src/test/java/org/apache/wss4j/common/cache/ReplayCacheTest.java
+++ b/ws-security-common/src/test/java/org/apache/wss4j/common/cache/ReplayCacheTest.java
@@ -44,7 +44,7 @@ public class ReplayCacheTest {
     }
 
     @Test
-    public void testEhCacheReplayCache() throws InterruptedException, IOException {
+    public void testEhCacheReplayCache() throws Exception {
         ReplayCache replayCache = new EHCacheReplayCache("xyz", (URL)null);
 
         testReplayCacheInstance(replayCache);
@@ -52,6 +52,27 @@ public class ReplayCacheTest {
         replayCache.close();
     }
 
+    @Test
+    public void testEhCacheDifferentCaches() throws Exception {
+        ReplayCache replayCache = new EHCacheReplayCache("abc", (URL)null);
+        ReplayCache replayCache2 = new EHCacheReplayCache("cba", (URL)null);
+
+        String id = UUID.randomUUID().toString();
+        replayCache.add(id);
+        assertTrue(replayCache.contains(id));
+        assertFalse(replayCache2.contains(id));
+
+        replayCache.close();
+        replayCache2.close();
+    }
+
+    @Test
+    public void testEhCacheCloseCacheTwice() throws Exception {
+        ReplayCache replayCache = new EHCacheReplayCache("abc", (URL) null);
+        replayCache.close();
+        replayCache.close();
+    }
+
     private void testReplayCacheInstance(ReplayCache replayCache) throws InterruptedException, IOException {
 
         // Test default TTL caches OK
diff --git a/ws-security-common/src/test/resources/test-ehcache.xml b/ws-security-common/src/test/resources/test-ehcache.xml
deleted file mode 100644
index eaef32e..0000000
--- a/ws-security-common/src/test/resources/test-ehcache.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<ehcache xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false" monitoring="autodetect" dynamicConfig="true">
-
-    <diskStore path="java.io.tmpdir"/>
-
-    <defaultCache
-            maxEntriesLocalHeap="5000"
-            eternal="false"
-            timeToIdleSeconds="3600"
-            timeToLiveSeconds="3600"
-            overflowToDisk="true"
-            maxElementsOnDisk="10000000"
-            diskPersistent="false"
-            diskExpiryThreadIntervalSeconds="120"
-            memoryStoreEvictionPolicy="LRU"
-            />
-</ehcache>
diff --git a/ws-security-common/src/test/resources/test-ehcache2.xml b/ws-security-common/src/test/resources/test-ehcache2.xml
deleted file mode 100644
index cb0ee07..0000000
--- a/ws-security-common/src/test/resources/test-ehcache2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<ehcache xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false" monitoring="autodetect" dynamicConfig="true">
-
-    <diskStore path="java.io.tmpdir"/>
-
-    <cache name="org.apache.wss4j.TokenStore" overflowToDisk="false" maxEntriesLocalHeap="10000" 
-           timeToIdleSeconds="3600" timeToLiveSeconds="3600"/>
-           
-    <cache name="org.apache.wss4j.TokenStore-{http://ws.apache.org}wss4j" overflowToDisk="false" maxEntriesLocalHeap="10000" 
-           timeToIdleSeconds="360000" timeToLiveSeconds="3600"/>
-           
-</ehcache>
diff --git a/ws-security-dom/pom.xml b/ws-security-dom/pom.xml
index a88628c..88027a5 100644
--- a/ws-security-dom/pom.xml
+++ b/ws-security-dom/pom.xml
@@ -90,7 +90,7 @@
             <scope>compile</scope>
         </dependency>
         <dependency>
-            <groupId>net.sf.ehcache</groupId>
+            <groupId>org.ehcache</groupId>
             <artifactId>ehcache</artifactId>
             <scope>runtime</scope>
         </dependency>
diff --git a/ws-security-stax/pom.xml b/ws-security-stax/pom.xml
index e01748f..2a0508a 100644
--- a/ws-security-stax/pom.xml
+++ b/ws-security-stax/pom.xml
@@ -47,7 +47,7 @@
             <scope>compile</scope>
         </dependency>
         <dependency>
-            <groupId>net.sf.ehcache</groupId>
+            <groupId>org.ehcache</groupId>
             <artifactId>ehcache</artifactId>
             <scope>runtime</scope>
         </dependency>