| /* |
| * 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 static junit.framework.Assert.assertEquals; |
| import static junit.framework.Assert.assertFalse; |
| import static junit.framework.Assert.assertNotNull; |
| import static junit.framework.Assert.assertTrue; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.fail; |
| |
| import java.security.Principal; |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.UUID; |
| |
| import javax.jcr.RepositoryException; |
| import javax.jcr.UnsupportedRepositoryOperationException; |
| |
| import org.apache.jackrabbit.JcrConstants; |
| import org.apache.jackrabbit.api.security.user.Authorizable; |
| import org.apache.jackrabbit.api.security.user.User; |
| import org.apache.jackrabbit.api.security.user.UserManager; |
| import org.apache.jackrabbit.oak.AbstractSecurityTest; |
| import org.apache.jackrabbit.oak.api.CommitFailedException; |
| 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.api.Type; |
| import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl; |
| import org.apache.jackrabbit.oak.spi.security.user.UserConstants; |
| import org.apache.jackrabbit.oak.spi.security.user.util.PasswordUtil; |
| import org.apache.jackrabbit.oak.util.NodeUtil; |
| import org.junit.After; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| /** |
| * @since OAK 1.0 |
| */ |
| public class UserManagerImplTest extends AbstractSecurityTest { |
| |
| private UserManagerImpl userMgr; |
| private String testUserId = "testUser"; |
| private Set<String> beforeAuthorizables = new HashSet<String>(); |
| |
| @Before |
| public void before() throws Exception { |
| super.before(); |
| |
| userMgr = new UserManagerImpl(root, getPartialValueFactory(), getSecurityProvider()); |
| beforeAuthorizables.clear(); |
| Iterator<Authorizable> iter = userMgr.findAuthorizables("jcr:primaryType", null, UserManager.SEARCH_TYPE_AUTHORIZABLE); |
| while (iter.hasNext()) { |
| beforeAuthorizables.add(iter.next().getID()); |
| } |
| } |
| |
| @After |
| public void after() throws Exception { |
| Iterator<Authorizable> iter = userMgr.findAuthorizables("jcr:primaryType", null, UserManager.SEARCH_TYPE_AUTHORIZABLE); |
| while (iter.hasNext()) { |
| Authorizable auth = iter.next(); |
| if (!beforeAuthorizables.remove(auth.getID())) { |
| try { |
| auth.remove(); |
| } catch (RepositoryException e) { |
| // ignore |
| } |
| } |
| } |
| super.after(); |
| } |
| |
| /** |
| * @see <a href="https://issues.apache.org/jira/browse/OAK-3191">OAK-3191</a> |
| */ |
| @Test |
| public void testGetAuthorizableByEmptyId() throws Exception { |
| assertNull(userMgr.getAuthorizable("")); |
| } |
| |
| /** |
| * @see <a href="https://issues.apache.org/jira/browse/OAK-3191">OAK-3191</a> |
| */ |
| @Test |
| public void testGetTypedAuthorizableByEmptyId() throws Exception { |
| assertNull(userMgr.getAuthorizable("", User.class)); |
| } |
| |
| /** |
| * @see <a href="https://issues.apache.org/jira/browse/OAK-3191">OAK-3191</a> |
| */ |
| @Test |
| public void testGetAuthorizableByNullId() throws Exception { |
| assertNull(userMgr.getAuthorizable((String) null)); |
| } |
| |
| /** |
| * @see <a href="https://issues.apache.org/jira/browse/OAK-3191">OAK-3191</a> |
| */ |
| @Test |
| public void testGetTypedAuthorizableByNullId() throws Exception { |
| assertNull(userMgr.getAuthorizable(null, User.class)); |
| } |
| |
| /** |
| * @see <a href="https://issues.apache.org/jira/browse/OAK-3191">OAK-3191</a> |
| */ |
| @Test |
| public void testGetTypedAuthorizableByNullPrincipal() throws Exception { |
| assertNull(userMgr.getAuthorizable((Principal) null)); |
| } |
| |
| @Test |
| public void testSetPassword() throws Exception { |
| User user = userMgr.createUser(testUserId, "pw"); |
| root.commit(); |
| |
| List<String> pwds = new ArrayList<String>(); |
| pwds.add("pw"); |
| pwds.add(""); |
| pwds.add("{sha1}pw"); |
| |
| Tree userTree = root.getTree(user.getPath()); |
| for (String pw : pwds) { |
| userMgr.setPassword(userTree, testUserId, pw, true); |
| String pwHash = userTree.getProperty(UserConstants.REP_PASSWORD).getValue(Type.STRING); |
| assertNotNull(pwHash); |
| assertTrue(PasswordUtil.isSame(pwHash, pw)); |
| } |
| |
| for (String pw : pwds) { |
| userMgr.setPassword(userTree, testUserId, pw, false); |
| String pwHash = userTree.getProperty(UserConstants.REP_PASSWORD).getValue(Type.STRING); |
| assertNotNull(pwHash); |
| if (!pw.startsWith("{")) { |
| assertTrue(PasswordUtil.isSame(pwHash, pw)); |
| } else { |
| assertFalse(PasswordUtil.isSame(pwHash, pw)); |
| assertEquals(pw, pwHash); |
| } |
| } |
| } |
| |
| @Test |
| public void setPasswordNull() throws Exception { |
| User user = userMgr.createUser(testUserId, null); |
| root.commit(); |
| |
| Tree userTree = root.getTree(user.getPath()); |
| try { |
| userMgr.setPassword(userTree, testUserId, null, true); |
| fail("setting null password should fail"); |
| } catch (NullPointerException e) { |
| // expected |
| } |
| |
| try { |
| userMgr.setPassword(userTree, testUserId, null, false); |
| fail("setting null password should fail"); |
| } catch (NullPointerException e) { |
| // expected |
| } |
| } |
| |
| @Test |
| public void testGetPasswordHash() throws Exception { |
| User user = userMgr.createUser(testUserId, null); |
| root.commit(); |
| |
| Tree userTree = root.getTree(user.getPath()); |
| assertNull(userTree.getProperty(UserConstants.REP_PASSWORD)); |
| } |
| |
| @Test |
| public void testIsAutoSave() throws Exception { |
| assertFalse(userMgr.isAutoSave()); |
| } |
| |
| @Test |
| public void testAutoSave() throws Exception { |
| try { |
| userMgr.autoSave(true); |
| fail("should fail"); |
| } catch (UnsupportedRepositoryOperationException e) { |
| // success |
| } |
| } |
| |
| @Test |
| public void testEnforceAuthorizableFolderHierarchy() throws RepositoryException, CommitFailedException { |
| User user = userMgr.createUser(testUserId, null); |
| root.commit(); |
| |
| NodeUtil userNode = new NodeUtil(root.getTree(user.getPath())); |
| |
| NodeUtil folder = userNode.addChild("folder", UserConstants.NT_REP_AUTHORIZABLE_FOLDER); |
| String path = folder.getTree().getPath(); |
| |
| // authNode - authFolder -> create User |
| try { |
| Principal p = new PrincipalImpl("test2"); |
| userMgr.createUser(p.getName(), p.getName(), p, path); |
| root.commit(); |
| |
| fail("Users may not be nested."); |
| } catch (CommitFailedException e) { |
| // success |
| } finally { |
| Authorizable a = userMgr.getAuthorizable("test2"); |
| if (a != null) { |
| a.remove(); |
| root.commit(); |
| } |
| } |
| |
| NodeUtil someContent = userNode.addChild("mystuff", JcrConstants.NT_UNSTRUCTURED); |
| path = someContent.getTree().getPath(); |
| try { |
| // authNode - anyNode -> create User |
| try { |
| Principal p = new PrincipalImpl("test3"); |
| userMgr.createUser(p.getName(), p.getName(), p, path); |
| root.commit(); |
| |
| fail("Users may not be nested."); |
| } catch (CommitFailedException e) { |
| // success |
| } finally { |
| Authorizable a = userMgr.getAuthorizable("test3"); |
| if (a != null) { |
| a.remove(); |
| root.commit(); |
| } |
| } |
| |
| // authNode - anyNode - authFolder -> create User |
| folder = someContent.addChild("folder", UserConstants.NT_REP_AUTHORIZABLE_FOLDER); |
| root.commit(); // this time save node structure |
| try { |
| Principal p = new PrincipalImpl("test4"); |
| userMgr.createUser(p.getName(), p.getName(), p, folder.getTree().getPath()); |
| root.commit(); |
| |
| fail("Users may not be nested."); |
| } catch (CommitFailedException e) { |
| // success |
| } finally { |
| root.refresh(); |
| Authorizable a = userMgr.getAuthorizable("test4"); |
| if (a != null) { |
| a.remove(); |
| root.commit(); |
| } |
| } |
| } finally { |
| root.refresh(); |
| Tree t = root.getTree(path); |
| if (t.exists()) { |
| t.remove(); |
| root.commit(); |
| } |
| } |
| } |
| |
| @Test |
| public void testFindWithNullValue() throws RepositoryException { |
| Iterator<Authorizable> result = userMgr.findAuthorizables(UserConstants.REP_PRINCIPAL_NAME, null); |
| assertTrue(result.hasNext()); |
| } |
| |
| @Test |
| public void testFindWithNullValue2() throws RepositoryException { |
| Iterator<Authorizable> result = userMgr.findAuthorizables("./" + UserConstants.REP_PRINCIPAL_NAME, null); |
| assertTrue(result.hasNext()); |
| } |
| |
| @Test |
| public void testConcurrentCreateUser() throws Exception { |
| final List<Exception> exceptions = new ArrayList<Exception>(); |
| List<Thread> workers = new ArrayList<Thread>(); |
| for (int i=0; i<10; i++) { |
| final String userId = "foo-user-" + i; |
| workers.add(new Thread(new Runnable() { |
| public void run() { |
| try { |
| ContentSession admin = login(getAdminCredentials()); |
| Root root = admin.getLatestRoot(); |
| UserManager userManager = new UserManagerImpl(root, getPartialValueFactory(), getSecurityProvider()); |
| userManager.createUser(userId, "pass"); |
| root.commit(); |
| admin.close(); |
| } catch (Exception e) { |
| exceptions.add(e); |
| } |
| } |
| })); |
| } |
| for (Thread t : workers) { |
| t.start(); |
| } |
| for (Thread t : workers) { |
| t.join(); |
| } |
| for (Exception e : exceptions) { |
| e.printStackTrace(); |
| } |
| if (!exceptions.isEmpty()) { |
| throw exceptions.get(0); |
| } |
| } |
| |
| /** |
| * Test related to OAK-1922: Asserting that the default behavior is such that |
| * no rep:pwd node is created upon user-creation. |
| * |
| * @since Oak 1.1 |
| */ |
| @Test |
| public void testNewUserHasNoPwdNode() throws Exception { |
| String newUserId = "newuser" + UUID.randomUUID(); |
| User user = null; |
| try { |
| user = getUserManager(root).createUser(newUserId, newUserId); |
| root.commit(); |
| |
| Assert.assertFalse(root.getTree(user.getPath()).hasChild(UserConstants.REP_PWD)); |
| Assert.assertFalse(user.hasProperty(UserConstants.REP_PWD + "/" + UserConstants.REP_PASSWORD_LAST_MODIFIED)); |
| } finally { |
| if (user != null) { |
| user.remove(); |
| root.commit(); |
| } |
| } |
| } |
| } |