Author: angela
Date: Tue Apr 8 15:43:26 2014
New Revision: 1585763
URL: http://svn.apache.org/r1585763
Log:
OAK-1697 : Unresolved conflicts in TokenProviderImpl#createToken()
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=1585763&r1=1585762&r2=1585763&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
Tue Apr 8 15:43:26 2014
@@ -29,6 +29,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.UUID;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.jcr.AccessDeniedException;
@@ -210,11 +211,7 @@ class TokenProviderImpl implements Token
if (tokenParent != null) {
try {
long creationTime = new Date().getTime();
- Calendar creation = GregorianCalendar.getInstance();
- creation.setTimeInMillis(creationTime);
- String tokenName = Text.replace(ISO8601.format(creation), ":",
".");
-
- NodeUtil tokenNode = tokenParent.addChild(tokenName,
TOKEN_NT_NAME);
+ NodeUtil tokenNode = createTokenNode(tokenParent,
creationTime);
tokenNode.setString(JcrConstants.JCR_UUID,
IdentifierManager.generateUUID());
String key =
generateKey(options.getConfigValue(PARAM_TOKEN_LENGTH, DEFAULT_KEY_SIZE));
@@ -397,6 +394,31 @@ class TokenProviderImpl implements Token
return tokenParent;
}
+ /**
+ * Create a new token node below the specified {@code parent}.
+ *
+ * @param parent The parent node.
+ * @param creationTime The creation time that is used as name hint.
+ * @return The new token node
+ * @throws AccessDeniedException
+ */
+ private NodeUtil createTokenNode(@Nonnull NodeUtil parent, @Nonnull long
creationTime) throws AccessDeniedException {
+ Calendar creation = GregorianCalendar.getInstance();
+ creation.setTimeInMillis(creationTime);
+ String tokenName = Text.replace(ISO8601.format(creation), ":", ".");
+ NodeUtil tokenNode;
+ try {
+ tokenNode = parent.addChild(tokenName, TOKEN_NT_NAME);
+ root.commit();
+ } catch (CommitFailedException e) {
+ // conflict while creating token node -> retry
+ log.debug("Failed to create token node " + tokenName + ". Using
random name as fallback.");
+ root.refresh();
+ tokenNode = parent.addChild(UUID.randomUUID().toString(),
TOKEN_NT_NAME);
+ }
+ return tokenNode;
+ }
+
//--------------------------------------------------------------------------
/**
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=1585763&r1=1585762&r2=1585763&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
Tue Apr 8 15:43:26 2014
@@ -23,6 +23,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import javax.jcr.AccessDeniedException;
import javax.jcr.Credentials;
import javax.jcr.GuestCredentials;
@@ -30,11 +34,14 @@ import javax.jcr.SimpleCredentials;
import org.apache.jackrabbit.JcrConstants;
import
org.apache.jackrabbit.api.security.authentication.token.TokenCredentials;
+import org.apache.jackrabbit.oak.api.ContentSession;
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.plugins.identifier.IdentifierManager;
import
org.apache.jackrabbit.oak.spi.security.authentication.ImpersonationCredentials;
+import
org.apache.jackrabbit.oak.spi.security.authentication.token.TokenConfiguration;
import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenInfo;
import
org.apache.jackrabbit.oak.spi.security.authentication.token.TokenProvider;
import org.apache.jackrabbit.oak.util.NodeUtil;
@@ -308,6 +315,51 @@ public class TokenProviderImplTest exten
}
}
+ /**
+ *@see <a
href="https://issues.apache.org/jira/browse/OAK-1697">OAK-1697</a>
+ */
+ @Test
+ public void testValidTokenCredentialsWithConflict() throws Exception {
+ ExecutorService pool = Executors.newFixedThreadPool(10);
+ List<ContentSession> sessions = new ArrayList<ContentSession>();
+
+ try {
+ TokenConfiguration tc = getSecurityProvider().getConfiguration(
+ TokenConfiguration.class);
+ SimpleCredentials sc = (SimpleCredentials) getAdminCredentials();
+
+ List<TokenProvider> tokenProviders = new
ArrayList<TokenProvider>();
+
+ for (int i = 0; i < 10; i++) {
+ ContentSession session = login(getAdminCredentials());
+ Root r = session.getLatestRoot();
+ tokenProviders.add(tc.getTokenProvider(r));
+ sessions.add(session);
+ }
+
+ ArrayList<DataFuture> list = new ArrayList<DataFuture>();
+
+ for (TokenProvider tokenProvider : tokenProviders) {
+ list.add(createDataFuture(pool, tokenProvider, sc.getUserID(),
+ Collections.<String, Object> emptyMap()));
+ }
+
+ for (DataFuture df : list) {
+ assertNotNull(df.future.get());
+ }
+ } finally {
+ for (ContentSession session : sessions) {
+ if (session != null) {
+ session.close();
+ }
+ }
+
+ if (pool != null) {
+ pool.shutdown();
+ }
+ }
+ }
+
//--------------------------------------------------------------------------
private static void assertTokenInfo(TokenInfo info, String userId) {
assertNotNull(info);
@@ -330,4 +382,23 @@ public class TokenProviderImplTest exten
tree.setProperty(tokenTree.getProperty("rep:token.key"));
tree.setProperty(tokenTree.getProperty("rep:token.exp"));
}
+
+ private static class DataFuture {
+ public Future<TokenInfo> future;
+
+ public DataFuture(Future<TokenInfo> future) {
+ super();
+ this.future = future;
+ }
+ }
+
+ private DataFuture createDataFuture(ExecutorService pool , final
TokenProvider tp,final String userId, final Map<String, ?> attributes){
+ Future<TokenInfo> future = pool.submit(new Callable<TokenInfo>() {
+ @Override
+ public TokenInfo call() throws Exception {
+ return tp.createToken(userId, attributes);
+ }
+ });
+ return new DataFuture(future);
+ }
}
\ No newline at end of file