This is an automated email from the ASF dual-hosted git repository.
reta pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/main by this push:
new a9053c2603 CXF-8765: Option to remove Ehcache (#2196)
a9053c2603 is described below
commit a9053c26036aac80630b030c413900da7df716b1
Author: Andriy Redko <[email protected]>
AuthorDate: Sun Jan 19 10:15:18 2025 -0500
CXF-8765: Option to remove Ehcache (#2196)
---
rt/rs/security/sso/saml/pom.xml | 7 +
.../saml/sso/jcache/JCacheTokenReplayCache.java | 162 ++++++++++++++++++
.../sso/state/jcache/JCacheSPStateManager.java | 165 +++++++++++++++++++
.../saml/src/main/resources/cxf-samlp-ehcache.xml | 18 ++
.../saml/src/main/resources/cxf-samlp-jcache.xml | 74 +++++++++
.../rs/security/saml/sso/SPStateManagerTest.java | 3 +-
.../rs/security/saml/sso/TokenReplayCacheTest.java | 43 +++--
rt/ws/security/pom.xml | 7 +
.../cache/jcache/CXFJCacheReplayCache.java | 50 ++++++
.../security/cache/jcache/JCacheReplayCache.java | 141 ++++++++++++++++
.../ws/security/tokenstore/TokenStoreFactory.java | 29 +---
.../tokenstore/jcache/JCacheTokenStore.java | 131 +++++++++++++++
.../tokenstore/jcache/JCacheTokenStoreFactory.java | 51 ++++++
.../apache/cxf/ws/security/utils/JCacheUtils.java | 73 +++++++++
.../apache/cxf/ws/security/wss4j/WSS4JUtils.java | 5 +
rt/ws/security/src/main/resources/cxf-ehcache.xml | 18 ++
rt/ws/security/src/main/resources/cxf-jcache.xml | 50 ++++++
.../cxf/ws/security/tokenstore/TokenStoreTest.java | 21 ++-
.../cxf/sts/cache/jcache/JCacheIdentityCache.java | 182 +++++++++++++++++++++
.../sts-core/src/main/resources/sts-ehcache.xml | 18 ++
.../sts/sts-core/src/main/resources/sts-jcache.xml | 40 +++++
.../sts/cache/jcache/JCacheIdentityCacheTest.java | 37 +++++
.../xkms/cache/jcache/JCacheXKMSClientCache.java | 124 ++++++++++++++
.../apache/cxf/xkms/cache/XKMSClientCacheTest.java | 20 ++-
.../systest/jaxrs/BookCxfContinuationStore.java | 2 +-
.../apache/cxf/systest/ws/cache/CachingTest.java | 36 ++--
26 files changed, 1451 insertions(+), 56 deletions(-)
diff --git a/rt/rs/security/sso/saml/pom.xml b/rt/rs/security/sso/saml/pom.xml
index 6a82eac384..8c70da2877 100644
--- a/rt/rs/security/sso/saml/pom.xml
+++ b/rt/rs/security/sso/saml/pom.xml
@@ -71,5 +71,12 @@
<classifier>jakarta</classifier>
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>org.ehcache.modules</groupId>
+ <artifactId>ehcache-107</artifactId>
+ <version>${cxf.ehcache3.version}</version>
+ <scope>provided</scope>
+ <optional>true</optional>
+ </dependency>
</dependencies>
</project>
diff --git
a/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/jcache/JCacheTokenReplayCache.java
b/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/jcache/JCacheTokenReplayCache.java
new file mode 100644
index 0000000000..e944c36227
--- /dev/null
+++
b/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/jcache/JCacheTokenReplayCache.java
@@ -0,0 +1,162 @@
+/**
+ * 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.cxf.rs.security.saml.sso.jcache;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.time.Instant;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.spi.CachingProvider;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
+import org.apache.cxf.rs.security.saml.sso.TokenReplayCache;
+import org.apache.wss4j.common.cache.EHCacheReplayCache;
+import org.apache.wss4j.common.cache.EHCacheValue;
+import org.apache.wss4j.common.util.Loader;
+
+/**
+ * An in-memory JCache based implementation of the TokenReplayCache interface.
+ * The default TTL is 60 minutes and the max TTL is 12 hours.
+ */
+
+public class JCacheTokenReplayCache implements TokenReplayCache<String> {
+
+ public static final String CACHE_KEY = "cxf.samlp.replay.cache";
+
+ private static final org.slf4j.Logger LOG =
+ org.slf4j.LoggerFactory.getLogger(EHCacheReplayCache.class);
+ private static final String DEFAULT_CONFIG_URL = "/cxf-samlp-jcache.xml";
+
+ private final Cache<String, EHCacheValue> cache;
+ private final CacheManager cacheManager;
+
+ public JCacheTokenReplayCache() throws URISyntaxException {
+ this(DEFAULT_CONFIG_URL, null);
+ }
+
+ public JCacheTokenReplayCache(Bus bus) throws URISyntaxException {
+ this(DEFAULT_CONFIG_URL, bus);
+ }
+
+ public JCacheTokenReplayCache(String configFile) throws URISyntaxException
{
+ this(configFile, null);
+ }
+
+ public JCacheTokenReplayCache(String configFile, Bus bus) throws
URISyntaxException {
+ if (bus == null) {
+ bus = BusFactory.getThreadDefaultBus(true);
+ }
+ URL configFileURL = null;
+ try {
+ configFileURL =
+ ResourceUtils.getClasspathResourceURL(configFile,
JCacheTokenReplayCache.class, bus);
+ } catch (Exception ex) {
+ // ignore
+ }
+
+ final CachingProvider cachingProvider = Caching.getCachingProvider();
+
+ cacheManager = cachingProvider.getCacheManager(
+ getConfigFileURL(configFileURL).toURI(),
+ getClass().getClassLoader());
+
+ cache = getOrCreate(cacheManager, CACHE_KEY, String.class,
EHCacheValue.class);
+ }
+
+ private static <K, V> Cache<K, V> getOrCreate(CacheManager cacheManager,
String name,
+ Class<K> kclass, Class<V> vclass) {
+
+ final Cache<K, V> cache = cacheManager.getCache(name, kclass, vclass);
+ if (cache != null) {
+ return cache;
+ }
+
+ final MutableConfiguration<K, V> cacheConfiguration = new
MutableConfiguration<>();
+ cacheConfiguration.setTypes(kclass, vclass);
+
+ return cacheManager.createCache(name, cacheConfiguration);
+ }
+
+ private URL getConfigFileURL(URL suppliedConfigFileURL) {
+ if (suppliedConfigFileURL == null) {
+ //using the default
+ try {
+ URL configFileURL = Loader.getResource(DEFAULT_CONFIG_URL);
+ if (configFileURL == null) {
+ configFileURL = new URL(DEFAULT_CONFIG_URL);
+ }
+ return configFileURL;
+ } catch (IOException e) {
+ // Do nothing
+ LOG.debug(e.getMessage());
+ }
+ }
+ return suppliedConfigFileURL;
+ }
+
+ /**
+ * Add the given identifier to the cache. It will be cached for a default
amount of time.
+ * @param identifier The identifier to be added
+ */
+ public void putId(String identifier) {
+ putId(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. Can be null in
which case, the default expiry is used.
+ */
+ public void putId(String identifier, Instant expiry) {
+ if (identifier == null || "".equals(identifier)) {
+ return;
+ }
+
+ cache.put(identifier, new EHCacheValue(identifier, expiry));
+ }
+
+ /**
+ * Return true if the given identifier is contained in the cache
+ * @param identifier The identifier to check
+ */
+ public boolean contains(String identifier) {
+ if (cache == null) {
+ return false;
+ }
+ EHCacheValue element = cache.get(identifier);
+ return element != null;
+ }
+
+ public synchronized void close() {
+ if (!cacheManager.isClosed()) {
+ cacheManager.destroyCache(CACHE_KEY);
+ cacheManager.close();
+ }
+ }
+
+
+}
diff --git
a/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/state/jcache/JCacheSPStateManager.java
b/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/state/jcache/JCacheSPStateManager.java
new file mode 100644
index 0000000000..4932a5d0dd
--- /dev/null
+++
b/rt/rs/security/sso/saml/src/main/java/org/apache/cxf/rs/security/saml/sso/state/jcache/JCacheSPStateManager.java
@@ -0,0 +1,165 @@
+/**
+ * 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.cxf.rs.security.saml.sso.state.jcache;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.configuration.MutableConfiguration;
+import javax.cache.spi.CachingProvider;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
+import org.apache.cxf.rs.security.saml.sso.state.RequestState;
+import org.apache.cxf.rs.security.saml.sso.state.ResponseState;
+import org.apache.cxf.rs.security.saml.sso.state.SPStateManager;
+import org.apache.wss4j.common.util.Loader;
+
+/**
+ * An in-memory JCache based implementation of the SPStateManager interface.
+ * The default TTL is 5 minutes.
+ */
+public class JCacheSPStateManager implements SPStateManager {
+
+ public static final String REQUEST_CACHE_KEY =
"cxf.samlp.request.state.cache";
+ public static final String RESPONSE_CACHE_KEY =
"cxf.samlp.response.state.cache";
+ private static final String DEFAULT_CONFIG_URL = "/cxf-samlp-jcache.xml";
+ private static final org.slf4j.Logger LOG =
+ org.slf4j.LoggerFactory.getLogger(JCacheSPStateManager.class);
+
+ private final Cache<String, RequestState> requestCache;
+ private final Cache<String, ResponseState> responseCache;
+ private final CacheManager cacheManager;
+
+ public JCacheSPStateManager() throws URISyntaxException {
+ this(DEFAULT_CONFIG_URL, null);
+ }
+
+ public JCacheSPStateManager(Bus bus) throws URISyntaxException {
+ this(DEFAULT_CONFIG_URL, bus);
+ }
+
+ public JCacheSPStateManager(String configFileURL) throws
URISyntaxException {
+ this(configFileURL, null);
+ }
+
+ public JCacheSPStateManager(String configFile, Bus bus) throws
URISyntaxException {
+ if (bus == null) {
+ bus = BusFactory.getThreadDefaultBus(true);
+ }
+
+ URL configFileURL = null;
+ try {
+ configFileURL =
+ ResourceUtils.getClasspathResourceURL(configFile,
JCacheSPStateManager.class, bus);
+ } catch (Exception ex) {
+ // ignore
+ }
+
+ final CachingProvider cachingProvider = Caching.getCachingProvider();
+
+ cacheManager = cachingProvider.getCacheManager(
+ getConfigFileURL(configFileURL).toURI(),
+ getClass().getClassLoader());
+
+ requestCache = getOrCreate(cacheManager, REQUEST_CACHE_KEY,
String.class, RequestState.class);
+ responseCache = getOrCreate(cacheManager, RESPONSE_CACHE_KEY,
String.class, ResponseState.class);
+ }
+
+ private static <K, V> Cache<K, V> getOrCreate(CacheManager cacheManager,
String name,
+ Class<K> kclass, Class<V> vclass) {
+
+ final Cache<K, V> cache = cacheManager.getCache(name, kclass, vclass);
+ if (cache != null) {
+ return cache;
+ }
+
+ final MutableConfiguration<K, V> cacheConfiguration = new
MutableConfiguration<>();
+ cacheConfiguration.setTypes(kclass, vclass);
+
+ return cacheManager.createCache(name, cacheConfiguration);
+ }
+
+ private URL getConfigFileURL(URL suppliedConfigFileURL) {
+ if (suppliedConfigFileURL == null) {
+ //using the default
+ try {
+ URL configFileURL = Loader.getResource(DEFAULT_CONFIG_URL);
+ if (configFileURL == null) {
+ configFileURL = new URL(DEFAULT_CONFIG_URL);
+ }
+ return configFileURL;
+ } catch (IOException e) {
+ // Do nothing
+ LOG.debug(e.getMessage());
+ }
+ }
+ return suppliedConfigFileURL;
+ }
+
+ public ResponseState getResponseState(String securityContextKey) {
+ return responseCache.get(securityContextKey);
+ }
+
+ public ResponseState removeResponseState(String securityContextKey) {
+ ResponseState responseState = getResponseState(securityContextKey);
+ if (responseState != null) {
+ responseCache.remove(securityContextKey);
+ }
+ return responseState;
+ }
+
+ public void setResponseState(String securityContextKey, ResponseState
state) {
+ if (securityContextKey == null || "".equals(securityContextKey)) {
+ return;
+ }
+
+ responseCache.put(securityContextKey, state);
+ }
+
+ public void setRequestState(String relayState, RequestState state) {
+ if (relayState == null || "".equals(relayState)) {
+ return;
+ }
+
+ requestCache.put(relayState, state);
+ }
+
+ public RequestState removeRequestState(String relayState) {
+ RequestState state = requestCache.get(relayState);
+ if (state != null) {
+ requestCache.remove(relayState);
+ }
+ return state;
+ }
+
+ public synchronized void close() throws IOException {
+ if (!cacheManager.isClosed()) {
+ cacheManager.destroyCache(REQUEST_CACHE_KEY);
+ cacheManager.destroyCache(RESPONSE_CACHE_KEY);
+ cacheManager.close();
+ }
+ }
+
+}
diff --git a/rt/rs/security/sso/saml/src/main/resources/cxf-samlp-ehcache.xml
b/rt/rs/security/sso/saml/src/main/resources/cxf-samlp-ehcache.xml
index f3b73551e4..3991aa4f91 100644
--- a/rt/rs/security/sso/saml/src/main/resources/cxf-samlp-ehcache.xml
+++ b/rt/rs/security/sso/saml/src/main/resources/cxf-samlp-ehcache.xml
@@ -1,4 +1,22 @@
<?xml version="1.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.
+-->
<config
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
diff --git a/rt/rs/security/sso/saml/src/main/resources/cxf-samlp-jcache.xml
b/rt/rs/security/sso/saml/src/main/resources/cxf-samlp-jcache.xml
new file mode 100644
index 0000000000..4615649554
--- /dev/null
+++ b/rt/rs/security/sso/saml/src/main/resources/cxf-samlp-jcache.xml
@@ -0,0 +1,74 @@
+<?xml version="1.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.
+-->
+<config
+ xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
+ xmlns='http://www.ehcache.org/v3'
+ xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
+ xsi:schemaLocation="http://www.ehcache.org/v3
http://www.ehcache.org/schema/ehcache-core-3.8.xsd
+ http://www.ehcache.org/v3/jsr107
http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
+
+ <service>
+ <jsr107:defaults>
+ <jsr107:cache name="cxf.samlp.response.state.cache"
template="cxf.samlp.response.state.cache.template"/>
+ <jsr107:cache name="cxf.samlp.request.state.cache"
template="cxf.samlp.request.state.cache.template"/>
+ <jsr107:cache name="cxf.samlp.replay.cache"
template="cxf.samlp.replay.cache.template"/>
+ </jsr107:defaults>
+ </service>
+
+ <persistence directory="${java.io.tmpdir}/ehcache/" />
+
+ <cache-template name="cxf.samlp.replay.cache.template">
+ <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>
+ </cache-template>
+
+ <cache-template name="cxf.samlp.request.state.cache.template">
+ <key-type>java.lang.String</key-type>
+
<value-type>org.apache.cxf.rs.security.saml.sso.state.RequestState</value-type>
+ <expiry>
+ <ttl unit="seconds">300</ttl>
+ </expiry>
+ <resources>
+ <heap unit="entries">5000</heap>
+ <disk unit="MB" persistent="false">10</disk>
+ </resources>
+ </cache-template>
+
+ <cache-template name="cxf.samlp.response.state.cache.template">
+ <key-type>java.lang.String</key-type>
+
<value-type>org.apache.cxf.rs.security.saml.sso.state.ResponseState</value-type>
+ <expiry>
+ <ttl unit="seconds">300</ttl>
+ </expiry>
+ <resources>
+ <heap unit="entries">5000</heap>
+ <disk unit="MB" persistent="false">10</disk>
+ </resources>
+ </cache-template>
+
+</config>
+
diff --git
a/rt/rs/security/sso/saml/src/test/java/org/apache/cxf/rs/security/saml/sso/SPStateManagerTest.java
b/rt/rs/security/sso/saml/src/test/java/org/apache/cxf/rs/security/saml/sso/SPStateManagerTest.java
index 802b46da6f..73e588a18b 100644
---
a/rt/rs/security/sso/saml/src/test/java/org/apache/cxf/rs/security/saml/sso/SPStateManagerTest.java
+++
b/rt/rs/security/sso/saml/src/test/java/org/apache/cxf/rs/security/saml/sso/SPStateManagerTest.java
@@ -30,6 +30,7 @@ import
org.apache.cxf.rs.security.saml.sso.state.MemorySPStateManager;
import org.apache.cxf.rs.security.saml.sso.state.RequestState;
import org.apache.cxf.rs.security.saml.sso.state.ResponseState;
import org.apache.cxf.rs.security.saml.sso.state.SPStateManager;
+import org.apache.cxf.rs.security.saml.sso.state.jcache.JCacheSPStateManager;
import org.junit.After;
import org.junit.Before;
@@ -55,7 +56,7 @@ public class SPStateManagerTest {
@Parameterized.Parameters(name = "{0}")
public static Collection<Class<? extends SPStateManager>> data() {
- return Arrays.asList(MemorySPStateManager.class,
EHCacheSPStateManager.class);
+ return Arrays.asList(MemorySPStateManager.class,
EHCacheSPStateManager.class, JCacheSPStateManager.class);
}
@Before
diff --git
a/rt/rs/security/sso/saml/src/test/java/org/apache/cxf/rs/security/saml/sso/TokenReplayCacheTest.java
b/rt/rs/security/sso/saml/src/test/java/org/apache/cxf/rs/security/saml/sso/TokenReplayCacheTest.java
index 66c8d9ced8..0b3731366b 100644
---
a/rt/rs/security/sso/saml/src/test/java/org/apache/cxf/rs/security/saml/sso/TokenReplayCacheTest.java
+++
b/rt/rs/security/sso/saml/src/test/java/org/apache/cxf/rs/security/saml/sso/TokenReplayCacheTest.java
@@ -21,9 +21,15 @@ package org.apache.cxf.rs.security.saml.sso;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.UUID;
+import org.apache.cxf.rs.security.saml.sso.jcache.JCacheTokenReplayCache;
+
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -31,12 +37,23 @@ import static org.junit.Assert.assertTrue;
/**
* Some unit tests for the TokenReplayCache implementations
*/
+@RunWith(value = org.junit.runners.Parameterized.class)
public class TokenReplayCacheTest {
+ private final Class<? extends TokenReplayCache<String>>
tokenReplayCacheClass;
+
+ public TokenReplayCacheTest(Class<? extends TokenReplayCache<String>>
tokenReplayCacheClass) {
+ this.tokenReplayCacheClass = tokenReplayCacheClass;
+ }
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Collection<Class<? extends TokenReplayCache<String>>> data()
{
+ return Arrays.asList(EHCacheTokenReplayCache.class,
JCacheTokenReplayCache.class);
+ }
@Test
- public void testEhCacheTokenReplayCache() throws Exception {
+ public void testTokenReplayCacheTokenReplayCache() throws Exception {
- TokenReplayCache<String> replayCache = new EHCacheTokenReplayCache();
+ TokenReplayCache<String> replayCache = createCache();
testTokenReplayCacheInstance(replayCache);
@@ -44,16 +61,16 @@ public class TokenReplayCacheTest {
}
@Test
- public void testEhCacheCloseCacheTwice() throws Exception {
- TokenReplayCache<String> replayCache = new EHCacheTokenReplayCache();
+ public void testTokenReplayCacheCloseCacheTwice() throws Exception {
+ TokenReplayCache<String> replayCache = createCache();
replayCache.close();
replayCache.close();
}
// No expiry specified so it falls back to the default
@Test
- public void testEhCacheTokenReplayCacheNoExpirySpecified() throws
Exception {
- TokenReplayCache<String> replayCache = new EHCacheTokenReplayCache();
+ public void testTokenReplayCacheNoExpirySpecified() throws Exception {
+ TokenReplayCache<String> replayCache = createCache();
String id = UUID.randomUUID().toString();
replayCache.putId(id);
@@ -64,8 +81,8 @@ public class TokenReplayCacheTest {
// The negative expiry is rejected and it falls back to the default
@Test
- public void testEhCacheTokenReplayCacheNegativeExpiry() throws Exception {
- TokenReplayCache<String> replayCache = new EHCacheTokenReplayCache();
+ public void testTokenReplayCacheNegativeExpiry() throws Exception {
+ TokenReplayCache<String> replayCache = createCache();
String id = UUID.randomUUID().toString();
replayCache.putId(id, Instant.now().minusSeconds(100L));
@@ -76,8 +93,8 @@ public class TokenReplayCacheTest {
// The huge expiry is rejected and it falls back to the default
@Test
- public void testEhCacheTokenReplayCacheHugeExpiry() throws Exception {
- TokenReplayCache<String> replayCache = new EHCacheTokenReplayCache();
+ public void testTokenReplayCacheHugeExpiry() throws Exception {
+ TokenReplayCache<String> replayCache = createCache();
String id = UUID.randomUUID().toString();
replayCache.putId(id, Instant.now().plus(14, ChronoUnit.HOURS));
@@ -105,4 +122,8 @@ public class TokenReplayCacheTest {
assertFalse(replayCache.contains(id));
}
-}
\ No newline at end of file
+
+ private TokenReplayCache<String> createCache() throws Exception {
+ return tokenReplayCacheClass.getDeclaredConstructor().newInstance();
+ }
+}
diff --git a/rt/ws/security/pom.xml b/rt/ws/security/pom.xml
index a806e4ceca..ac714c7dee 100644
--- a/rt/ws/security/pom.xml
+++ b/rt/ws/security/pom.xml
@@ -97,6 +97,13 @@
<classifier>jakarta</classifier>
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>org.ehcache.modules</groupId>
+ <artifactId>ehcache-107</artifactId>
+ <version>${cxf.ehcache3.version}</version>
+ <scope>provided</scope>
+ <optional>true</optional>
+ </dependency>
<dependency>
<groupId>org.apache.wss4j</groupId>
<artifactId>wss4j-ws-security-dom</artifactId>
diff --git
a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/cache/jcache/CXFJCacheReplayCache.java
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/cache/jcache/CXFJCacheReplayCache.java
new file mode 100644
index 0000000000..e751ad8f39
--- /dev/null
+++
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/cache/jcache/CXFJCacheReplayCache.java
@@ -0,0 +1,50 @@
+/**
+ * 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.cxf.ws.security.cache.jcache;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.buslifecycle.BusLifeCycleListener;
+import org.apache.cxf.buslifecycle.BusLifeCycleManager;
+import org.apache.wss4j.common.ext.WSSecurityException;
+
+/**
+ * Wrap the default JCacheReplayCache in a BusLifeCycleListener, to make sure
that
+ * the cache is shutdown correctly.
+ */
+public class CXFJCacheReplayCache extends JCacheReplayCache implements
BusLifeCycleListener {
+ private final Bus bus;
+
+ public CXFJCacheReplayCache(String key, Bus bus) throws
WSSecurityException {
+ super(key);
+ this.bus = bus;
+ if (bus != null) {
+
bus.getExtension(BusLifeCycleManager.class).registerLifeCycleListener(this);
+ }
+ }
+
+ @Override
+ public void close() {
+ super.close();
+
+ if (bus != null) {
+
bus.getExtension(BusLifeCycleManager.class).unregisterLifeCycleListener(this);
+ }
+ }
+}
diff --git
a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/cache/jcache/JCacheReplayCache.java
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/cache/jcache/JCacheReplayCache.java
new file mode 100644
index 0000000000..fca66a8551
--- /dev/null
+++
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/cache/jcache/JCacheReplayCache.java
@@ -0,0 +1,141 @@
+/**
+ * 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.cxf.ws.security.cache.jcache;
+
+import java.time.Instant;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.expiry.Duration;
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.spi.CachingProvider;
+
+import org.apache.cxf.ws.security.utils.JCacheUtils;
+import org.apache.wss4j.common.cache.EHCacheExpiry;
+import org.apache.wss4j.common.cache.EHCacheValue;
+import org.apache.wss4j.common.cache.ReplayCache;
+import org.apache.wss4j.common.ext.WSSecurityException;
+
+/**
+ * An in-memory JCache based implementation of the ReplayCache interface.
+ * The default TTL is 60 minutes and the max TTL is 12 hours.
+ */
+class JCacheReplayCache implements ReplayCache {
+ private static final org.slf4j.Logger LOG =
+ org.slf4j.LoggerFactory.getLogger(JCacheReplayCache.class);
+
+ private final Cache<String, EHCacheValue> cache;
+ private final CacheManager cacheManager;
+ private final String key;
+
+ JCacheReplayCache(String key) throws WSSecurityException {
+ this(key, 10000);
+ }
+
+ JCacheReplayCache(String key, long heapEntries) throws WSSecurityException
{
+ this.key = Objects.requireNonNull(key);
+
+ // Do some checking on the arguments
+ try {
+ final CachingProvider cachingProvider =
Caching.getCachingProvider();
+ cacheManager = cachingProvider.getCacheManager();
+ cache = JCacheUtils.getOrCreate(cacheManager, key, String.class,
EHCacheValue.class,
+ cacheConfiguration ->
cacheConfiguration.setExpiryPolicyFactory(() -> new ExpiryPolicy() {
+ @Override
+ public Duration getExpiryForCreation() {
+ return new Duration(TimeUnit.SECONDS,
EHCacheExpiry.DEFAULT_TTL);
+ }
+
+ @Override
+ public Duration getExpiryForAccess() {
+ return null;
+ }
+
+ @Override
+ public Duration getExpiryForUpdate() {
+ return null;
+ }
+ }));
+ } catch (Exception ex) {
+ LOG.error("Error configuring JCacheReplayCache: {}",
ex.getMessage());
+ throw new
WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex,
"replayCacheError");
+ }
+ }
+
+ /**
+ * Add the given identifier to the cache. It will be cached for a default
amount of time.
+ * @param identifier The identifier to be added
+ */
+ public void add(String identifier) {
+ 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. Can be null in
which case, the default expiry is used.
+ */
+ public void add(String identifier, Instant expiry) {
+ if (identifier == null || identifier.length() == 0) {
+ return;
+ }
+
+ cache.put(identifier, new EHCacheValue(identifier, expiry));
+ }
+
+ /**
+ * Return true if the given identifier is contained in the cache
+ * @param identifier The identifier to check
+ */
+ public boolean contains(String identifier) {
+ if (cache == null) {
+ 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.isClosed()) {
+ cacheManager.destroyCache(key);
+ cacheManager.close();
+ }
+ }
+
+ public void initComplete() {
+ }
+
+ public void preShutdown() {
+ close();
+ }
+
+ public void postShutdown() {
+ close();
+ }
+}
diff --git
a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/TokenStoreFactory.java
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/TokenStoreFactory.java
index 728fa3a553..436508d79d 100644
---
a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/TokenStoreFactory.java
+++
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/TokenStoreFactory.java
@@ -20,36 +20,23 @@
package org.apache.cxf.ws.security.tokenstore;
import org.apache.cxf.message.Message;
+import org.apache.cxf.ws.security.tokenstore.jcache.JCacheTokenStoreFactory;
+import org.apache.cxf.ws.security.utils.JCacheUtils;
+import org.apache.wss4j.common.cache.WSS4JCacheUtil;
/**
* An abstract factory to return a TokenStore instance. It returns an
EHCacheTokenStoreFactory
* if EH-Cache is available. Otherwise it returns a MemoryTokenStoreFactory.
*/
public abstract class TokenStoreFactory {
-
- private static boolean ehCacheInstalled;
-
- static {
- try {
- Class<?> cacheManagerClass =
Class.forName("org.ehcache.CacheManager");
- if (cacheManagerClass != null) {
- ehCacheInstalled = true;
- }
- } catch (Exception e) {
- //ignore
- }
- }
-
- public static synchronized boolean isEhCacheInstalled() {
- return ehCacheInstalled;
- }
-
public static TokenStoreFactory newInstance() {
- if (isEhCacheInstalled()) {
+ if (WSS4JCacheUtil.isEhCacheInstalled()) {
return new EHCacheTokenStoreFactory();
+ } else if (JCacheUtils.isJCacheInstalled()) {
+ return new JCacheTokenStoreFactory();
+ } else {
+ return new MemoryTokenStoreFactory();
}
-
- return new MemoryTokenStoreFactory();
}
public abstract TokenStore newTokenStore(String key, Message message)
throws TokenStoreException;
diff --git
a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/jcache/JCacheTokenStore.java
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/jcache/JCacheTokenStore.java
new file mode 100644
index 0000000000..a179c6ab30
--- /dev/null
+++
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/jcache/JCacheTokenStore.java
@@ -0,0 +1,131 @@
+/**
+ * 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.cxf.ws.security.tokenstore.jcache;
+
+import java.io.Closeable;
+import java.net.URL;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.spi.CachingProvider;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.buslifecycle.BusLifeCycleListener;
+import org.apache.cxf.buslifecycle.BusLifeCycleManager;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.ws.security.tokenstore.SecurityToken;
+import org.apache.cxf.ws.security.tokenstore.TokenStore;
+import org.apache.cxf.ws.security.tokenstore.TokenStoreException;
+import org.apache.cxf.ws.security.utils.JCacheUtils;
+
+/**
+ * An in-memory JCache implementation of the TokenStore interface. The default
TTL is 60 minutes
+ * and the max TTL is 12 hours.
+ */
+public class JCacheTokenStore implements TokenStore, Closeable,
BusLifeCycleListener {
+ private final Bus bus;
+ private final Cache<String, SecurityToken> cache;
+ private final CacheManager cacheManager;
+ private final String key;
+
+ public JCacheTokenStore(String key, Bus b, URL configFileURL) throws
TokenStoreException {
+ bus = b;
+ if (bus != null) {
+
b.getExtension(BusLifeCycleManager.class).registerLifeCycleListener(this);
+ }
+
+ this.key = key;
+ try {
+ // Exclude the endpoint info bit added in TokenStoreUtils when
getting the template name
+ String template = key;
+ if (template.contains("-")) {
+ template = key.substring(0, key.lastIndexOf('-'));
+ }
+
+ final CachingProvider cachingProvider =
Caching.getCachingProvider();
+ cacheManager =
cachingProvider.getCacheManager(configFileURL.toURI(),
+ SecurityToken.class.getClassLoader());
+ cache = JCacheUtils.getOrCreate(cacheManager, key, String.class,
SecurityToken.class);
+ } catch (Exception e) {
+ throw new TokenStoreException(e);
+ }
+ }
+
+ public void add(SecurityToken token) {
+ if (token != null && !StringUtils.isEmpty(token.getId())) {
+ cache.put(token.getId(), token);
+ }
+ }
+
+ public void add(String identifier, SecurityToken token) {
+ if (token != null && !StringUtils.isEmpty(identifier)) {
+ cache.put(identifier, token);
+ }
+ }
+
+ public void remove(String identifier) {
+ if (cache != null && !StringUtils.isEmpty(identifier)) {
+ cache.remove(identifier);
+ }
+ }
+
+ public Collection<String> getTokenIdentifiers() {
+ if (cache == null) {
+ return null;
+ }
+
+ // Not very efficient, but we are only using this method for testing
+ Set<String> keys = new HashSet<>();
+ for (Cache.Entry<String, SecurityToken> entry : cache) {
+ keys.add(entry.getKey());
+ }
+
+ return keys;
+ }
+
+ public SecurityToken getToken(String identifier) {
+ if (cache == null) {
+ return null;
+ }
+ return cache.get(identifier);
+ }
+
+ public synchronized void close() {
+ if (!cacheManager.isClosed()) {
+ cacheManager.destroyCache(key);
+ cacheManager.close();
+ }
+ }
+
+ public void initComplete() {
+ }
+
+ public void preShutdown() {
+ close();
+ }
+
+ public void postShutdown() {
+ close();
+ }
+}
diff --git
a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/jcache/JCacheTokenStoreFactory.java
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/jcache/JCacheTokenStoreFactory.java
new file mode 100644
index 0000000000..039b94912b
--- /dev/null
+++
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/tokenstore/jcache/JCacheTokenStoreFactory.java
@@ -0,0 +1,51 @@
+/**
+ * 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.cxf.ws.security.tokenstore.jcache;
+
+import java.net.URL;
+
+import org.apache.cxf.message.Message;
+import org.apache.cxf.rt.security.utils.SecurityUtils;
+import org.apache.cxf.ws.security.SecurityConstants;
+import org.apache.cxf.ws.security.tokenstore.TokenStore;
+import org.apache.cxf.ws.security.tokenstore.TokenStoreException;
+import org.apache.cxf.ws.security.tokenstore.TokenStoreFactory;
+import org.apache.wss4j.common.util.Loader;
+
+
+/**
+ * A factory to return an JCacheTokenStore instance.
+ */
+public class JCacheTokenStoreFactory extends TokenStoreFactory {
+
+ private static final String DEFAULT_CONFIG_FILE = "cxf-jcache.xml";
+
+ @Override
+ public TokenStore newTokenStore(String key, Message message) throws
TokenStoreException {
+ URL configFileURL = SecurityUtils.getConfigFileURL(message,
SecurityConstants.CACHE_CONFIG_FILE,
+ DEFAULT_CONFIG_FILE);
+ if (configFileURL == null) {
+ configFileURL =
Loader.getResource(this.getClass().getClassLoader(),
+ DEFAULT_CONFIG_FILE);
+ }
+ return new JCacheTokenStore(key, message.getExchange().getBus(),
configFileURL);
+ }
+
+}
diff --git
a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/utils/JCacheUtils.java
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/utils/JCacheUtils.java
new file mode 100644
index 0000000000..223207695e
--- /dev/null
+++
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/utils/JCacheUtils.java
@@ -0,0 +1,73 @@
+/**
+ * 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.cxf.ws.security.utils;
+
+import java.util.function.Function;
+import java.util.logging.Logger;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.configuration.MutableConfiguration;
+
+import org.apache.cxf.common.logging.LogUtils;
+
+public final class JCacheUtils {
+ private static final Logger LOG = LogUtils.getL7dLogger(JCacheUtils.class);
+ private static final boolean JCACHE_INSTALLED;
+
+ static {
+ boolean jcacheInstalled = false;
+ try {
+ final Class<?> caching = Class.forName("javax.cache.Caching");
+ if (caching != null) {
+ jcacheInstalled = true;
+ }
+ } catch (Exception e) {
+ LOG.fine("No JCache SPIs detected on classpath: " +
e.getMessage());
+ }
+ JCACHE_INSTALLED = jcacheInstalled;
+ }
+
+ private JCacheUtils() {
+ }
+
+ public static <K, V> Cache<K, V> getOrCreate(CacheManager cacheManager,
String name, Class<K> kclass,
+ Class<V> vclass) {
+ return getOrCreate(cacheManager, name, kclass, vclass,
Function.identity());
+ }
+
+ public static <K, V> Cache<K, V> getOrCreate(CacheManager cacheManager,
String name, Class<K> kclass,
+ Class<V> vclass, Function<MutableConfiguration<K, V>,
MutableConfiguration<K, V>> customizer) {
+
+ final Cache<K, V> cache = cacheManager.getCache(name, kclass, vclass);
+ if (cache != null) {
+ return cache;
+ }
+
+ MutableConfiguration<K, V> cacheConfiguration = new
MutableConfiguration<>();
+ cacheConfiguration =
customizer.apply(cacheConfiguration.setTypes(kclass, vclass));
+
+ return cacheManager.createCache(name, cacheConfiguration);
+ }
+
+ public static boolean isJCacheInstalled() {
+ return JCACHE_INSTALLED;
+ }
+
+}
diff --git
a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/WSS4JUtils.java
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/WSS4JUtils.java
index b2eda68c50..df6f1b7f1f 100644
---
a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/WSS4JUtils.java
+++
b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/WSS4JUtils.java
@@ -47,9 +47,11 @@ import org.apache.cxf.rt.security.utils.SecurityUtils;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.ws.security.SecurityConstants;
import org.apache.cxf.ws.security.cache.CXFEHCacheReplayCache;
+import org.apache.cxf.ws.security.cache.jcache.CXFJCacheReplayCache;
import org.apache.cxf.ws.security.tokenstore.SecurityToken;
import org.apache.cxf.ws.security.tokenstore.TokenStoreException;
import org.apache.cxf.ws.security.tokenstore.TokenStoreUtils;
+import org.apache.cxf.ws.security.utils.JCacheUtils;
import org.apache.wss4j.common.cache.MemoryReplayCache;
import org.apache.wss4j.common.cache.ReplayCache;
import org.apache.wss4j.common.cache.WSS4JCacheUtil;
@@ -146,6 +148,9 @@ public final class WSS4JUtils {
throw new
WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex);
}
replayCache = new CXFEHCacheReplayCache(cacheKey, bus,
diskstoreParent);
+ } else if (JCacheUtils.isJCacheInstalled()) {
+ Bus bus = message.getExchange().getBus();
+ replayCache = new CXFJCacheReplayCache(cacheKey, bus);
} else {
replayCache = new MemoryReplayCache();
}
diff --git a/rt/ws/security/src/main/resources/cxf-ehcache.xml
b/rt/ws/security/src/main/resources/cxf-ehcache.xml
index eedfa20f13..c8238c712d 100644
--- a/rt/ws/security/src/main/resources/cxf-ehcache.xml
+++ b/rt/ws/security/src/main/resources/cxf-ehcache.xml
@@ -1,4 +1,22 @@
<?xml version="1.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.
+-->
<config
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
diff --git a/rt/ws/security/src/main/resources/cxf-jcache.xml
b/rt/ws/security/src/main/resources/cxf-jcache.xml
new file mode 100644
index 0000000000..48800ebb4c
--- /dev/null
+++ b/rt/ws/security/src/main/resources/cxf-jcache.xml
@@ -0,0 +1,50 @@
+<?xml version="1.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.
+-->
+<config
+ xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
+ xmlns='http://www.ehcache.org/v3'
+ xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
+ xsi:schemaLocation="http://www.ehcache.org/v3
http://www.ehcache.org/schema/ehcache-core-3.8.xsd
+ http://www.ehcache.org/v3/jsr107
http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">
+
+ <service>
+ <jsr107:defaults
default-template="org.apache.cxf.ws.security.tokenstore.TokenStore.template">
+ <jsr107:cache
name="org.apache.cxf.ws.security.tokenstore.TokenStore"
template="org.apache.cxf.ws.security.tokenstore.TokenStore.template"/>
+ </jsr107:defaults>
+ </service>
+
+ <!--
+ Security Tokens are not writable to Disk so use a memory only
+ cache with a bit larger maxEntriesLocalHeap. However, this
+ cache is per-endpoint so not "too large" to not consume the
+ entire heap.
+ -->
+ <cache-template
name="org.apache.cxf.ws.security.tokenstore.TokenStore.template">
+ <key-type>java.lang.String</key-type>
+ <value-type
copier="org.ehcache.impl.copy.IdentityCopier">org.apache.cxf.ws.security.tokenstore.SecurityToken</value-type>
+ <expiry>
+ <ttl unit="seconds">3600</ttl>
+ </expiry>
+ <resources>
+ <heap unit="entries">10000</heap>
+ </resources>
+ </cache-template>
+
+</config>
diff --git
a/rt/ws/security/src/test/java/org/apache/cxf/ws/security/tokenstore/TokenStoreTest.java
b/rt/ws/security/src/test/java/org/apache/cxf/ws/security/tokenstore/TokenStoreTest.java
index 506bb78a67..44707bb147 100644
---
a/rt/ws/security/src/test/java/org/apache/cxf/ws/security/tokenstore/TokenStoreTest.java
+++
b/rt/ws/security/src/test/java/org/apache/cxf/ws/security/tokenstore/TokenStoreTest.java
@@ -25,11 +25,14 @@ import org.apache.cxf.message.ExchangeImpl;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageImpl;
import org.apache.cxf.ws.security.SecurityConstants;
+import org.apache.cxf.ws.security.tokenstore.jcache.JCacheTokenStoreFactory;
import org.apache.xml.security.utils.ClassLoaderUtils;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -46,14 +49,13 @@ public class TokenStoreTest {
@Parameterized.Parameters(name = "{0}")
public static Collection<TokenStore> data() throws TokenStoreException {
Message message = new MessageImpl();
- message.put(
- SecurityConstants.CACHE_CONFIG_FILE,
- ClassLoaderUtils.getResource("cxf-ehcache.xml",
TokenStoreTest.class)
- );
message.setExchange(new ExchangeImpl());
return Arrays.asList(
new
MemoryTokenStoreFactory().newTokenStore(SecurityConstants.TOKEN_STORE_CACHE_INSTANCE,
message),
- new
EHCacheTokenStoreFactory().newTokenStore(SecurityConstants.TOKEN_STORE_CACHE_INSTANCE,
message)
+ new
EHCacheTokenStoreFactory().newTokenStore(SecurityConstants.TOKEN_STORE_CACHE_INSTANCE,
+ withConfigFile(message, "cxf-ehcache.xml")),
+ new
JCacheTokenStoreFactory().newTokenStore(SecurityConstants.TOKEN_STORE_CACHE_INSTANCE,
+ withConfigFile(message, "cxf-jcache.xml"))
);
}
@@ -84,7 +86,7 @@ public class TokenStoreTest {
store.add(token1);
store.add(token2);
store.add(token3);
- assertTrue(store.getTokenIdentifiers().size() == 3);
+ assertThat(store.getTokenIdentifiers(), hasSize(3));
store.remove(token3.getId());
assertNull(store.getToken("test3"));
store.remove(token1.getId());
@@ -92,4 +94,11 @@ public class TokenStoreTest {
assertTrue(store.getTokenIdentifiers().isEmpty());
}
+ private static Message withConfigFile(Message message, String configFile) {
+ message.put(
+ SecurityConstants.CACHE_CONFIG_FILE,
+ ClassLoaderUtils.getResource(configFile, TokenStoreTest.class)
+ );
+ return message;
+ }
}
diff --git
a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/cache/jcache/JCacheIdentityCache.java
b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/cache/jcache/JCacheIdentityCache.java
new file mode 100644
index 0000000000..cf58dde1ce
--- /dev/null
+++
b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/cache/jcache/JCacheIdentityCache.java
@@ -0,0 +1,182 @@
+/**
+ * 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.cxf.sts.cache.jcache;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.spi.CachingProvider;
+import javax.management.JMException;
+import javax.management.ObjectName;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.buslifecycle.BusLifeCycleListener;
+import org.apache.cxf.buslifecycle.BusLifeCycleManager;
+import org.apache.cxf.common.classloader.ClassLoaderUtils;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.management.InstrumentationManager;
+import org.apache.cxf.management.ManagementConstants;
+import org.apache.cxf.management.annotation.ManagedOperation;
+import org.apache.cxf.management.annotation.ManagedResource;
+import org.apache.cxf.resource.ResourceManager;
+import org.apache.cxf.sts.IdentityMapper;
+import org.apache.cxf.sts.cache.AbstractIdentityCache;
+import org.apache.cxf.sts.cache.EHCacheIdentityValue;
+import org.apache.cxf.ws.security.tokenstore.TokenStoreFactory;
+import org.apache.cxf.ws.security.utils.JCacheUtils;
+
+/**
+ * A JCache based cache to cache identities in different realms where
+ * the relationship is of type FederateIdentity.
+ */
+@ManagedResource()
+public class JCacheIdentityCache extends AbstractIdentityCache
+ implements Closeable, BusLifeCycleListener {
+
+ private static final Logger LOG =
LogUtils.getL7dLogger(JCacheIdentityCache.class);
+ private static final String KEY =
"org.apache.cxf.sts.cache.EHCacheIdentityCache";
+ private Cache<String, EHCacheIdentityValue> cache;
+ private final CacheManager cacheManager;
+
+
+ public JCacheIdentityCache(
+ IdentityMapper identityMapper, Bus b
+ ) {
+ this(identityMapper, JCacheIdentityCache.class.getName(), b, null);
+ }
+
+ public JCacheIdentityCache(IdentityMapper identityMapper, String key, Bus
b, URL configFileURL) {
+ this(Caching.getCachingProvider(), identityMapper, key, b,
configFileURL);
+ }
+
+ JCacheIdentityCache(CachingProvider cachingProvider, IdentityMapper
identityMapper,
+ String key, Bus b, URL configFileURL) {
+ super(b, identityMapper);
+ if (b != null) {
+
b.getExtension(BusLifeCycleManager.class).registerLifeCycleListener(this);
+ InstrumentationManager im =
b.getExtension(InstrumentationManager.class);
+ if (im != null) {
+ try {
+ im.register(this);
+ } catch (JMException e) {
+ LOG.log(Level.WARNING, "Registering JCacheIdentityCache
failed.", e);
+ }
+ }
+ }
+
+ final URL xmlConfigURL = configFileURL != null ? configFileURL :
getDefaultConfigFileURL();
+ try {
+ cacheManager =
cachingProvider.getCacheManager(xmlConfigURL.toURI(),
getClass().getClassLoader());
+ cache = JCacheUtils.getOrCreate(cacheManager, KEY, String.class,
EHCacheIdentityValue.class);
+ } catch (final URISyntaxException ex) {
+ throw new IllegalStateException("Unable to convert " +
xmlConfigURL + " to URI", ex);
+ }
+ }
+
+ @Override
+ public void add(String user, String realm, Map<String, String> identities)
{
+ cache.put(user + "@" + realm, new EHCacheIdentityValue(identities));
+ }
+
+ @ManagedOperation()
+ @Override
+ public Map<String, String> get(String user, String realm) {
+ EHCacheIdentityValue value = cache.get(user + "@" + realm);
+ if (value != null) {
+ return value.getValue();
+ }
+
+ return null;
+ }
+
+ @Override
+ public void remove(String user, String realm) {
+ cache.remove(user + "@" + realm);
+ }
+
+ @ManagedOperation()
+ public String getContent() {
+ return this.cache.toString();
+ }
+
+ public synchronized void close() {
+ if (!cacheManager.isClosed()) {
+ cacheManager.destroyCache(KEY);
+ cacheManager.close();
+
+ if (super.getBus() != null) {
+
super.getBus().getExtension(BusLifeCycleManager.class).unregisterLifeCycleListener(this);
+ }
+ }
+ }
+
+ public void initComplete() {
+ }
+
+ public void preShutdown() {
+ close();
+ }
+
+ public void postShutdown() {
+ close();
+ }
+
+ private URL getDefaultConfigFileURL() {
+ URL url = null;
+ if (super.getBus() != null) {
+ ResourceManager rm =
super.getBus().getExtension(ResourceManager.class);
+ url = rm.resolveResource("sts-jcache.xml", URL.class);
+ }
+ try {
+ if (url == null) {
+ url = ClassLoaderUtils.getResource("sts-jcache.xml",
TokenStoreFactory.class);
+ }
+ if (url == null) {
+ url = new URL("sts-jcache.xml");
+ }
+ return url;
+ } catch (IOException e) {
+ // Do nothing
+ }
+ return null;
+ }
+
+ public ObjectName getObjectName() throws JMException {
+ StringBuilder buffer = new StringBuilder(128);
+ buffer.append(ManagementConstants.DEFAULT_DOMAIN_NAME).append(':');
+ if (super.getBus() != null) {
+ buffer.append(
+
ManagementConstants.BUS_ID_PROP).append('=').append(super.getBus().getId()).append(',');
+ }
+
buffer.append(ManagementConstants.TYPE_PROP).append('=').append("EHCacheIdentityCache").append(',');
+ buffer.append(ManagementConstants.NAME_PROP).append('=')
+
.append("EHCacheIdentityCache-").append(System.identityHashCode(this));
+ return new ObjectName(buffer.toString());
+ }
+}
+
diff --git a/services/sts/sts-core/src/main/resources/sts-ehcache.xml
b/services/sts/sts-core/src/main/resources/sts-ehcache.xml
index c1a307f44a..b5409540fc 100644
--- a/services/sts/sts-core/src/main/resources/sts-ehcache.xml
+++ b/services/sts/sts-core/src/main/resources/sts-ehcache.xml
@@ -1,4 +1,22 @@
<?xml version="1.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.
+-->
<config
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
diff --git a/services/sts/sts-core/src/main/resources/sts-jcache.xml
b/services/sts/sts-core/src/main/resources/sts-jcache.xml
new file mode 100644
index 0000000000..e27555b8e7
--- /dev/null
+++ b/services/sts/sts-core/src/main/resources/sts-jcache.xml
@@ -0,0 +1,40 @@
+<?xml version="1.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.
+-->
+<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">
+
+ <persistence directory="${java.io.tmpdir}" />
+
+ <cache alias="org.apache.cxf.sts.cache.EHCacheIdentityCache">
+ <key-type>java.lang.String</key-type>
+ <value-type
copier="org.ehcache.impl.copy.IdentityCopier">org.apache.cxf.sts.cache.EHCacheIdentityValue</value-type>
+ <expiry>
+ <ttl unit="seconds">3600</ttl>
+ </expiry>
+ <resources>
+ <heap unit="entries">5000</heap>
+ <disk unit="MB" persistent="false">10</disk>
+ </resources>
+ </cache>
+
+</config>
+
diff --git
a/services/sts/sts-core/src/test/java/org/apache/cxf/sts/cache/jcache/JCacheIdentityCacheTest.java
b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/cache/jcache/JCacheIdentityCacheTest.java
new file mode 100644
index 0000000000..c69dee6163
--- /dev/null
+++
b/services/sts/sts-core/src/test/java/org/apache/cxf/sts/cache/jcache/JCacheIdentityCacheTest.java
@@ -0,0 +1,37 @@
+/**
+ * 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.cxf.sts.cache.jcache;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.sts.IdentityMapper;
+import org.apache.cxf.sts.cache.AbstractIdentityCache;
+import org.apache.cxf.sts.cache.MemoryIdentityCacheTest;
+import org.ehcache.jsr107.EhcacheCachingProvider;
+
+public class JCacheIdentityCacheTest extends MemoryIdentityCacheTest {
+
+ @Override
+ protected AbstractIdentityCache getIdentityCache(IdentityMapper mapper) {
+ Bus bus = BusFactory.getDefaultBus();
+ return new JCacheIdentityCache(new EhcacheCachingProvider(), mapper,
+ JCacheIdentityCache.class.getName(), bus, null);
+ }
+
+}
diff --git
a/services/xkms/xkms-client/src/main/java/org/apache/cxf/xkms/cache/jcache/JCacheXKMSClientCache.java
b/services/xkms/xkms-client/src/main/java/org/apache/cxf/xkms/cache/jcache/JCacheXKMSClientCache.java
new file mode 100644
index 0000000000..c1c078d139
--- /dev/null
+++
b/services/xkms/xkms-client/src/main/java/org/apache/cxf/xkms/cache/jcache/JCacheXKMSClientCache.java
@@ -0,0 +1,124 @@
+/**
+ * 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.cxf.xkms.cache.jcache;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import javax.cache.Cache;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.cache.expiry.Duration;
+import javax.cache.expiry.ExpiryPolicy;
+import javax.cache.spi.CachingProvider;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.buslifecycle.BusLifeCycleListener;
+import org.apache.cxf.buslifecycle.BusLifeCycleManager;
+import org.apache.cxf.ws.security.utils.JCacheUtils;
+import org.apache.cxf.xkms.cache.XKMSCacheToken;
+import org.apache.cxf.xkms.cache.XKMSClientCache;
+import org.apache.cxf.xkms.cache.XKMSClientCacheException;
+
+/**
+ * An in-memory JCache implementation of the XKMSClientCache interface.
+ */
+public class JCacheXKMSClientCache implements XKMSClientCache,
BusLifeCycleListener {
+ private final Cache<String, XKMSCacheToken> cache;
+ private final CacheManager cacheManager;
+ private final Bus bus;
+ private final String cacheKey;
+
+ public JCacheXKMSClientCache() throws XKMSClientCacheException {
+ this(null);
+ }
+
+ public JCacheXKMSClientCache(Bus cxfBus) throws XKMSClientCacheException {
+ if (cxfBus == null) {
+ cxfBus = BusFactory.getThreadDefaultBus(true);
+ }
+ if (cxfBus != null) {
+
cxfBus.getExtension(BusLifeCycleManager.class).registerLifeCycleListener(this);
+ }
+
+ this.bus = cxfBus;
+ this.cacheKey = UUID.randomUUID().toString();
+
+ final CachingProvider cachingProvider = Caching.getCachingProvider();
+ cacheManager = cachingProvider.getCacheManager();
+
+ cache = JCacheUtils.getOrCreate(cacheManager, cacheKey, String.class,
XKMSCacheToken.class,
+ cacheConfiguration -> cacheConfiguration.setExpiryPolicyFactory(()
-> new ExpiryPolicy() {
+ @Override
+ public Duration getExpiryForCreation() {
+ return new Duration(TimeUnit.SECONDS, 3600);
+ }
+
+ @Override
+ public Duration getExpiryForAccess() {
+ return null;
+ }
+
+ @Override
+ public Duration getExpiryForUpdate() {
+ return new Duration(TimeUnit.SECONDS, 3600);
+ }
+ }).setStoreByValue(false));
+
+ }
+
+ /**
+ * Store an XKMSCacheToken in the Cache using the given key
+ */
+ public void put(String key, XKMSCacheToken cacheToken) {
+ cache.put(key, cacheToken);
+ }
+
+ /**
+ * Get an XKMSCacheToken from the cache matching the given key. Returns
null if there
+ * is no such XKMSCacheToken in the cache.
+ */
+ public XKMSCacheToken get(String key) {
+ return cache.get(key);
+ }
+
+ public synchronized void close() {
+ if (!cacheManager.isClosed()) {
+ cacheManager.destroyCache(cacheKey);
+ cacheManager.close();
+
+ if (bus != null) {
+
bus.getExtension(BusLifeCycleManager.class).unregisterLifeCycleListener(this);
+ }
+ }
+ }
+
+ public void initComplete() {
+ }
+
+ public void preShutdown() {
+ close();
+ }
+
+ public void postShutdown() {
+ close();
+ }
+}
diff --git
a/services/xkms/xkms-client/src/test/java/org/apache/cxf/xkms/cache/XKMSClientCacheTest.java
b/services/xkms/xkms-client/src/test/java/org/apache/cxf/xkms/cache/XKMSClientCacheTest.java
index e5dcabab6e..b9ea506e4a 100644
---
a/services/xkms/xkms-client/src/test/java/org/apache/cxf/xkms/cache/XKMSClientCacheTest.java
+++
b/services/xkms/xkms-client/src/test/java/org/apache/cxf/xkms/cache/XKMSClientCacheTest.java
@@ -22,8 +22,14 @@ package org.apache.cxf.xkms.cache;
import java.math.BigInteger;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
import org.apache.cxf.common.classloader.ClassLoaderUtils;
+import org.apache.cxf.xkms.cache.jcache.JCacheXKMSClientCache;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -33,14 +39,15 @@ import static org.junit.Assert.assertTrue;
/**
* A test for the XKMSClientCache
*/
+@RunWith(value = org.junit.runners.Parameterized.class)
public class XKMSClientCacheTest {
private final XKMSClientCache cache;
- private final X509Certificate alice;
- private final X509Certificate bob;
+ private X509Certificate alice;
+ private X509Certificate bob;
- public XKMSClientCacheTest() throws Exception {
- cache = new EHCacheXKMSClientCache();
+ public XKMSClientCacheTest(XKMSClientCache cache) throws Exception {
+ this.cache = cache;
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(ClassLoaderUtils.getResourceAsStream("keys/alice.jks",
@@ -55,6 +62,11 @@ public class XKMSClientCacheTest {
bob = (X509Certificate)keystore.getCertificate("bob");
}
+ @Parameterized.Parameters(name = "{0}")
+ public static Collection<XKMSClientCache> cache() throws
XKMSClientCacheException {
+ return Arrays.asList(new EHCacheXKMSClientCache(), new
JCacheXKMSClientCache());
+ }
+
@org.junit.Test
public void testCache() {
assertNotNull(alice);
diff --git
a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookCxfContinuationStore.java
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookCxfContinuationStore.java
index 1dae72a693..fc20076fcf 100644
---
a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookCxfContinuationStore.java
+++
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/BookCxfContinuationStore.java
@@ -24,6 +24,7 @@ import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -40,7 +41,6 @@ import org.apache.cxf.jaxrs.ext.MessageContext;
import org.apache.cxf.jaxrs.impl.UriInfoImpl;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.PhaseInterceptorChain;
-import org.ehcache.impl.internal.concurrent.ConcurrentHashMap;
@Path("/bookstore")
public class BookCxfContinuationStore {
diff --git
a/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/cache/CachingTest.java
b/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/cache/CachingTest.java
index e15fa649ac..fbe3cbc640 100644
---
a/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/cache/CachingTest.java
+++
b/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/cache/CachingTest.java
@@ -20,8 +20,6 @@
package org.apache.cxf.systest.ws.cache;
import java.net.URL;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.Random;
import javax.xml.namespace.QName;
@@ -40,6 +38,8 @@ import
org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
import org.apache.cxf.ws.security.SecurityConstants;
import org.apache.cxf.ws.security.tokenstore.EHCacheTokenStore;
import org.apache.cxf.ws.security.tokenstore.TokenStore;
+import org.apache.cxf.ws.security.tokenstore.TokenStoreException;
+import org.apache.cxf.ws.security.tokenstore.jcache.JCacheTokenStore;
import org.example.contract.doubleit.DoubleItPortType;
import org.junit.BeforeClass;
@@ -59,11 +59,18 @@ public class CachingTest extends
AbstractBusClientServerTestBase {
private static final String NAMESPACE =
"http://www.example.org/contract/DoubleIt";
private static final QName SERVICE_QNAME = new QName(NAMESPACE,
"DoubleItService");
+
+ @FunctionalInterface
+ private interface TokenStoreCacheFactory {
+ TokenStore create(String key, Bus b) throws TokenStoreException;
+ }
- final TestParam test;
+ private final TestParam test;
+ private final TokenStoreCacheFactory factory;
- public CachingTest(TestParam type) {
+ public CachingTest(TestParam type, TokenStoreCacheFactory factory) {
this.test = type;
+ this.factory = factory;
}
@BeforeClass
@@ -76,12 +83,18 @@ public class CachingTest extends
AbstractBusClientServerTestBase {
);
}
- @Parameters(name = "{0}")
- public static Collection<TestParam> data() {
-
- return Arrays.asList(new TestParam[] {new TestParam(PORT, false),
- new TestParam(PORT, true),
- });
+ @Parameters(name = "{0},{1}")
+ public static Object[][] data() {
+ return new Object[][] {
+ {new TestParam(PORT, false), (TokenStoreCacheFactory) (String key,
Bus b) ->
+ new EHCacheTokenStore(key, b,
ClassLoaderUtils.getResource("cxf-ehcache.xml", CachingTest.class))},
+ {new TestParam(PORT, false), (TokenStoreCacheFactory) (String key,
Bus b) ->
+ new JCacheTokenStore(key, b,
ClassLoaderUtils.getResource("cxf-jcache.xml", CachingTest.class))},
+ {new TestParam(PORT, true), (TokenStoreCacheFactory) (String key,
Bus b) ->
+ new EHCacheTokenStore(key, b,
ClassLoaderUtils.getResource("cxf-ehcache.xml", CachingTest.class))},
+ {new TestParam(PORT, true), (TokenStoreCacheFactory) (String key,
Bus b) ->
+ new JCacheTokenStore(key, b,
ClassLoaderUtils.getResource("cxf-jcache.xml", CachingTest.class))}
+ };
}
@org.junit.AfterClass
@@ -174,8 +187,7 @@ public class CachingTest extends
AbstractBusClientServerTestBase {
// Create shared cache
String cacheKey = SecurityConstants.TOKEN_STORE_CACHE_INSTANCE + '-' +
Math.abs(new Random().nextInt());
- TokenStore tokenStore = new EHCacheTokenStore(cacheKey, bus,
- ClassLoaderUtils.getResource("cxf-ehcache.xml",
this.getClass()));
+ TokenStore tokenStore = factory.create(cacheKey, bus);
Client client = ClientProxy.getClient(port);
client.getEndpoint().getEndpointInfo().setProperty(SecurityConstants.TOKEN_STORE_CACHE_INSTANCE,
tokenStore);