[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 <sberyoz...@gmail.com> Authored: Fri May 20 09:49:59 2016 +0100 Committer: Sergey Beryozkin <sberyoz...@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