You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by re...@apache.org on 2016/05/26 21:45:42 UTC

[14/50] [abbrv] cxf git commit: [CXF-6909] Adding JCache OAuth2 providers, patch from Luca Burgazzoli applied with thanks, This closes #137

[CXF-6909] Adding JCache OAuth2 providers, patch from Luca Burgazzoli applied with thanks, This closes #137


Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/2b160783
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/2b160783
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/2b160783

Branch: refs/heads/master-jaxrs-2.1
Commit: 2b1607831ccf97909122eae9247116d9a075c7cf
Parents: c681373
Author: Sergey Beryozkin <sb...@gmail.com>
Authored: Fri May 20 09:49:59 2016 +0100
Committer: Sergey Beryozkin <sb...@gmail.com>
Committed: Fri May 20 09:49:59 2016 +0100

----------------------------------------------------------------------
 parent/pom.xml                                  |   2 +
 rt/rs/security/oauth-parent/oauth2/pom.xml      |  29 ++-
 .../grants/code/JCacheCodeDataProvider.java     | 126 +++++++++++
 .../provider/JCacheOAuthDataProvider.java       | 215 ++++++++++++++++++
 .../grants/code/JCacheCodeDataProviderTest.java | 105 +++++++++
 .../provider/JCacheOAuthDataProviderTest.java   | 217 +++++++++++++++++++
 .../src/test/resources/cxf-oauth2-ehcache3.xml  |  27 +++
 7 files changed, 716 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/2b160783/parent/pom.xml
----------------------------------------------------------------------
diff --git a/parent/pom.xml b/parent/pom.xml
index ce1dc37..5f256d4 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -83,6 +83,7 @@
         <cxf.derby.version>10.2.2.0</cxf.derby.version>
         <cxf.dropwizard.version>3.1.2</cxf.dropwizard.version>
         <cxf.ehcache.version>2.10.1</cxf.ehcache.version>
+        <cxf.ehcache3.version>3.0.1</cxf.ehcache3.version>
         <cxf.fastinfoset.bundle.version>1.2.13_1</cxf.fastinfoset.bundle.version>
         <cxf.guava.version>18.0</cxf.guava.version>
         <cxf.hazelcast.version>1.9.4</cxf.hazelcast.version>
@@ -99,6 +100,7 @@
         <cxf.mina.version>2.0.13</cxf.mina.version>
         <cxf.rx.java.version>1.1.3</cxf.rx.java.version>
         <cxf.javax.annotation-api.version>1.2</cxf.javax.annotation-api.version>
+        <cxf.jcache.version>1.0.0</cxf.jcache.version>
         <cxf.geronimo.jms.version>1.1.1</cxf.geronimo.jms.version>
         <cxf.geronimo.j2ee.management.version>1.0.1</cxf.geronimo.j2ee.management.version>
         <cxf.geronimo.jpa.version>1.0</cxf.geronimo.jpa.version>

http://git-wip-us.apache.org/repos/asf/cxf/blob/2b160783/rt/rs/security/oauth-parent/oauth2/pom.xml
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/pom.xml b/rt/rs/security/oauth-parent/oauth2/pom.xml
index bb8ee54..08f0a1e 100644
--- a/rt/rs/security/oauth-parent/oauth2/pom.xml
+++ b/rt/rs/security/oauth-parent/oauth2/pom.xml
@@ -62,11 +62,18 @@
             <optional>true</optional>
         </dependency>
         <dependency>
-            <groupId>net.sf.ehcache</groupId>
-            <artifactId>ehcache</artifactId>
-            <version>${cxf.ehcache.version}</version>
-            <scope>provided</scope>
-            <optional>true</optional>
+          <groupId>net.sf.ehcache</groupId>
+          <artifactId>ehcache</artifactId>
+          <version>${cxf.ehcache.version}</version>
+          <scope>provided</scope>
+          <optional>true</optional>
+        </dependency>
+        <dependency>
+          <groupId>javax.cache</groupId>
+          <artifactId>cache-api</artifactId>
+          <version>${cxf.jcache.version}</version>
+          <scope>provided</scope>
+          <optional>true</optional>
         </dependency>
         <dependency>
             <groupId>org.apache.geronimo.specs</groupId>
