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 2009/09/24 12:30:35 UTC

svn commit: r818433 [1/2] - in /jackrabbit/trunk: jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/principa...

Author: angela
Date: Thu Sep 24 10:30:34 2009
New Revision: 818433

URL: http://svn.apache.org/viewvc?rev=818433&view=rev
Log:
JCR-2313: Improvements to user management (2)  [NOTE: work in progress]

- calculate jcr:uuid of user/group nodes from the ID  and consequently 
   -> simplify getAuthorizable(String id)
   -> enabled intermediatePath param upon creation
   -> remove some limitations of the built-in node structure
- remove referees concept form API and node type definition.
- typo and inconsistencies in javadoc

Modified:
    jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Authorizable.java
    jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Group.java
    jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/UserManager.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ProtectedItemModifier.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/principal/DefaultPrincipalProvider.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/GroupImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/ImpersonationImpl.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/IndexNodeResolver.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/NodeResolver.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.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/UserManagerImpl.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/AuthorizableTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AuthorizableImplTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/GroupAdministratorTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/ImpersonationImplTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/NodeResolverTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/NotUserAdministratorTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserAdministratorTest.java

Modified: jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Authorizable.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Authorizable.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Authorizable.java (original)
+++ jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Authorizable.java Thu Sep 24 10:30:34 2009
@@ -22,8 +22,6 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 
-import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
-
 /**
  * The Authorizable is the common base interface for {@link User} and
  * {@link Group}. It provides access to the <code>Principal</code>s associated
@@ -44,7 +42,7 @@
  * login mechanisms.<br>
  * <p/>
  * Consequently an one-to-many relationship exists between Authorizable
- * and Principal (see also {@link #getPrincipal()} and {@link #getPrincipals()}).
+ * and Principal (see also {@link #getPrincipal()}.
  * <p/>
  * <p/>
  * The interfaces derived from Authorizable are defined as follows:
@@ -82,35 +80,6 @@
     Principal getPrincipal() throws RepositoryException;
 
     /**
-     * Add the given Principal to this Authorizable.
-     * Note, that a Principal can only be refered by a single Authorizable in
-     * the Repository. If another User or Group already refers to the given
-     * Principal a <code>AuthorizableExistsException</code> is thrown.
-     *
-     * @param principal
-     * @return AuthorizableExistsException If the given principal is already refered
-     *         to by another Authorizable.
-     * @throws RepositoryException
-     */
-    boolean addReferee(Principal principal) throws AuthorizableExistsException, RepositoryException;
-
-    /**
-     * Remove the specified Principal for the referees of this Authorizable.
-     *
-     * @param principal
-     * @return true if principal has been referee before. False otherwise.
-     * @throws RepositoryException
-     */
-    boolean removeReferee(Principal principal) throws RepositoryException;
-
-    /**
-     * @return Iterator of all Principal related to this authentication Object
-     *         including the main principal, (see {@link #getPrincipal()}).
-     * @throws RepositoryException
-     */
-    PrincipalIterator getPrincipals() throws RepositoryException;
-
-    /**
      * @return all {@link Group}s, this Authorizable is declared member of.
      * @throws RepositoryException
      */

Modified: jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Group.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Group.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Group.java (original)
+++ jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Group.java Thu Sep 24 10:30:34 2009
@@ -47,8 +47,7 @@
     boolean isMember(Authorizable authorizable) throws RepositoryException;
 
     /**
-     * Add a member to this Group.<br>
-     * Changes will be persisted immediately.
+     * Add a member to this Group.
      *
      * @return true if the <code>Authorizable</code> has successfully been added
      * to this Group, false otherwise (e.g. unknown implemention
@@ -59,8 +58,7 @@
     boolean addMember(Authorizable authorizable) throws RepositoryException;
 
     /**
-     * Remove a member from this Group.<br>
-     * Changes will be persisted immediately.
+     * Remove a member from this Group.
      *
      * @return true if the Authorizable was successfully removed. False otherwise.
      * @throws RepositoryException

Modified: jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/UserManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/UserManager.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/UserManager.java (original)
+++ jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/UserManager.java Thu Sep 24 10:30:34 2009
@@ -117,9 +117,9 @@
 
     /**
      * Creates an User for the given parameters. If the implementation is not
-     * able to deal with the <code>itermediatePath</code> that parameter should
+     * able to deal with the <code>intermediatePath</code> that parameter should
      * be ignored.
-     * Except for the <code>itermediatePath</code>, neither of the specified
+     * Except for the <code>intermediatePath</code>, neither of the specified
      * parameters can be <code>null</code>.
      *
      * @param userID

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ProtectedItemModifier.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ProtectedItemModifier.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ProtectedItemModifier.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ProtectedItemModifier.java Thu Sep 24 10:30:34 2009
@@ -64,6 +64,10 @@
     }
 
     protected NodeImpl addNode(NodeImpl parentImpl, Name name, Name ntName) throws RepositoryException {
+        return addNode(parentImpl, name, ntName, null);
+    }
+
+    protected NodeImpl addNode(NodeImpl parentImpl, Name name, Name ntName, NodeId nodeId) throws RepositoryException {
         checkPermission(parentImpl, name, getPermission(true, false));
         // validation: make sure Node is not locked or checked-in.
         parentImpl.checkSetProperty();
@@ -89,7 +93,7 @@
             }
         }
 
-        return parentImpl.createChildNode(name, nodeType, null);
+        return parentImpl.createChildNode(name, nodeType, nodeId);
     }
 
     protected Property setProperty(NodeImpl parentImpl, Name name, Value value) throws RepositoryException {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/principal/DefaultPrincipalProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/principal/DefaultPrincipalProvider.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/principal/DefaultPrincipalProvider.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/principal/DefaultPrincipalProvider.java Thu Sep 24 10:30:34 2009
@@ -101,9 +101,17 @@
             pGroupName = "rep:groups";
             pPrincipalName = "rep:principalName";
         }
+
+        // find common ancestor of all user and group nodes.
+        String userPath = userManager.getUsersPath();
+        String groupPath = userManager.getGroupsPath();
+        String obsPath = userPath;
+        while (!Text.isDescendant(obsPath, groupPath)) {
+            obsPath = Text.getRelativeParent(obsPath, 1);
+        }       
         securitySession.getWorkspace().getObservationManager().addEventListener(this,
                 Event.NODE_REMOVED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED,
-                UserManagerImpl.SECURITY_ROOT_PATH,
+                obsPath,
                 true,
                 null,
                 ntNames,

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/AuthorizableImpl.java Thu Sep 24 10:30:34 2009
@@ -16,28 +16,8 @@
  */
 package org.apache.jackrabbit.core.security.user;
 
-import java.security.Principal;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.jcr.ItemNotFoundException;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-import javax.jcr.PropertyType;
-import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.nodetype.PropertyDefinition;
-
 import org.apache.jackrabbit.api.security.principal.ItemBasedPrincipal;
-import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
-import org.apache.jackrabbit.api.security.principal.PrincipalManager;
 import org.apache.jackrabbit.api.security.user.Authorizable;
-import org.apache.jackrabbit.api.security.user.AuthorizableExistsException;
 import org.apache.jackrabbit.api.security.user.Group;
 import org.apache.jackrabbit.api.security.user.User;
 import org.apache.jackrabbit.core.NodeImpl;
@@ -45,11 +25,23 @@
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
 import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
-import org.apache.jackrabbit.core.security.principal.PrincipalIteratorAdapter;
 import org.apache.jackrabbit.spi.Name;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.PropertyDefinition;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
 /**
  * AuthorizableImpl
  */
