Author: angela Date: Wed Aug 22 12:47:14 2012 New Revision: 1376023 URL: http://svn.apache.org/viewvc?rev=1376023&view=rev Log: OAK-50 : Implement User Management (WIP)
Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserProviderImplTest.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserConstants.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserConstants.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserConstants.java?rev=1376023&r1=1376022&r2=1376023&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserConstants.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserConstants.java Wed Aug 22 12:47:14 2012 @@ -33,7 +33,8 @@ public interface UserConstants { String REP_MEMBERS = "rep:members"; String REP_IMPERSONATORS = "rep:impersonators"; - String DEFAULT_USER_PATH = "rep:security/rep:authorizables/rep:users"; - String DEFAULT_GROUP_PATH = "rep:security/rep:authorizables/rep:groups"; + String DEFAULT_USER_PATH = "/rep:security/rep:authorizables/rep:users"; + String DEFAULT_GROUP_PATH = "/rep:security/rep:authorizables/rep:groups"; + int DEFAULT_DEPTH = 2; } \ No newline at end of file Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserProviderImplTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserProviderImplTest.java?rev=1376023&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserProviderImplTest.java (added) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserProviderImplTest.java Wed Aug 22 12:47:14 2012 @@ -0,0 +1,371 @@ +/* + * 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.jackrabbit.oak.security.user; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.jcr.RepositoryException; + +import org.apache.jackrabbit.api.security.user.UserManager; +import org.apache.jackrabbit.oak.AbstractOakTest; +import org.apache.jackrabbit.oak.api.CommitFailedException; +import org.apache.jackrabbit.oak.api.ContentRepository; +import org.apache.jackrabbit.oak.api.ContentSession; +import org.apache.jackrabbit.oak.api.Root; +import org.apache.jackrabbit.oak.api.Tree; +import org.apache.jackrabbit.oak.core.DefaultConflictHandler; +import org.apache.jackrabbit.oak.spi.security.user.UserConfig; +import org.apache.jackrabbit.oak.spi.security.user.UserConstants; +import org.apache.jackrabbit.oak.spi.security.user.UserProvider; +import org.apache.jackrabbit.oak.spi.security.user.action.AuthorizableAction; +import org.apache.jackrabbit.util.Text; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * UserProviderImplTest... + * + * TODO: create tests with custom config that persists changes (currently fails since config used in UserValidator is different) + * TODO: add tests for setProtectedProperty (might still be refactored...) + */ +public class UserProviderImplTest extends AbstractOakTest { + + private ContentSession contentSession; + private Root root; + + private UserConfig defaultConfig; + private String defaultUserPath; + private String defaultGroupPath; + + private Map<String, Object> customOptions; + private String customUserPath = "/home/users"; + private String customGroupPath = "/home/groups"; + + private List<String> cleanupPaths = new ArrayList<String>(); + + @Before + public void setUp() throws Exception { + contentSession = createAdminSession(); + root = contentSession.getCurrentRoot(); + + defaultConfig = new UserConfig("admin"); + defaultUserPath = defaultConfig.getConfigValue(UserConfig.PARAM_USER_PATH, UserConstants.DEFAULT_USER_PATH); + defaultGroupPath = defaultConfig.getConfigValue(UserConfig.PARAM_GROUP_PATH, UserConstants.DEFAULT_GROUP_PATH); + + customOptions = new HashMap<String, Object>(); + customOptions.put(UserConfig.PARAM_GROUP_PATH, customGroupPath); + customOptions.put(UserConfig.PARAM_USER_PATH, customUserPath); + + cleanupPaths.add(defaultUserPath); + cleanupPaths.add(defaultGroupPath); + cleanupPaths.add(customUserPath); + cleanupPaths.add(customGroupPath); + + } + + @After + public void tearDown() throws Exception { + for (String path : cleanupPaths) { + Tree t = root.getTree(path); + if (t != null) { + t.remove(); + } + } + } + + @Override + protected ContentRepository createRepository() { + return createEmptyRepository(); + } + + private UserProvider createUserProvider() { + return new UserProviderImpl(contentSession, root, defaultConfig); + } + + private UserProvider createUserProvider(int defaultDepth) { + Map<String, Object> options = new HashMap<String, Object>(customOptions); + options.put(UserConfig.PARAM_DEFAULT_DEPTH, defaultDepth); + return new UserProviderImpl(contentSession, root, new UserConfig("admin", options, Collections.<AuthorizableAction>emptySet())); + } + + @Test + public void testCreateUser() throws Exception { + UserProvider up = createUserProvider(); + + // create test user + Tree userTree = up.createUser("user1", null); + + assertNotNull(userTree); + assertTrue(Text.isDescendant(defaultUserPath, userTree.getPath())); + int level = defaultConfig.getConfigValue(UserConfig.PARAM_DEFAULT_DEPTH, UserConstants.DEFAULT_DEPTH) + 1; + assertEquals(defaultUserPath, Text.getRelativeParent(userTree.getPath(), level)); + + // make sure all users are created in a structure with default depth + userTree = up.createUser("b", null); + assertEquals(defaultUserPath + "/b/bb/b", userTree.getPath()); + + Map<String, String> m = new HashMap<String,String>(); + m.put("bb", "/b/bb/bb"); + m.put("bbb", "/b/bb/bbb"); + m.put("bbbb", "/b/bb/bbbb"); + m.put("bh", "/b/bh/bh"); + m.put("bHbh", "/b/bH/bHbh"); + m.put("b_Hb", "/b/b_/b_Hb"); + m.put("basim", "/b/ba/basim"); + + for (String uid : m.keySet()) { + userTree = up.createUser(uid, null); + assertEquals(defaultUserPath + m.get(uid), userTree.getPath()); + } + } + + @Test + public void testCreateUserWithPath() throws Exception { + UserProvider up = createUserProvider(1); + + // create test user + Tree userTree = up.createUser("nadine", "a/b/c"); + assertNotNull(userTree); + assertTrue(Text.isDescendant(customUserPath, userTree.getPath())); + String userPath = customUserPath + "/a/b/c/nadine"; + assertEquals(userPath, userTree.getPath()); + } + + @Test + public void testCreateGroup() throws RepositoryException { + UserProvider up = createUserProvider(); + + Tree groupTree = up.createGroup("group1", null); + + assertNotNull(groupTree); + assertTrue(Text.isDescendant(defaultGroupPath, groupTree.getPath())); + + int level = defaultConfig.getConfigValue(UserConfig.PARAM_DEFAULT_DEPTH, UserConstants.DEFAULT_DEPTH) + 1; + assertEquals(defaultGroupPath, Text.getRelativeParent(groupTree.getPath(), level)); + } + + @Test + public void testCreateGroupWithPath() throws Exception { + UserProvider up = createUserProvider(4); + + // create test user + Tree group = up.createGroup("authors", "a/b/c"); + assertNotNull(group); + assertTrue(Text.isDescendant(customGroupPath, group.getPath())); + String groupPath = customGroupPath + "/a/b/c/authors"; + assertEquals(groupPath, group.getPath()); + } + + @Test + public void testCreateWithCustomDepth() throws Exception { + UserProvider userProvider = createUserProvider(3); + + Tree userTree = userProvider.createUser("b", null); + assertEquals(customUserPath + "/b/bb/bbb/b", userTree.getPath()); + + Map<String, String> m = new HashMap<String,String>(); + m.put("bb", "/b/bb/bbb/bb"); + m.put("bbb", "/b/bb/bbb/bbb"); + m.put("bbbb", "/b/bb/bbb/bbbb"); + m.put("bL", "/b/bL/bLL/bL"); + m.put("bLbh", "/b/bL/bLb/bLbh"); + m.put("b_Lb", "/b/b_/b_L/b_Lb"); + m.put("basiL", "/b/ba/bas/basiL"); + + for (String uid : m.keySet()) { + userTree = userProvider.createUser(uid, null); + assertEquals(customUserPath + m.get(uid), userTree.getPath()); + } + } + + @Ignore("OAK-270: UUID collisions are not yet detected upon commit.") + @Test + public void testCreateWithCollision() throws Exception { + UserProvider userProvider = createUserProvider(); + + Tree userTree = userProvider.createUser("AmaLia", null); + + Map<String, String> colliding = new HashMap<String, String>(); + colliding.put("AmaLia", null); + colliding.put("AmaLia", "s/ome/path"); + colliding.put("amalia", null); + colliding.put("Amalia", "a/b/c"); + + for (String uid : colliding.keySet()) { + try { + Tree c = userProvider.createUser(uid, colliding.get(uid)); + root.commit(DefaultConflictHandler.OURS); + fail("userID collision must be detected"); + } catch (CommitFailedException e) { + // success + } + } + + for (String uid : colliding.keySet()) { + try { + Tree c = userProvider.createGroup(uid, colliding.get(uid)); + root.commit(DefaultConflictHandler.OURS); + fail("userID collision must be detected"); + } catch (CommitFailedException e) { + // success + } + } + } + + @Test + public void testIllegalChars() throws Exception { + UserProvider userProvider = createUserProvider(); + + Map<String, String> m = new HashMap<String, String>(); + m.put("z[x]", "/z/" + Text.escapeIllegalJcrChars("z[") + '/' + Text.escapeIllegalJcrChars("z[x]")); + m.put("z*x", "/z/" + Text.escapeIllegalJcrChars("z*") + '/' + Text.escapeIllegalJcrChars("z*x")); + m.put("z/x", "/z/" + Text.escapeIllegalJcrChars("z/") + '/' + Text.escapeIllegalJcrChars("z/x")); + m.put("%\r|", '/' +Text.escapeIllegalJcrChars("%")+ '/' + Text.escapeIllegalJcrChars("%\r") + '/' + Text.escapeIllegalJcrChars("%\r|")); + + for (String uid : m.keySet()) { + Tree user = userProvider.createUser(uid, null); + root.commit(DefaultConflictHandler.OURS); + + assertEquals(defaultUserPath + m.get(uid), user.getPath()); + assertEquals(uid, userProvider.getAuthorizableId(user)); + + Tree ath = userProvider.getAuthorizable(uid); + assertNotNull("Tree with id " + uid + " must exist.", ath); + } + } + + @Test + public void testGetAuthorizable() throws Exception { + UserProvider up = createUserProvider(); + + String userID = "hannah"; + String groupID = "cLevel"; + + Tree user = up.createUser(userID, null); + Tree group = up.createGroup(groupID, null); + root.commit(DefaultConflictHandler.OURS); + + Tree a = up.getAuthorizable(userID); + assertNotNull(a); + assertEquals(user.getPath(), a.getPath()); + + a = up.getAuthorizable(groupID); + assertNotNull(a); + assertEquals(group.getPath(), a.getPath()); + } + + @Test + public void testGetAuthorizableWithType() throws Exception { + UserProvider up = createUserProvider(); + + String userID = "thabit"; + Tree user = up.createUser(userID, null); + root.commit(DefaultConflictHandler.OURS); + + Tree a = up.getAuthorizable(userID, UserManager.SEARCH_TYPE_USER); + assertNotNull(a); + assertEquals(user.getPath(), a.getPath()); + + assertNotNull(up.getAuthorizable(userID, UserManager.SEARCH_TYPE_AUTHORIZABLE)); + assertNull(up.getAuthorizable(userID, UserManager.SEARCH_TYPE_GROUP)); + + String groupID = "hr"; + Tree group = up.createGroup(groupID, null); + root.commit(DefaultConflictHandler.OURS); + + Tree g = up.getAuthorizable(groupID, UserManager.SEARCH_TYPE_GROUP); + assertNotNull(a); + assertEquals(user.getPath(), a.getPath()); + + assertNotNull(up.getAuthorizable(groupID, UserManager.SEARCH_TYPE_AUTHORIZABLE)); + assertNull(up.getAuthorizable(groupID, UserManager.SEARCH_TYPE_USER)); + } + + @Test + public void testGetAuthorizableByPath() throws Exception { + UserProvider up = createUserProvider(); + + Tree user = up.createUser("shams", null); + Tree a = up.getAuthorizableByPath(user.getPath()); + assertNotNull(a); + assertEquals(user, a); + + Tree group = up.createGroup("devs", null); + a = up.getAuthorizableByPath(group.getPath()); + assertNotNull(a); + assertEquals(group, a); + } + + @Test + public void testIsAdminUser() throws Exception { + UserProvider userProvider = createUserProvider(); + + Tree adminTree = userProvider.createUser(defaultConfig.getAdminId(), null); + userProvider.isAdminUser(adminTree); + + List<Tree> others = new ArrayList<Tree>(); + others.add(userProvider.createUser("laura", null)); + others.add(userProvider.createGroup("administrators", null)); + + for (Tree other : others) { + assertFalse(userProvider.isAdminUser(other)); + } + } + + @Test + public void testGetAuthorizableId() throws Exception { + UserProvider up = createUserProvider(); + + String userID = "Amanda"; + Tree user = up.createUser(userID, null); + assertEquals(userID, up.getAuthorizableId(user)); + + String groupID = "visitors"; + Tree group = up.createGroup(groupID, null); + assertEquals(groupID, up.getAuthorizableId(group)); + } + + @Test + public void testRemoveParentTree() throws Exception { + UserProvider up = createUserProvider(); + Tree u1 = up.createUser("b", "b"); + Tree u2 = up.createUser("bb", "bb"); + + Tree folder = root.getTree(Text.getRelativeParent(u1.getPath(), 2)); + folder.remove(); + if (up.getAuthorizable("b") != null) { + fail("Removing the top authorizable folder must remove all users contained."); + u1.remove(); + } + if (up.getAuthorizable("bb") != null) { + fail("Removing the top authorizable folder must remove all users contained."); + u2.remove(); + } + } +}