@@ -102,6 +109,12 @@
             <version>${hsqldb.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+          <groupId>org.ehcache</groupId>
+          <artifactId>ehcache</artifactId>
+          <version>${cxf.ehcache3.version}</version>
+          <scope>test</scope>
+        </dependency>
         <!--
         <dependency>
              <groupId>org.apache.openjpa</groupId>
@@ -116,6 +129,12 @@
             <version>${hibernate.em.version}</version>
             <scope>test</scope>
         </dependency>
+      <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>slf4j-nop</artifactId>
+        <version>${cxf.slf4j.version}</version>
+        <scope>test</scope>
+      </dependency>
         
      </dependencies>
      <build>

http://git-wip-us.apache.org/repos/asf/cxf/blob/2b160783/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/code/JCacheCodeDataProvider.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/code/JCacheCodeDataProvider.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/code/JCacheCodeDataProvider.java
new file mode 100644
index 0000000..867e99f
--- /dev/null
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/code/JCacheCodeDataProvider.java
@@ -0,0 +1,126 @@
+/**
+ * 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.oauth2.grants.code;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import javax.cache.Cache;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.rs.security.oauth2.common.Client;
+import org.apache.cxf.rs.security.oauth2.common.UserSubject;
+import org.apache.cxf.rs.security.oauth2.provider.JCacheOAuthDataProvider;
+import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
+
+public class JCacheCodeDataProvider extends JCacheOAuthDataProvider
+    implements AuthorizationCodeDataProvider {
+    public static final String CODE_GRANT_CACHE_KEY = "cxf.oauth2.codegrant.cache";
+
+    private long codeLifetime = 10 * 60;
+    private Cache<String, ServerAuthorizationCodeGrant> grantCache;
+
+    protected JCacheCodeDataProvider() throws Exception {
+        this(DEFAULT_CONFIG_URL, BusFactory.getThreadDefaultBus(true));
+    }
+
+    protected JCacheCodeDataProvider(String configFileURL, Bus bus) throws Exception {
+        this(configFileURL, bus, CLIENT_CACHE_KEY, CODE_GRANT_CACHE_KEY,
+             ACCESS_TOKEN_CACHE_KEY, REFRESH_TOKEN_CACHE_KEY);
+    }
+
+    protected JCacheCodeDataProvider(String configFileURL,
+                                     Bus bus,
+                                     String clientCacheKey,
+                                     String codeCacheKey,
+                                     String accessTokenKey,
+                                     String refreshTokenKey) throws Exception {
+        super(configFileURL, bus, clientCacheKey, accessTokenKey, refreshTokenKey);
+        grantCache = createCache(cacheManager, codeCacheKey, String.class, ServerAuthorizationCodeGrant.class);
+    }
+
+    @Override
+    protected void doRemoveClient(Client c) {
+        for (ServerAuthorizationCodeGrant grant : getCodeGrants(c, null)) {
+            removeCodeGrant(grant.getCode());
+        }
+
+        super.doRemoveClient(c);
+    }
+    
+    @Override
+    public ServerAuthorizationCodeGrant createCodeGrant(AuthorizationCodeRegistration reg)
+        throws OAuthServiceException {
+        ServerAuthorizationCodeGrant grant = AbstractCodeDataProvider.initCodeGrant(reg, codeLifetime);
+        grantCache.put(grant.getCode(), grant);
+
+        return grant;
+    }
+
+    @Override
+    public List<ServerAuthorizationCodeGrant> getCodeGrants(Client c, UserSubject sub) {
+        final Set<String> toRemove = new HashSet<>();
+        final List<ServerAuthorizationCodeGrant> grants = new ArrayList<>();
+
+        for (Iterator<Cache.Entry<String, ServerAuthorizationCodeGrant>> it = grantCache.iterator(); it.hasNext();) {
+            Cache.Entry<String, ServerAuthorizationCodeGrant> entry = it.next();
+            ServerAuthorizationCodeGrant grant = entry.getValue();
+
+            if (!isExpired(grant)) {
+                toRemove.add(entry.getKey());
+            } else if (AbstractCodeDataProvider.isCodeMatched(grant, c, sub)) {
+                grants.add(grant);
+            }
+        }
+
+        grantCache.removeAll(toRemove);
+
+        return grants;
+    }
+    
+    @Override
+    public ServerAuthorizationCodeGrant removeCodeGrant(String code) throws OAuthServiceException {
+        ServerAuthorizationCodeGrant grant = getCodeGrant(code);
+        if (grant != null) {
+            grantCache.remove(code);
+        }
+        return grant;
+    }
+
+    public void setCodeLifetime(long codeLifetime) {
+        this.codeLifetime = codeLifetime;
+    }
+
+    protected ServerAuthorizationCodeGrant getCodeGrant(String code) throws OAuthServiceException {
+        ServerAuthorizationCodeGrant grant = grantCache.get(code);
+        if (grant != null && isExpired(grant)) {
+            grantCache.remove(code);
+            grant = null;
+        }
+
+        return grant;
+    }
+
+    protected static boolean isExpired(ServerAuthorizationCodeGrant grant) {
+        return System.currentTimeMillis() < (grant.getIssuedAt() + grant.getExpiresIn());
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/2b160783/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/JCacheOAuthDataProvider.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/JCacheOAuthDataProvider.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/JCacheOAuthDataProvider.java
new file mode 100644
index 0000000..3a2bbb8
--- /dev/null
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/JCacheOAuthDataProvider.java
@@ -0,0 +1,215 @@
+/**
+ * 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.oauth2.provider;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+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.rs.security.oauth2.common.Client;
+import org.apache.cxf.rs.security.oauth2.common.ServerAccessToken;
+import org.apache.cxf.rs.security.oauth2.common.UserSubject;
+import org.apache.cxf.rs.security.oauth2.tokens.refresh.RefreshToken;
+
+import static org.apache.cxf.jaxrs.utils.ResourceUtils.getClasspathResourceURL;
+
+public class JCacheOAuthDataProvider extends AbstractOAuthDataProvider {
+    public static final String CLIENT_CACHE_KEY = "cxf.oauth2.client.cache";
+    public static final String ACCESS_TOKEN_CACHE_KEY = "cxf.oauth2.accesstoken.cache";
+    public static final String REFRESH_TOKEN_CACHE_KEY = "cxf.oauth2.refreshtoken.cache";
+    public static final String DEFAULT_CONFIG_URL = "cxf-oauth2-ehcache3.xml";
+
+    protected final CacheManager cacheManager;
+    private final Cache<String, Client> clientCache;
+    private final Cache<String, ServerAccessToken> accessTokenCache;
+    private final Cache<String, RefreshToken> refreshTokenCache;
+
+    public JCacheOAuthDataProvider() throws Exception {
+        this(DEFAULT_CONFIG_URL, BusFactory.getThreadDefaultBus(true));
+    }
+
+    public JCacheOAuthDataProvider(String configFileURL, Bus bus) throws Exception {
+        this(configFileURL, bus, CLIENT_CACHE_KEY, ACCESS_TOKEN_CACHE_KEY, REFRESH_TOKEN_CACHE_KEY);
+    }
+
+    public JCacheOAuthDataProvider(String configFileURL,
+                                          Bus bus,
+                                          String clientCacheKey,
+                                          String accessTokenKey,
+                                          String refreshTokenKey) throws Exception {
+
+        cacheManager = createCacheManager(configFileURL, bus);
+        clientCache = createCache(cacheManager, clientCacheKey, String.class, Client.class);
+        accessTokenCache = createCache(cacheManager, accessTokenKey, String.class, ServerAccessToken.class);
+        refreshTokenCache = createCache(cacheManager, refreshTokenKey, String.class, RefreshToken.class);
+    }
+    
+    @Override
+    public Client getClient(String clientId) throws OAuthServiceException {
+        return clientCache.get(clientId);
+    }
+    
+    public void setClient(Client client) {
+        clientCache.put(client.getClientId(), client);
+    }
+    
+    @Override
+    protected void doRemoveClient(Client c) {
+        clientCache.remove(c.getClientId());
+    }
+
+    @Override
+    public List<Client> getClients(UserSubject resourceOwner) {
+        List<Client> clients = new ArrayList<>();
+        for (Iterator<Cache.Entry<String, Client>> it = clientCache.iterator(); it.hasNext();) {
+            Cache.Entry<String, Client> entry = it.next();
+            Client client = entry.getValue();
+
+            if (isClientMatched(client, resourceOwner)) {
+                clients.add(client);
+            }
+        }
+
+        return clients;
+    }
+
+    @Override
+    public List<ServerAccessToken> getAccessTokens(Client c, UserSubject sub) {
+        return getTokens(accessTokenCache, c, sub);
+    }
+
+    @Override
+    public List<RefreshToken> getRefreshTokens(Client c, UserSubject sub) {
+        return getTokens(refreshTokenCache, c, sub);
+    }
+    
+    @Override
+    public ServerAccessToken getAccessToken(String accessTokenKey) throws OAuthServiceException {
+        return getToken(accessTokenCache, accessTokenKey);
+    }
+
+    @Override
+    protected void doRevokeAccessToken(ServerAccessToken at) {
+        accessTokenCache.remove(at.getTokenKey());
+    }
+
+    @Override
+    protected RefreshToken getRefreshToken(String refreshTokenKey) {
+        return getToken(refreshTokenCache, refreshTokenKey);
+    }
+
+    @Override
+    protected void doRevokeRefreshToken(RefreshToken rt) { 
+        refreshTokenCache.remove(rt.getTokenKey());
+    }
+
+    @Override
+    protected void saveAccessToken(ServerAccessToken serverToken) {
+        accessTokenCache.put(serverToken.getTokenKey(), serverToken);
+    }
+
+    @Override
+    protected void saveRefreshToken(RefreshToken refreshToken) {
+        refreshTokenCache.put(refreshToken.getTokenKey(), refreshToken);
+    }
+
+    @Override
+    public void close() {
+        cacheManager.close();
+    }
+
+    protected static <K, V extends ServerAccessToken> V getToken(Cache<K, V> cache, K key) {
+        V token = cache.get(key);
+        if (token != null && isExpired(token)) {
+            cache.remove(key);
+            token = null;
+        }
+
+        return token;
+    }
+
+    protected static <K, V extends ServerAccessToken> List<V> getTokens(Cache<K, V> cache,
+                                                                      Client client, UserSubject sub) {
+        final Set<K> toRemove = new HashSet<>();
+        final List<V> tokens = new ArrayList<>();
+
+        for (Iterator<Cache.Entry<K, V>> it = cache.iterator(); it.hasNext();) {
+            Cache.Entry<K, V> entry = it.next();
+            V token = entry.getValue();
+
+            if (!isExpired(token)) {
+                toRemove.add(entry.getKey());
+            } else if (isTokenMatched(token, client, sub)) {
+                tokens.add(token);
+            }
+        }
+
+        cache.removeAll(toRemove);
+
+        return tokens;
+    }
+
+    protected static boolean isExpired(ServerAccessToken token) {
+        return System.currentTimeMillis() < (token.getIssuedAt() + token.getExpiresIn());
+    }
+
+    protected static CacheManager createCacheManager(String configFile, Bus bus) throws Exception {
+        if (bus == null) {
+            bus = BusFactory.getThreadDefaultBus(true);
+        }
+
+        CachingProvider provider = Caching.getCachingProvider();
+
+        URI configFileURI;
+        try {
+            configFileURI = getClasspathResourceURL(configFile, JCacheOAuthDataProvider.class, bus).toURI();
+        } catch (Exception ex) {
+            configFileURI = provider.getDefaultURI();
+        }
+
+        return provider.getCacheManager(configFileURI, Thread.currentThread().getContextClassLoader());
+    }
+    
+    protected static <K, V> Cache<K, V> createCache(CacheManager cacheManager,
+                                                    String cacheKey, Class<K> keyType, Class<V> valueType) {
+
+        Cache<K, V> cache = cacheManager.getCache(cacheKey, keyType, valueType);
+        if (cache == null) {
+            cache = cacheManager.createCache(
+                cacheKey,
+                new MutableConfiguration<K, V>()
+                    .setTypes(keyType, valueType)
+                    .setStoreByValue(true)
+                    .setStatisticsEnabled(false)
+            );
+        }
+
+        return cache;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/2b160783/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/grants/code/JCacheCodeDataProviderTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/grants/code/JCacheCodeDataProviderTest.java b/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/grants/code/JCacheCodeDataProviderTest.java
new file mode 100644
index 0000000..eb698b7
--- /dev/null
+++ b/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/grants/code/JCacheCodeDataProviderTest.java
@@ -0,0 +1,105 @@
+/**
+ * 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.oauth2.grants.code;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cxf.rs.security.oauth2.common.Client;
+import org.apache.cxf.rs.security.oauth2.common.UserSubject;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class JCacheCodeDataProviderTest extends Assert {
+    private JCacheCodeDataProvider provider;
+
+    @Before
+    public void setUp() throws Exception {
+        provider = new JCacheCodeDataProvider();
+    }
+
+    @Ignore
+    @Test
+    public void testAddGetDeleteCodeGrants() {
+        Client c = addClient("111", "bob");
+        
+        AuthorizationCodeRegistration atr = new AuthorizationCodeRegistration();
+        atr.setClient(c);
+        atr.setApprovedScope(Collections.singletonList("a"));
+        atr.setSubject(c.getResourceOwnerSubject());
+        
+        ServerAuthorizationCodeGrant grant = provider.createCodeGrant(atr);
+        
+        List<ServerAuthorizationCodeGrant> grants = provider.getCodeGrants(c, c.getResourceOwnerSubject());
+        assertNotNull(grants);
+        assertEquals(1, grants.size());
+        assertEquals(grant.getCode(), grants.get(0).getCode());
+        
+        grants = provider.getCodeGrants(c, null);
+        assertNotNull(grants);
+        assertEquals(1, grants.size());
+        assertEquals(grant.getCode(), grants.get(0).getCode());
+        
+        ServerAuthorizationCodeGrant grant2 = provider.removeCodeGrant(grant.getCode());
+        assertEquals(grant.getCode(), grant2.getCode());
+        
+        grants = provider.getCodeGrants(c, null);
+        assertNotNull(grants);
+        assertEquals(0, grants.size());
+    }
+
+    @Ignore
+    @Test
+    public void testAddGetDeleteCodeGrants2() {
+        Client c = addClient("111", "bob");
+        
+        AuthorizationCodeRegistration atr = new AuthorizationCodeRegistration();
+        atr.setClient(c);
+        atr.setApprovedScope(Collections.singletonList("a"));
+        atr.setSubject(c.getResourceOwnerSubject());
+        
+        provider.createCodeGrant(atr);
+        
+        List<ServerAuthorizationCodeGrant> grants = provider.getCodeGrants(c, c.getResourceOwnerSubject());
+        assertNotNull(grants);
+        assertEquals(1, grants.size());
+        provider.removeClient(c.getClientId());
+        grants = provider.getCodeGrants(c, c.getResourceOwnerSubject());
+        assertNotNull(grants);
+        assertEquals(0, grants.size());
+    }
+    
+    private Client addClient(String clientId, String userLogin) {
+        Client c = new Client();
+        c.setRedirectUris(Collections.singletonList("http://client/redirect"));
+        c.setClientId(clientId);
+        c.setResourceOwnerSubject(new UserSubject(userLogin));
+        provider.setClient(c);
+        return c;
+    }
+    @After
+    public void tearDown() throws Exception {
+        if (provider != null) {
+            provider.close();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/2b160783/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/provider/JCacheOAuthDataProviderTest.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/provider/JCacheOAuthDataProviderTest.java b/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/provider/JCacheOAuthDataProviderTest.java
new file mode 100644
index 0000000..2ed60ad
--- /dev/null
+++ b/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/provider/JCacheOAuthDataProviderTest.java
@@ -0,0 +1,217 @@
+/**
+ * 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.oauth2.provider;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cxf.rs.security.oauth2.common.AccessTokenRegistration;
+import org.apache.cxf.rs.security.oauth2.common.Client;
+import org.apache.cxf.rs.security.oauth2.common.OAuthPermission;
+import org.apache.cxf.rs.security.oauth2.common.ServerAccessToken;
+import org.apache.cxf.rs.security.oauth2.common.UserSubject;
+import org.apache.cxf.rs.security.oauth2.tokens.refresh.RefreshToken;
+import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class JCacheOAuthDataProviderTest extends Assert {
+    private JCacheOAuthDataProvider provider;
+
+    @Before
+    public void setUp() throws Exception {
+        provider = new JCacheOAuthDataProvider();
+    }
+
+    @Test
+    public void testAddGetDeleteClient() {
+        Client c = addClient("12345", "alice");
+        Client c2 = provider.getClient(c.getClientId());
+        compareClients(c, c2);
+        
+        c2.setClientSecret("567");
+        provider.setClient(c2);
+        Client c22 = provider.getClient(c.getClientId());
+        compareClients(c2, c22);
+        
+        provider.removeClient(c.getClientId());
+        Client c3 = provider.getClient(c.getClientId());
+        assertNull(c3);
+    }
+    
+    @Test
+    public void testAddGetDeleteClients() {
+        Client c = addClient("12345", "alice");
+        Client c2 = addClient("56789", "alice");
+        Client c3 = addClient("09876", "bob");
+        
+        List<Client> aliceClients = provider.getClients(new UserSubject("alice"));
+        assertNotNull(aliceClients);
+        assertEquals(2, aliceClients.size());
+        compareClients(c, aliceClients.get(0).getClientId().equals("12345") 
+                       ? aliceClients.get(0) : aliceClients.get(1));
+        compareClients(c2, aliceClients.get(0).getClientId().equals("56789") 
+                       ? aliceClients.get(0) : aliceClients.get(1));
+        
+        List<Client> bobClients = provider.getClients(new UserSubject("bob"));
+        assertNotNull(bobClients);
+        assertEquals(1, bobClients.size());
+        Client bobClient = bobClients.get(0);
+        compareClients(c3, bobClient);
+        
+        List<Client> allClients = provider.getClients(null);
+        assertNotNull(allClients);
+        assertEquals(3, allClients.size());
+        provider.removeClient(c.getClientId());
+        provider.removeClient(c2.getClientId());
+        provider.removeClient(c3.getClientId());
+        allClients = provider.getClients(null);
+        assertNotNull(allClients);
+        assertEquals(0, allClients.size());
+    }
+
+    @Ignore
+    @Test
+    public void testAddGetDeleteAccessToken() {
+        Client c = addClient("101", "bob");
+        
+        AccessTokenRegistration atr = new AccessTokenRegistration();
+        atr.setClient(c);
+        atr.setApprovedScope(Collections.singletonList("a"));
+        atr.setSubject(c.getResourceOwnerSubject());
+        
+        ServerAccessToken at = provider.createAccessToken(atr);
+        ServerAccessToken at2 = provider.getAccessToken(at.getTokenKey());
+        assertEquals(at.getTokenKey(), at2.getTokenKey());
+        List<OAuthPermission> scopes = at2.getScopes();
+        assertNotNull(scopes);
+        assertEquals(1, scopes.size());
+        OAuthPermission perm = scopes.get(0);
+        assertEquals("a", perm.getPermission());
+        
+        List<ServerAccessToken> tokens = provider.getAccessTokens(c, c.getResourceOwnerSubject());
+        assertNotNull(tokens);
+        assertEquals(1, tokens.size());
+        assertEquals(at.getTokenKey(), tokens.get(0).getTokenKey());
+        
+        tokens = provider.getAccessTokens(c, null);
+        assertNotNull(tokens);
+        assertEquals(1, tokens.size());
+        assertEquals(at.getTokenKey(), tokens.get(0).getTokenKey());
+        
+        tokens = provider.getAccessTokens(null, c.getResourceOwnerSubject());
+        assertNotNull(tokens);
+        assertEquals(1, tokens.size());
+        assertEquals(at.getTokenKey(), tokens.get(0).getTokenKey());
+        
+        tokens = provider.getAccessTokens(null, null);
+        assertNotNull(tokens);
+        assertEquals(1, tokens.size());
+        assertEquals(at.getTokenKey(), tokens.get(0).getTokenKey());
+        
+        provider.revokeToken(c, at.getTokenKey(), OAuthConstants.ACCESS_TOKEN);
+        assertNull(provider.getAccessToken(at.getTokenKey()));
+    }
+
+    @Ignore
+    @Test
+    public void testAddGetDeleteAccessToken2() {
+        Client c = addClient("102", "bob");
+        
+        AccessTokenRegistration atr = new AccessTokenRegistration();
+        atr.setClient(c);
+        atr.setApprovedScope(Collections.singletonList("a"));
+        atr.setSubject(c.getResourceOwnerSubject());
+        
+        provider.createAccessToken(atr);
+        List<ServerAccessToken> tokens = provider.getAccessTokens(c, null);
+        assertNotNull(tokens);
+        assertEquals(1, tokens.size());
+        
+        provider.removeClient(c.getClientId());
+        
+        tokens = provider.getAccessTokens(c, null);
+        assertNotNull(tokens);
+        assertEquals(0, tokens.size());
+    }
+
+    @Ignore
+    @Test
+    public void testAddGetDeleteRefreshToken() {
+        Client c = addClient("101", "bob");
+        
+        AccessTokenRegistration atr = new AccessTokenRegistration();
+        atr.setClient(c);
+        atr.setApprovedScope(Arrays.asList("a", "refreshToken"));
+        atr.setSubject(c.getResourceOwnerSubject());
+        
+        ServerAccessToken at = provider.createAccessToken(atr);
+        ServerAccessToken at2 = provider.getAccessToken(at.getTokenKey());
+        assertEquals(at.getTokenKey(), at2.getTokenKey());
+        List<OAuthPermission> scopes = at2.getScopes();
+        assertNotNull(scopes);
+        assertEquals(2, scopes.size());
+        OAuthPermission perm = scopes.get(0);
+        assertEquals("a", perm.getPermission());
+        OAuthPermission perm2 = scopes.get(1);
+        assertEquals("refreshToken", perm2.getPermission());
+        
+        RefreshToken rt = provider.getRefreshToken(at2.getRefreshToken());
+        assertNotNull(rt);
+        assertEquals(at2.getTokenKey(), rt.getAccessTokens().get(0));
+        
+        List<RefreshToken> tokens = provider.getRefreshTokens(c, c.getResourceOwnerSubject());
+        assertNotNull(tokens);
+        assertEquals(1, tokens.size());
+        assertEquals(rt.getTokenKey(), tokens.get(0).getTokenKey());
+        
+        provider.revokeToken(c, rt.getTokenKey(), OAuthConstants.REFRESH_TOKEN);
+        
+        assertNull(provider.getRefreshToken(rt.getTokenKey()));
+    }
+    
+    private Client addClient(String clientId, String userLogin) {
+        Client c = new Client();
+        c.setRedirectUris(Collections.singletonList("http://client/redirect"));
+        c.setClientId(clientId);
+        c.setClientSecret("123");
+        c.setResourceOwnerSubject(new UserSubject(userLogin));
+        provider.setClient(c);
+        return c;
+    }
+    private void compareClients(Client c, Client c2) {
+        assertNotNull(c2);
+        assertEquals(c.getClientId(), c2.getClientId());
+        assertEquals(1, c.getRedirectUris().size());
+        assertEquals(1, c2.getRedirectUris().size());
+        assertEquals("http://client/redirect", c.getRedirectUris().get(0));
+        assertEquals(c.getResourceOwnerSubject().getLogin(), c2.getResourceOwnerSubject().getLogin());
+    }
+    
+    @After
+    public void tearDown() throws Exception {
+        if (provider != null) {
+            provider.close();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/2b160783/rt/rs/security/oauth-parent/oauth2/src/test/resources/cxf-oauth2-ehcache3.xml
----------------------------------------------------------------------
diff --git a/rt/rs/security/oauth-parent/oauth2/src/test/resources/cxf-oauth2-ehcache3.xml b/rt/rs/security/oauth-parent/oauth2/src/test/resources/cxf-oauth2-ehcache3.xml
new file mode 100644
index 0000000..50ebfae
--- /dev/null
+++ b/rt/rs/security/oauth-parent/oauth2/src/test/resources/cxf-oauth2-ehcache3.xml
@@ -0,0 +1,27 @@
+<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.0.xsd">
+
+  <cache alias="cxf.oauth2.client.cache">
+    <key-type>java.lang.String</key-type>
+    <value-type>org.apache.cxf.rs.security.oauth2.common.Client</value-type>
+    <heap unit="entries">100</heap>
+    <jsr107:mbeans enable-management="false" enable-statistics="false"/>
+  </cache>
+  <cache alias="cxf.oauth2.accesstoken.cache">
+    <key-type>java.lang.String</key-type>
+    <value-type>org.apache.cxf.rs.security.oauth2.common.ServerAccessToken</value-type>
+    <heap unit="entries">100</heap>
+    <jsr107:mbeans enable-management="false" enable-statistics="false"/>
+  </cache>
+  <cache alias="cxf.oauth2.refreshtoken.cache">
+    <key-type>java.lang.String</key-type>
+    <value-type>org.apache.cxf.rs.security.oauth2.tokens.refresh.RefreshToken</value-type>
+    <heap unit="entries">100</heap>
+    <jsr107:mbeans enable-management="false" enable-statistics="false"/>
+  </cache>
+
+</config>
\ No newline at end of file