@@ -61,7 +53,7 @@
     private final NodeImpl node;
 
     /**
-     * @param node    the Authorizable is persisted to.
+     * @param node The node this Authorizable is persisted to.
      * @param userManager UserManager that created this Authorizable.
      * @throws IllegalArgumentException if the given node isn't of node type
      * {@link #NT_REP_AUTHORIZABLE}.
@@ -78,68 +70,6 @@
 
     //-------------------------------------------------------< Authorizable >---
     /**
-     * @see Authorizable#getPrincipals()
-     */
-    public PrincipalIterator getPrincipals() throws RepositoryException {
-        Collection<Principal> coll = new ArrayList<Principal>();
-        // the first element is the main principal of this user.
-        coll.add(getPrincipal());
-        // in addition add all referees.
-        PrincipalManager prMgr = getSession().getPrincipalManager();
-        for (Object o : getRefereeValues()) {
-            String refName = ((Value) o).getString();
-            Principal princ = prMgr.getPrincipal(refName);
-            if (princ == null) {
-                log.warn("Principal " + refName + " unknown to PrincipalManager.");
-                princ = new PrincipalImpl(refName);
-            }
-            coll.add(princ);
-        }
-        return new PrincipalIteratorAdapter(coll);
-    }
-
-    /**
-     * @see Authorizable#addReferee(Principal)
-     */
-    public synchronized boolean addReferee(Principal principal) throws RepositoryException {
-        String principalName = principal.getName();
-        Value princValue = getSession().getValueFactory().createValue(principalName);
-
-        List<Value> refereeValues = getRefereeValues();
-        if (refereeValues.contains(princValue) || getPrincipal().getName().equals(principalName)) {
-            return false;
-        }
-        if (userManager.hasAuthorizableOrReferee(principal)) {
-            throw new AuthorizableExistsException("Another authorizable already represented by or refeering to " +  principalName);
-        }
-        refereeValues.add(princValue);
-
-        userManager.setProtectedProperty(node, P_REFEREES, refereeValues.toArray(new Value[refereeValues.size()]));
-        return true;
-    }
-
-    /**
-     * @see Authorizable#removeReferee(Principal)
-     */
-    public synchronized boolean removeReferee(Principal principal) throws RepositoryException {
-        Value princValue = getSession().getValueFactory().createValue(principal.getName());
-        List<Value> existingValues = getRefereeValues();
-
-        if (existingValues.remove(princValue))  {
-            PropertyImpl prop = node.getProperty(P_REFEREES);
-            if (existingValues.isEmpty()) {
-                userManager.removeProtectedItem(prop, node);
-            } else {
-                userManager.setProtectedProperty(node, P_REFEREES, existingValues.toArray(new Value[existingValues.size()]));
-            }
-            return true;
-        }
-
-        // specified principal was not referee of this authorizable.
-        return false;
-    }
-
-    /**
      * @see Authorizable#declaredMemberOf()
      */
     public Iterator<Group> declaredMemberOf() throws RepositoryException {
@@ -211,7 +141,9 @@
         checkProtectedProperty(name);
         try {
             node.setProperty(name, value);
-            node.save();
+            if (!userManager.batchModus) {
+                node.save();
+            }
         } catch (RepositoryException e) {
             log.warn("Failed to set Property " + name + " for Authorizable " + getID());
             node.refresh(false);
@@ -234,7 +166,9 @@
         checkProtectedProperty(name);
         try {
             node.setProperty(name, values);
-            node.save();
+            if (!userManager.batchModus) {
+                node.save();
+            }
         } catch (RepositoryException e) {
             log.warn("Failed to set Property " + name + " for Authorizable " + getID());
             node.refresh(false);
@@ -255,7 +189,9 @@
                 } else {
                     p.setValue((Value) null);
                 }
-                node.save();
+                if (!userManager.batchModus) {
+                    node.save();
+                }
                 return true;
             } else {
                 return false;
@@ -416,7 +352,7 @@
     private boolean isProtectedProperty(String propertyName) throws RepositoryException {
         Name pName = getSession().getQName(propertyName);
         return P_PRINCIPAL_NAME.equals(pName) || P_USERID.equals(pName)
-                || P_REFEREES.equals(pName) || P_GROUPS.equals(pName)
+                || P_GROUPS.equals(pName)
                 || P_IMPERSONATORS.equals(pName) || P_PASSWORD.equals(pName);
     }
 
@@ -435,19 +371,6 @@
         }
     }
 
-    private List<Value> getRefereeValues() throws RepositoryException {
-        List<Value> principalNames = new ArrayList<Value>();
-        if (node.hasProperty(P_REFEREES)) {
-            try {
-                principalNames.addAll(Arrays.asList(
-                        node.getProperty(P_REFEREES).getValues()));
-            } catch (PathNotFoundException e) {
-                // ignore. should never occur.
-            }
-        }
-        return principalNames;
-    }
-
     //--------------------------------------------------------------------------
     /**
      *

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/GroupImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/GroupImpl.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/GroupImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/GroupImpl.java Thu Sep 24 10:30:34 2009
@@ -35,7 +35,6 @@
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.NoSuchElementException;
 import java.util.Set;
 
 /**
@@ -55,7 +54,7 @@
         if (node == null || !node.isNodeType(NT_REP_GROUP)) {
             throw new IllegalArgumentException();
         }
-        if (!Text.isDescendant(GROUPS_PATH, node.getPath())) {
+        if (!Text.isDescendant(userManager.getGroupsPath(), node.getPath())) {
             throw new IllegalArgumentException("Group has to be within the Group Path");
         }
         return new GroupImpl(node, userManager);
@@ -213,54 +212,6 @@
     }
 
     //------------------------------------------------------< inner classes >---
-    private class MemberIterator implements Iterator {
-
-        private final Iterator ids;
-        private Authorizable next;
-
-        private MemberIterator(Iterator ids) {
-            this.ids = ids;
-            next = seekNext();
-        }
-
-        public boolean hasNext() {
-            return next != null;
-        }
-
-        public Object next() {
-            if (next == null) {
-                throw new NoSuchElementException();
-            }
-
-            Authorizable n = next;
-            next = seekNext();
-            return n;
-        }
-
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-
-        private Authorizable seekNext() {
-            Authorizable auth = null;
-            while (auth == null && ids.hasNext()) {
-                String uuid = (String) ids.next();
-                try {
-                    NodeImpl mem = (NodeImpl) getSession().getNodeByUUID(uuid);
-                    if (mem.isNodeType(NT_REP_GROUP)) {
-                        auth = userManager.createGroup(mem);
-                    } else {
-                        auth = userManager.createUser(mem);
-                    }
-                } catch (RepositoryException e) {
-                    log.warn("Internal error while building next member.", e.getMessage());
-                    // ignore and try next
-                }
-            }
-            return auth;
-        }
-    }
-
     /**
      *
      */
