You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2010/08/11 14:50:11 UTC

svn commit: r984395 - in /jackrabbit/trunk: jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core...

Author: angela
Date: Wed Aug 11 12:50:11 2010
New Revision: 984395

URL: http://svn.apache.org/viewvc?rev=984395&view=rev
Log:
JCR-2635 : Disable Users

Modified:
    jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/User.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/DefaultLoginModule.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserConstants.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImporter.java
    jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/UserTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/SimpleCredentialsAuthenticationTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImporterTest.java

Modified: jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/User.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/User.java?rev=984395&r1=984394&r2=984395&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/User.java (original)
+++ jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/User.java Wed Aug 11 12:50:11 2010
@@ -57,4 +57,36 @@ public interface User extends Authorizab
      * @throws RepositoryException If an error occurs.
      */
     void changePassword(String password) throws RepositoryException;
+
+    /**
+     * Disable this user thus preventing future login if the <code>reason</code>
+     * is a non-null String.<br>
+     * Note however, that this user will still be accessible by
+     * {@link UserManager#getAuthorizable}.
+     *
+     * @param reason String describing the reason for disable this user or
+     * <code>null</code> if the user account should be enabled again.
+     * @throws RepositoryException
+     */
+    void disable(String reason) throws RepositoryException;
+
+    /**
+     * Returns <code>true</code> if this user is disabled, <code>false</code>
+     * otherwise.
+     *
+     * @return <code>true</code> if this user is disabled, <code>false</code>
+     * otherwise.
+     * @throws RepositoryException
+     */
+    boolean isDisabled() throws RepositoryException;
+
+    /**
+     * Returns the String specified upon disabling this user or <code>null</code>
+     * if {@link #isDisabled()} returns <code>false</code>.
+     * 
+     * @return The reason specified upon disabling this user or <code>null</code>
+     * if this user is not disabled.
+     * @throws RepositoryException
+     */
+    String getDisabledReason() throws RepositoryException;
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java?rev=984395&r1=984394&r2=984395&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/AbstractLoginModule.java Wed Aug 11 12:50:11 2010
@@ -312,8 +312,8 @@ public abstract class AbstractLoginModul
         try {
             Principal userPrincipal = getPrincipal(creds);
             if (userPrincipal == null) {
-                // unknown principal or a Group-principal
-                log.debug("Unknown User -> ignore.");
+                // unknown or disabled user or a group
+                log.debug("No valid user -> ignore.");
                 return false;
             }
             boolean authenticated;

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/DefaultLoginModule.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/DefaultLoginModule.java?rev=984395&r1=984394&r2=984395&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/DefaultLoginModule.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/authentication/DefaultLoginModule.java Wed Aug 11 12:50:11 2010
@@ -76,7 +76,7 @@ public class DefaultLoginModule extends 
      * If the the userID cannot be resolved to a User or if obtaining the
      * principal fail, <code>null</code> is returned.
      *
-     * @param credentials Credentions to retrieve the principal for.
+     * @param credentials Credentials to retrieve the principal for.
      * @return a user principal or <code>null</code>.
      * @see AbstractLoginModule#getPrincipal(Credentials)
      */
@@ -88,7 +88,12 @@ public class DefaultLoginModule extends 
             Authorizable authrz = userManager.getAuthorizable(userId);
             if (authrz != null && !authrz.isGroup()) {
                 user = (User) authrz;
-                principal = user.getPrincipal();
+                if (user.isDisabled()) {
+                    // log message and return null -> login module returns false.
+                    log.debug("User " + userId + " has been disabled.");
+                } else {
+                    principal = user.getPrincipal();
+                }
             }
         } catch (RepositoryException e) {
             // should not get here
@@ -130,17 +135,16 @@ public class DefaultLoginModule extends 
     @Override
     protected boolean impersonate(Principal principal, Credentials credentials)
             throws RepositoryException, FailedLoginException {
-
-        Authorizable authrz = userManager.getAuthorizable(principal);
-        if (authrz == null || authrz.isGroup()) {
-            return false;
-        }
-        Subject impersSubject = getImpersonatorSubject(credentials);
-        User user = (User) authrz;
-        if (user.getImpersonation().allows(impersSubject)) {
-            return true;
+        if (user != null) {
+            Subject impersSubject = getImpersonatorSubject(credentials);
+            if (user.getImpersonation().allows(impersSubject)) {
+                return true;
+            } else {
+                throw new FailedLoginException("attempt to impersonate denied for " + principal.getName());
+            }
         } else {
-            throw new FailedLoginException("attempt to impersonate denied for " + principal.getName());
+            log.debug("Failed to retrieve user to impersonate for principal name " + principal.getName());
+            return false;
         }
     }
-}
+}
\ No newline at end of file

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserConstants.java?rev=984395&r1=984394&r2=984395&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserConstants.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserConstants.java Wed Aug 11 12:50:11 2010
@@ -54,6 +54,7 @@ interface UserConstants {
      */
     Name P_USERID = NF.create(Name.NS_REP_URI, "userId");
     Name P_PASSWORD = NF.create(Name.NS_REP_URI, "password");
+    Name P_DISABLED = NF.create(Name.NS_REP_URI, "disabled");
 
     /**
      * @deprecated As of 2.0 group membership is stored with the group node.
@@ -74,4 +75,4 @@ interface UserConstants {
     Name NT_REP_GROUP = NF.create(Name.NS_REP_URI, "Group");
     Name MIX_REP_IMPERSONATABLE = NF.create(Name.NS_REP_URI, "Impersonatable");
 
-}
\ No newline at end of file
+}

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImpl.java?rev=984395&r1=984394&r2=984395&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImpl.java Wed Aug 11 12:50:11 2010
@@ -20,6 +20,7 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.api.security.user.Impersonation;
 import org.apache.jackrabbit.api.security.user.User;
 import org.apache.jackrabbit.core.NodeImpl;
+import org.apache.jackrabbit.core.PropertyImpl;
 import org.apache.jackrabbit.core.security.authentication.CryptedSimpleCredentials;
 import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
 
@@ -126,6 +127,43 @@ public class UserImpl extends Authorizab
         userManager.setProtectedProperty(getNode(), P_PASSWORD, v);
     }
 
+    /**
+     * @see User#disable(String)
+     */
+    public void disable(String reason) throws RepositoryException {
+        if (isAdmin()) {
+            throw new RepositoryException("The administrator user cannot be disabled.");
+        }
+        if (reason == null) {
+            if (isDisabled()) {
+                // enable the user again.
+                PropertyImpl disableProp = getNode().getProperty(P_DISABLED);
+                userManager.removeProtectedItem(disableProp, getNode());
+            } // else: nothing to do.
+        } else {
+            Value v = getSession().getValueFactory().createValue(reason);
+            userManager.setProtectedProperty(getNode(), P_DISABLED, v);
+        }
+    }
+
+    /**
+     * @see User#isDisabled()
+     */
+    public boolean isDisabled() throws RepositoryException {
+        return getNode().hasProperty(P_DISABLED);
+    }
+
+    /**
+     * @see User#getDisabledReason()
+     */
+    public String getDisabledReason() throws RepositoryException {
+        if (isDisabled()) {
+            return getNode().getProperty(P_DISABLED).getString();
+        } else {
+            return null;
+        }
+    }
+
     //--------------------------------------------------------------------------
     /**
      *

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImporter.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImporter.java?rev=984395&r1=984394&r2=984395&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImporter.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserImporter.java Wed Aug 11 12:50:11 2010
@@ -246,6 +246,23 @@ public class UserImporter extends Defaul
                 referenceTracker.processedReference(new Impersonators(a.getID(), vs));
                 return true;
 
+            } else if (UserConstants.P_DISABLED.equals(propName)) {
+                if (a.isGroup()) {
+                    log.warn("Expected parent node of type rep:User.");
+                    return false;
+                }
+                // minimal validation of the passed definition
+                if (def.isMultiple() || !UserConstants.NT_REP_USER.equals(def.getDeclaringNodeType())) {
+                    // some other unexpected property definition -> cannot handle
+                    log.warn("Unexpected definition for property rep:disabled");
+                    return false;
+                }
+
+                Value v = protectedPropInfo.getValues(PropertyType.STRING, resolver)[0];
+                ((User) a).disable(v.getString());
+
+                return true;
+
             } else if (UserConstants.P_MEMBERS.equals(propName)) {
                 if (!a.isGroup()) {
                     // unexpected parent type -> cannot handle

Modified: jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd?rev=984395&r1=984394&r2=984395&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/nodetype/builtin_nodetypes.cnd Wed Aug 11 12:50:11 2010
@@ -600,6 +600,7 @@
 
 [rep:User] > rep:Authorizable, rep:Impersonatable
   - rep:password (STRING) protected mandatory
+  - rep:disabled (STRING) protected
 
 [rep:Group] > rep:Authorizable
   - rep:members (WEAKREFERENCE) protected multiple < 'rep:Authorizable'

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/UserTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/UserTest.java?rev=984395&r1=984394&r2=984395&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/UserTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/UserTest.java Wed Aug 11 12:50:11 2010
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.api.security.user;
 
+import org.apache.jackrabbit.api.JackrabbitSession;
 import org.apache.jackrabbit.test.NotExecutableException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -102,4 +103,84 @@ public class UserTest extends AbstractUs
             save(superuser);
         }
     }
+
+    public void testDisable() throws Exception {
+        boolean remove = false;
+        Session s = getHelper().getReadOnlySession();
+
+        User user = null;
+        String userID = null;
+        String pw = "";
+
+        try {
+            User readonlyUser = getTestUser(s);
+            if (readonlyUser.isAdmin()) {
+                // configured readonly user is admin
+                // -> need to create another test user
+                pw = "test";
+                userID = getUserManager(superuser).createUser(getTestPrincipal().getName(), pw).getID();
+                remove = true;
+            } else {
+                userID = readonlyUser.getID();
+            }
+
+            user = (User) getUserManager(superuser).getAuthorizable(userID);
+
+            // by default a user isn't disabled
+            assertFalse(user.isDisabled());
+            assertNull(user.getDisabledReason());
+
+            // disable user
+            String reason = "readonly user is disabled!";
+            user.disable(reason);
+            save(superuser);
+            assertTrue(user.isDisabled());
+            assertEquals(reason, user.getDisabledReason());
+
+            // user must still be retrievable from user manager
+            assertNotNull(getUserManager(superuser).getAuthorizable(userID));
+            // ... and from principal manager as well
+            assertTrue(((JackrabbitSession) superuser).getPrincipalManager().hasPrincipal(user.getPrincipal().getName()));
+
+            // -> login must fail
+            try {
+                Session ss = getHelper().getRepository().login(new SimpleCredentials(userID, pw.toCharArray()));
+                ss.logout();
+                fail("A disabled user must not be allowed to login any more");
+            } catch (LoginException e) {
+                // success
+            }
+
+            // -> impersonating this user must fail
+            try {
+                Session ss = superuser.impersonate(new SimpleCredentials(userID, new char[0]));
+                ss.logout();
+                fail("A disabled user cannot be impersonated any more.");
+            } catch (LoginException e) {
+                // success
+            }
+            
+            // enable user again
+            user.disable(null);
+            save(superuser);
+            assertFalse(user.isDisabled());
+
+            // -> login must succeed again
+            getHelper().getRepository().login(new SimpleCredentials(userID, pw.toCharArray())).logout();
+
+        } finally {
+            s.logout();
+
+            if (user != null) {
+                if (user.isDisabled()) {
+                    user.disable(null);
+                }
+
+                if (remove) {
+                    user.remove();
+                    save(superuser);
+                }
+            }
+        }
+    }
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/SimpleCredentialsAuthenticationTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/SimpleCredentialsAuthenticationTest.java?rev=984395&r1=984394&r2=984395&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/SimpleCredentialsAuthenticationTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/authentication/SimpleCredentialsAuthenticationTest.java Wed Aug 11 12:50:11 2010
@@ -134,6 +134,17 @@ public class SimpleCredentialsAuthentica
         public void changePassword(String password) throws RepositoryException {
         }
 
+        public void disable(String reason) throws RepositoryException {
+        }
+
+        public boolean isDisabled() throws RepositoryException {
+            return false;
+        }
+
+        public String getDisabledReason() throws RepositoryException {
+            return null;
+        }
+
         public String getID() throws RepositoryException {
             return null;
         }

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImporterTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImporterTest.java?rev=984395&r1=984394&r2=984395&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImporterTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImporterTest.java Wed Aug 11 12:50:11 2010
@@ -194,6 +194,7 @@ public class UserImporterTest extends Ab
                 "   <sv:property sv:name=\"jcr:uuid\" sv:type=\"String\"><sv:value>e358efa4-89f5-3062-b10d-d7316b65649e</sv:value></sv:property>" +
                 "   <sv:property sv:name=\"rep:password\" sv:type=\"String\"><sv:value>{sha1}8efd86fb78a56a5145ed7739dcb00c78581c5375</sv:value></sv:property>" +
                 "   <sv:property sv:name=\"rep:principalName\" sv:type=\"String\"><sv:value>t</sv:value></sv:property>" +
+                "   <sv:property sv:name=\"rep:disabled\" sv:type=\"String\"><sv:value>disabledUser</sv:value></sv:property>" +
                 "</sv:node>";
 
         NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getUsersPath());
@@ -208,6 +209,8 @@ public class UserImporterTest extends Ab
             assertFalse(newUser.isGroup());
             assertEquals("t", newUser.getPrincipal().getName());
             assertEquals("t", newUser.getID());
+            assertTrue(((User) newUser).isDisabled());
+            assertEquals("disabledUser", ((User) newUser).getDisabledReason());
 
             NodeImpl n = ((UserImpl) newUser).getNode();
             assertTrue(n.isNew());
@@ -216,6 +219,7 @@ public class UserImporterTest extends Ab
             assertEquals("t", n.getName());
             assertEquals("t", n.getProperty(UserConstants.P_PRINCIPAL_NAME).getString());
             assertEquals("{sha1}8efd86fb78a56a5145ed7739dcb00c78581c5375", n.getProperty(UserConstants.P_PASSWORD).getString());
+            assertEquals("disabledUser", n.getProperty(UserConstants.P_DISABLED).getString());
 
             // saving changes of the import -> must succeed. add mandatory
             // props should have been created.