/* * 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.core.security.user; import org.apache.commons.collections.map.ListOrderedMap; import org.apache.jackrabbit.api.security.user.AbstractUserTest; import org.apache.jackrabbit.api.security.user.Authorizable; import org.apache.jackrabbit.api.security.user.AuthorizableExistsException; import org.apache.jackrabbit.api.security.user.User; import org.apache.jackrabbit.core.NodeImpl; import org.apache.jackrabbit.core.RepositoryImpl; import org.apache.jackrabbit.core.SessionImpl; import org.apache.jackrabbit.core.security.TestPrincipal; import org.apache.jackrabbit.test.NotExecutableException; import org.apache.jackrabbit.util.Text; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jcr.RepositoryException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; /** * <code>NodeCreationTest</code>... */ public class NodeCreationTest extends AbstractUserTest { /** * logger instance */ private static final Logger log = LoggerFactory.getLogger(NodeCreationTest.class); private SessionImpl s; private UserManagerImpl uMgr; private final List<NodeImpl> toRemove = new ArrayList(); private String usersPath; private String groupsPath; @Override protected void setUp() throws Exception { super.setUp(); String workspaceName = ((RepositoryImpl) superuser.getRepository()).getConfig().getSecurityConfig().getSecurityManagerConfig().getWorkspaceName(); s = (SessionImpl) ((SessionImpl) superuser).createSession(workspaceName); usersPath = ((UserManagerImpl) userMgr).getUsersPath(); groupsPath = ((UserManagerImpl) userMgr).getGroupsPath(); } @Override protected void tearDown() throws Exception { try { for (NodeImpl node : toRemove) { uMgr.removeProtectedItem(node, (NodeImpl) node.getParent()); save(s); } } finally { s.logout(); } super.tearDown(); } private void createUserManager(int depth, boolean expandTree, long size) throws RepositoryException { Properties props = new Properties(); props.put(UserManagerImpl.PARAM_DEFAULT_DEPTH, depth); props.put(UserManagerImpl.PARAM_AUTO_EXPAND_TREE, expandTree); props.put(UserManagerImpl.PARAM_AUTO_EXPAND_SIZE, size); props.put(UserManagerImpl.PARAM_GROUPS_PATH, groupsPath); props.put(UserManagerImpl.PARAM_USERS_PATH, usersPath); uMgr = new UserManagerImpl(s, "admin", props); } public void testRemoveTree() throws RepositoryException, NotExecutableException { UserImpl u = (UserImpl) userMgr.createUser("z", "z"); save(superuser); UserImpl u2 = (UserImpl) userMgr.createUser("zz", "zz"); save(superuser); assertEquals(usersPath + "/z/zz/z", u.getNode().getPath()); try { NodeImpl folder = (NodeImpl) u.getNode().getParent().getParent(); ((UserManagerImpl) userMgr).removeProtectedItem(folder, (NodeImpl) folder.getParent()); save(superuser); } finally { boolean fail = false; if (userMgr.getAuthorizable("z") != null) { fail = true; u.remove(); save(superuser); } if (userMgr.getAuthorizable("zz") != null) { fail = true; u2.remove(); save(superuser); } if (fail) { fail("Removing the top authorizable folder must remove all users contained."); } } } /** * If auto-expand is false all users must be created on the second level. */ public void testDefault() throws RepositoryException, NotExecutableException { createUserManager(2, false, 1); UserImpl u = (UserImpl) uMgr.createUser("z", "z"); save(s); // remember the z-folder for later removal toRemove.add((NodeImpl) u.getNode().getParent().getParent()); assertEquals(usersPath + "/z/zz/z", u.getNode().getPath()); Map<String, String> m = new ListOrderedMap(); m.put("zz", "/z/zz/zz"); m.put("zzz", "/z/zz/zzz"); m.put("zzzz", "/z/zz/zzzz"); m.put("zh", "/z/zh/zh"); m.put("zHzh", "/z/zH/zHzh"); m.put("z_Hz", "/z/z_/z_Hz"); m.put("z\u00cfrich", "/z/z\u00cf/z\u00cfrich"); for (String uid : m.keySet()) { u = (UserImpl) uMgr.createUser(uid, uid); save(s); assertEquals(usersPath + m.get(uid), u.getNode().getPath()); } } /** * Having 3 default levels -> test uids again. * * @throws RepositoryException */ public void testChangedDefaultLevel() throws RepositoryException, NotExecutableException { createUserManager(3, false, 1); UserImpl u = (UserImpl) uMgr.createUser("z", "z"); save(s); // remember the z-folder for later removal toRemove.add((NodeImpl) u.getNode().getParent().getParent().getParent()); assertEquals(usersPath + "/z/zz/zzz/z", u.getNode().getPath()); Map<String, String> m = new ListOrderedMap(); m.put("zz", "/z/zz/zzz/zz"); m.put("zzz", "/z/zz/zzz/zzz"); m.put("zzzz", "/z/zz/zzz/zzzz"); m.put("zH", "/z/zH/zHH/zH"); m.put("zHzh", "/z/zH/zHz/zHzh"); m.put("z_Hz", "/z/z_/z_H/z_Hz"); m.put("z\u00cfrich", "/z/z\u00cf/z\u00cfr/z\u00cfrich"); for (String uid : m.keySet()) { u = (UserImpl) uMgr.createUser(uid, uid); save(s); assertEquals(usersPath + m.get(uid), u.getNode().getPath()); Authorizable az = uMgr.getAuthorizable(uid); assertNotNull(az); } } public void testIllegalChars() throws RepositoryException, NotExecutableException { createUserManager(2, true, 2); UserImpl u = (UserImpl) uMgr.createUser("z", "z"); save(s); // remember the z-folder for later removal toRemove.add((NodeImpl) u.getNode().getParent().getParent()); String zu = Text.escapeIllegalJcrChars("z*"); String zur = Text.escapeIllegalJcrChars("z*r"); Map<String, String> m = new ListOrderedMap(); // test illegal JCR chars in uid // on level 2 m.put("z*rich", "/z/" + zu + "/" + Text.escapeIllegalJcrChars("z*rich")); m.put("z*riq", "/z/" + zu + "/" + Text.escapeIllegalJcrChars("z*riq")); m.put("z*", "/z/" + zu + "/" + zu); // still on level 2 (too short for 3) // on level 3 m.put("z*rik", "/z/" + zu + "/" + zur + "/" + Text.escapeIllegalJcrChars("z*rik")); m.put("z*.ri", "/z/" + zu + "/" + Text.escapeIllegalJcrChars("z*.") + "/" + Text.escapeIllegalJcrChars("z*.ri")); for (String uid : m.keySet()) { u = (UserImpl) uMgr.createUser(uid, uid); save(s); assertEquals(usersPath + m.get(uid), u.getNode().getPath()); Authorizable ath = uMgr.getAuthorizable(uid); assertNotNull("User with id " + uid + " must exist.", ath); assertFalse("User with id " + uid + " must not be a group.", ath.isGroup()); } // test for groups as well GroupImpl gr = (GroupImpl) uMgr.createGroup(new TestPrincipal("z[x]")); save(s); // remember the z-folder for later removal toRemove.add((NodeImpl) gr.getNode().getParent().getParent()); assertEquals("z[x]", gr.getID()); String expectedPath = groupsPath + "/z/" + Text.escapeIllegalJcrChars("z[") + "/" + Text.escapeIllegalJcrChars("z[x]"); assertEquals(expectedPath, gr.getNode().getPath()); Authorizable ath = uMgr.getAuthorizable(gr.getID()); assertNotNull(ath); assertTrue(ath.isGroup()); // test if conflicting authorizables are detected. try { uMgr.createUser("z[x]", "z[x]"); save(s); fail("A group \"z[x]\" already exists."); } catch (AuthorizableExistsException e) { // success } try { uMgr.createGroup(new TestPrincipal("z*rik")); save(s); fail("A user \"z*rik\" already exists"); } catch (AuthorizableExistsException e) { // success } } /** * If auto-expand is true users must be distributed over more than default-depth * levels if max-size is reached. * In addition the special cases must be respected (see DefaultIdResolver). * * @throws RepositoryException */ public void testAutoExpand() throws RepositoryException, NotExecutableException { createUserManager(2, true, 5); UserImpl u = (UserImpl) uMgr.createUser("z", "z"); save(s); // remember the z-folder for later removal toRemove.add((NodeImpl) u.getNode().getParent().getParent()); assertEquals(usersPath + "/z/zz/z", u.getNode().getPath()); Map<String, String> m = new ListOrderedMap(); m.put("zz", "/z/zz/zz"); // zzz -> potential conflict: must be added to 3rd level m.put("zzz", "/z/zz/zzz/zzz"); // more users -> added to 2nd level until max-size (5) is reached. m.put("zzABC", "/z/zz/zzABC"); m.put("zzzh", "/z/zz/zzzh"); // max-size on level 2 (zz) is reached -> added to 3rd level. m.put("zzzzZ", "/z/zz/zzz/zzzzZ"); m.put("zzh", "/z/zz/zzh/zzh"); m.put("zzXyzzz", "/z/zz/zzX/zzXyzzz"); // zzzz, zzza -> potential conflicts on the 3rd level // -> must be added to 4th level m.put("zzzz", "/z/zz/zzz/zzzz/zzzz"); m.put("zzza", "/z/zz/zzz/zzza/zzza"); // zA -> to short for 3rd -> must be inserted at the 2nd level. m.put("zA", "/z/zA/zA"); for (String uid : m.keySet()) { u = (UserImpl) uMgr.createUser(uid, uid); save(s); assertEquals(usersPath + m.get(uid), u.getNode().getPath()); } } /** * Test special case of turning autoexpandtree option on having colliding * authorizables already present a leve N: In this case auto-expansion must * be aborted at that level and the authorizable will be create at level N * ignoring that max-size has been reached. * * @throws RepositoryException */ public void testConflictUponChangingAutoExpandFlag() throws RepositoryException, NotExecutableException { createUserManager(2, false, 1); UserImpl u = (UserImpl) uMgr.createUser("zzz", "zzz"); save(s); // remember the z-folder for later removal toRemove.add((NodeImpl) u.getNode().getParent().getParent()); assertEquals(usersPath + "/z/zz/zzz", u.getNode().getPath()); // now create a second user manager that has auto-expand-tree enabled createUserManager(2, true, 1); Map<String, String> m = new ListOrderedMap(); // upon creation of any a new user 'zzzA' an additional intermediate // folder would be created if there wasn't the colliding authorizable // 'zzz' -> autoexpansion is aborted. m.put("zzzA", "/z/zz/zzzA"); // this is also true for 'zzzzz' and zzzBsl m.put("zzzzz", "/z/zz/zzzzz"); m.put("zzzBsl", "/z/zz/zzzBsl"); // on other levels the expansion must still work as expected. // - zzBsl -> zz is completed -> create zzB -> insert zzBsl user // - zzBslrich -> zz, zzB are completed -> create zzBs -> insert zzBslrich user m.put("zzBsl", "/z/zz/zzB/zzBsl"); m.put("zzBslrich", "/z/zz/zzB/zzBs/zzBslrich"); for (String uid : m.keySet()) { u = (UserImpl) uMgr.createUser(uid, uid); save(s); assertEquals(usersPath + m.get(uid), u.getNode().getPath()); assertNotNull(uMgr.getAuthorizable(uid)); } } /** * Find by ID must succeed. * * @throws RepositoryException */ public void testFindById() throws RepositoryException, NotExecutableException { createUserManager(2, true, 2); UserImpl u = (UserImpl) uMgr.createUser("z", "z"); save(s); // remember the z-folder for later removal toRemove.add((NodeImpl) u.getNode().getParent().getParent()); assertEquals(usersPath + "/z/zz/z", u.getNode().getPath()); Map<String, String> m = new ListOrderedMap(); // potential conflicting uid m.put("zzz", "/z/zz/zzz/zzz"); // max-size (2) is reached m.put("zzzuerich", "/z/zz/zzz/zzzuerich"); m.put("zzuerich", "/z/zz/zzu/zzuerich"); // too short for expanded folders m.put("zz", "/z/zz/zz"); for (String uid : m.keySet()) { u = (UserImpl) uMgr.createUser(uid, uid); save(s); assertEquals(usersPath + m.get(uid), u.getNode().getPath()); User us = (User) uMgr.getAuthorizable(uid); assertNotNull(us); assertEquals(uid, us.getID()); } } public void testIdIsCaseSensitive() throws RepositoryException, NotExecutableException { createUserManager(2, true, 2); UserImpl u = (UserImpl) uMgr.createUser("ZuRiCh", "z"); save(s); // remember the z-folder for later removal toRemove.add((NodeImpl) u.getNode().getParent().getParent()); assertEquals("ZuRiCh", u.getID()); } public void testUUIDIsBuildCaseInsensitive() throws RepositoryException, NotExecutableException { createUserManager(2, true, 2); UserImpl u = (UserImpl) uMgr.createUser("ZuRiCh", "z"); save(s); // remember the z-folder for later removal toRemove.add((NodeImpl) u.getNode().getParent().getParent()); try { User u2 = uMgr.createUser("zurich", "z"); fail("uuid is built from insensitive userID -> must conflict"); } catch (AuthorizableExistsException e) { // success } } }