Author: angela Date: Wed Oct 31 18:12:37 2012 New Revision: 1404278 URL: http://svn.apache.org/viewvc?rev=1404278&view=rev Log: OAK-91 - Implement Authentication Support (WIP)
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImplTest.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java?rev=1404278&r1=1404277&r2=1404278&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImpl.java Wed Oct 31 18:12:37 2012 @@ -26,7 +26,9 @@ import java.util.Collections; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import javax.jcr.Credentials; @@ -98,6 +100,13 @@ public class TokenProviderImpl implement private static final int DEFAULT_KEY_SIZE = 8; private static final char DELIM = '_'; + private static final Set<String> RESERVED_ATTRIBUTES = new HashSet(2); + static { + RESERVED_ATTRIBUTES.add(TOKEN_ATTRIBUTE); + RESERVED_ATTRIBUTES.add(TOKEN_ATTRIBUTE_EXPIRY); + RESERVED_ATTRIBUTES.add(TOKEN_ATTRIBUTE_KEY); + } + private final Root root; private final ConfigurationParameters options; @@ -174,14 +183,13 @@ public class TokenProviderImpl implement tokenNode.setDate(TOKEN_ATTRIBUTE_EXPIRY, expirationTime); for (String name : attributes.keySet()) { - if (!TOKEN_ATTRIBUTE.equals(name)) { + if (!RESERVED_ATTRIBUTES.contains(name)) { String attr = attributes.get(name).toString(); tokenNode.setString(name, attr); } } root.commit(); - return new TokenInfoImpl(tokenNode, token, userId); } else { log.debug("Cannot create login token: No corresponding node for User " + userId + '.'); @@ -203,8 +211,8 @@ public class TokenProviderImpl implement @Override public TokenInfo getTokenInfo(String token) { int pos = token.indexOf(DELIM); - String tokenPath = (pos == -1) ? token : token.substring(0, pos); - Tree tokenTree = root.getTree(tokenPath); + String nodeId = (pos == -1) ? token : token.substring(0, pos); + Tree tokenTree = identifierManager.getTree(nodeId); String userId = getUserId(tokenTree); if (tokenTree == null || userId == null) { return null; @@ -343,7 +351,7 @@ public class TokenProviderImpl implement for (PropertyState propertyState : tokenNode.getTree().getProperties()) { String name = propertyState.getName(); String value = propertyState.getValue(STRING); - if (TOKEN_ATTRIBUTE_KEY.equals(name) || TOKEN_ATTRIBUTE_EXPIRY.equals(name)) { + if (RESERVED_ATTRIBUTES.contains(name)) { continue; } if (isMandatoryAttribute(name)) { Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImplTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImplTest.java?rev=1404278&r1=1404277&r2=1404278&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImplTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/token/TokenProviderImplTest.java Wed Oct 31 18:12:37 2012 @@ -16,16 +16,38 @@ */ package org.apache.jackrabbit.oak.security.authentication.token; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import javax.annotation.Nonnull; +import javax.jcr.Credentials; import javax.jcr.GuestCredentials; import javax.jcr.SimpleCredentials; import org.apache.jackrabbit.api.security.authentication.token.TokenCredentials; +import org.apache.jackrabbit.api.security.user.Authorizable; +import org.apache.jackrabbit.api.security.user.UserManager; +import org.apache.jackrabbit.oak.api.PropertyState; +import org.apache.jackrabbit.oak.api.Root; +import org.apache.jackrabbit.oak.api.Tree; +import org.apache.jackrabbit.oak.api.Type; +import org.apache.jackrabbit.oak.namepath.NamePathMapper; import org.apache.jackrabbit.oak.security.AbstractSecurityTest; import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; +import org.apache.jackrabbit.oak.spi.security.authentication.ImpersonationCredentials; +import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenInfo; +import org.junit.After; import org.junit.Before; import org.junit.Test; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; /** @@ -33,15 +55,39 @@ import static org.junit.Assert.assertTru */ public class TokenProviderImplTest extends AbstractSecurityTest { + private Root root; private TokenProviderImpl tokenProvider; + private String userId; + private UserManager userManager; + @Before public void before() throws Exception { super.before(); - tokenProvider = new TokenProviderImpl(admin.getLatestRoot(), + root = admin.getLatestRoot(); + tokenProvider = new TokenProviderImpl(root, ConfigurationParameters.EMPTY, getSecurityProvider().getUserConfiguration()); + + userId = "testUser"; + userManager = getSecurityProvider().getUserConfiguration().getUserManager(root, NamePathMapper.DEFAULT); + + userManager.createUser(userId, "pw"); + root.commit(); + } + + @After + public void after() throws Exception { + try { + Authorizable a = userManager.getAuthorizable(userId); + if (a != null) { + a.remove(); + root.commit(); + } + } finally { + super.after(); + } } @@ -68,27 +114,245 @@ public class TokenProviderImplTest exten } @Test + public void testCreateTokenFromInvalidCredentials() throws Exception { + List<Credentials> invalid = new ArrayList<Credentials>(); + invalid.add(new GuestCredentials()); + invalid.add(new TokenCredentials("sometoken")); + invalid.add(new ImpersonationCredentials(new GuestCredentials(), null)); + invalid.add(new SimpleCredentials("unknownUserId", new char[0])); + + for (Credentials creds : invalid) { + assertNull(tokenProvider.createToken(creds)); + } + } + + @Test public void testCreateTokenFromCredentials() throws Exception { - // TODO + SimpleCredentials sc = new SimpleCredentials(userId, new char[0]); + List<Credentials> valid = new ArrayList<Credentials>(); + valid.add(sc); + valid.add(new ImpersonationCredentials(sc, null)); + + for (Credentials creds : valid) { + TokenInfo info = tokenProvider.createToken(creds); + assertTokenInfo(info, userId); + } + } + + @Test + public void testCreateTokenFromInvalidUserId() throws Exception { + TokenInfo info = tokenProvider.createToken("unknownUserId", Collections.<String, Object>emptyMap()); + assertNull(info); } @Test public void testCreateTokenFromUserId() throws Exception { - // TODO + TokenInfo info = tokenProvider.createToken(userId, Collections.<String, Object>emptyMap()); + assertTokenInfo(info, userId); + } + + @Test + public void testCreateTokenWithAttributes() throws Exception { + Map<String, String> reserved = new HashMap<String, String>(); + reserved.put(".token", "value"); + reserved.put(".token.key", "value"); + reserved.put(".token.exp", "value"); + + Map<String, String> privateAttributes = new HashMap<String, String>(); + privateAttributes.put(".token_exp", "value"); + privateAttributes.put(".tokenTest", "value"); + privateAttributes.put(".token_something", "value"); + + Map<String, String> publicAttributes = new HashMap<String, String>(); + publicAttributes.put("any", "value"); + publicAttributes.put("another", "value"); + + Map<String, String> attributes = new HashMap<String, String>(); + attributes.putAll(reserved); + attributes.putAll(publicAttributes); + attributes.putAll(privateAttributes); + + TokenInfo info = tokenProvider.createToken(userId, attributes); + assertTokenInfo(info, userId); + + Map<String,String> pubAttr = info.getPublicAttributes(); + assertEquals(publicAttributes.size(), pubAttr.size()); + for (String key : publicAttributes.keySet()) { + assertTrue(pubAttr.containsKey(key)); + assertEquals(publicAttributes.get(key), pubAttr.get(key)); + } + + Map<String,String> privAttr = info.getPrivateAttributes(); + assertEquals(privateAttributes.size(), privAttr.size()); + for (String key : privateAttributes.keySet()) { + assertTrue(privAttr.containsKey(key)); + assertEquals(privateAttributes.get(key), privAttr.get(key)); + } + + for (String key : reserved.keySet()) { + assertFalse(privAttr.containsKey(key)); + assertFalse(pubAttr.containsKey(key)); + } + } + + @Test + public void testTokenNode() throws Exception { + Map<String, String> reserved = new HashMap<String, String>(); + reserved.put(".token", "value"); + reserved.put(".token.key", "value"); + reserved.put(".token.exp", "value"); + + Map<String, String> privateAttributes = new HashMap<String, String>(); + privateAttributes.put(".token_exp", "value"); + privateAttributes.put(".tokenTest", "value"); + privateAttributes.put(".token_something", "value"); + + Map<String, String> publicAttributes = new HashMap<String, String>(); + publicAttributes.put("any", "value"); + publicAttributes.put("another", "value"); + + Map<String, String> attributes = new HashMap<String, String>(); + attributes.putAll(reserved); + attributes.putAll(publicAttributes); + attributes.putAll(privateAttributes); + + TokenInfo info = tokenProvider.createToken(userId, attributes); + + Tree userTree = root.getTree(userManager.getAuthorizable(userId).getPath()); + Tree tokens = userTree.getChild(".tokens"); + assertNotNull(tokens); + assertEquals(1, tokens.getChildrenCount()); + + Tree tokenNode = tokens.getChildren().iterator().next(); + assertNotNull(tokenNode.getProperty(".token.key")); + assertNotNull(tokenNode.getProperty(".token.exp")); + + for (String key : reserved.keySet()) { + PropertyState p = tokenNode.getProperty(key); + if (p != null) { + assertFalse(reserved.get(key).equals(p.getValue(Type.STRING))); + } + } + + for (String key : privateAttributes.keySet()) { + assertEquals(privateAttributes.get(key), tokenNode.getProperty(key).getValue(Type.STRING)); + } + + for (String key : publicAttributes.keySet()) { + assertEquals(publicAttributes.get(key), tokenNode.getProperty(key).getValue(Type.STRING)); + } + } + + @Test + public void testGetTokenInfoFromInvalidToken() throws Exception { + List<String> invalid = new ArrayList<String>(); + invalid.add("/invalid"); + invalid.add(UUID.randomUUID().toString()); + + for (String token : invalid) { + TokenInfo info = tokenProvider.getTokenInfo(token); + assertNull(info); + } + + try { + assertNull(tokenProvider.getTokenInfo("invalidToken")); + } catch (Exception e) { + // success + } } @Test public void testGetTokenInfo() throws Exception { - // TODO + String token = tokenProvider.createToken(userId, Collections.<String, Object>emptyMap()).getToken(); + TokenInfo info = tokenProvider.getTokenInfo(token); + assertTokenInfo(info, userId); + } + + @Test + public void testRemoveTokenInvalidInfo() throws Exception { + assertFalse(tokenProvider.removeToken(new InvalidTokenInfo())); } @Test public void testRemoveToken() throws Exception { - // TODO + TokenInfo info = tokenProvider.createToken(userId, Collections.<String, Object>emptyMap()); + assertTrue(tokenProvider.removeToken(info)); + } + + @Test + public void testRemoveToken2() throws Exception { + TokenInfo info = tokenProvider.createToken(userId, Collections.<String, Object>emptyMap()); + assertTrue(tokenProvider.removeToken(tokenProvider.getTokenInfo(info.getToken()))); + } + + @Test + public void testRemoveTokenRemovesNode() throws Exception { + TokenInfo info = tokenProvider.createToken(userId, Collections.<String, Object>emptyMap()); + + Tree userTree = root.getTree(userManager.getAuthorizable(userId).getPath()); + Tree tokens = userTree.getChild(".tokens"); + String tokenNodePath = tokens.getChildren().iterator().next().getPath(); + + tokenProvider.removeToken(info); + assertNull(root.getTree(tokenNodePath)); + } + + @Test + public void testResetTokenExpirationInvalidToken() throws Exception { + assertFalse(tokenProvider.resetTokenExpiration(new InvalidTokenInfo(), new Date().getTime())); } @Test public void testResetTokenExpiration() throws Exception { - // TODO + TokenInfo info = tokenProvider.createToken(userId, Collections.<String, Object>emptyMap()); + + assertFalse(tokenProvider.resetTokenExpiration(info, new Date().getTime())); + + long loginTime = new Date().getTime() + 3600000; + assertFalse(info.isExpired(loginTime)); + assertTrue(tokenProvider.resetTokenExpiration(info, loginTime)); + + long expiredTime = new Date().getTime() + 7200000; + assertTrue(info.isExpired(expiredTime)); + assertTrue(tokenProvider.resetTokenExpiration(info, expiredTime)); + } + + //-------------------------------------------------------------------------- + private static void assertTokenInfo(TokenInfo info, String userId) { + assertNotNull(info); + assertNotNull(info.getToken()); + assertEquals(userId, info.getUserId()); + assertFalse(info.isExpired(new Date().getTime())); + } + + private final class InvalidTokenInfo implements TokenInfo { + @Nonnull + @Override + public String getUserId() { + return "invalid"; + } + @Nonnull + @Override + public String getToken() { + return "invalid"; + } + @Override + public boolean isExpired(long loginTime) { + return true; + } + @Override + public boolean matches(TokenCredentials tokenCredentials) { + return false; + } + @Nonnull + @Override + public Map<String, String> getPrivateAttributes() { + return null; + } + @Nonnull + @Override + public Map<String, String> getPublicAttributes() { + return null; + } } } \ No newline at end of file