@@ -345,8 +296,6 @@
                 try {
                     for (Iterator it = GroupImpl.this.getMembers(); it.hasNext();) {
                         Authorizable authrz = (Authorizable) it.next();
-                        // NOTE: only add main principal, since 'referees' belong
-                        // to a different provider and should not be exposed here
                         members.add(authrz.getPrincipal());
                     }
                 } catch (RepositoryException e) {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/ImpersonationImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/ImpersonationImpl.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/ImpersonationImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/ImpersonationImpl.java Thu Sep 24 10:30:34 2009
@@ -97,12 +97,9 @@
 
         String pName = principal.getName();
         // make sure user does not impersonate himself
-        for (PrincipalIterator it = user.getPrincipals(); it.hasNext();) {
-            Principal p = it.nextPrincipal();
-            if (p.getName().equals(pName)) {
-                log.debug("Cannot grant impersonation to oneself.");
-                return false;
-            }
+        if (user.getPrincipal().getName().equals(pName)) {
+            log.debug("Cannot grant impersonation to oneself.");
+            return false;
         }
 
         boolean granted = false;

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/IndexNodeResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/IndexNodeResolver.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/IndexNodeResolver.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/IndexNodeResolver.java Thu Sep 24 10:30:34 2009
@@ -27,7 +27,6 @@
 import javax.jcr.query.Query;
 import javax.jcr.query.QueryManager;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.Set;
 
 /**

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/NodeResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/NodeResolver.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/NodeResolver.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/NodeResolver.java Thu Sep 24 10:30:34 2009
@@ -26,6 +26,7 @@
 
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
+import org.apache.jackrabbit.test.api.util.Text;
 
 /**
  * Resolver: searches for Principals stored in Nodes of a {@link javax.jcr.Workspace}
@@ -37,6 +38,10 @@
     private final Session session;
     private final NamePathResolver resolver;
 
+    private String userSearchRoot = UserConstants.USERS_PATH;
+    private String groupSearchRoot = UserConstants.GROUPS_PATH;
+    private String authorizableSearchRoot = UserConstants.AUTHORIZABLES_PATH;
+
     /**
      * Create a new <code>NodeResolver</code>.
      *
@@ -49,6 +54,16 @@
         this.resolver = resolver;
     }
 
+    void setSearchRoots(String userSearchRoot, String groupSearchRoot) {
+        this.userSearchRoot = userSearchRoot;
+        this.groupSearchRoot = groupSearchRoot;
+
+        authorizableSearchRoot = userSearchRoot;
+        while (!Text.isDescendant(authorizableSearchRoot, groupSearchRoot)) {
+            authorizableSearchRoot = Text.getRelativeParent(authorizableSearchRoot, 1);
+        }
+    }
+
     /**
      * Get the first node that matches <code>ntName</code> and whose name
      * exactly matches the given <code>nodeName</code>.
@@ -133,11 +148,11 @@
     String getSearchRoot(Name ntName) {
         String searchRoot;
         if (UserConstants.NT_REP_USER.equals(ntName)) {
-            searchRoot = UserConstants.USERS_PATH;
+            searchRoot = userSearchRoot;
         } else if (UserConstants.NT_REP_GROUP.equals(ntName)) {
-            searchRoot = UserConstants.GROUPS_PATH;
+            searchRoot = groupSearchRoot;
         } else {
-            searchRoot = UserConstants.AUTHORIZABLES_PATH;
+            searchRoot = authorizableSearchRoot;
         }
         return searchRoot;
     }

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserAccessControlProvider.java Thu Sep 24 10:30:34 2009
@@ -239,11 +239,14 @@
             return session.getProperty(absPath).getParent();
         } else {
             String pPath = Text.getRelativeParent(absPath, 1);
-            if (session.nodeExists(pPath)) {
-                return session.getNode(pPath);
-            } else {
-                throw new ItemNotFoundException("Unable to determine permissions: No item and no existing parent for target path " + absPath);
-            }
+            while (!"/".equals(pPath)) {
+                if (session.nodeExists(pPath)) {
+                    return session.getNode(pPath);
+                } else {
+                    pPath = Text.getRelativeParent(pPath, 1);
+                }
+            }         
+            throw new ItemNotFoundException("Unable to determine permissions: No item and no existing parent for target path " + absPath);
         }
     }
 

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=818433&r1=818432&r2=818433&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 Thu Sep 24 10:30:34 2009
@@ -46,9 +46,7 @@
      */
     String GROUP_ADMIN_GROUP_NAME = "GroupAdmin";
 
-    Name P_REFEREES = NF.create(Name.NS_REP_URI, "referees");
     Name P_PRINCIPAL_NAME = NF.create(Name.NS_REP_URI, "principalName");
-
     Name P_USERID = NF.create(Name.NS_REP_URI, "userId");
     Name P_PASSWORD = NF.create(Name.NS_REP_URI, "password");
 

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=818433&r1=818432&r2=818433&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 Thu Sep 24 10:30:34 2009
@@ -87,8 +87,7 @@
     public Credentials getCredentials() throws RepositoryException {
         try {
             String password = getNode().getProperty(P_PASSWORD).getString();
-            Credentials creds = new CryptedSimpleCredentials(getID(), password);
-            return creds;
+            return new CryptedSimpleCredentials(id, password);
         } catch (NoSuchAlgorithmException e) {
             throw new RepositoryException(e);
         } catch (UnsupportedEncodingException e) {

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/security/user/UserManagerImpl.java Thu Sep 24 10:30:34 2009
@@ -27,9 +27,9 @@
 import org.apache.jackrabbit.core.ProtectedItemModifier;
 import org.apache.jackrabbit.core.SessionImpl;
 import org.apache.jackrabbit.core.SessionListener;
+import org.apache.jackrabbit.core.id.NodeId;
 import org.apache.jackrabbit.core.security.principal.PrincipalImpl;
 import org.apache.jackrabbit.spi.Name;
-import org.apache.jackrabbit.spi.commons.name.NameConstants;
 import org.apache.jackrabbit.util.Text;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -41,6 +41,8 @@
 import javax.jcr.NodeIterator;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
+import javax.jcr.Session;
+import javax.jcr.ItemNotFoundException;
 import javax.jcr.lock.LockException;
 import javax.jcr.nodetype.ConstraintViolationException;
 import javax.jcr.version.VersionException;
@@ -50,6 +52,8 @@
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.Properties;
+import java.util.UUID;
+import java.io.UnsupportedEncodingException;
 
 /**
  * Default implementation of the <code>UserManager</code> interface with the
@@ -58,30 +62,33 @@
  * <ul>
  * <li>Users and Groups are stored in the repository as JCR nodes.</li>
  * <li>Users are created below {@link UserConstants#USERS_PATH},<br>Groups are
- * created below {@link UserConstants#GROUPS_PATH}.</li>
- * <li>In order to structure the users and groups tree and void creating a flat
+ * created below {@link UserConstants#GROUPS_PATH} (unless otherwise configured).</li>
+ * <li>The Id of an authorizable is stored in the jcr:uuid property (md5 hash).</li>
+ * <li>In order to structure the users and groups tree and avoid creating a flat
  * hierarchy, additional hierarchy nodes of type "rep:AuthorizableFolder" are
- * introduced.</li>
+ * introduced using
+ *    <ul>
+ *    <li>the specified intermediate path passed to the create methods</li>
+ *    <li>or some built-in logic if the intermediate path is missing.</li>
+ *    </ul>
+ * </li>
+ * </ul>
+ *
+ * The built-in logic applies the following rules:
+ * <ul>
  * <li>The names of the hierarchy folders is determined from ID of the
  * authorizable to be created, consisting of the leading N chars where N is
  * the relative depth starting from the node at {@link UserConstants#USERS_PATH}
  * or {@link UserConstants#GROUPS_PATH}.</li>
  * <li>By default 2 levels (depth == 2) are created.</li>
- * <li>Searching authorizables by ID always starts looking at that specific
- * hierarchy level. Parent nodes are expected to consist of folder structure only.</li>
+ * <li>Parent nodes are expected to consist of folder structure only.</li>
  * <li>If the ID contains invalid JCR chars that would prevent the creation of
  * a Node with that name, the names of authorizable node and the intermediate
  * hierarchy nodes are {@link Text#escapeIllegalJcrChars(String) escaped}.</li>
- * <li>Any intermediate path passed to either
- * {@link #createUser(String, String, Principal, String) createUser} or
- * {@link #createGroup(Principal, String) createGroup} are ignored. This allows
- * to directly find authorizables by ID without having to search or traverse
- * the complete tree.<br>
- * See also {@link #PARAM_COMPATIBILE_JR16}.
- * </li>
  * </ul>
- * Example: Creating an non-existing authorizable with ID 'aSmith' would result
- * in the following structure:
+ * Examples:
+ * Creating an non-existing user with ID 'aSmith' without specifying an
+ * intermediate path would result in the following structure:
  * 
  * <pre>
  * + rep:security            [nt:unstructured]
@@ -92,10 +99,26 @@
  *           + aSmith        [rep:User]
  * </pre>
  *
+ * Creating a non-existing user with ID 'aSmith' specifying an intermediate
+ * path 'some/tree' would result in the following structure:
+ *
+ * <pre>
+ * + rep:security            [nt:unstructured]
+ *   + rep:authorizables     [rep:AuthorizableFolder]
+ *     + rep:users           [rep:AuthorizableFolder]
+ *       + some              [rep:AuthorizableFolder]
+ *         + tree            [rep:AuthorizableFolder]
+ *           + aSmith        [rep:User]
+ * </pre>
+ *
  * This <code>UserManager</code> is able to handle the following configuration
  * options:
  *
  * <ul>
+ * <li>{@link #PARAM_USERS_PATH}: Defines where user nodes are created.
+ * If missing set to {@link #USERS_PATH}.</li>
+ * <li>{@link #PARAM_GROUPS_PATH}. Defines where group nodes are created.
+ * If missing set to {@link #GROUPS_PATH}.</li>
  * <li>{@link #PARAM_COMPATIBILE_JR16}: If the param is present and its
  * value is <code>true</code> looking up authorizables by ID will use the
  * <code>NodeResolver</code> if not found otherwise.<br>
@@ -103,23 +126,9 @@
  * with a Jackrabbit repository &lt; v2.0 will not be found any more.<br>
  * By default this option is disabled.</li>
  * <li>{@link #PARAM_DEFAULT_DEPTH}: Parameter used to change the number of
- * levels that are used by default store authorizable nodes.<br>The value is
+ * levels that are used by default to store authorizable nodes.<br>The value is
  * expected to be a positive integer greater than zero. The default
  * number of levels is 2.
- * <p/>
- * <strong>NOTE:</strong> Changing the default depth once users and groups
- * have been created in the repository will cause inconsistencies, due to
- * the fact that the resolution of ID to an authorizable relies on the
- * structure defined by the default depth.<br>
- * It is recommended to remove all authorizable nodes that will not be
- * reachable any more, before this config option is changed.
- * <ul>
- * <li>If default depth is increased:<br>
- * All authorizables on levels &lt; default depth are not reachable any more.</li>
- * <li>If default depth is decreased:<br>
- * All authorizables on levels &gt; default depth aren't reachable any more
- * unless the {@link #PARAM_AUTO_EXPAND_TREE} flag is set to <code>true</code>.</li>
- * </ul>
  * </li>
  * <li>{@link #PARAM_AUTO_EXPAND_TREE}: If this parameter is present and its
  * value is <code>true</code>, the trees containing user and group nodes will
@@ -135,6 +144,18 @@
         implements UserManager, UserConstants, SessionListener {
 
     /**
+     * Configuration option to change the {@link #USERS_PATH default path} for
+     * creating users.
+     */
+    public static final String PARAM_USERS_PATH = "usersPath";
+
+    /**
+     * Configuration option to change the {@link #GROUPS_PATH default path} for
+     * creating groups.
+     */
+    public static final String PARAM_GROUPS_PATH = "groupsPath";
+
+    /**
      * Flag to enable a minimal backwards compatibility with Jackrabbit &lt;
      * v2.0<br>
      * If the param is present and its value is <code>true</code> looking up
@@ -186,7 +207,19 @@
     private final SessionImpl session;
     private final String adminId;
     private final NodeResolver authResolver;
-    private final IdResolver idResolver;
+    private final NodeCreator nodeCreator;
+
+    /**
+     * Configuration value defining the node where User nodes will be created.
+     * Default value is {@link #USERS_PATH}.
+     */
+    private final String usersPath;
+
+    /**
+     * Configuration value defining the node where Group nodes will be created.
+     * Default value is {@link #GROUPS_PATH}.
+     */
+    private final String groupsPath;
 
     /**
      * Flag indicating if {@link #getAuthorizable(String)} should find users or
@@ -199,6 +232,17 @@
     private final boolean compatibleJR16;
 
     /**
+     * Flat storing the batch modus.
+     * If this option is turned on changes made through this user manager will
+     * only be persisted upon an explicit call to {@link javax.jcr.Session#save()},
+     * which must be the editing session object. Otherwise (default behavior)
+     * changes are immediately persisted.
+     *
+     * @see #setPersistenceModus(boolean, Session)
+     */
+    boolean batchModus = false;
+
+    /**
      * Create a new <code>UserManager</code> with the default configuration.
      *
      * @param session
@@ -214,7 +258,8 @@
      * Currently the following configuration options are respected:
      *
      * <ul>
-     * <li>{@link #PARAM_COMPATIBILE_JR16}. By default this option is disabled.</li>
+     * <li>{@link #PARAM_USERS_PATH}. If missing set to {@link #USERS_PATH}.</li>
+     * <li>{@link #PARAM_GROUPS_PATH}. If missing set to {@link #GROUPS_PATH}.</li>
      * <li>{@link #PARAM_DEFAULT_DEPTH}. The default number of levels is 2.</li>
      * <li>{@link #PARAM_AUTO_EXPAND_TREE}. By default this option is disabled.</li>
      * <li>{@link #PARAM_AUTO_EXPAND_SIZE}. The default value is 1000.</li>
@@ -231,6 +276,17 @@
         this.session = session;
         this.adminId = adminId;
 
+        nodeCreator = new NodeCreator(config);
+
+        Object param = (config != null) ? config.get(PARAM_USERS_PATH) : null;
+        usersPath = (param != null) ? param.toString() : USERS_PATH;
+
+        param = (config != null) ? config.get(PARAM_GROUPS_PATH) : null;
+        groupsPath = (param != null) ? param.toString() : GROUPS_PATH;
+
+        param = (config != null) ? config.get(PARAM_COMPATIBILE_JR16) : null;
+        compatibleJR16 = (param != null) && Boolean.parseBoolean(param.toString());
+
         NodeResolver nr;
         try {
             nr = new IndexNodeResolver(session, session);
@@ -239,13 +295,45 @@
             nr = new TraversingNodeResolver(session, session);
         }
         authResolver = nr;
+        authResolver.setSearchRoots(usersPath, groupsPath);
+    }
 
-        idResolver = new IdResolver(config);
-        boolean compatMode = false;
-        if (config != null && config.containsKey(PARAM_COMPATIBILE_JR16)) {
-            compatMode = Boolean.parseBoolean(config.get(PARAM_COMPATIBILE_JR16).toString());
+    /**
+     * @param batched If <code>true</code> changes made through this manager and
+     * to authorizables are only persisted upon explict call to {@link
+     * javax.jcr.Session#save()}.
+     * @throws RepositoryException If the passed <code>editingSession</code> is
+     * not the same this UserManager is writing to.
+     */
+    /* COMMENTED. WORK IN PROGRESS
+    public void setPersistenceModus(boolean batched, Session editingSession) throws RepositoryException {
+        if (editingSession != session) {
+            throw new RepositoryException("Cannot change persistence modus: Session mismatch.");
         }
-        compatibleJR16 = compatMode;
+        batchModus = batched;
+    }
+    */
+
+    /**
+     * Implementation specific methods releaving where users are created within
+     * the content.
+     *
+     * @return root path for user content.
+     * @see #PARAM_USERS_PATH For the corresponding configuration parameter.
+     */
+    public String getUsersPath() {
+        return usersPath;
+    }
+
+    /**
+     * Implementation specific methods releaving where groups are created within
+     * the content.
+     *
+     * @return root path for group content.
+     * @see #PARAM_GROUPS_PATH For the corresponding configuration parameter.
+     */
+    public String getGroupsPath() {
+        return groupsPath;
     }
 
     //--------------------------------------------------------< UserManager >---
@@ -257,15 +345,34 @@
             throw new IllegalArgumentException("Invalid authorizable name '" + id + "'");
         }
         Authorizable authorz = null;
-        NodeImpl n = getUserNode(id);
+        NodeId nodeId = buildNodeId(id);        
+        NodeImpl n = null;
+        try {
+            n = session.getNodeById(nodeId);
+        } catch (ItemNotFoundException e) {
+            if (compatibleJR16) {
+                // backwards-compatibility with JR < 2.0 user/group structure that doesn't
+                // allow to determine existance of an authorizable from the id directly.
+                // search for it the node belonging to that id
+                n = (NodeImpl) authResolver.findNode(P_USERID, id, NT_REP_USER);
+                if (n == null) {
+                    // no user -> look for group.
+                    // NOTE: JR < 2.0 always returned groupIDs that didn't contain any
+                    // illegal JCR chars. Since Group.getID() now unescapes the node
+                    // name additional escaping is required.
+                    Name nodeName = session.getQName(Text.escapeIllegalJcrChars(id));
+                    n = (NodeImpl) authResolver.findNode(nodeName, NT_REP_GROUP);
+                }
+            } // else: no matching node found -> ignore exception.
+        }
+
         if (n != null) {
-            authorz = createUser(n);
-        } else {
-            n = getGroupNode(id);
-            if (n != null) {
+            if (n.isNodeType(NT_REP_USER)) {
+                authorz = createUser(n);
+            } else if (n.isNodeType(NT_REP_GROUP)) {
                 authorz = createGroup(n);
-            }
-        }
+            } // else some other node but not an authorizable -> return null.
+        } // else no matching node -> return null.
         return authorz;
     }
 
@@ -373,21 +480,19 @@
         if (getAuthorizable(userID) != null) {
             throw new AuthorizableExistsException("User for '" + userID + "' already exists");
         }
-        if (hasAuthorizableOrReferee(principal)) {
+        if (hasAuthorizable(principal)) {
             throw new AuthorizableExistsException("Authorizable for '" + principal.getName() + "' already exists");
         }
-        if (intermediatePath != null) {
-            log.debug("Intermediate path param " + intermediatePath + " is ignored.");
-        }
 
-        NodeImpl parent = null;
         try {
-            NodeImpl userNode = (NodeImpl) idResolver.createUserNode(userID);
+            NodeImpl userNode = (NodeImpl) nodeCreator.createUserNode(userID, intermediatePath);
 
             setProperty(userNode, P_USERID, getValue(userID), true);
             setProperty(userNode, P_PASSWORD, getValue(UserImpl.buildPasswordValue(password)), true);
             setProperty(userNode, P_PRINCIPAL_NAME, getValue(principal.getName()), true);
-            session.save();
+            if (!batchModus) {
+                session.save();
+            }
 
             log.debug("User created: " + userID + "; " + userNode.getPath());
             return createUser(userNode);
@@ -429,20 +534,18 @@
         if (!isValidPrincipal(principal)) {
             throw new IllegalArgumentException("Cannot create Group: Principal may not be null and must have a valid name.");
         }
-        if (hasAuthorizableOrReferee(principal)) {
+        if (hasAuthorizable(principal)) {
             throw new AuthorizableExistsException("Authorizable for '" + principal.getName() + "' already exists: ");
         }
-        if (intermediatePath != null) {
-            log.debug("Intermediate path param " + intermediatePath + " is ignored.");
-        }
         
-        NodeImpl parent = null;
         try {
             String groupID = getGroupId(principal.getName());
-            NodeImpl groupNode = (NodeImpl) idResolver.createGroupNode(groupID);
+            NodeImpl groupNode = (NodeImpl) nodeCreator.createGroupNode(groupID, intermediatePath);
 
             setProperty(groupNode, P_PRINCIPAL_NAME, getValue(principal.getName()));
-            session.save();
+            if (!batchModus) {
+                session.save();
+            }
 
             log.debug("Group created: " + groupID + "; " + groupNode.getPath());
 
@@ -461,32 +564,36 @@
      * @return
      * @throws RepositoryException
      */
-    boolean hasAuthorizableOrReferee(Principal principal) throws RepositoryException {
-        Set<Name> s = new HashSet<Name>(2);
-        s.add(P_PRINCIPAL_NAME);
-        s.add(P_REFEREES);
-        NodeIterator res = authResolver.findNodes(s, principal.getName(), NT_REP_AUTHORIZABLE, true, 1);
-        return res.hasNext();
+    private boolean hasAuthorizable(Principal principal) throws RepositoryException {
+        return getAuthorizable(principal) != null;
     }
 
     void setProtectedProperty(NodeImpl node, Name propName, Value value) throws RepositoryException, LockException, ConstraintViolationException, ItemExistsException, VersionException {
         setProperty(node, propName, value);
-        node.save();
+        if (!batchModus) {
+            node.save();
+        }
     }
 
     void setProtectedProperty(NodeImpl node, Name propName, Value[] values) throws RepositoryException, LockException, ConstraintViolationException, ItemExistsException, VersionException {
         setProperty(node, propName, values);
-        node.save();
+        if (!batchModus) {
+            node.save();
+        }
     }
 
     void setProtectedProperty(NodeImpl node, Name propName, Value[] values, int type) throws RepositoryException, LockException, ConstraintViolationException, ItemExistsException, VersionException {
         setProperty(node, propName, values, type);
-        node.save();
+        if (!batchModus) {
+            node.save();
+        }
     }
 
     void removeProtectedItem(ItemImpl item, Node parent) throws RepositoryException, AccessDeniedException, VersionException {
         removeItem(item);
-        parent.save();
+        if (!batchModus) {
+            parent.save();
+        }
     }
 
     /**
@@ -499,11 +606,10 @@
      * @throws RepositoryException
      */
     private String getGroupId(String principalName) throws RepositoryException {
-        String escHint = principalName;
-        String groupID = escHint;
+        String groupID = principalName;
         int i = 0;
         while (getAuthorizable(groupID) != null) {
-            groupID = escHint + "_" + i;
+            groupID = principalName + "_" + i;
             i++;
         }
         return groupID;
@@ -532,11 +638,10 @@
         if (userNode == null || !userNode.isNodeType(NT_REP_USER)) {
             throw new IllegalArgumentException();
         }
-        if (!Text.isDescendant(USERS_PATH, userNode.getPath())) {
+        if (!Text.isDescendant(usersPath, userNode.getPath())) {
             throw new IllegalArgumentException("User has to be within the User Path");
         }
-        User user = doCreateUser(userNode);
-        return user;
+        return doCreateUser(userNode);
     }
 
     /**
@@ -560,52 +665,26 @@
      * @throws RepositoryException
      */
     Group createGroup(NodeImpl groupNode) throws RepositoryException {
-        Group group = GroupImpl.create(groupNode, this);
-        return group;
+        return GroupImpl.create(groupNode, this);
     }
 
-    /**
-     * Resolve the given <code>userID</code> to an rep:user node in the repository.
-     *
-     * @param userID A valid userID.
-     * @return the node associated with the given userID or <code>null</code>.
-     * @throws RepositoryException If an error occurs.
-     */
-    private NodeImpl getUserNode(String userID) throws RepositoryException {
-        NodeImpl n = (NodeImpl) idResolver.findNode(userID, false);
-        if (n == null && compatibleJR16) {
-            // backwards-compatibility with JR < 2.0 user structure that doesn't
-            // allow to determine the auth-path from the id directly.
-            // search for it the node belonging to that userID
-            n = (NodeImpl) authResolver.findNode(P_USERID, userID, NT_REP_USER);
-        } // else: no such user -> return null.
-        return n;
+    private static boolean isValidPrincipal(Principal principal) {
+        return principal != null && principal.getName() != null && principal.getName().length() > 0;
     }
 
     /**
-     * Resolve the given <code>groupID</code> to an rep:group node in the repository.
      *
-     * @param groupID A valid groupID.
-     * @return the node associated with the given userID or <code>null</code>.
-     * @throws RepositoryException If an error occurs.
-     */
-    private NodeImpl getGroupNode(String groupID) throws RepositoryException {
-        NodeImpl n = (NodeImpl) idResolver.findNode(groupID, true);
-        if (n == null && compatibleJR16) {
-            // backwards-compatibility with JR < 2.0 group structure that doesn't
-            // allow to determine the auth-path from the id directly
-            // search for it the node belonging to that groupID.
-            // NOTE: JR < 2.0 always returned groupIDs that didn't contain any
-            // illegal JCR chars. Since Group.getID() now unescapes the node
-            // name additional escaping is required.
-            Name nodeName = session.getQName(Text.escapeIllegalJcrChars(groupID));
-            n = (NodeImpl) authResolver.findNode(nodeName, NT_REP_GROUP);
-        } // else: no such group -> return null.
-        return n;
-    }
-
-    private static boolean isValidPrincipal(Principal principal) {
-        return principal != null && principal.getName() != null && principal.getName().length() > 0;
+     * @param id
+     * @return
+     * @throws RepositoryException
+     */
+    private static NodeId buildNodeId(String id) throws RepositoryException {
+        try {
+            UUID uuid = UUID.nameUUIDFromBytes(id.getBytes("UTF-8"));
+            return new NodeId(uuid);
+        } catch (UnsupportedEncodingException e) {
+            throw new RepositoryException("Unexpected error while build ID hash", e);
+        }
     }
 
     //----------------------------------------------------< SessionListener >---
@@ -700,14 +779,16 @@
 
     //--------------------------------------------------------------------------
     /**
-     * Inner class creating and finding the JCR nodes corresponding the a given
+     * Inner class creating the JCR nodes corresponding the a given
      * authorizable ID with the following behavior:
      * <ul>
-     * <li>Users are created below /rep:security/rep:authorizables/rep:users</li>
-     * <li>Groups are created below /rep:security/rep:authorizables/rep:users</li>
+     * <li>Users are created below /rep:security/rep:authorizables/rep:users or
+     * the corresponding path configured.</li>
+     * <li>Groups are created below /rep:security/rep:authorizables/rep:groups or
+     * the corresponding path configured.</li>
      * <li>Below each category authorizables are created within a human readable
-     * structure, whose depth is defined by the <code>defaultDepth</code> config
-     * option.<br>
+     * structure based on the defined intermediate path or some internal logic
+     * with a depth defined by the <code>defaultDepth</code> config option.<br>
      * E.g. creating a user node for an ID 'aSmith' would result in the following
      * structure assuming defaultDepth == 2 is used:
      * <pre>
@@ -723,8 +804,8 @@
      * {@link Text#escapeIllegalJcrChars(String) escaping} any illegal JCR chars.
      * In case of a Group the node name is calculated from the specified principal
      * name circumventing any conflicts with existing ids and escaping illegal chars.</li>
-     * <li>The names of the intermediate folders are caculated from the leading
-     * chars of the escaped node name.</li>
+     * <li>If no intermediate path is passed the names of the intermediate
+     * folders are calculated from the leading chars of the escaped node name.</li>
      * <li>If the escaped node name is shorter than the <code>defaultDepth</code>
      * the last char is repeated.<br>
      * E.g. creating a user node for an ID 'a' would result in the following
@@ -832,7 +913,7 @@
      * autoExpandSize.</li>
      * </ul>
      */
-    private class IdResolver {
+    private class NodeCreator {
 
         private static final String DELIMITER = "/";
         private static final int DEFAULT_DEPTH = 2;
@@ -845,7 +926,7 @@
         // all child nodes.
         private final long autoExpandSize;
 
-        private IdResolver(Properties config) {
+        private NodeCreator(Properties config) {
             int d = DEFAULT_DEPTH;
             boolean expand = false;
             long size = DEFAULT_SIZE;
@@ -883,83 +964,46 @@
             autoExpandSize = size;
         }
 
-        public Node createUserNode(String userID) throws RepositoryException {
-            return createAuthorizableNode(userID, false);
+        public Node createUserNode(String userID, String intermediatePath) throws RepositoryException {
+            return createAuthorizableNode(userID, false, intermediatePath);
         }
 
-        public Node createGroupNode(String groupID) throws RepositoryException {
-            return createAuthorizableNode(groupID, true);
+        public Node createGroupNode(String groupID, String intermediatePath) throws RepositoryException {
+            return createAuthorizableNode(groupID, true, intermediatePath);
         }
 
-        public Node findNode(String id, boolean isGroup) throws RepositoryException {
-            String defaultFolderPath = getDefaultFolderPath(id, isGroup);
-            String escapedId = Text.escapeIllegalJcrChars(id);
-
-            if (session.nodeExists(defaultFolderPath)) {
-                Node folder = session.getNode(defaultFolderPath);
-                Name expectedNt = (isGroup) ? NT_REP_GROUP : NT_REP_USER;
-
-                // traverse the potentially existing hierarchy looking for the
-                // authorizable node.
-                int segmLength = defaultDepth +1;
-                while (folder != null) {
-                    if (folder.hasNode(escapedId)) {
-                        NodeImpl aNode = (NodeImpl) folder.getNode(escapedId);
-                        if (aNode.isNodeType(expectedNt)) {
-                            // done. found the right auth-node
-                            return aNode;
-                        } else {
-                            folder = aNode;
-                        }
-                    } else {
-                        // no child node with name 'escapedId' -> look for
-                        // additional levels that may exist.
-                        Node parent = folder;
-                        folder = null;
-                        if (id.length() >= segmLength) {
-                            String folderName = Text.escapeIllegalJcrChars(id.substring(0, segmLength));
-                            if (parent.hasNode(folderName)) {
-                                NodeImpl f = (NodeImpl) parent.getNode(folderName);
-                                if (f.isNodeType(NT_REP_AUTHORIZABLE_FOLDER)) {
-                                    folder = f;
-                                } // else: matching node isn't an authorizable-folder
-                            } // else: failed to find a suitable next level
-                        } // else: id is shorter than required length at the current level.
-                    }
-                    segmLength++;
-                }
-            } // else: no node at default-path
-
-            // no matching node found -> authorizable doesn't exist.
-            return null;
-        }
-
-        private Node createAuthorizableNode(String id, boolean isGroup) throws RepositoryException {
+        private Node createAuthorizableNode(String id, boolean isGroup, String intermediatePath) throws RepositoryException {
             String escapedId = Text.escapeIllegalJcrChars(id);
 
+            Node folder;
             // first create the default folder nodes, that are always present.
-            Node folder = createDefaultFolderNodes(id, escapedId, isGroup);
+            folder = createDefaultFolderNodes(id, escapedId, isGroup, intermediatePath);
             // eventually create additional intermediate folders.
-            folder = createIntermediateFolderNodes(id, escapedId, folder);
+            if (intermediatePath == null) {
+                // internal logic only
+                folder = createIntermediateFolderNodes(id, escapedId, folder);
+            }
 
             // finally create the authorizable node
             Name nodeName = session.getQName(escapedId);
             Name ntName = (isGroup) ? NT_REP_GROUP : NT_REP_USER;
-            Node authNode = addNode((NodeImpl) folder, nodeName, ntName);
+            NodeId nid = buildNodeId(id);
 
-            return authNode;
+            return addNode((NodeImpl) folder, nodeName, ntName, nid);
         }
 
-        private Node createDefaultFolderNodes(String id, String escapedId, boolean isGroup) throws RepositoryException {
+        private Node createDefaultFolderNodes(String id, String escapedId,
+                                              boolean isGroup, String intermediatePath) throws RepositoryException {
             NodeImpl folder;
-            // first create the levels that are always present -> see #getDefaultFolderPath
-            String defaultPath = getDefaultFolderPath(id, isGroup);
+            String defaultPath = getDefaultFolderPath(id, isGroup, intermediatePath);
             if (session.nodeExists(defaultPath)) {
                 folder = (NodeImpl) session.getNode(defaultPath);
+                if (!folder.isNodeType(NT_REP_AUTHORIZABLE_FOLDER)) {
+                    throw new RepositoryException("Invalid intermediate path. Must be of type rep:AuthorizableFolder.");
+                }
             } else {
                 String[] segmts = defaultPath.split("/");
                 folder = (NodeImpl) session.getRootNode();
-                String repSecurity = SECURITY_ROOT_PATH.substring(1);
 
                 for (String segment : segmts) {
                     if (segment.length() < 1) {
@@ -967,42 +1011,52 @@
                     }
                     if (folder.hasNode(segment)) {
                         folder = (NodeImpl) folder.getNode(segment);
-                    } else {
-                        Name ntName;
-                        if (repSecurity.equals(segment)) {
-                            // rep:security node
-                            ntName = NameConstants.NT_UNSTRUCTURED;
-                        } else {
-                            ntName = NT_REP_AUTHORIZABLE_FOLDER;
+                        if (!folder.isNodeType(NT_REP_AUTHORIZABLE_FOLDER)) {
+                            throw new RepositoryException("Invalid intermediate path. Must be of type rep:AuthorizableFolder.");
                         }
-                        NodeImpl added = addNode(folder, session.getQName(segment), ntName);
-                        folder = added;
+                    } else {
+                        folder = addNode(folder, session.getQName(segment), NT_REP_AUTHORIZABLE_FOLDER);
                     }
                 }
             }
 
-            // validation check if authorizable to be create doesn't conflict.
+            // validation check if authorizable to be created doesn't conflict.
             checkAuthorizableNodeExists(escapedId, folder);
             return folder;
         }
 
-        private String getDefaultFolderPath(String id, boolean isGroup) {
+        private String getDefaultFolderPath(String id, boolean isGroup, String intermediatePath) {
             StringBuilder bld = new StringBuilder();
             if (isGroup) {
-                bld.append(GROUPS_PATH);
+                bld.append(groupsPath);
             } else {
-                bld.append(USERS_PATH);
+                bld.append(usersPath);
             }
-            StringBuilder lastSegment = new StringBuilder(defaultDepth);
-            int idLength = id.length();
-            for (int i = 0; i < defaultDepth; i++) {
-                if (idLength > i) {
-                    lastSegment.append(id.charAt(i));
-                } else {
-                    // escapedID is too short -> append the last char again
-                    lastSegment.append(id.charAt(idLength-1));
+
+            if (intermediatePath == null) {
+                // internal logic
+                StringBuilder lastSegment = new StringBuilder(defaultDepth);
+                int idLength = id.length();
+                for (int i = 0; i < defaultDepth; i++) {
+                    if (idLength > i) {
+                        lastSegment.append(id.charAt(i));
+                    } else {
+                        // escapedID is too short -> append the last char again
+                        lastSegment.append(id.charAt(idLength-1));
+                    }
+                    bld.append(DELIMITER).append(Text.escapeIllegalJcrChars(lastSegment.toString()));
+                }
+            } else {
+                // structure defined by intermediate path
+                if (intermediatePath.startsWith(bld.toString())) {
+                    intermediatePath = intermediatePath.substring(bld.toString().length());
+                }
+                if (intermediatePath.length() > 0 && !"/".equals(intermediatePath)) {
+                    if (!intermediatePath.startsWith("/")) {
+                        bld.append("/");
+                    }
+                    bld.append(intermediatePath);
                 }
-                bld.append(DELIMITER).append(Text.escapeIllegalJcrChars(lastSegment.toString()));
             }
             return bld.toString();
         }
@@ -1018,8 +1072,7 @@
             // - if the auth-node to be created potentially collides with any
             //   of the intermediate nodes.
             int segmLength = defaultDepth +1;
-            int idLength = id.length();
-
+            
             while (intermediateFolderNeeded(escapedId, folder)) {
                 String folderName = Text.escapeIllegalJcrChars(id.substring(0, segmLength));
                 if (folder.hasNode(folderName)) {

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=818433&r1=818432&r2=818433&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 Thu Sep 24 10:30:34 2009
@@ -591,7 +591,6 @@
   + * (rep:Authorizable) = rep:Authorizable protected VERSION
   + * (rep:AuthorizableFolder) = rep:AuthorizableFolder protected VERSION
   - rep:principalName (STRING) protected mandatory
-  - rep:referees (STRING) protected multiple
   - rep:groups (WEAKREFERENCE) protected multiple < 'rep:Group'
   - * (UNDEFINED)
   - * (UNDEFINED) multiple

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AuthorizableTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AuthorizableTest.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AuthorizableTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/api/security/user/AuthorizableTest.java Thu Sep 24 10:30:34 2009
@@ -16,7 +16,6 @@
  */
 package org.apache.jackrabbit.api.security.user;
 
-import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
 import org.apache.jackrabbit.test.NotExecutableException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -54,32 +53,6 @@
         assertNotNull(gr.getPrincipal());
     }
 
-    public void testGetPrincipals() throws NotExecutableException, RepositoryException {
-        User user = getTestUser(superuser);
-        assertNotNull(user.getPrincipals());
-        assertTrue(user.getPrincipals().getSize() > 0);
-    }
-
-    public void testGroupGetPrincipals() throws NotExecutableException, RepositoryException {
-        Group gr = getTestGroup(superuser);
-        assertNotNull(gr.getPrincipals());
-        assertTrue(gr.getPrincipals().getSize() > 0);
-    }
-
-    public void testGetPrincipalsContainsPrincipal() throws RepositoryException, NotExecutableException {
-        Authorizable auth = getTestUser(superuser);
-        Principal p = auth.getPrincipal();
-        PrincipalIterator it = auth.getPrincipals();
-
-        while (it.hasNext()) {
-            if (it.nextPrincipal().equals(p)) {
-                // main principal is indeed present in the iterator.
-                return;
-            }
-        }
-        fail("Main principal (Authorizable.getPrincipal()) must be present in the iterator obtained by Authorizable.getPrincipals()");
-    }
-
     public void testSetProperty() throws NotExecutableException, RepositoryException {
         Authorizable auth = getTestUser(superuser);
 
@@ -204,156 +177,16 @@
         }
     }
 
-    public void testAddReferee() throws NotExecutableException, RepositoryException {
-        Authorizable auth = getTestUser(superuser);
-
-        Principal testPrincipal = getTestPrincipal();
-        try {
-            assertTrue(auth.addReferee(testPrincipal));
-        } catch (AuthorizableExistsException e) {
-            throw new NotExecutableException(e.getMessage());
-        } finally {
-            auth.removeReferee(testPrincipal);
-        }
-    }
-
-    public void testAddRefereeTwice() throws NotExecutableException, RepositoryException {
-        Authorizable auth = getTestUser(superuser);
-
-        Principal testPrincipal = getTestPrincipal();
-        try {
-            auth.addReferee(testPrincipal);
-            // adding same principal again must return false;
-            assertFalse(auth.addReferee(testPrincipal));
-        } finally {
-            auth.removeReferee(testPrincipal);
-        }
-    }
-
-    public void testGetPrincipalsExposeReferees() throws NotExecutableException, RepositoryException {
-        Authorizable auth = getTestUser(superuser);
-
-        Principal testPrincipal = getTestPrincipal();
-        try {
-            if (auth.addReferee(testPrincipal)) {
-                // make sure the referee is part of principals-set
-                boolean found = false;
-                for (PrincipalIterator it = auth.getPrincipals(); it.hasNext() && !found;) {
-                    found = testPrincipal.equals(it.nextPrincipal());
-                }
-                assertTrue("The referee added must be part of the 'getPrincipals()' iterator.", found);
-            } else {
-                throw new NotExecutableException();
-            }
-        } finally {
-            auth.removeReferee(testPrincipal);
-        }
-    }
-
-    public void testRemoveReferee() throws NotExecutableException, RepositoryException {
-        Authorizable auth = getTestUser(superuser);
-
-        Principal testPrincipal = getTestPrincipal();
-        try {
-            auth.addReferee(testPrincipal);
-            assertTrue(auth.removeReferee(testPrincipal));
-        } finally {
-            auth.removeReferee(testPrincipal);
-        }
-    }
-
-    public void testRefereeNotFoundByUserManager() throws NotExecutableException, RepositoryException {
-        Authorizable auth = getTestUser(superuser);
-        Principal testPrincipal = getTestPrincipal();
-
-        try {
-            assertTrue(auth.addReferee(testPrincipal));
-            Authorizable a = userMgr.getAuthorizable(testPrincipal);
-            assertNull(a);
-        } catch (RepositoryException e) {
-            auth.removeReferee(testPrincipal);
-        }
-    }
-
-    public void testAddExistingReferee() throws NotExecutableException, RepositoryException {
-        Authorizable auth = getTestUser(superuser);
-        Authorizable auth2 = getTestGroup(superuser);
-        Principal testPrincipal = getTestPrincipal();
-        try {
-            try {
-                assertTrue(auth.addReferee(testPrincipal));
-            } catch (AuthorizableExistsException e) {
-                throw new NotExecutableException(e.getMessage());
-            }
-
-            // adding same principal to another authorizable must fail
-            try {
-                auth2.addReferee(testPrincipal);
-                fail("Adding an existing referee-principal to another authorizable must fail.");
-            } catch (AuthorizableExistsException e) {
-                // success
-            }
-        } finally {
-            auth.removeReferee(testPrincipal);
-            auth2.removeReferee(testPrincipal);
-        }
-    }
-
-    public void testAddMainPrincipalAsReferee() throws NotExecutableException, RepositoryException {
-        Authorizable auth = getTestUser(superuser);
-        Principal mainPrinc = auth.getPrincipal();
-        try {
-            // adding main principal as referee to another authorizable must
-            // return false
-            assertFalse(auth.addReferee(mainPrinc));
-        } finally {
-            auth.removeReferee(mainPrinc);
-        }
-    }
-
-    public void testAddMainPrincipalAsOthersReferee() throws NotExecutableException, RepositoryException {
-        Authorizable auth = getTestUser(superuser);
-        Authorizable auth2 = getTestGroup(superuser);
-        Principal mainPrinc = auth.getPrincipal();
-        try {
-            // adding main principal as referee to another authorizable must fail
-            try {
-                auth2.addReferee(mainPrinc);
-                fail("Adding an existing main-principal as referee to another authorizable must fail.");
-            } catch (AuthorizableExistsException e) {
-                // success
-            }
-        } finally {
-            auth2.removeReferee(mainPrinc);
-        }
-    }
-
-    public void testRemoveNotExistingReferee() throws NotExecutableException, RepositoryException {
-        Authorizable auth = getTestUser(superuser);
-        Principal testPrincipal = getTestPrincipal();
-
-        if (userMgr.getAuthorizable(testPrincipal) != null) {
-            throw new NotExecutableException("test principal " + testPrincipal.getName() + " already associated with an authorizable.");
-        }
-        for (PrincipalIterator it = auth.getPrincipals(); it.hasNext();) {
-            if (it.nextPrincipal().getName().equals(testPrincipal.getName())) {
-                throw new NotExecutableException("test principal " + testPrincipal.getName() + " already referee.");
-            }
-        }
-        assertFalse(auth.removeReferee(testPrincipal));
-    }
-
     /**
      * Removing an authorizable that is still listed as member of a group.
      */
-    /*
     public void testRemoveListedAuthorizable() throws RepositoryException, NotExecutableException {
         String newUserId = null;
         Group newGroup = null;
 
         try {
             Principal uP = getTestPrincipal();
-            User newUser = userMgr.createUser(uP.getName(), buildCredentials(uP), uP);
+            User newUser = userMgr.createUser(uP.getName(), uP.getName());
             newUserId = newUser.getID();
 
             newGroup = userMgr.createGroup(getTestPrincipal());
@@ -376,5 +209,4 @@
             }
         }
     }
-    */
 }

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AuthorizableImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AuthorizableImplTest.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AuthorizableImplTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/AuthorizableImplTest.java Thu Sep 24 10:30:34 2009
@@ -59,11 +59,9 @@
             protectedUserProps.add(resolver.getJCRName(UserConstants.P_GROUPS));
             protectedUserProps.add(resolver.getJCRName(UserConstants.P_IMPERSONATORS));
             protectedUserProps.add(resolver.getJCRName(UserConstants.P_PRINCIPAL_NAME));
-            protectedUserProps.add(resolver.getJCRName(UserConstants.P_REFEREES));
 
             protectedUserProps.add(resolver.getJCRName(UserConstants.P_GROUPS));
             protectedGroupProps.add(resolver.getJCRName(UserConstants.P_PRINCIPAL_NAME));
-            protectedGroupProps.add(resolver.getJCRName(UserConstants.P_REFEREES));
         } else {
             throw new NotExecutableException();
         }
@@ -86,8 +84,8 @@
 
     public void testSetSpecialProperties() throws NotExecutableException, RepositoryException {
         Value v = superuser.getValueFactory().createValue("any_value");
-        User u = getTestUser(superuser);
 
+        User u = getTestUser(superuser);
         for (Iterator it = protectedUserProps.iterator(); it.hasNext();) {
             String pName = it.next().toString();
             try {
@@ -97,11 +95,12 @@
                 // success
             }
         }
+        
         Group g = getTestGroup(superuser);
         for (Iterator it = protectedGroupProps.iterator(); it.hasNext();) {
             String pName = it.next().toString();
             try {
-                u.setProperty(pName, v);
+                g.setProperty(pName, v);
                 fail("changing the '" +pName+ "' property on a Group should fail.");
             } catch (RepositoryException e) {
                 // success
@@ -124,7 +123,7 @@
         for (Iterator it = protectedGroupProps.iterator(); it.hasNext();) {
             String pName = it.next().toString();
             try {
-                u.removeProperty(pName);
+                g.removeProperty(pName);
                 fail("removing the '" +pName+ "' property on a Group should fail.");
             } catch (RepositoryException e) {
                 // success
@@ -138,9 +137,6 @@
 
         checkProtected(n.getProperty(UserConstants.P_USERID));
         checkProtected(n.getProperty(UserConstants.P_PRINCIPAL_NAME));
-        if (n.hasProperty(UserConstants.P_REFEREES)) {
-           checkProtected(n.getProperty(UserConstants.P_REFEREES));
-        }
         if (n.hasProperty(UserConstants.P_GROUPS)) {
             checkProtected(n.getProperty(UserConstants.P_GROUPS));
         }
@@ -157,9 +153,6 @@
         if (n.hasProperty(UserConstants.P_GROUPS)) {
             checkProtected(n.getProperty(UserConstants.P_GROUPS));
         }
-        if (n.hasProperty(UserConstants.P_REFEREES)) {
-           checkProtected(n.getProperty(UserConstants.P_REFEREES));
-        }
     }
 
     public void testSetSpecialPropertiesDirectly() throws NotExecutableException, RepositoryException {
@@ -175,14 +168,7 @@
         } catch (ConstraintViolationException e) {
             // ok.
         }
-
-        try {
-            String refereeName = "anyreferee";
-            n.setProperty(UserConstants.P_REFEREES, new Value[] {new StringValue(refereeName)});
-            fail("Attempt to change protected property rep:referees should fail.");
-        } catch (ConstraintViolationException e) {
-            // ok.
-        }
+        
         try {
             String imperson = "anyimpersonator";
             n.setProperty(UserConstants.P_IMPERSONATORS, new Value[] {new StringValue(imperson)});

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/GroupAdministratorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/GroupAdministratorTest.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/GroupAdministratorTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/GroupAdministratorTest.java Thu Sep 24 10:30:34 2009
@@ -39,7 +39,6 @@
 
     // group-admin
     private String uID;
-    private String uPath;
     private Session uSession;
 
     private String otherUID;
@@ -63,7 +62,6 @@
         Credentials creds = buildCredentials(p.getName(), pw);
         User user = userMgr.createUser(p.getName(), pw);
         uID = user.getID();
-        uPath = ((UserImpl) user).getNode().getPath();
 
         // make other user a group-administrator:
         Authorizable grAdmin = userMgr.getAuthorizable(UserConstants.GROUP_ADMIN_GROUP_NAME);
@@ -101,7 +99,7 @@
         if (otherUID2 == null) {
             // create a third user
             Principal p = getTestPrincipal();
-            otherUID2 = userMgr.createUser(p.getName(), buildPassword(p), p, uPath).getID();
+            otherUID2 = userMgr.createUser(p.getName(), buildPassword(p)).getID();
         }
         return otherUID2;
     }
@@ -157,7 +155,7 @@
         Group testGroup = null;
         try {
             testGroup = umgr.createGroup(getTestPrincipal(), "/any/intermediate/path");
-            assertEquals("Intermediate path must be ignored.",-1, ((GroupImpl)testGroup).getNode().getPath().indexOf("/any/intermediate/path"));
+            assertTrue(Text.isDescendant(UserConstants.GROUPS_PATH + "/any/intermediate/path", ((GroupImpl)testGroup).getNode().getPath()));
         } finally {
             if (testGroup != null) {
                 testGroup.remove();

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/ImpersonationImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/ImpersonationImplTest.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/ImpersonationImplTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/ImpersonationImplTest.java Thu Sep 24 10:30:34 2009
@@ -21,8 +21,6 @@
 import org.apache.jackrabbit.api.security.user.User;
 import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.jackrabbit.test.NotExecutableException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import javax.jcr.AccessDeniedException;
 import javax.jcr.Credentials;
@@ -35,15 +33,12 @@
  */
 public class ImpersonationImplTest extends AbstractUserTest {
 
-    private static Logger log = LoggerFactory.getLogger(ImpersonationImplTest.class);
-
     private Credentials creds;
     private String uID;
     private Session uSession;
     private UserManager uMgr;
 
     private String otherUID;
-    private Credentials otherCreds;
 
     protected void setUp() throws Exception {
         super.setUp();
@@ -61,8 +56,7 @@
         // create a second user 'below' the first user.
         p = getTestPrincipal();
         pw = buildPassword(p);
-        otherCreds = buildCredentials(p.getName(), pw);
-        User u2 = userMgr.createUser(p.getName(), pw, p, u.getNode().getPath());
+        User u2 = userMgr.createUser(p.getName(), pw);
         otherUID = u2.getID();
     }
 

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/NodeResolverTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/NodeResolverTest.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/NodeResolverTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/NodeResolverTest.java Thu Sep 24 10:30:34 2009
@@ -209,7 +209,7 @@
             throw new NotExecutableException();
         }
 
-        NodeIterator result = nodeResolver.findNodes(UserConstants.P_REFEREES, "anyValue", UserConstants.NT_REP_AUTHORIZABLE, true);
+        NodeIterator result = nodeResolver.findNodes(UserConstants.P_PRINCIPAL_NAME, "anyValue", UserConstants.NT_REP_AUTHORIZABLE, true);
         assertNotNull(result);
         assertFalse(result.hasNext());
     }

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/NotUserAdministratorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/NotUserAdministratorTest.java?rev=818433&r1=818432&r2=818433&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/NotUserAdministratorTest.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/NotUserAdministratorTest.java Thu Sep 24 10:30:34 2009
@@ -39,7 +39,6 @@
 
     // test user that is NOT user admin
     private String uID;
-    private String uPath;
     private Session uSession;
     private UserManager uMgr;
 
@@ -52,7 +51,6 @@
         String pw = buildPassword(p);
         UserImpl u = (UserImpl) userMgr.createUser(p.getName(), pw);
         uID = u.getID();
-        uPath = u.getNode().getPath();
 
         // create a session for the other user.
         uSession = getHelper().getRepository().login(new SimpleCredentials(uID, pw.toCharArray()));
@@ -118,7 +116,7 @@
     public void testRemoveChildUser() throws RepositoryException {
         // let superuser create a child-user.
         Principal p = getTestPrincipal();
-        String childID = userMgr.createUser(p.getName(), buildPassword(p), p, uPath).getID();
+        String childID = userMgr.createUser(p.getName(), buildPassword(p)).getID();
         try {
             Authorizable a = uMgr.getAuthorizable(childID);
             a.remove();
@@ -156,7 +154,7 @@
     public void testModifyImpersonation() throws RepositoryException {
         // let superuser create a child-user.
         Principal p = getTestPrincipal();
-        Authorizable child = userMgr.createUser(p.getName(), buildPassword(p), p, uPath);
+        Authorizable child = userMgr.createUser(p.getName(), buildPassword(p));
         try {
             p = child.getPrincipal();
 
@@ -178,7 +176,7 @@
     public void testModifyImpersonationOfChildUser() throws RepositoryException {
         // let superuser create a child-user.
         Principal p = getTestPrincipal();
-        String childID = userMgr.createUser(p.getName(), buildPassword(p), p, uPath).getID();
+        String childID = userMgr.createUser(p.getName(), buildPassword(p)).getID();
         try {
             Authorizable child = uMgr.getAuthorizable(childID);