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:20 UTC

[ws-wss4j] branch WSS-632 created (now 5a7db73)

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

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


      at 5a7db73  WSS-632 - Support EhCache 3+

This branch includes the following new commits:

     new 5a7db73  WSS-632 - Support EhCache 3+

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



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

Posted by co...@apache.org.
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>