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 2013/04/24 15:02:26 UTC

svn commit: r1471392 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/ oak-core/src/main/java/org/apache/jackrabbit/o...

Author: angela
Date: Wed Apr 24 13:02:26 2013
New Revision: 1471392

URL: http://svn.apache.org/r1471392
Log:
OAK-785 : PermissionValidator: add compatibility flag to ignore USER_MGT permission

Added:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/Jr2CompatibilityTest.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/authorization/UserManagementTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlConfigurationImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlConstants.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlInitializer.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidator.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidatorProvider.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParameters.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AccessControlConfiguration.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/ConfigurationParametersTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlConfigurationImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlConfigurationImpl.java?rev=1471392&r1=1471391&r2=1471392&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlConfigurationImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlConfigurationImpl.java Wed Apr 24 13:02:26 2013
@@ -35,6 +35,7 @@ import org.apache.jackrabbit.oak.securit
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
 import org.apache.jackrabbit.oak.spi.lifecycle.WorkspaceInitializer;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
 import org.apache.jackrabbit.oak.spi.security.Context;
 import org.apache.jackrabbit.oak.spi.security.SecurityConfiguration;
 import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
@@ -49,9 +50,11 @@ import org.apache.jackrabbit.oak.spi.xml
 public class AccessControlConfigurationImpl extends SecurityConfiguration.Default implements AccessControlConfiguration {
 
     private final SecurityProvider securityProvider;
+    private final ConfigurationParameters config;
 
     public AccessControlConfigurationImpl(SecurityProvider securityProvider) {
         this.securityProvider = securityProvider;
+        config = securityProvider.getConfiguration(PARAM_ACCESS_CONTROL_OPTIONS);
     }
 
     //----------------------------------------------< SecurityConfiguration >---
@@ -63,6 +66,12 @@ public class AccessControlConfigurationI
 
     @Nonnull
     @Override
+    public ConfigurationParameters getConfigurationParameters() {
+        return config;
+    }
+
+    @Nonnull
+    @Override
     public WorkspaceInitializer getWorkspaceInitializer() {
         return new AccessControlInitializer();
     }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlConstants.java?rev=1471392&r1=1471391&r2=1471392&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlConstants.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlConstants.java Wed Apr 24 13:02:26 2013
@@ -36,7 +36,6 @@ public interface AccessControlConstants 
      */
     String REP_RESTRICTIONS = "rep:restrictions";
 
-
     String MIX_REP_ACCESS_CONTROLLABLE = "rep:AccessControllable";
     String MIX_REP_REPO_ACCESS_CONTROLLABLE = "rep:RepoAccessControllable";
     String NT_REP_POLICY = "rep:Policy";
@@ -55,4 +54,16 @@ public interface AccessControlConstants 
     Collection<String> ACE_PROPERTY_NAMES = ImmutableSet.of(REP_PRINCIPAL_NAME, REP_PRIVILEGES);
 
     Collection<String> AC_NODETYPE_NAMES = ImmutableSet.of(NT_REP_POLICY, NT_REP_ACL, NT_REP_ACE, NT_REP_DENY_ACE, NT_REP_GRANT_ACE, NT_REP_RESTRICTIONS);
+
+    /**
+     * Configuration parameter to enforce backwards compatible permission
+     * validation with respect to user/group creation, modification and removal.
+     * As of OAK 1.0 those actions require
+     * {@link org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions#USER_MANAGEMENT USER_MANAGEMENT}
+     * permissions while in Jackrabbit 2.0 they were covered by regular item
+     * write permissions.
+     *
+     * @since OAK 1.0
+     */
+    String PARAM_PERMISSIONS_JR2 = "permissionsJr2";
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlInitializer.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlInitializer.java?rev=1471392&r1=1471391&r2=1471392&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlInitializer.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AccessControlInitializer.java Wed Apr 24 13:02:26 2013
@@ -31,7 +31,7 @@ import org.apache.jackrabbit.oak.spi.sta
  * a property index definitions for {@link #REP_PRINCIPAL_NAME rep:principalName}
  * properties defined with ACE nodes.
  */
-public class AccessControlInitializer implements WorkspaceInitializer, AccessControlConstants {
+class AccessControlInitializer implements WorkspaceInitializer, AccessControlConstants {
 
     @Nonnull
     @Override

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidator.java?rev=1471392&r1=1471391&r2=1471392&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidator.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidator.java Wed Apr 24 13:02:26 2013
@@ -161,7 +161,7 @@ class PermissionValidator extends Defaul
             if (!permissionProvider.isGranted(tree, null, toTest)) {
                 throw new CommitFailedException(ACCESS, 0, "Access denied");
             }
-            if (noTraverse(toTest)) {
+            if (noTraverse(toTest, defaultPermission)) {
                 return null;
             } else {
                 return (isBefore) ?
@@ -207,7 +207,8 @@ class PermissionValidator extends Defaul
         long perm;
         if (provider.getAccessControlContext().definesTree(tree)) {
             perm = Permissions.MODIFY_ACCESS_CONTROL;
-        } else if (provider.getUserContext().definesTree(tree)) {
+        } else if (provider.getUserContext().definesTree(tree)
+                && !provider.jr2Permissions()) {
             perm = Permissions.USER_MANAGEMENT;
         } else {
             // FIXME: OAK-710 (identify renaming/move of nodes that only required MODIFY_CHILD_NODE_COLLECTION permission)
@@ -232,7 +233,8 @@ class PermissionValidator extends Defaul
             perm = Permissions.VERSION_MANAGEMENT;
         } else if (provider.getAccessControlContext().definesProperty(parent, propertyState)) {
             perm = Permissions.MODIFY_ACCESS_CONTROL;
-        } else if (provider.getUserContext().definesProperty(parent, propertyState)) {
+        } else if (provider.getUserContext().definesProperty(parent, propertyState)
+                 && !provider.jr2Permissions()) {
             perm = Permissions.USER_MANAGEMENT;
         } else {
             perm = defaultPermission;
@@ -245,10 +247,11 @@ class PermissionValidator extends Defaul
     }
 
     // TODO
-    public static boolean noTraverse(long permission) {
+    public static boolean noTraverse(long permission, long defaultPermission) {
         return permission == Permissions.MODIFY_ACCESS_CONTROL ||
                 permission == Permissions.VERSION_MANAGEMENT ||
-                permission == Permissions.REMOVE_NODE;
+                permission == Permissions.REMOVE_NODE ||
+                defaultPermission == Permissions.REMOVE_NODE;
     }
 
     // TODO

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidatorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidatorProvider.java?rev=1471392&r1=1471391&r2=1471392&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidatorProvider.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionValidatorProvider.java Wed Apr 24 13:02:26 2013
@@ -22,8 +22,10 @@ import javax.security.auth.Subject;
 
 import org.apache.jackrabbit.oak.core.ImmutableTree;
 import org.apache.jackrabbit.oak.core.TreeTypeProviderImpl;
+import org.apache.jackrabbit.oak.security.authorization.AccessControlConstants;
 import org.apache.jackrabbit.oak.spi.commit.Validator;
 import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
 import org.apache.jackrabbit.oak.spi.security.Context;
 import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
@@ -35,12 +37,16 @@ import org.apache.jackrabbit.oak.spi.sta
 public class PermissionValidatorProvider extends ValidatorProvider {
 
     private final SecurityProvider securityProvider;
+    private final boolean jr2Permissions;
 
     private Context acCtx;
     private Context userCtx;
 
     public PermissionValidatorProvider(SecurityProvider securityProvider) {
         this.securityProvider = securityProvider;
+
+        ConfigurationParameters params = securityProvider.getAccessControlConfiguration().getConfigurationParameters();
+        jr2Permissions = params.getConfigValue(AccessControlConstants.PARAM_PERMISSIONS_JR2, false);
     }
 
     //--------------------------------------------------< ValidatorProvider >---
@@ -67,6 +73,10 @@ public class PermissionValidatorProvider
         return userCtx;
     }
 
+    boolean jr2Permissions() {
+        return jr2Permissions;
+    }
+
     private ImmutableTree createTree(NodeState root) {
         return new ImmutableTree(root, new TreeTypeProviderImpl(getAccessControlContext()));
     }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParameters.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParameters.java?rev=1471392&r1=1471391&r2=1471392&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParameters.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/ConfigurationParameters.java Wed Apr 24 13:02:26 2013
@@ -18,6 +18,9 @@ package org.apache.jackrabbit.oak.spi.se
 
 import java.util.Collections;
 import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -40,11 +43,45 @@ public class ConfigurationParameters {
         this(null);
     }
 
-    public ConfigurationParameters(Map<String, ?> options) {
+    public ConfigurationParameters(@Nullable Map<String, ?> options) {
         this.options = (options == null) ? Collections.<String, Object>emptyMap() : Collections.unmodifiableMap(options);
     }
 
-    public <T> T getConfigValue(String key, T defaultValue) {
+    /**
+     * Returns {@code true} if this instance contains a configuration entry with
+     * the specified key irrespective of the defined value; {@code false} otherwise.
+     *
+     * @param key The key to be tested.
+     * @return {@code true} if this instance contains a configuration entry with
+     * the specified key irrespective of the defined value; {@code false} otherwise.
+     */
+    public boolean contains(@Nonnull String key) {
+        return options.containsKey(key);
+    }
+
+    /**
+     * Returns the value of the configuration entry with the given {@code key}
+     * applying the following rules:
+     *
+     * <ul>
+     *     <li>If this instance doesn't contain a configuration entry with that
+     *     key the specified {@code defaultValue} will be returned.</li>
+     *     <li>If {@code defaultValue} is {@code null} the original value will
+     *     be returned.</li>
+     *     <li>If the configured value is {@code null} this method will always
+     *     return {@code null}.</li>
+     *     <li>If neither {@code defaultValue} nor the configured value is
+     *     {@code null} an attempt is made to convert the configured value to
+     *     match the type of the default value.</li>
+     * </ul>
+     *
+     * @param key The name of the configuration option.
+     * @param defaultValue The default value to return if no such entry exists
+     * or to use for conversion.
+     * @return The original or converted configuration value or {@code null}.
+     */
+    @CheckForNull
+    public <T> T getConfigValue(@Nonnull String key, @Nullable T defaultValue) {
         if (options != null && options.containsKey(key)) {
             return convert(options.get(key), defaultValue);
         } else {
@@ -54,7 +91,8 @@ public class ConfigurationParameters {
 
     //--------------------------------------------------------< private >---
     @SuppressWarnings("unchecked")
-    private static <T> T convert(Object configProperty, T defaultValue) {
+    @CheckForNull
+    private static <T> T convert(@Nullable Object configProperty, @Nullable T defaultValue) {
         if (configProperty == null) {
             return null;
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AccessControlConfiguration.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AccessControlConfiguration.java?rev=1471392&r1=1471391&r2=1471392&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AccessControlConfiguration.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/AccessControlConfiguration.java Wed Apr 24 13:02:26 2013
@@ -32,6 +32,8 @@ import org.apache.jackrabbit.oak.spi.sec
  */
 public interface AccessControlConfiguration extends SecurityConfiguration {
 
+    String PARAM_ACCESS_CONTROL_OPTIONS = "org.apache.jackrabbit.oak.accesscontrol.options";
+
     @Nonnull
     AccessControlManager getAccessControlManager(@Nonnull Root root,
                                                  @Nonnull NamePathMapper namePathMapper);

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java?rev=1471392&r1=1471391&r2=1471392&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java Wed Apr 24 13:02:26 2013
@@ -97,13 +97,17 @@ public abstract class AbstractSecurityTe
 
     protected SecurityProvider getSecurityProvider() {
         if (securityProvider == null) {
-            securityProvider = new SecurityProviderImpl();
+            securityProvider = new SecurityProviderImpl(getSecurityConfigParameters());
         }
         return securityProvider;
     }
 
+    protected ConfigurationParameters getSecurityConfigParameters() {
+        return ConfigurationParameters.EMPTY;
+    }
+
     protected Configuration getConfiguration() {
-        return ConfigurationUtil.getDefaultConfiguration(ConfigurationParameters.EMPTY);
+        return ConfigurationUtil.getDefaultConfiguration(getSecurityConfigParameters());
     }
 
     protected ContentSession login(@Nullable Credentials credentials)

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/ConfigurationParametersTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/ConfigurationParametersTest.java?rev=1471392&r1=1471391&r2=1471392&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/ConfigurationParametersTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/ConfigurationParametersTest.java Wed Apr 24 13:02:26 2013
@@ -26,8 +26,10 @@ import org.junit.Before;
 import org.junit.Test;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
 
 /**
  * ConfigurationParametersTest...
@@ -41,6 +43,22 @@ public class ConfigurationParametersTest
     public void tearDown() {}
 
     @Test
+    public void testContains() {
+        ConfigurationParameters params = ConfigurationParameters.EMPTY;
+        assertFalse(params.contains("some"));
+        assertFalse(params.contains(""));
+
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("key1", "v");
+        map.put("key2", "v");
+        params = new ConfigurationParameters(map);
+        assertTrue(params.contains("key1"));
+        assertTrue(params.contains("key2"));
+        assertFalse(params.contains("another"));
+        assertFalse(params.contains(""));
+    }
+
+    @Test
     public void testGetConfigValue() {
         Map<String, String> map = new HashMap<String, String>();
         map.put("o1", "v");
@@ -120,6 +138,7 @@ public class ConfigurationParametersTest
         assertNull(options.getConfigValue("test", null));
         assertNull(options.getConfigValue("test", "value"));
         assertNull(options.getConfigValue("test", new TestObject("t")));
+        assertNull(options.getConfigValue("test", false));
     }
 
     private class TestObject {

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/Jr2CompatibilityTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/Jr2CompatibilityTest.java?rev=1471392&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/Jr2CompatibilityTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/evaluation/Jr2CompatibilityTest.java Wed Apr 24 13:02:26 2013
@@ -0,0 +1,108 @@
+/*
+ * 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.security.authorization.evaluation;
+
+import java.util.Collections;
+import java.util.Map;
+
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlManager;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.security.authorization.AccessControlConstants;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+import org.apache.jackrabbit.oak.spi.security.authorization.AccessControlConfiguration;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Jr2CompatibilityTest... TODO
+ */
+public class Jr2CompatibilityTest extends AbstractOakCoreTest {
+
+    @Override
+    @Before
+    public void before() throws Exception {
+        super.before();
+        setupPermission("/", getTestUser().getPrincipal(), true, PrivilegeConstants.JCR_READ, PrivilegeConstants.REP_WRITE);
+    }
+
+    @Override
+    @After
+    public void after() throws Exception {
+        try {
+            AccessControlManager acMgr = getAccessControlManager(root);
+            JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, "/");
+            if (acl != null) {
+                boolean modified = false;
+                for (AccessControlEntry entry : acl.getAccessControlEntries()) {
+                    if (entry.getPrincipal().equals(getTestUser().getPrincipal())) {
+                        acl.removeAccessControlEntry(entry);
+                        modified = true;
+                    }
+                }
+                if (modified) {
+                    acMgr.setPolicy("/", acl);
+                    root.commit();
+                }
+            }
+        } finally {
+            super.after();
+        }
+    }
+    @Override
+    protected ConfigurationParameters getSecurityConfigParameters() {
+        Map<String, Boolean> map = Collections.singletonMap(AccessControlConstants.PARAM_PERMISSIONS_JR2, Boolean.TRUE);
+        ConfigurationParameters acConfig = new ConfigurationParameters(map);
+
+        return new ConfigurationParameters(ImmutableMap.of(AccessControlConfiguration.PARAM_ACCESS_CONTROL_OPTIONS, acConfig));
+    }
+
+    @Test
+    public void testUserManagementPermissionWithJr2Flag() throws Exception {
+        Root testRoot = getTestRoot();
+        testRoot.refresh();
+
+        UserManager testUserMgr = getUserConfiguration().getUserManager(testRoot, NamePathMapper.DEFAULT);
+        try {
+            User u = testUserMgr.createUser("a", "b");
+            testRoot.commit();
+
+            u.changePassword("c");
+            testRoot.commit();
+
+            u.remove();
+            testRoot.commit();
+        } finally {
+            root.refresh();
+            Authorizable user = getUserManager().getAuthorizable("a");
+            if (user != null) {
+                user.remove();
+                root.commit();
+            }
+        }
+    }
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/authorization/UserManagementTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/authorization/UserManagementTest.java?rev=1471392&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/authorization/UserManagementTest.java (added)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/authorization/UserManagementTest.java Wed Apr 24 13:02:26 2013
@@ -0,0 +1,337 @@
+/*
+ * 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.jcr.security.authorization;
+
+import java.util.List;
+import javax.jcr.AccessDeniedException;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.Privilege;
+
+import com.google.common.collect.Lists;
+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.api.security.user.UserManager;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Testing permission evaluation for user management operations.
+ *
+ * @since OAK 1.0 As of OAK user mgt related operations require a specific
+ * user management permission (unless the system in configured to behave like
+ * jackrabbit 2x).
+ */
+public class UserManagementTest extends AbstractEvaluationTest {
+
+    private final String userId = "testUser2";
+    private final String groupId = "testGroup2";
+
+    private List<String> authorizablesToRemove = Lists.newArrayList(userId, groupId);
+
+    @Override
+    @Before
+    public void tearDown() throws Exception {
+        try {
+            testSession.refresh(false);
+            superuser.refresh(false);
+
+            UserManager userMgr = getUserManager(superuser);
+            for (String id : authorizablesToRemove) {
+                Authorizable a = userMgr.getAuthorizable(id);
+                if (a != null) {
+                    a.remove();
+                }
+            }
+
+            JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, "/");
+            if (acl != null) {
+                boolean modified = false;
+                for (AccessControlEntry entry : acl.getAccessControlEntries()) {
+                    if (testUser.getPrincipal().equals(entry.getPrincipal())) {
+                        acl.removeAccessControlEntry(entry);
+                        modified = true;
+                    }
+                }
+                if (modified) {
+                    acMgr.setPolicy("/", acl);
+                }
+            }
+
+            superuser.save();
+        } finally {
+            super.tearDown();
+        }
+    }
+
+    private void createUser(String userId) throws Exception {
+        getUserManager(superuser).createUser(userId, "pw");
+        superuser.save();
+        testSession.refresh(false);
+    }
+
+    @Test
+    public void testCreateUserWithoutPermission() throws Exception {
+        UserManager testUserMgr = getUserManager(testSession);
+
+        // testSession has read-only access
+        try {
+            testUserMgr.createUser(userId, "pw");
+            testSession.save();
+            fail("Test session doesn't have sufficient permission -> creating user should fail.");
+        } catch (AccessDeniedException e) {
+            // success
+        }
+
+        // testSession has write permission but no user-mgt permission
+        // -> should still fail
+        modify("/", PrivilegeConstants.REP_WRITE, true);
+        try {
+            testUserMgr.createUser(userId, "pw");
+            testSession.save();
+            fail("Test session doesn't have sufficient permission -> creating user should fail.");
+        } catch (AccessDeniedException e) {
+            // success
+        }
+    }
+
+    @Test
+    public void testCreateUser() throws Exception {
+        UserManager testUserMgr = getUserManager(testSession);
+        Privilege[] privs = privilegesFromNames(new String[] {PrivilegeConstants.REP_USER_MANAGEMENT, PrivilegeConstants.REP_WRITE});
+        allow("/", privs);
+
+        // creating user should succeed
+        testUserMgr.createUser(userId, "pw");
+        testSession.save();
+    }
+
+    @Test
+    public void testCreateGroup() throws Exception {
+        UserManager testUserMgr = getUserManager(testSession);
+        Privilege[] privs = privilegesFromNames(new String[] {PrivilegeConstants.REP_USER_MANAGEMENT, PrivilegeConstants.REP_WRITE});
+        allow("/", privs);
+
+        // creating group should succeed
+        Group gr = testUserMgr.createGroup(groupId);
+        testSession.save();
+    }
+
+    @Test
+    public void testChangePasswordWithoutPermission() throws Exception {
+        createUser(userId);
+
+        UserManager testUserMgr = getUserManager(testSession);
+        User user = (User) testUserMgr.getAuthorizable(userId);
+        try {
+            user.changePassword("pw2");
+            testSession.save();
+            fail();
+        } catch (AccessDeniedException e) {
+            // success
+        }
+    }
+
+    @Test
+    public void testChangePasswordWithoutPermission2() throws Exception {
+        createUser(userId);
+
+        modify("/", PrivilegeConstants.REP_WRITE, true);
+
+        UserManager testUserMgr = getUserManager(testSession);
+        User user = (User) testUserMgr.getAuthorizable(userId);
+        try {
+            user.changePassword("pw2");
+            testSession.save();
+            fail();
+        } catch (AccessDeniedException e) {
+            // success
+        }
+    }
+
+    @Test
+    public void testChangePassword() throws Exception {
+        createUser(userId);
+
+        // after granting user-mgt privilege changing the pw must succeed.
+        modify("/", PrivilegeConstants.REP_USER_MANAGEMENT, true);
+
+        UserManager testUserMgr = getUserManager(testSession);
+        User user = (User) testUserMgr.getAuthorizable(userId);
+        user.changePassword("pw2");
+        testSession.save();
+    }
+
+    @Test
+    public void testDisableUserWithoutPermission() throws Exception {
+        createUser(userId);
+
+        UserManager testUserMgr = getUserManager(testSession);
+        User user = (User) testUserMgr.getAuthorizable(userId);
+        try {
+            user.disable("disabled!");
+            testSession.save();
+            fail();
+        } catch (AccessDeniedException e) {
+            // success
+        }
+    }
+
+    @Test
+    public void testDisableUserWithoutPermission2() throws Exception {
+        createUser(userId);
+
+        modify("/", PrivilegeConstants.REP_WRITE, true);
+
+        UserManager testUserMgr = getUserManager(testSession);
+        User user = (User) testUserMgr.getAuthorizable(userId);
+        try {
+            user.disable("disabled!");
+            testSession.save();
+            fail();
+        } catch (AccessDeniedException e) {
+            // success
+        }
+    }
+
+    @Test
+    public void testDisableUser() throws Exception {
+        createUser(userId);
+
+        // after granting user-mgt privilege changing the pw must succeed.
+        modify("/", PrivilegeConstants.REP_USER_MANAGEMENT, true);
+
+        UserManager testUserMgr = getUserManager(testSession);
+        User user = (User) testUserMgr.getAuthorizable(userId);
+        user.disable("disabled!");
+        testSession.save();
+    }
+
+    @Test
+    public void testRemoveUserWithoutPermission() throws Exception {
+        createUser(userId);
+
+        UserManager testUserMgr = getUserManager(testSession);
+        // testSession has read-only access
+        try {
+            Authorizable a = testUserMgr.getAuthorizable(userId);
+            a.remove();
+            testSession.save();
+            fail("Test session doesn't have sufficient permission to remove a user.");
+        } catch (AccessDeniedException e) {
+            // success
+        }
+
+        // testSession has write permission but no user-mgt permission
+        // -> should still fail
+        modify("/", PrivilegeConstants.REP_WRITE, true);
+        try {
+            Authorizable a = testUserMgr.getAuthorizable(userId);
+            a.remove();
+            testSession.save();
+            fail("Test session doesn't have sufficient permission to remove a user.");
+        } catch (AccessDeniedException e) {
+            // success
+        }
+    }
+
+    @Test
+    public void testRemoveUser() throws Exception {
+        createUser(userId);
+
+        // testSession has user-mgt permission -> removal should succeed.
+        modify("/", PrivilegeConstants.REP_USER_MANAGEMENT, true);
+
+        UserManager testUserMgr = getUserManager(testSession);
+        Authorizable a = testUserMgr.getAuthorizable(userId);
+        a.remove();
+        testSession.save();
+    }
+
+    @Test
+    public void testRemoveUser2() throws Exception {
+        createUser(userId);
+
+        // testSession has user-mgt permission -> removal should succeed.
+        Privilege[] privs = privilegesFromNames(new String[] {
+                PrivilegeConstants.REP_USER_MANAGEMENT,
+                PrivilegeConstants.REP_WRITE});
+        allow("/", privs);
+
+        UserManager testUserMgr = getUserManager(testSession);
+        Authorizable a = testUserMgr.getAuthorizable(userId);
+        a.remove();
+        testSession.save();
+    }
+
+    @Test
+    public void testChangeUserPropertiesWithoutPermission() throws Exception {
+        createUser(userId);
+
+        // testSession has read-only access
+        UserManager testUserMgr = getUserManager(testSession);
+        try {
+            Authorizable a = testUserMgr.getAuthorizable(userId);
+            a.setProperty("someProp", testSession.getValueFactory().createValue("value"));
+            testSession.save();
+            fail("Test session doesn't have sufficient permission to alter user properties.");
+        } catch (AccessDeniedException e) {
+            // success
+        }
+    }
+
+    @Test
+    public void testChangeUserPropertiesWithoutPermission2() throws Exception {
+        createUser(userId);
+
+        // testSession has read and user-mgt permission but lacks permission to
+        // alter regular properties
+        modify("/", PrivilegeConstants.REP_USER_MANAGEMENT, true);
+
+        UserManager testUserMgr = getUserManager(testSession);
+        try {
+            Authorizable a = testUserMgr.getAuthorizable(userId);
+            a.setProperty("someProp", testSession.getValueFactory().createValue("value"));
+            testSession.save();
+            fail("Test session doesn't have sufficient permission to alter user properties.");
+        } catch (AccessDeniedException e) {
+            // success
+        }
+    }
+
+    @Test
+    public void testChangeUserProperties() throws Exception {
+        createUser(userId);
+
+        // make sure user can create/modify/remove regular properties
+        modify("/", PrivilegeConstants.JCR_MODIFY_PROPERTIES, true);
+
+        UserManager testUserMgr = getUserManager(testSession);
+        Authorizable a = testUserMgr.getAuthorizable(userId);
+        a.setProperty("someProp", testSession.getValueFactory().createValue("value"));
+        testSession.save();
+
+        a.setProperty("someProperty", testSession.getValueFactory().createValue("modified"));
+        testSession.save();
+
+        a.removeProperty("someProperty");
+        testSession.save();
+    }
+}
\ No newline at end of file