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/16 07:10:59 UTC
[ws-wss4j] branch master updated: WSS-632 - Support EhCache 3+ (#10)
This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ws-wss4j.git
The following commit(s) were added to refs/heads/master by this push:
new 09ca920 WSS-632 - Support EhCache 3+ (#10)
09ca920 is described below
commit 09ca920f741d727ecbfcedadb1ea377989292711
Author: Colm O hEigeartaigh <co...@users.noreply.github.com>
AuthorDate: Thu Apr 16 08:10:53 2020 +0100
WSS-632 - Support EhCache 3+ (#10)
* WSS-632 - Support EhCache 3+
* Adding more expiration unit tests + fixing the caching logic
* Adding StAX OSGi import - thanks to Alexey Markevich for the suggestion.
* Using 3.8 namespace in the schema
---
parent/pom.xml | 4 +-
ws-security-common/pom.xml | 2 +-
.../apache/wss4j/common/cache/EHCacheExpiry.java | 69 ++++++++
.../wss4j/common/cache/EHCacheManagerHolder.java | 188 ---------------------
.../wss4j/common/cache/EHCacheReplayCache.java | 163 +++++++-----------
.../common/cache/EHCacheReplayCacheFactory.java | 4 +-
...heReplayCacheFactory.java => EHCacheValue.java} | 29 +++-
.../common/cache/MemoryReplayCacheFactory.java | 4 +-
.../wss4j/common/cache/ReplayCacheFactory.java | 5 +-
.../resources/messages/wss4j_errors.properties | 1 +
.../src/main/resources/wss4j-ehcache.xml | 32 ++--
.../wss4j/common/cache/EHCacheExpiryTest.java | 100 +++++++++++
.../common/cache/EHCacheManagerHolderTest.java | 83 ---------
.../apache/wss4j/common/cache/ReplayCacheTest.java | 78 ++++++++-
.../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 | 3 +-
18 files changed, 364 insertions(+), 430 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..721931c
--- /dev/null
+++ b/ws-security-common/src/main/java/org/apache/wss4j/common/cache/EHCacheExpiry.java
@@ -0,0 +1,69 @@
+/**
+ * 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.Instant;
+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 in seconds (60 minutes)
+ */
+ public static final long DEFAULT_TTL = 3600L;
+
+ /**
+ * The max time to live in seconds (12 hours)
+ */
+ public static final long MAX_TTL = DEFAULT_TTL * 12L;
+
+
+ @Override
+ public Duration getExpiryForCreation(String s, EHCacheValue ehCacheValue) {
+ Instant expiry = ehCacheValue.getExpiry();
+ Instant now = Instant.now();
+
+ if (expiry == null || expiry.isBefore(now) || expiry.isAfter(now.plusSeconds(MAX_TTL))) {
+ return Duration.of(DEFAULT_TTL, ChronoUnit.SECONDS);
+ }
+
+ return Duration.of(expiry.toEpochMilli() - now.toEpochMilli(), ChronoUnit.MILLIS);
+ }
+
+ @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..222f2a8 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,20 @@ 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;
- }
- }
-
- Element cacheElement = new Element(identifier, identifier, parsedTTL, parsedTTL);
- cacheElement.resetAccessStatistics();
- cache.put(cacheElement);
+ cache.put(identifier, new EHCacheValue(identifier, expiry));
}
/**
@@ -137,33 +115,20 @@ 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;
+ }
+
+ // Only exposed for testing
+ EHCacheValue get(String identifier) {
+ return cache.get(identifier);
}
@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 60%
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..65d460e 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
@@ -6,9 +6,9 @@
* 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
- *
+ * <p>
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ * <p>
* 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
@@ -19,16 +19,29 @@
package org.apache.wss4j.common.cache;
-import java.net.URL;
+import java.io.Serializable;
+import java.time.Instant;
/**
- * 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 Instant expiry;
+
+ public EHCacheValue(String identifier, Instant expiry) {
+ this.identifier = identifier;
+ this.expiry = expiry;
+ }
+
+ public String getIdentifier() {
+ return identifier;
}
+ public Instant 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..86fc27b 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-3.8.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/EHCacheExpiryTest.java b/ws-security-common/src/test/java/org/apache/wss4j/common/cache/EHCacheExpiryTest.java
new file mode 100644
index 0000000..fd3b3ca
--- /dev/null
+++ b/ws-security-common/src/test/java/org/apache/wss4j/common/cache/EHCacheExpiryTest.java
@@ -0,0 +1,100 @@
+/**
+ * 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.Instant;
+import java.time.temporal.ChronoUnit;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Some unit tests for the EHCacheExpiry implementation
+ */
+public class EHCacheExpiryTest {
+
+ @Test
+ public void testNoExpirySpecified() {
+ EHCacheExpiry cacheExpiry = new EHCacheExpiry();
+
+ Duration expiryForCreation =
+ cacheExpiry.getExpiryForCreation("xyz",
+ new EHCacheValue("xyz", null));
+ assertNotNull(expiryForCreation);
+
+ assertEquals(EHCacheExpiry.DEFAULT_TTL, expiryForCreation.getSeconds());
+ }
+
+ @Test
+ public void testExpirySpecified() {
+ EHCacheExpiry cacheExpiry = new EHCacheExpiry();
+
+ Duration expiryForCreation =
+ cacheExpiry.getExpiryForCreation("xyz",
+ new EHCacheValue("xyz", Instant.now().plusSeconds(30L)));
+ assertNotNull(expiryForCreation);
+
+ // Some loose boundary checking to allow for slow tests
+ assertTrue(expiryForCreation.getSeconds() <= 30L);
+ assertTrue(expiryForCreation.getSeconds() > 30L - 5L);
+ }
+
+ @Test
+ public void testExpirySpecified2() {
+ EHCacheExpiry cacheExpiry = new EHCacheExpiry();
+
+ Duration expiryForCreation =
+ cacheExpiry.getExpiryForCreation("xyz",
+ new EHCacheValue("xyz", Instant.now().plus(6L, ChronoUnit.HOURS)));
+ assertNotNull(expiryForCreation);
+
+ // Some loose boundary checking to allow for slow tests
+ assertTrue(expiryForCreation.getSeconds() <= 6 * 60 * 60L);
+ assertTrue(expiryForCreation.getSeconds() > 6 * 60 * 60L - 5L);
+ }
+
+ @Test
+ public void testNegativeExpirySpecified() {
+ EHCacheExpiry cacheExpiry = new EHCacheExpiry();
+
+ Duration expiryForCreation =
+ cacheExpiry.getExpiryForCreation("xyz",
+ new EHCacheValue("xyz", Instant.now().minusSeconds(30L)));
+ assertNotNull(expiryForCreation);
+
+ assertEquals(EHCacheExpiry.DEFAULT_TTL, expiryForCreation.getSeconds());
+ }
+
+ @Test
+ public void testHugeExpirySpecified() {
+ EHCacheExpiry cacheExpiry = new EHCacheExpiry();
+
+ Duration expiryForCreation =
+ cacheExpiry.getExpiryForCreation("xyz",
+ new EHCacheValue("xyz", Instant.now().plus(14, ChronoUnit.HOURS)));
+ assertNotNull(expiryForCreation);
+
+ assertEquals(EHCacheExpiry.DEFAULT_TTL, expiryForCreation.getSeconds());
+ }
+}
\ No newline at end of file
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..90778a7 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
@@ -22,11 +22,15 @@ package org.apache.wss4j.common.cache;
import java.io.IOException;
import java.net.URL;
import java.time.Instant;
+import java.time.temporal.ChronoUnit;
import java.util.UUID;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
@@ -44,7 +48,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 +56,78 @@ 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();
+ }
+
+ // No expiry specified so it falls back to the default
+ @Test
+ public void testEhCacheReplayCacheNoExpirySpecified() throws Exception {
+ ReplayCache replayCache = new EHCacheReplayCache("xyz", (URL)null);
+
+ String id = UUID.randomUUID().toString();
+ replayCache.add(id);
+ assertTrue(replayCache.contains(id));
+
+ EHCacheValue ehCacheValue = ((EHCacheReplayCache) replayCache).get(id);
+ assertNotNull(ehCacheValue);
+ assertNull(ehCacheValue.getExpiry());
+ assertEquals(id, ehCacheValue.getIdentifier());
+
+ replayCache.close();
+ }
+
+ // The negative expiry is rejected and it falls back to the default
+ @Test
+ public void testEhCacheReplayCacheNegativeExpiry() throws Exception {
+ ReplayCache replayCache = new EHCacheReplayCache("xyz", (URL)null);
+
+ String id = UUID.randomUUID().toString();
+ replayCache.add(id, Instant.now().minusSeconds(100L));
+ assertTrue(replayCache.contains(id));
+
+ EHCacheValue ehCacheValue = ((EHCacheReplayCache) replayCache).get(id);
+ assertNotNull(ehCacheValue);
+ assertNotNull(ehCacheValue.getExpiry());
+ assertEquals(id, ehCacheValue.getIdentifier());
+
+ replayCache.close();
+ }
+
+ // The huge expiry is rejected and it falls back to the default
+ @Test
+ public void testEhCacheReplayCacheHugeExpiry() throws Exception {
+ ReplayCache replayCache = new EHCacheReplayCache("xyz", (URL)null);
+
+ String id = UUID.randomUUID().toString();
+ replayCache.add(id, Instant.now().plus(14, ChronoUnit.HOURS));
+ assertTrue(replayCache.contains(id));
+
+ EHCacheValue ehCacheValue = ((EHCacheReplayCache) replayCache).get(id);
+ assertNotNull(ehCacheValue);
+ assertNotNull(ehCacheValue.getExpiry());
+ assertEquals(id, ehCacheValue.getIdentifier());
+
+ 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 de7ae2e..3e6459c 100644
--- a/ws-security-dom/pom.xml
+++ b/ws-security-dom/pom.xml
@@ -95,7 +95,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..c7ceccc 100644
--- a/ws-security-stax/pom.xml
+++ b/ws-security-stax/pom.xml
@@ -31,6 +31,7 @@
<properties>
<wss4j.module.name>org.apache.wss4j.stax</wss4j.module.name>
+ <wss4j.osgi.import>javax.xml.bind*;version=!</wss4j.osgi.import>
</properties>
<dependencies>
@@ -47,7 +48,7 @@
<scope>compile</scope>
</dependency>
<dependency>
- <groupId>net.sf.ehcache</groupId>
+ <groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<scope>runtime</scope>
</dependency>