You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2012/06/07 16:43:28 UTC

svn commit: r1347647 - in /jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user: AuthorizableNodeCreator.java UserManagerConfig.java

Author: angela
Date: Thu Jun  7 14:43:28 2012
New Revision: 1347647

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

Modified:
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/AuthorizableNodeCreator.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerConfig.java

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/AuthorizableNodeCreator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/AuthorizableNodeCreator.java?rev=1347647&r1=1347646&r2=1347647&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/AuthorizableNodeCreator.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/AuthorizableNodeCreator.java Thu Jun  7 14:43:28 2012
@@ -37,10 +37,12 @@ import java.util.UUID;
  * Utility class creating the JCR nodes corresponding the a given
  * authorizable ID with the following behavior:
  * <ul>
- * <li>Users are created below /home/users or
- * the corresponding path configured.</li>
- * <li>Groups are created below /home/groups or
- * the corresponding path configured.</li>
+ * <li>Users are created below /rep:security/rep:authorizables/rep:users or
+ * the path configured in the {@link UserManagerConfig#PARAM_USER_PATH}
+ * respectively.</li>
+ * <li>Groups are created below /rep:security/rep:authorizables/rep:groups or
+ * the path configured in the {@link UserManagerConfig#PARAM_GROUP_PATH}
+ * respectively.</li>
  * <li>Below each category authorizables are created within a human readable
  * structure based on the defined intermediate path or some internal logic
  * with a depth defined by the {@code defaultDepth} config option.<br>
@@ -55,10 +57,8 @@ import java.util.UUID;
  * ->        + aSmith        [rep:User]
  * </pre>
  * </li>
- * <li>In case of a user the node name is calculated from the specified UserID
- * {@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 node name is calculated from the specified authorizable ID
+ * {@link Text#escapeIllegalJcrChars(String) escaping} any illegal JCR chars.</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}
@@ -72,100 +72,41 @@ import java.util.UUID;
  *       + a                 [rep:AuthorizableFolder]
  *         + aa              [rep:AuthorizableFolder]
  * ->        + a             [rep:User]
- * </pre>
- * </li>
- * <li>If the {@code autoExpandTree} option is {@code true} the
- * user tree will be automatically expanded using additional levels if
- * {@code autoExpandSize} is exceeded within a given level.</li>
+ * </pre></li>
+ *
+ * <h3>Conflicts</h3>
+ *
+ * <ul>
+ *     <li>If the authorizable node to be created would collide with an existing
+ *     folder the conflict is resolved by using the colling folder as target.</li>
+ *     <li>The current implementation asserts that authorizable nodes are always
+ *     created underneath an node of type {@code rep:AuthorizableFolder}. If this
+ *     condition is violated a {@code ConstraintViolationException} is thrown.</li>
+ *     <li>If the specified intermediate path results in an authorizable node
+ *     being located outside of the configured content structure a
+ *     {@code ConstraintViolationException} is thrown.</li>
  * </ul>
  *
- * The auto-expansion of the authorizable tree is defined by the following
- * steps and exceptional cases:
+ * <h3>Configuration Options</h3>
  * <ul>
- * <li>As long as {@code autoExpandSize} isn't reached authorizable
- * nodes are created within the structure defined by the
- * {@code defaultDepth}. (see above)</li>
- * <li>If {@code autoExpandSize} is reached additional intermediate
- * folders will be created.<br>
- * E.g. creating a user node for an ID 'aSmith1001' would result in the
- * following structure:
- * <pre>
- * + rep:security            [rep:AuthorizableFolder]
- *   + rep:authorizables     [rep:AuthorizableFolder]
- *     + rep:users           [rep:AuthorizableFolder]
- *       + a                 [rep:AuthorizableFolder]
- *         + aS              [rep:AuthorizableFolder]
- *           + aSmith1       [rep:User]
- *           + aSmith2       [rep:User]
- *           [...]
- *           + aSmith1000    [rep:User]
- * ->        + aSm           [rep:AuthorizableFolder]
- * ->          + aSmith1001  [rep:User]
- * </pre>
- * </li>
- * <li>Conflicts: In order to prevent any conflicts that would arise from
- * creating a authorizable node that upon later expansion could conflict
- * with an authorizable folder, intermediate levels are always created if
- * the node name equals any of the names reserved for the next level of
- * folders.<br>
- * In the example above any attempt to create a user with ID 'aSm' would
- * result in an intermediate level irrespective if max-size has been
- * reached or not:
- * <pre>
- * + rep:security            [rep:AuthorizableFolder]
- *   + rep:authorizables     [rep:AuthorizableFolder]
- *     + rep:users           [rep:AuthorizableFolder]
- *       + a                 [rep:AuthorizableFolder]
- *         + aS              [rep:AuthorizableFolder]
- * ->        + aSm           [rep:AuthorizableFolder]
- * ->          + aSm         [rep:User]
- * </pre>
- * </li>
- * <li>Special case: If the name of the authorizable node to be created is
- * shorter or equal to the length of the folder at level N, the authorizable
- * node is created even if max-size has been reached before.<br>
- * An attempt to create the users 'aS' and 'aSm' in a structure containing
- * tons of 'aSmith' users will therefore result in:
- * <pre>
- * + rep:security            [rep:AuthorizableFolder]
- *   + rep:authorizables     [rep:AuthorizableFolder]
- *     + rep:users           [rep:AuthorizableFolder]
- *       + a                 [rep:AuthorizableFolder]
- *         + aS              [rep:AuthorizableFolder]
- *           + aSmith1       [rep:User]
- *           + aSmith2       [rep:User]
- *           [...]
- *           + aSmith1000    [rep:User]
- * ->        + aS            [rep:User]
- *           + aSm           [rep:AuthorizableFolder]
- *             + aSmith1001  [rep:User]
- * ->          + aSm         [rep:User]
- * </pre>
- * </li>
- * <li>Special case: If {@code autoExpandTree} is enabled later on
- * AND any of the existing authorizable nodes collides with an intermediate
- * folder to be created the auto-expansion is aborted and the new
- * authorizable is inserted at the last valid level irrespective of
- * max-size being reached.
- * </li>
+ *     <li>{@link UserManagerConfig#PARAM_USER_PATH}: Underneath this structure
+ *     all user nodes are created. Default value is
+ *     "/rep:security/rep:authorizables/rep:users"</li>
+ *     <li>{@link UserManagerConfig#PARAM_GROUP_PATH}: Underneath this structure
+ *     all group nodes are created. Default value is
+ *     "/rep:security/rep:authorizables/rep:groups"</li>
+ *     <li>{@link UserManagerConfig#PARAM_DEFAULT_DEPTH}: A positive {@code integer}
+ *     greater than zero defining the depth of the default structure that is
+ *     always created. Default value: 2</li>
  * </ul>
  *
- * The configuration options:
+ * <h3>Compatibility with Jackrabbit 2.x</h3>
+ *
+ * Due to the fact that this JCR implementation is expected to deal with huge amount
+ * of child nodes the following configuration options are no longer supported:
  * <ul>
- * <li><strong>defaultDepth</strong>:<br>
- * A positive {@code integer} greater than zero defining the depth of
- * the default structure that is always created.<br>
- * Default value: 2</li>
- * <li><strong>autoExpandTree</strong>:<br>
- * {@code boolean} defining if the tree gets automatically expanded
- * if within a level the maximum number of child nodes is reached.<br>
- * Default value: {@code false}</li>
- * <li><strong>autoExpandSize</strong>:<br>
- * A positive {@code long} greater than zero defining the maximum
- * number of child nodes that are allowed at a given level.<br>
- * Default value: 1000<br>
- * NOTE: that total number of child nodes may still be greater that
- * autoExpandSize.</li>
+ *     <li>autoExpandTree</li>
+ *     <li>autoExpandSize</li>
  * </ul>
  */
 class AuthorizableNodeCreator {
@@ -177,33 +118,26 @@ class AuthorizableNodeCreator {
 
     private static final String DELIMITER = "/";
     private static final int DEFAULT_DEPTH = 2;
-    private static final int DEFAULT_SIZE = 1000;
 
     private final SessionDelegate sessionDelegate;
 
     private final int defaultDepth;
-    private final boolean autoExpandTree;
-    private final long autoExpandSize;
 
     private final String groupPath;
     private final String userPath;
 
     private final String ntAuthorizableFolder;
-    private final String ntAuthorizable;
 
     AuthorizableNodeCreator(SessionDelegate sessionDelegate, UserManagerConfig config) {
         this.sessionDelegate = sessionDelegate;
 
         defaultDepth = config.getConfigValue(UserManagerConfig.PARAM_DEFAULT_DEPTH, DEFAULT_DEPTH);
-        autoExpandTree = config.getConfigValue(UserManagerConfig.PARAM_AUTO_EXPAND_TREE, false);
-        autoExpandSize = config.getConfigValue(UserManagerConfig.PARAM_AUTO_EXPAND_SIZE, DEFAULT_SIZE);
 
         groupPath = config.getConfigValue(UserManagerConfig.PARAM_GROUP_PATH, "/rep:security/rep:authorizables/rep:groups");
         userPath = config.getConfigValue(UserManagerConfig.PARAM_USER_PATH, "/rep:security/rep:authorizables/rep:users");
 
         NamePathMapper namePathMapper = sessionDelegate.getNamePathMapper();
         ntAuthorizableFolder = namePathMapper.getJcrName(UserConstants.NT_REP_AUTHORIZABLE_FOLDER);
-        ntAuthorizable = namePathMapper.getJcrName(UserConstants.NT_REP_AUTHORIZABLE);
     }
 
     String getNodeID(String authorizableId) throws RepositoryException {
@@ -247,8 +181,8 @@ class AuthorizableNodeCreator {
      * @param nodeName
      * @param isGroup
      * @param intermediatePath
-     * @return
-     * @throws RepositoryException
+     * @return The folder node.
+     * @throws RepositoryException If an error occurs
      */
     private Node createFolderNodes(String authorizableId, String nodeName,
                                    boolean isGroup, String intermediatePath) throws RepositoryException {
@@ -280,10 +214,6 @@ class AuthorizableNodeCreator {
             }
         }
 
-        if (intermediatePath == null && autoExpandTree) {
-            folder = expandTree(authorizableId, nodeName, folder);
-        }
-
         // test for colliding folder child node.
         while (folder.hasNode(nodeName)) {
             Node colliding = folder.getNode(nodeName);
@@ -322,92 +252,4 @@ class AuthorizableNodeCreator {
         }
         return sb.toString();
     }
-
-    /**
-     * Expand the tree structure adding additional folders if any of the
-     * following conditions is met:
-     * <ul>
-     *     <li>number of child node exceeds the configured max value</li>
-     *     <li>the authorizable node collides with an intermediate folder</li>
-     * </ul>
-     *
-     * @param authorizableId The authorizable id
-     * @param nodeName The name of the authorizable node.
-     * @param folder The folder node.
-     * @return The node in the authorizable folder tree underneath with the
-     * authorizable node will be created.
-     * @throws RepositoryException If an error occurs.
-     */
-    private Node expandTree(String authorizableId, String nodeName, Node folder) throws RepositoryException {
-        int segmLength = defaultDepth +1;
-        while (isExpand(folder, nodeName.length())) {
-            String folderName = Text.escapeIllegalJcrChars(authorizableId.substring(0, segmLength));
-            if (folder.hasNode(folderName)) {
-                Node n = folder.getNode(folderName);
-                // assert that the folder is of type rep:AuthorizableFolder
-                if (n.isNodeType(ntAuthorizableFolder)) {
-                    folder = n;
-                } else if (n.isNodeType(ntAuthorizable)){
-                    /*
-                     an authorizable node has been created before with the
-                     name of the intermediate folder to be created.
-                     this may only occur if the 'autoExpandTree' option has
-                     been enabled later on.
-                     Resolution:
-                     - abort auto-expanding and create the authorizable
-                       at the current level, ignoring that max-size is reached.
-                     - note, that this behavior has been preferred over tmp.
-                       removing and recreating the colliding authorizable node.
-                    */
-                    log.warn("Auto-expanding aborted. An existing authorizable node '" + n.getName() +"' conflicts with intermediate folder to be created.");
-                    break;
-                } else {
-                    // should never get here: some other, unexpected node type
-                    String msg = "Failed to create authorizable node: Detected conflict with node of unexpected nodetype '" + n.getPrimaryNodeType().getName() + "'.";
-                    log.error(msg);
-                    throw new ConstraintViolationException(msg);
-                }
-            } else {
-                // folder doesn't exist nor does another colliding child node.
-                folder = folder.addNode(folderName, ntAuthorizableFolder);
-            }
-            segmLength++;
-        }
-        return folder;
-    }
-
-    private boolean isExpand(Node folder, int nameLength) throws RepositoryException {
-        int folderNameLength = folder.getName().length();
-        // don't create additional intermediate folders for ids that are
-        // shorter or equally long as the folder name. In this case the
-        // MAX_SIZE flag is ignored.
-        if (nameLength <= folderNameLength) {
-            return false;
-        }
-
-        // test for potential (or existing) collision in which case the
-        // intermediate node is created irrespective of the MAX_SIZE and the
-        // existing number of children.
-        if (nameLength == folderNameLength+1) {
-            // max-size may not yet be reached yet on folder but the node to
-            // be created potentially collides with an intermediate folder.
-            // e.g.:
-            // existing folder structure: a/ab
-            // authID to be created     : abt
-            // OR
-            // existing collision that would result from
-            // existing folder structure: a/ab/abt
-            // authID to be create      : abt
-            return true;
-        }
-
-        // last possibility: max-size is reached.
-        if (folder.getNodes().getSize() >= autoExpandSize) {
-            return true;
-        }
-
-        // no collision and no need to create an additional intermediate
-        // folder due to max-size reached
-        return false;
-    }
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerConfig.java?rev=1347647&r1=1347646&r2=1347647&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerConfig.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerConfig.java Thu Jun  7 14:43:28 2012
@@ -47,41 +47,13 @@ public class UserManagerConfig {
     /**
      * Parameter used to change the number of levels that are used by default
      * store authorizable nodes.<br>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}.</li>
-     * </ul>
      */
     public static final String PARAM_DEFAULT_DEPTH = "defaultDepth";
 
     /**
-     * If this parameter is present and its value is {@code true}, the trees
-     * containing user and group nodes will automatically created additional
-     * hierarchy levels if the number of nodes on a given level exceeds the
-     * maximal allowed {@link #PARAM_AUTO_EXPAND_SIZE size}.
-     */
-    public static final String PARAM_AUTO_EXPAND_TREE = "autoExpandTree";
-
-    /**
-     * This parameter only takes effect if {@link #PARAM_AUTO_EXPAND_TREE} is
-     * enabled.
-     */
-    public static final String PARAM_AUTO_EXPAND_SIZE = "autoExpandSize";
-
-    /**
      * If this parameter is present group members are collected in a node
-     * structure below a {@link AuthorizableImpl#REP_MEMBERS} node instead of the
-     * default multi valued property {@link AuthorizableImpl#REP_MEMBERS}.
+     * structure below a {@link UserConstants#REP_MEMBERS} node instead of the
+     * default multi valued property {@link UserConstants#REP_MEMBERS}.
      * Its value determines the maximum number of member properties until
      * additional intermediate nodes are inserted.
      */