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 < default depth are not reachable any more.</li>
- * <li>If default depth is decreased:<br>
- * All authorizables on levels > 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.
*/