You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2012/10/11 15:31:19 UTC

svn commit: r1397041 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/ oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/ oak-jcr...

Author: angela
Date: Thu Oct 11 13:31:19 2012
New Revision: 1397041

URL: http://svn.apache.org/viewvc?rev=1397041&view=rev
Log:
OAK-50 : Implement User Management (WIP)

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserProviderImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/PasswordUtility.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserProviderImplTest.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AbstractUserTest.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/UserTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImpl.java?rev=1397041&r1=1397040&r2=1397041&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImpl.java Thu Oct 11 13:31:19 2012
@@ -23,7 +23,6 @@ import javax.jcr.UnsupportedRepositoryOp
 
 import org.apache.jackrabbit.api.security.user.Impersonation;
 import org.apache.jackrabbit.api.security.user.User;
-import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.spi.security.principal.TreeBasedPrincipal;
 import org.apache.jackrabbit.oak.spi.security.user.PasswordUtility;
@@ -31,8 +30,6 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.jackrabbit.oak.api.Type.STRING;
-
 /**
  * UserImpl...
  */
@@ -104,6 +101,9 @@ class UserImpl extends AuthorizableImpl 
      */
     @Override
     public void changePassword(String password) throws RepositoryException {
+        if (password == null) {
+            throw new RepositoryException("Attempt to set 'null' password for user " + getID());
+        }
         UserManagerImpl userManager = getUserManager();
         userManager.onPasswordChange(this, password);
         getUserProvider().setPassword(getTree(), password, true);
@@ -115,11 +115,7 @@ class UserImpl extends AuthorizableImpl 
     @Override
     public void changePassword(String password, String oldPassword) throws RepositoryException {
         // make sure the old password matches.
-        String pwHash = null;
-        PropertyState pwProp = getTree().getProperty(REP_PASSWORD);
-        if (pwProp != null) {
-            pwHash = pwProp.getValue(STRING);
-        }
+        String pwHash = getUserProvider().getPasswordHash(getTree());
         if (!PasswordUtility.isSame(pwHash, oldPassword)) {
             throw new RepositoryException("Failed to change password: Old password does not match.");
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserProviderImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserProviderImpl.java?rev=1397041&r1=1397040&r2=1397041&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserProviderImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserProviderImpl.java Thu Oct 11 13:31:19 2012
@@ -269,10 +269,6 @@ class UserProviderImpl extends Authoriza
 
     @Override
     public void setPassword(Tree userTree, String password, boolean forceHash) throws RepositoryException {
-        if (password == null) {
-            log.debug("Password is null.");
-            return;
-        }
         String pwHash;
         if (forceHash || PasswordUtility.isPlainTextPassword(password)) {
             try {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/PasswordUtility.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/PasswordUtility.java?rev=1397041&r1=1397040&r2=1397041&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/PasswordUtility.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/PasswordUtility.java Thu Oct 11 13:31:19 2012
@@ -108,7 +108,7 @@ public class PasswordUtility {
         int iterations = config.getConfigValue(UserConfig.PARAM_PASSWORD_HASH_ITERATIONS, DEFAULT_ITERATIONS);
         int saltSize = config.getConfigValue(UserConfig.PARAM_PASSWORD_SALT_SIZE, DEFAULT_SALT_SIZE);
 
-        return buildPasswordHash(password, algorithm, iterations, saltSize);
+        return buildPasswordHash(password, algorithm, saltSize, iterations);
     }
 
     /**

Modified: 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=1397041&r1=1397040&r2=1397041&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserProviderImplTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserProviderImplTest.java Thu Oct 11 13:31:19 2012
@@ -33,6 +33,7 @@ import org.apache.jackrabbit.oak.api.Tre
 import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexHook;
 import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
 import org.apache.jackrabbit.oak.spi.security.user.AuthorizableType;
+import org.apache.jackrabbit.oak.spi.security.user.PasswordUtility;
 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;
@@ -373,4 +374,62 @@ public class UserProviderImplTest extend
             u2.remove();
         }
     }
+
+    @Test
+    public void testGetPasswordHash() throws Exception {
+        UserProvider up = createUserProvider();
+        Tree user = up.createUser("a", null);
+
+        assertNull(up.getPasswordHash(user));
+    }
+
+    @Test
+    public void testSetPassword() throws Exception {
+        UserProvider up = createUserProvider();
+        Tree user = up.createUser("a", null);
+
+        List<String> pwds = new ArrayList<String>();
+        pwds.add("pw");
+        pwds.add("");
+        pwds.add("{sha1}pw");
+
+        for (String pw : pwds) {
+            up.setPassword(user, pw, true);
+            String pwHash = up.getPasswordHash(user);
+            assertNotNull(pwHash);
+            assertTrue(PasswordUtility.isSame(pwHash, pw));
+        }
+
+        for (String pw : pwds) {
+            up.setPassword(user, pw, false);
+            String pwHash = up.getPasswordHash(user);
+            assertNotNull(pwHash);
+            if (!pw.startsWith("{")) {
+                assertTrue(PasswordUtility.isSame(pwHash, pw));
+            } else {
+                assertFalse(PasswordUtility.isSame(pwHash, pw));
+                assertEquals(pw, pwHash);
+            }
+        }
+    }
+
+    @Test
+    public void setPasswordNull() throws Exception {
+        UserProvider up = createUserProvider();
+        Tree user = up.createUser("a", null);
+
+        try {
+            up.setPassword(user, null, true);
+            fail("setting null password should fail");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        try {
+            up.setPassword(user, null, false);
+            fail("setting null password should fail");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
 }

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AbstractUserTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AbstractUserTest.java?rev=1397041&r1=1397040&r2=1397041&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AbstractUserTest.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AbstractUserTest.java Thu Oct 11 13:31:19 2012
@@ -40,6 +40,8 @@ import org.junit.Before;
  */
 public abstract class AbstractUserTest extends AbstractJCRTest {
 
+    protected String testPw = "pw";
+
     protected UserManager userMgr;
     protected User user;
     protected Group group;
@@ -51,7 +53,7 @@ public abstract class AbstractUserTest e
 
         userMgr = getUserManager(superuser);
 
-        user = userMgr.createUser(createUserId(), "pw");
+        user = userMgr.createUser(createUserId(), testPw);
         group = userMgr.createGroup(createGroupId());
         superuser.save();
     }

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/UserTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/UserTest.java?rev=1397041&r1=1397040&r2=1397041&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/UserTest.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/UserTest.java Thu Oct 11 13:31:19 2012
@@ -16,6 +16,8 @@
  */
 package org.apache.jackrabbit.oak.jcr.security.user;
 
+import java.security.Principal;
+import javax.jcr.Credentials;
 import javax.jcr.LoginException;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
@@ -25,6 +27,7 @@ import javax.jcr.UnsupportedRepositoryOp
 import org.apache.jackrabbit.api.JackrabbitSession;
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
 import org.apache.jackrabbit.test.NotExecutableException;
 import org.junit.Test;
 
@@ -73,122 +76,170 @@ public class UserTest extends AbstractUs
     }
 
     @Test
-    public void testChangePassword() throws RepositoryException, NotExecutableException {
-        String oldPw = getHelper().getProperty("javax.jcr.tck.superuser.pwd");
-        if (oldPw == null) {
-            // missing property
-            throw new NotExecutableException();
+    public void testChangePasswordNull() throws RepositoryException, NotExecutableException {
+        // invalid 'null' pw string
+        try {
+            user.changePassword(null);
+            superuser.save();
+            fail("invalid pw null");
+        } catch (Exception e) {
+            // success
         }
+    }
 
-        User user = getTestUser(superuser);
+    @Test
+    public void testChangePassword() throws RepositoryException, NotExecutableException {
         try {
-            user.changePassword("pw");
-            superuser.save();
+            String hash = getNode(user, superuser).getProperty(UserConstants.REP_PASSWORD).getString();
 
-            // make sure the user can login with the new pw
-            Session s = getHelper().getRepository().login(new SimpleCredentials(user.getID(), "pw".toCharArray()));
-            s.logout();
-        } finally {
-            user.changePassword(oldPw);
+            user.changePassword("changed");
             superuser.save();
+
+            assertFalse(hash.equals(getNode(user, superuser).getProperty(UserConstants.REP_PASSWORD).getString()));
+        } catch (Exception e) {
+            // success
         }
     }
 
     @Test
-    public void testChangePassword2() throws RepositoryException, NotExecutableException {
-        String oldPw = getHelper().getProperty("javax.jcr.tck.superuser.pwd");
-        if (oldPw == null) {
-            // missing property
-            throw new NotExecutableException();
+    public void testChangePasswordWithInvalidOldPassword() throws RepositoryException, NotExecutableException {
+        try {
+            user.changePassword("changed", "wrongOldPw");
+            superuser.save();
+            fail("old password didn't match -> changePassword(String,String) should fail.");
+        } catch (RepositoryException e) {
+            // success.
         }
+    }
 
-        User user = getTestUser(superuser);
+    @Test
+    public void testChangePasswordWithOldPassword() throws RepositoryException, NotExecutableException {
         try {
-            user.changePassword("pw");
+            String hash = getNode(user, superuser).getProperty(UserConstants.REP_PASSWORD).getString();
+
+            user.changePassword("changed", testPw);
             superuser.save();
 
-            Session s = getHelper().getRepository().login(new SimpleCredentials(user.getID(), oldPw.toCharArray()));
-            s.logout();
-            fail("superuser pw has changed. login must fail.");
-        } catch (LoginException e) {
-            // success
+            assertFalse(hash.equals(getNode(user, superuser).getProperty(UserConstants.REP_PASSWORD).getString()));
         } finally {
-            user.changePassword(oldPw);
+            user.changePassword(testPw);
             superuser.save();
         }
     }
 
+      @Test
+    public void testLoginAfterChangePassword() throws RepositoryException {
+        user.changePassword("changed");
+        superuser.save();
+
+        // make sure the user can login with the new pw
+        Session s = getHelper().getRepository().login(new SimpleCredentials(user.getID(), "changed".toCharArray()));
+        s.logout();
+    }
+
     @Test
-    public void testChangePasswordWithOldPassword() throws RepositoryException, NotExecutableException {
-        String oldPw = getHelper().getProperty("javax.jcr.tck.superuser.pwd");
-        if (oldPw == null) {
-            // missing property
-            throw new NotExecutableException();
-        }
-
-        User user = getTestUser(superuser);
-        try {
-            try {
-                user.changePassword("pw", "wrongOldPw");
-                superuser.save();
-                fail("old password didn't match -> changePassword(String,String) should fail.");
-            } catch (RepositoryException e) {
-                // success.
-            }
+    public void testLoginAfterChangePassword2() throws RepositoryException, NotExecutableException {
+        try {
 
-            user.changePassword("pw", oldPw);
+            user.changePassword("changed", testPw);
             superuser.save();
 
             // make sure the user can login with the new pw
-            Session s = getHelper().getRepository().login(new SimpleCredentials(user.getID(), "pw".toCharArray()));
+            Session s = getHelper().getRepository().login(new SimpleCredentials(user.getID(), "changed".toCharArray()));
             s.logout();
         } finally {
-            user.changePassword(oldPw);
+            user.changePassword(testPw);
             superuser.save();
         }
     }
 
     @Test
-    public void testChangePasswordWithOldPassword2() throws RepositoryException, NotExecutableException {
-        String oldPw = getHelper().getProperty("javax.jcr.tck.superuser.pwd");
-        if (oldPw == null) {
-            // missing property
-            throw new NotExecutableException();
+    public void testLoginWithOldPassword() throws RepositoryException, NotExecutableException {
+        try {
+            user.changePassword("changed");
+            superuser.save();
+
+            Session s = getHelper().getRepository().login(new SimpleCredentials(user.getID(), testPw.toCharArray()));
+            s.logout();
+            fail("user pw has changed. login must fail.");
+        } catch (LoginException e) {
+            // success
         }
+    }
 
-        User user = getTestUser(superuser);
+    @Test
+    public void testLoginWithOldPassword2() throws RepositoryException, NotExecutableException {
         try {
-            user.changePassword("pw", oldPw);
+            user.changePassword("changed", testPw);
             superuser.save();
 
-            Session s = getHelper().getRepository().login(new SimpleCredentials(user.getID(), oldPw.toCharArray()));
+            Session s = getHelper().getRepository().login(new SimpleCredentials(user.getID(), testPw.toCharArray()));
             s.logout();
             fail("superuser pw has changed. login must fail.");
         } catch (LoginException e) {
             // success
         } finally {
-            user.changePassword(oldPw);
+            user.changePassword(testPw);
             superuser.save();
         }
     }
 
     @Test
-    public void testDisable() throws Exception {
+    public void testEnabledByDefault() throws Exception {
         // by default a user isn't disabled
         assertFalse(user.isDisabled());
         assertNull(user.getDisabledReason());
+    }
 
-        // disable user
+    @Test
+    public void testDisable() throws Exception {
         String reason = "readonly user is disabled!";
         user.disable(reason);
         superuser.save();
         assertTrue(user.isDisabled());
         assertEquals(reason, user.getDisabledReason());
+    }
+
+    @Test
+    public void testAccessDisabledUser() throws Exception {
+        user.disable("readonly user is disabled!");
+        superuser.save();
 
         // user must still be retrievable from user manager
         assertNotNull(getUserManager(superuser).getAuthorizable(user.getID()));
         // ... and from principal manager as well
         assertTrue(((JackrabbitSession) superuser).getPrincipalManager().hasPrincipal(user.getPrincipal().getName()));
+    }
+
+    @Test
+    public void testAccessPrincipalOfDisabledUser()  throws Exception {
+        user.disable("readonly user is disabled!");
+        superuser.save();
+
+        Principal principal = user.getPrincipal();
+        assertTrue(((JackrabbitSession) superuser).getPrincipalManager().hasPrincipal(principal.getName()));
+        assertEquals(principal, ((JackrabbitSession) superuser).getPrincipalManager().getPrincipal(principal.getName()));
+    }
+
+    @Test
+    public void testEnableUser() throws Exception {
+        user.disable("readonly user is disabled!");
+        superuser.save();
+
+        // enable user again
+        user.disable(null);
+        superuser.save();
+        assertFalse(user.isDisabled());
+        assertNull(user.getDisabledReason());
+
+        // -> login must succeed again
+        getHelper().getRepository().login(new SimpleCredentials(user.getID(), "pw".toCharArray())).logout();
+    }
+
+    @Test
+    public void testLoginDisabledUser() throws Exception {
+        user.disable("readonly user is disabled!");
+        superuser.save();
 
         // -> login must fail
         try {
@@ -198,6 +249,12 @@ public class UserTest extends AbstractUs
         } catch (LoginException e) {
             // success
         }
+    }
+
+    @Test
+    public void testImpersonateDisabledUser() throws Exception {
+        user.disable("readonly user is disabled!");
+        superuser.save();
 
         // -> impersonating this user must fail
         try {
@@ -207,13 +264,27 @@ public class UserTest extends AbstractUs
         } catch (LoginException e) {
             // success
         }
+    }
 
-        // enable user again
-        user.disable(null);
-        superuser.save();
-        assertFalse(user.isDisabled());
+    public void testUserGetCredentials() throws RepositoryException, NotExecutableException {
+        try {
+            Credentials creds = user.getCredentials();
+            fail("getCredentials is not yet implemented");
+        } catch (UnsupportedRepositoryOperationException e) {
+            // expected
+        }
+    }
 
-        // -> login must succeed again
-        getHelper().getRepository().login(new SimpleCredentials(user.getID(), "pw".toCharArray())).logout();
+    public void testLoginWithGetCredentials() throws RepositoryException, NotExecutableException {
+        try {
+            Credentials creds = user.getCredentials();
+            Session s = getHelper().getRepository().login(creds);
+            s.logout();
+            fail("Login using credentials exposed on user must fail.");
+        } catch (UnsupportedRepositoryOperationException e) {
+            throw new NotExecutableException(e.getMessage());
+        } catch (LoginException e) {
+            // success
+        }
     }
 }
\ No newline at end of file