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/08/08 12:24:32 UTC

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

Author: angela
Date: Wed Aug  8 10:24:32 2012
New Revision: 1370730

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

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserManagerConfig.java   (contents, props changed)
      - copied, changed from r1368830, jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerConfig.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/
      - copied from r1368830, jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/action/
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AbstractAuthorizableAction.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AccessControlAction.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AuthorizableAction.java
      - copied, changed from r1370710, jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/action/AuthorizableAction.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/ClearMembershipAction.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordValidationAction.java
Removed:
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerConfig.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/action/
Modified:
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java
    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/UserManagerImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OakRepositoryStub.java

Copied: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserManagerConfig.java (from r1368830, 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-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserManagerConfig.java?p2=jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserManagerConfig.java&p1=jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerConfig.java&r1=1368830&r2=1370730&rev=1370730&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerConfig.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserManagerConfig.java Wed Aug  8 10:24:32 2012
@@ -14,9 +14,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.jackrabbit.oak.jcr.security.user;
+package org.apache.jackrabbit.oak.spi.security.user;
 
-import org.apache.jackrabbit.oak.jcr.security.user.action.AuthorizableAction;
+import org.apache.jackrabbit.oak.spi.security.user.action.AuthorizableAction;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -26,7 +26,9 @@ import java.util.Set;
 import javax.annotation.Nonnull;
 
 /**
- * UserManagerConfig...
+ * UserManagerConfig provides utilities to retrieve configuration options
+ * related to user management. In addition it defines some constants that
+ * have been used in Jackrabbit 2.0 default user management implementation.
  */
 public class UserManagerConfig {
 
@@ -51,11 +53,15 @@ public class UserManagerConfig {
     public static final String PARAM_DEFAULT_DEPTH = "defaultDepth";
 
     /**
-     * If this parameter is present group members are collected in a node
-     * 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.
+     * Its value determines the maximum number of members within a given
+     * content structure until additional intermediate structuring is being
+     * added. This may for example be used to
+     * <ul>
+     *     <li>switch storing group members in JCR properties or nodes</li>
+     *     <li>define maximum number of members is a multivalued property</li>
+     *     <li>define maximum number of member properties within a given
+     *     node structure</li>
+     * </ul>
      */
     public static final String PARAM_GROUP_MEMBERSHIP_SPLIT_SIZE = "groupMembershipSplitSize";
 
@@ -81,6 +87,10 @@ public class UserManagerConfig {
     private final Map<String, Object> options;
     private final Set<AuthorizableAction> actions;
 
+    public UserManagerConfig(String adminId) {
+        this(adminId, null, null);
+    }
+
     public UserManagerConfig(String adminId, Map<String, Object> options, Set<AuthorizableAction> actions) {
         assert adminId != null;
 

Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserManagerConfig.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AbstractAuthorizableAction.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AbstractAuthorizableAction.java?rev=1370730&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AbstractAuthorizableAction.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AbstractAuthorizableAction.java Wed Aug  8 10:24:32 2012
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.spi.security.user.action;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+
+/**
+ * Abstract implementation of the {@code AuthorizableAction} interface that
+ * doesn't perform any action. This is a convenience implementation allowing
+ * subclasses to only implement methods that need extra attention.
+ */
+public abstract class AbstractAuthorizableAction implements AuthorizableAction {
+
+    /**
+     * Doesn't perform any action.
+     *
+     * @see AuthorizableAction#onCreate(org.apache.jackrabbit.api.security.user.Group, javax.jcr.Session)
+     */
+    public void onCreate(Group group, Session session) throws RepositoryException {
+        // nothing to do
+
+    }
+
+    /**
+     * Doesn't perform any action.
+     *
+     * @see AuthorizableAction#onCreate(org.apache.jackrabbit.api.security.user.User, String, javax.jcr.Session)
+     */
+    public void onCreate(User user, String password, Session session) throws RepositoryException {
+        // nothing to do
+    }
+
+    /**
+     * Doesn't perform any action.
+     *
+     * @see AuthorizableAction#onRemove(org.apache.jackrabbit.api.security.user.Authorizable, javax.jcr.Session)
+     */
+    public void onRemove(Authorizable authorizable, Session session) throws RepositoryException {
+        // nothing to do
+    }
+
+    /**
+     * Doesn't perform any action.
+     *
+     * @see AuthorizableAction#onPasswordChange(org.apache.jackrabbit.api.security.user.User, String, javax.jcr.Session)
+     */
+    public void onPasswordChange(User user, String newPassword, Session session) throws RepositoryException {
+        // nothing to do
+    }
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AccessControlAction.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AccessControlAction.java?rev=1370730&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AccessControlAction.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AccessControlAction.java Wed Aug  8 10:24:32 2012
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.spi.security.user.action;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.AccessControlPolicyIterator;
+import javax.jcr.security.Privilege;
+
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@code AccessControlAction} allows to setup permissions upon creation
+ * of a new authorizable; namely the privileges the new authorizable should be
+ * granted on it's own 'home directory' being represented by the new node
+ * associated with that new authorizable.
+ *
+ * <p>The following to configuration parameters are available with this implementation:
+ * <ul>
+ *    <li><strong>groupPrivilegeNames</strong>: the value is expected to be a
+ *    comma separated list of privileges that will be granted to the new group on
+ *    the group node</li>
+ *    <li><strong>userPrivilegeNames</strong>: the value is expected to be a
+ *    comma separated list of privileges that will be granted to the new user on
+ *    the user node.</li>
+ * </ul>
+ * </p>
+ * <p>Example configuration:
+ * <pre>
+ *    groupPrivilegeNames : "jcr:read"
+ *    userPrivilegeNames  : "jcr:read, rep:write"
+ * </pre>
+ * </p>
+ * <p>This configuration could for example lead to the following content
+ * structure upon user or group creation. Note however that the resulting
+ * structure depends on the actual access control management being in place:
+ *
+ * <pre>
+ *     UserManager umgr = ((JackrabbitSession) session).getUserManager();
+ *     User user = umgr.createUser("testUser", "t");
+ *
+ *     + t                           rep:AuthorizableFolder
+ *       + te                        rep:AuthorizableFolder
+ *         + testUser                rep:User, mix:AccessControllable
+ *           + rep:policy            rep:ACL
+ *             + allow               rep:GrantACE
+ *               - rep:principalName = "testUser"
+ *               - rep:privileges    = ["jcr:read","rep:write"]
+ *           - rep:password
+ *           - rep:principalName     = "testUser"
+ * </pre>
+ *
+ * <pre>
+ *     UserManager umgr = ((JackrabbitSession) session).getUserManager();
+ *     Group group = umgr.createGroup("testGroup");
+ *
+ *     + t                           rep:AuthorizableFolder
+ *       + te                        rep:AuthorizableFolder
+ *         + testGroup               rep:Group, mix:AccessControllable
+ *           + rep:policy            rep:ACL
+ *             + allow               rep:GrantACE
+ *               - rep:principalName = "testGroup"
+ *               - rep:privileges    = ["jcr:read"]
+ *           - rep:principalName     = "testGroup"
+ * </pre>
+ * </p>
+ */
+public class AccessControlAction extends AbstractAuthorizableAction {
+
+    /**
+     * logger instance
+     */
+    private static final Logger log = LoggerFactory.getLogger(AccessControlAction.class);
+
+    private String[] groupPrivilegeNames = new String[0];
+    private String[] userPrivilegeNames = new String[0];
+
+    //-------------------------------------------------< AuthorizableAction >---
+    /**
+     * @see AuthorizableAction#onCreate(org.apache.jackrabbit.api.security.user.Group, javax.jcr.Session)
+     */
+    @Override
+    public void onCreate(Group group, Session session) throws RepositoryException {
+        setAC(group, session);
+    }
+
+    /**
+     * @see AuthorizableAction#onCreate(org.apache.jackrabbit.api.security.user.User, String, javax.jcr.Session)
+     */
+    @Override
+    public void onCreate(User user, String password, Session session) throws RepositoryException {
+        setAC(user, session);
+    }
+
+    //------------------------------------------------------< Configuration >---
+    /**
+     * Sets the privileges a new group will be granted on the group's home directory.
+     *
+     * @param privilegeNames A comma separated list of privilege names.
+     */
+    public void setGroupPrivilegeNames(String privilegeNames) {
+        if (privilegeNames != null && privilegeNames.length() > 0) {
+            groupPrivilegeNames = split(privilegeNames);
+        }
+
+    }
+
+    /**
+     * Sets the privileges a new user will be granted on the user's home directory.
+     *
+     * @param privilegeNames  A comma separated list of privilege names.
+     */
+    public void setUserPrivilegeNames(String privilegeNames) {
+        if (privilegeNames != null && privilegeNames.length() > 0) {
+            userPrivilegeNames = split(privilegeNames);
+        }
+    }
+
+    //------------------------------------------------------------< private >---
+    private void setAC(Authorizable authorizable, Session session) throws RepositoryException {
+        Node aNode;
+        String path = authorizable.getPath();
+
+        JackrabbitAccessControlList acl = null;
+        AccessControlManager acMgr = session.getAccessControlManager();
+        for (AccessControlPolicyIterator it = acMgr.getApplicablePolicies(path); it.hasNext();) {
+            AccessControlPolicy plc = it.nextAccessControlPolicy();
+            if (plc instanceof JackrabbitAccessControlList) {
+                acl = (JackrabbitAccessControlList) plc;
+                break;
+            }
+        }
+
+        if (acl == null) {
+            log.warn("Cannot process AccessControlAction: no applicable ACL at " + path);
+        } else {
+            // setup acl according to configuration.
+            Principal principal = authorizable.getPrincipal();
+            boolean modified = false;
+            if (authorizable.isGroup()) {
+                // new authorizable is a Group
+                if (groupPrivilegeNames.length > 0) {
+                    modified = acl.addAccessControlEntry(principal, getPrivileges(groupPrivilegeNames, acMgr));
+                }
+            } else {
+                // new authorizable is a User
+                if (userPrivilegeNames.length > 0) {
+                    modified = acl.addAccessControlEntry(principal, getPrivileges(userPrivilegeNames, acMgr));
+                }
+            }
+            if (modified) {
+                acMgr.setPolicy(path, acl);
+            }
+        }
+    }
+
+    /**
+     * Retrieve privileges for the specified privilege names.
+     *
+     * @param privNames The privilege names.
+     * @param acMgr The access control manager.
+     * @return Array of {@code Privilege}
+     * @throws javax.jcr.RepositoryException If a privilege name cannot be
+     * resolved to a valid privilege.
+     */
+    private static Privilege[] getPrivileges(String[] privNames, AccessControlManager acMgr) throws RepositoryException {
+        if (privNames == null || privNames.length == 0) {
+            return new Privilege[0];
+        }
+        Privilege[] privileges = new Privilege[privNames.length];
+        for (int i = 0; i < privNames.length; i++) {
+            privileges[i] = acMgr.privilegeFromName(privNames[i]);
+        }
+        return privileges;
+    }
+
+    /**
+     * Split the specified configuration parameter into privilege names.
+     *
+     * @param configParam The configuration parameter defining a comma separated
+     * list of privilege names.
+     * @return An array of privilege names.
+     */
+    private static String[] split(String configParam) {
+        List<String> nameList = new ArrayList<String>();
+        for (String pn : Text.explode(configParam, ',', false)) {
+            String privName = pn.trim();
+            if (privName.length()  > 0) {
+                nameList.add(privName);
+            }
+        }
+        return nameList.toArray(new String[nameList.size()]);
+    }
+}

Copied: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AuthorizableAction.java (from r1370710, jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/action/AuthorizableAction.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AuthorizableAction.java?p2=jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AuthorizableAction.java&p1=jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/action/AuthorizableAction.java&r1=1370710&r2=1370730&rev=1370730&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/action/AuthorizableAction.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/AuthorizableAction.java Wed Aug  8 10:24:32 2012
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.jackrabbit.oak.jcr.security.user.action;
+package org.apache.jackrabbit.oak.spi.security.user.action;
 
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.Group;

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/ClearMembershipAction.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/ClearMembershipAction.java?rev=1370730&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/ClearMembershipAction.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/ClearMembershipAction.java Wed Aug  8 10:24:32 2012
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.spi.security.user.action;
+
+import java.util.Iterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+
+/**
+ * Authorizable action attempting to clear all group membership before removing
+ * the specified authorizable. If {@link Group#removeMember(org.apache.jackrabbit.api.security.user.Authorizable)}
+ * fails due to lack of permissions {@link #onRemove(org.apache.jackrabbit.api.security.user.Authorizable, javax.jcr.Session)}
+ * throws an exception and removing the specified authorizable will be aborted.
+ */
+public class ClearMembershipAction extends AbstractAuthorizableAction {
+
+    //-------------------------------------------------< AuthorizableAction >---
+    /**
+     * @see AuthorizableAction#onRemove(org.apache.jackrabbit.api.security.user.Authorizable, javax.jcr.Session)
+     */
+    @Override
+    public void onRemove(Authorizable authorizable, Session session) throws RepositoryException {
+        Iterator<Group> membership = authorizable.declaredMemberOf();
+        while (membership.hasNext()) {
+            membership.next().removeMember(authorizable);
+        }
+    }
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordValidationAction.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordValidationAction.java?rev=1370730&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordValidationAction.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordValidationAction.java Wed Aug  8 10:24:32 2012
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.spi.security.user.action;
+
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.ConstraintViolationException;
+
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.oak.spi.security.user.PasswordUtility;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@code PasswordValidationAction} provides a simple password validation
+ * mechanism with the following configurable option:
+ *
+ * <ul>
+ *     <li><strong>constraint</strong>: a regular expression that can be compiled
+ *     to a {@link java.util.regex.Pattern} defining validation rules for a password.</li>
+ * </ul>
+ *
+ * <p>The password validation is executed on user creation and upon password
+ * change. It throws a {@code ConstraintViolationException} if the password
+ * validation fails.</p>
+ *
+ * @see org.apache.jackrabbit.api.security.user.UserManager#createUser(String, String)
+ * @see org.apache.jackrabbit.api.security.user.User#changePassword(String)
+ * @see org.apache.jackrabbit.api.security.user.User#changePassword(String, String)
+ */
+public class PasswordValidationAction extends AbstractAuthorizableAction {
+
+    /**
+     * logger instance
+     */
+    private static final Logger log = LoggerFactory.getLogger(PasswordValidationAction.class);
+
+    private Pattern pattern;
+
+    //-------------------------------------------------< AuthorizableAction >---
+    @Override
+    public void onCreate(User user, String password, Session session) throws RepositoryException {
+        validatePassword(password);
+    }
+
+    @Override
+    public void onPasswordChange(User user, String newPassword, Session session) throws RepositoryException {
+        validatePassword(newPassword);
+    }
+
+    //------------------------------------------------------< Configuration >---
+    /**
+     * Set the password constraint.
+     *
+     * @param constraint A regular expression that can be used to validate a new password.
+     */
+    public void setConstraint(String constraint) {
+        try {
+            pattern = Pattern.compile(constraint);
+        } catch (PatternSyntaxException e) {
+            log.warn("Invalid password constraint: ", e.getMessage());
+        }
+    }
+
+    //------------------------------------------------------------< private >---
+    /**
+     * Validate the specified password.
+     *
+     * @param password The password to be validated
+     * @throws RepositoryException If the specified password is too short or
+     * doesn't match the specified password pattern.
+     */
+    private void validatePassword(String password) throws RepositoryException {
+        if (password != null && isPlainText(password)) {
+            if (pattern != null && !pattern.matcher(password).matches()) {
+                throw new ConstraintViolationException("Password violates password constraint (" + pattern.pattern() + ").");
+            }
+        }
+    }
+
+    private static boolean isPlainText(String password) {
+        return !PasswordUtility.isPlainTextPassword(password);
+    }
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java?rev=1370730&r1=1370729&r2=1370730&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/SessionImpl.java Wed Aug  8 10:24:32 2012
@@ -50,7 +50,6 @@ import org.apache.jackrabbit.commons.Abs
 import org.apache.jackrabbit.commons.iterator.AccessControlPolicyIteratorAdapter;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.jcr.security.principal.PrincipalManagerImpl;
-import org.apache.jackrabbit.oak.jcr.security.user.UserManagerConfig;
 import org.apache.jackrabbit.oak.jcr.security.user.UserManagerImpl;
 import org.apache.jackrabbit.oak.jcr.xml.XmlImportHandler;
 import org.apache.jackrabbit.oak.security.principal.KernelPrincipalProvider;
@@ -534,8 +533,7 @@ public class SessionImpl extends Abstrac
     @Override
     @Nonnull
     public UserManager getUserManager() throws RepositoryException {
-        return TODO.unimplemented().returnValue(new UserManagerImpl(
-                dlg, new UserManagerConfig("admin", null, null)));
+        return TODO.unimplemented().returnValue(new UserManagerImpl(dlg, null));
     }
 
     //------------------------------------------------------------< private >---

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=1370730&r1=1370729&r2=1370730&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 Wed Aug  8 10:24:32 2012
@@ -21,6 +21,7 @@ import org.apache.jackrabbit.oak.api.Cor
 import org.apache.jackrabbit.oak.jcr.SessionDelegate;
 import org.apache.jackrabbit.oak.jcr.value.ValueConverter;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.spi.security.user.UserManagerConfig;
 import org.apache.jackrabbit.util.Text;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerImpl.java?rev=1370730&r1=1370729&r2=1370730&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/security/user/UserManagerImpl.java Wed Aug  8 10:24:32 2012
@@ -16,6 +16,20 @@
  */
 package org.apache.jackrabbit.oak.jcr.security.user;
 
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.util.Iterator;
+import java.util.List;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
+
 import org.apache.jackrabbit.api.security.principal.ItemBasedPrincipal;
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.AuthorizableExistsException;
@@ -26,27 +40,14 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.oak.api.CoreValue;
 import org.apache.jackrabbit.oak.jcr.PropertyDelegate;
 import org.apache.jackrabbit.oak.jcr.SessionDelegate;
-import org.apache.jackrabbit.oak.jcr.security.user.action.AuthorizableAction;
 import org.apache.jackrabbit.oak.jcr.value.ValueConverter;
 import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
 import org.apache.jackrabbit.oak.spi.security.user.PasswordUtility;
+import org.apache.jackrabbit.oak.spi.security.user.UserManagerConfig;
+import org.apache.jackrabbit.oak.spi.security.user.action.AuthorizableAction;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.jcr.ItemNotFoundException;
-import javax.jcr.Node;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.UnsupportedRepositoryOperationException;
-import javax.jcr.Value;
-import java.io.UnsupportedEncodingException;
-import java.security.NoSuchAlgorithmException;
-import java.security.Principal;
-import java.util.Iterator;
-import java.util.List;
-
 /**
  * UserManagerImpl...
  */
@@ -62,7 +63,7 @@ public class UserManagerImpl implements 
     
     public UserManagerImpl(SessionDelegate sessionDelegate, UserManagerConfig config) {
         this.sessionDelegate = sessionDelegate;
-        this.config = config;
+        this.config = (config == null) ? new UserManagerConfig("admin") : config;
         nodeCreator = new AuthorizableNodeCreator(sessionDelegate, this.config);
     }
 

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OakRepositoryStub.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OakRepositoryStub.java?rev=1370730&r1=1370729&r2=1370730&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OakRepositoryStub.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OakRepositoryStub.java Wed Aug  8 10:24:32 2012
@@ -23,6 +23,8 @@ import java.security.Principal;
 import java.util.Properties;
 import java.util.concurrent.Executors;
 
+import javax.jcr.Credentials;
+import javax.jcr.GuestCredentials;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
@@ -74,6 +76,11 @@ public class OakRepositoryStub extends R
     }
 
     @Override
+    public Credentials getReadOnlyCredentials() {
+        return new GuestCredentials();
+    }
+
+    @Override
     public Principal getKnownPrincipal(Session session) throws RepositoryException {
         throw new UnsupportedRepositoryOperationException();
     }