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 2015/09/29 14:04:45 UTC

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

Author: angela
Date: Tue Sep 29 12:04:44 2015
New Revision: 1705841

URL: http://svn.apache.org/viewvc?rev=1705841&view=rev
Log:
OAK-3457 : Multivalued restriction to limit effect of ACE to items with a given name

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNamePattern.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNamePatternTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNameRestrictionTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/restriction/RestrictionProviderImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AccessControlConstants.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/package-info.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/package-info.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/ACLTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/RestrictionProviderImplTest.java
    jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/accesscontrol/restriction.md

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java?rev=1705841&r1=1705840&r2=1705841&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java Tue Sep 29 12:04:44 2015
@@ -122,16 +122,4 @@ final class PermissionEntry implements C
     public int hashCode() {
         return Objects.hashCode(privilegeBits, index, path, isAllow, restriction);
     }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder("PermissionEntry{");
-        sb.append("isAllow=").append(isAllow);
-        sb.append(", privilegeBits=").append(privilegeBits);
-        sb.append(", index=").append(index);
-        sb.append(", path='").append(path).append('\'');
-        sb.append(", restriction=").append(restriction);
-        sb.append('}');
-        return sb.toString();
-    }
 }
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNamePattern.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNamePattern.java?rev=1705841&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNamePattern.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNamePattern.java Tue Sep 29 12:04:44 2015
@@ -0,0 +1,95 @@
+/*
+ * 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.restriction;
+
+import java.util.Set;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionPattern;
+
+/**
+ * Implementation of the {@link RestrictionPattern} interface that returns
+ * {@code true} if the name of the target item (property or node) is contained
+ * in the configured set of names. This allows to limit certain operations (e.g.
+ * reading or modifying properties) to a subset of items in the tree defined
+ * by the associated policy.
+ */
+class ItemNamePattern implements RestrictionPattern {
+
+    private final Set<String> names;
+
+    ItemNamePattern(Iterable<String> names) {
+        this.names = ImmutableSet.copyOf(names);
+    }
+
+    @Override
+    public boolean matches(@Nonnull Tree tree, @Nullable PropertyState property) {
+        if (property != null) {
+            return names.contains(property.getName());
+        } else {
+            return names.contains(tree.getName());
+        }
+    }
+
+    @Override
+    public boolean matches(@Nonnull String path) {
+        return (PathUtils.denotesRoot(path) ? false : names.contains(PathUtils.getName(path)));
+    }
+
+    @Override
+    public boolean matches() {
+        // name pattern never matches for repository level permissions
+        return false;
+    }
+
+    //-------------------------------------------------------------< Object >---
+    /**
+     * @see Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return names.hashCode();
+    }
+
+    /**
+     * @see Object#toString()
+     */
+    @Override
+    public String toString() {
+        return names.toString();
+    }
+
+    /**
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof ItemNamePattern) {
+            ItemNamePattern other = (ItemNamePattern) obj;
+            return names.equals(other.names);
+        }
+        return false;
+    }
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/restriction/RestrictionProviderImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/restriction/RestrictionProviderImpl.java?rev=1705841&r1=1705840&r2=1705841&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/restriction/RestrictionProviderImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/restriction/RestrictionProviderImpl.java Tue Sep 29 12:04:44 2015
@@ -72,7 +72,8 @@ public class RestrictionProviderImpl ext
         RestrictionDefinition glob = new RestrictionDefinitionImpl(REP_GLOB, Type.STRING, false);
         RestrictionDefinition nts = new RestrictionDefinitionImpl(REP_NT_NAMES, Type.NAMES, false);
         RestrictionDefinition pfxs = new RestrictionDefinitionImpl(REP_PREFIXES, Type.STRINGS, false);
-        return ImmutableMap.of(glob.getName(), glob, nts.getName(), nts, pfxs.getName(), pfxs);
+        RestrictionDefinition names = new RestrictionDefinitionImpl(REP_ITEM_NAMES, Type.NAMES, false);
+        return ImmutableMap.of(glob.getName(), glob, nts.getName(), nts, pfxs.getName(), pfxs, names.getName(), names);
     }
 
     //------------------------------------------------< RestrictionProvider >---
@@ -96,6 +97,11 @@ public class RestrictionProviderImpl ext
             if (prefixes != null) {
                 patterns.add(new PrefixPattern(prefixes.getValue(Type.STRINGS)));
             }
+            PropertyState itemNames = tree.getProperty(REP_ITEM_NAMES);
+            if (itemNames != null) {
+                patterns.add(new ItemNamePattern(itemNames.getValue(Type.NAMES)));
+            }
+
             return CompositePattern.create(patterns);
         }
     }
@@ -115,6 +121,8 @@ public class RestrictionProviderImpl ext
                     patterns.add(new NodeTypePattern(r.getProperty().getValue(Type.NAMES)));
                 } else if (REP_PREFIXES.equals(name)) {
                     patterns.add(new PrefixPattern(r.getProperty().getValue(Type.STRINGS)));
+                } else if (REP_ITEM_NAMES.equals(name)) {
+                    patterns.add(new ItemNamePattern(r.getProperty().getValue(Type.NAMES)));
                 } else {
                     log.debug("Ignoring unsupported restriction " + name);
                 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AccessControlConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AccessControlConstants.java?rev=1705841&r1=1705840&r2=1705841&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AccessControlConstants.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AccessControlConstants.java Tue Sep 29 12:04:44 2015
@@ -50,6 +50,14 @@ public interface AccessControlConstants
     String REP_PREFIXES = "rep:prefixes";
 
     /**
+     * Name of the optional multivalued access control restriction by item name.
+     * The corresponding restriction type is {@link org.apache.jackrabbit.oak.api.Type#NAMES}.
+     *
+     * @since OAK 1.3.8
+     */
+    String REP_ITEM_NAMES = "rep:itemNames";
+
+    /**
      * @since OAK 1.0
      */
     String REP_RESTRICTIONS = "rep:restrictions";

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/package-info.java?rev=1705841&r1=1705840&r2=1705841&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/package-info.java Tue Sep 29 12:04:44 2015
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.3.1")
+@Version("1.4.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol;
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/package-info.java?rev=1705841&r1=1705840&r2=1705841&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/package-info.java Tue Sep 29 12:04:44 2015
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.0")
+@Version("1.1")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.spi.security.authorization.restriction;
 

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/ACLTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/ACLTest.java?rev=1705841&r1=1705840&r2=1705841&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/ACLTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/ACLTest.java Tue Sep 29 12:04:44 2015
@@ -648,11 +648,12 @@ public class ACLTest extends AbstractAcc
     public void testRestrictions() throws Exception {
         String[] names = acl.getRestrictionNames();
         assertNotNull(names);
-        assertEquals(3, names.length);
-        assertArrayEquals(new String[] {REP_GLOB, REP_NT_NAMES, REP_PREFIXES}, names);
+        assertEquals(4, names.length);
+        assertArrayEquals(new String[] {REP_GLOB, REP_NT_NAMES, REP_PREFIXES, REP_ITEM_NAMES}, names);
         assertEquals(PropertyType.STRING, acl.getRestrictionType(names[0]));
         assertEquals(PropertyType.NAME, acl.getRestrictionType(names[1]));
         assertEquals(PropertyType.STRING, acl.getRestrictionType(names[2]));
+        assertEquals(PropertyType.NAME, acl.getRestrictionType(names[3]));
 
         Privilege[] writePriv = privilegesFromNames(JCR_WRITE);
 

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNamePatternTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNamePatternTest.java?rev=1705841&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNamePatternTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNamePatternTest.java Tue Sep 29 12:04:44 2015
@@ -0,0 +1,77 @@
+/*
+ * 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.restriction;
+
+import java.util.List;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
+import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class ItemNamePatternTest extends AbstractSecurityTest {
+
+    private ItemNamePattern pattern = new ItemNamePattern(ImmutableSet.of("a", "b", "c"));
+
+    @Test
+    public void testMatchesItem() throws Exception {
+
+        NodeUtil rootTree = new NodeUtil(root.getTree("/"));
+        List<String> matching = ImmutableList.of("a", "b", "c", "d/e/a", "a/b/c/d/b", "test/c");
+        for (String relPath : matching) {
+            Tree testTree = rootTree.getOrAddTree(relPath, NodeTypeConstants.NT_OAK_UNSTRUCTURED).getTree();
+
+            assertTrue(pattern.matches(testTree, null));
+            assertTrue(pattern.matches(testTree, PropertyStates.createProperty("a", Boolean.FALSE)));
+            assertFalse(pattern.matches(testTree, PropertyStates.createProperty("f", "anyval")));
+        }
+
+        List<String> notMatching = ImmutableList.of("d", "b/d", "d/e/f", "c/b/abc");
+        for (String relPath : notMatching) {
+            Tree testTree = rootTree.getOrAddTree(relPath, NodeTypeConstants.NT_OAK_UNSTRUCTURED).getTree();
+
+            assertFalse(pattern.matches(testTree, null));
+            assertTrue(pattern.matches(testTree, PropertyStates.createProperty("a", Boolean.FALSE)));
+            assertFalse(pattern.matches(testTree, PropertyStates.createProperty("f", "anyval")));
+        }
+    }
+
+    @Test
+    public void testMatchesPath() {
+        List<String> matching = ImmutableList.of("/a", "/b", "/c", "/d/e/a", "/a/b/c/d/b", "/test/c");
+        for (String p : matching) {
+            assertTrue(pattern.matches(p));
+        }
+
+        List<String> notMatching = ImmutableList.of("/", "/d", "/b/d", "/d/e/f", "/c/b/abc");
+        for (String p : notMatching) {
+            assertFalse(pattern.matches(p));
+        }
+    }
+
+    @Test
+    public void testMatchesNull() {
+        assertFalse(pattern.matches());
+    }
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNameRestrictionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNameRestrictionTest.java?rev=1705841&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNameRestrictionTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/ItemNameRestrictionTest.java Tue Sep 29 12:04:44 2015
@@ -0,0 +1,283 @@
+/*
+ * 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.restriction;
+
+import java.security.Principal;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+import javax.jcr.PropertyType;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.security.AccessControlManager;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+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.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
+import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.junit.Test;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class ItemNameRestrictionTest extends AbstractSecurityTest {
+
+    private ValueFactory vf;
+    private ContentSession testSession;
+
+    private Principal testPrincipal;
+    private Group testGroup;
+
+    @Override
+    public void before() throws Exception {
+        super.before();
+
+        Tree rootTree = root.getTree("/");
+        NodeUtil f = new NodeUtil(rootTree).getOrAddTree("a/d/b/e/c/f", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+        NodeUtil c = f.getParent();
+        c.setString("prop", "value");
+        c.setString("a", "value");
+
+        testPrincipal = getTestUser().getPrincipal();
+
+        AccessControlManager acMgr = getAccessControlManager(root);
+        JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, "/a");
+
+        vf = new ValueFactoryImpl(root, NamePathMapper.DEFAULT);
+        acl.addEntry(testPrincipal,
+                privilegesFromNames(
+                        PrivilegeConstants.JCR_READ,
+                        PrivilegeConstants.REP_ADD_PROPERTIES,
+                        PrivilegeConstants.JCR_ADD_CHILD_NODES,
+                        PrivilegeConstants.JCR_REMOVE_NODE), true,
+                Collections.<String, Value>emptyMap(),
+                ImmutableMap.of(AccessControlConstants.REP_ITEM_NAMES, new Value[] {
+                        vf.createValue("a", PropertyType.NAME),
+                        vf.createValue("b", PropertyType.NAME),
+                        vf.createValue("c", PropertyType.NAME)}));
+        acMgr.setPolicy(acl.getPath(), acl);
+
+        UserManager uMgr = getUserManager(root);
+        testGroup = uMgr.createGroup("testGroup" + UUID.randomUUID());
+
+        root.commit();
+        testSession = createTestSession();
+    }
+
+    @Override
+    public void after() throws Exception {
+        try {
+            testSession.close();
+            root.refresh();
+            Tree a = root.getTree("/a");
+            if (a.exists()) {
+                a.remove();
+                root.commit();
+            }
+        } finally {
+            super.after();
+        }
+    }
+
+    @Test
+    public void testRead() {
+        Root testRoot = testSession.getLatestRoot();
+
+        List<String> visible = ImmutableList.of("/a", "/a/d/b", "/a/d/b/e/c");
+        for (String p : visible) {
+            assertTrue(testRoot.getTree(p).exists());
+        }
+
+        List<String> invisible = ImmutableList.of("/", "/a/d", "/a/d/b/e", "/a/d/b/e/c/f");
+        for (String p : invisible) {
+            assertFalse(testRoot.getTree(p).exists());
+        }
+
+        Tree c = testRoot.getTree("/a/d/b/e/c");
+        assertNull(c.getProperty(JcrConstants.JCR_PRIMARYTYPE));
+        assertNull(c.getProperty("prop"));
+        assertNotNull(c.getProperty("a"));
+    }
+
+    @Test
+    public void testAddProperty() throws Exception {
+        Root testRoot = testSession.getLatestRoot();
+
+        List<String> paths = ImmutableList.of("/a", "/a/d/b", "/a/d/b/e/c");
+        for (String p : paths) {
+            Tree t = testRoot.getTree(p);
+            t.setProperty("b", "anyvalue");
+            testRoot.commit();
+        }
+
+        for (String p : paths) {
+            Tree t = testRoot.getTree(p);
+            try {
+                t.setProperty("notAllowed", "anyvalue");
+                testRoot.commit();
+                fail();
+            } catch (CommitFailedException e) {
+                // success
+                assertTrue(e.isAccessViolation());
+            } finally {
+                testRoot.refresh();
+            }
+        }
+    }
+
+    @Test
+    public void testModifyProperty() throws Exception {
+        Root testRoot = testSession.getLatestRoot();
+        Tree c = testRoot.getTree("/a/d/b/e/c");
+
+        try {
+            c.setProperty("a", "anyvalue");
+            testRoot.commit();
+            fail();
+        } catch (CommitFailedException e) {
+            // success
+            assertTrue(e.isAccessViolation());
+        } finally {
+            testRoot.refresh();
+        }
+    }
+
+    @Test
+    public void testAddChild() throws Exception {
+        Root testRoot = testSession.getLatestRoot();
+
+        List<String> paths = ImmutableList.of("/a", "/a/d/b", "/a/d/b/e/c");
+        for (String p : paths) {
+            NodeUtil t = new NodeUtil(testRoot.getTree(p));
+            t.addChild("c", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+            testRoot.commit();
+        }
+    }
+
+    @Test
+    public void testRemoveTree() throws Exception {
+        Root testRoot = testSession.getLatestRoot();
+        List<String> paths = ImmutableList.of("/a/d/b/e/c", "/a/d/b", "/a");
+        for (String p : paths) {
+            try {
+                testRoot.getTree(p).remove();
+                testRoot.commit();
+                fail();
+            } catch (CommitFailedException e) {
+                // success
+                assertTrue(e.isAccessViolation());
+            } finally {
+                testRoot.refresh();
+            }
+        }
+    }
+
+    @Test
+    public void testRemoveTree2() throws Exception {
+        AccessControlManager acMgr = getAccessControlManager(root);
+        JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, "/a");
+
+        acl.addEntry(testPrincipal,
+                privilegesFromNames(PrivilegeConstants.JCR_READ, PrivilegeConstants.JCR_REMOVE_CHILD_NODES), true);
+        acMgr.setPolicy(acl.getPath(), acl);
+        root.commit();
+
+        Root testRoot = testSession.getLatestRoot();
+        List<String> paths = ImmutableList.of("/a/d/b/e/c", "/a/d/b");
+        for (String p : paths) {
+            testRoot.getTree(p).remove();
+            testRoot.commit();
+        }
+
+        try {
+            testRoot.getTree("/a").remove();
+            testRoot.commit();
+            fail();
+        } catch (CommitFailedException e) {
+            // success
+            assertTrue(e.isAccessViolation());
+        } finally {
+            testRoot.refresh();
+        }
+    }
+
+    @Test
+    public void testModifyMembersOnly() throws Exception {
+        AccessControlManager acMgr = getAccessControlManager(root);
+        String path = PathUtils.getAncestorPath(UserConstants.DEFAULT_USER_PATH, 1);
+        try {
+            JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, path);
+            acl.addEntry(testPrincipal, privilegesFromNames(PrivilegeConstants.JCR_READ), true);
+            acl.addEntry(testPrincipal, privilegesFromNames(PrivilegeConstants.REP_USER_MANAGEMENT), true,
+                    Collections.<String,Value>emptyMap(),
+                    ImmutableMap.<String,Value[]>of (AccessControlConstants.REP_ITEM_NAMES, new Value[] {
+                                            vf.createValue(UserConstants.REP_MEMBERS, PropertyType.NAME)}));
+            acMgr.setPolicy(acl.getPath(), acl);
+            root.commit();
+
+            Root testRoot = testSession.getLatestRoot();
+
+            UserManager uMgr = getUserManager(testRoot);
+
+            // adding a group member must succeed
+            Group gr = uMgr.getAuthorizable(testGroup.getID(), Group.class);
+            User u = uMgr.getAuthorizable(getTestUser().getID(), User.class);
+            gr.addMember(u);
+            testRoot.commit();
+
+            // changing the pw property of the test user must fail
+            try {
+                u.changePassword("blub");
+                testRoot.commit();
+                fail();
+            } catch (CommitFailedException e) {
+                // success
+                assertTrue(e.isAccessViolation());
+            } finally {
+                testRoot.refresh();
+            }
+        } catch (CommitFailedException e) {
+            // success
+            assertTrue(e.isAccessViolation());
+        } finally {
+            JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, path);
+            if (acl != null) {
+                acMgr.removePolicy(acl.getPath(), acl);
+                root.commit();
+            }
+        }
+    }
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/RestrictionProviderImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/RestrictionProviderImplTest.java?rev=1705841&r1=1705840&r2=1705841&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/RestrictionProviderImplTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/restriction/RestrictionProviderImplTest.java Tue Sep 29 12:04:44 2015
@@ -68,7 +68,7 @@ public class RestrictionProviderImplTest
 
         Set<RestrictionDefinition> defs = provider.getSupportedRestrictions("/testPath");
         assertNotNull(defs);
-        assertEquals(3, defs.size());
+        assertEquals(4, defs.size());
 
         for (RestrictionDefinition def : defs) {
             if (REP_GLOB.equals(def.getName())) {
@@ -80,6 +80,9 @@ public class RestrictionProviderImplTest
             } else if (REP_PREFIXES.equals(def.getName())) {
                 assertEquals(Type.STRINGS, def.getRequiredType());
                 assertFalse(def.isMandatory());
+            } else if (REP_ITEM_NAMES.equals(def.getName())) {
+                assertEquals(Type.NAMES, def.getRequiredType());
+                assertFalse(def.isMandatory());
             } else {
                 fail("unexpected restriction " + def.getName());
             }
@@ -122,6 +125,8 @@ public class RestrictionProviderImplTest
         map.put(PropertyStates.createProperty(REP_NT_NAMES, ntNames, Type.NAMES), new NodeTypePattern(ntNames));
         List<String> prefixes = ImmutableList.of("rep", "jcr");
         map.put(PropertyStates.createProperty(REP_PREFIXES, prefixes, Type.STRINGS), new PrefixPattern(prefixes));
+        List<String> itemNames = ImmutableList.of("abc", "jcr:primaryType");
+        map.put(PropertyStates.createProperty(REP_ITEM_NAMES, prefixes, Type.NAMES), new ItemNamePattern(itemNames));
 
         NodeUtil tree = new NodeUtil(root.getTree("/")).getOrAddTree("testPath", JcrConstants.NT_UNSTRUCTURED);
         Tree restrictions = tree.addChild(REP_RESTRICTIONS, NT_REP_RESTRICTIONS).getTree();
@@ -137,11 +142,16 @@ public class RestrictionProviderImplTest
     public void testGetPatternFromRestrictions() throws Exception {
         Map<PropertyState, RestrictionPattern> map = newHashMap();
         map.put(PropertyStates.createProperty(REP_GLOB, "/*/jcr:content"), GlobPattern.create("/testPath", "/*/jcr:content"));
+
         List<String> ntNames = ImmutableList.of(JcrConstants.NT_FOLDER, JcrConstants.NT_LINKEDFILE);
         map.put(PropertyStates.createProperty(REP_NT_NAMES, ntNames, Type.NAMES), new NodeTypePattern(ntNames));
+
         List<String> prefixes = ImmutableList.of("rep", "jcr");
         map.put(PropertyStates.createProperty(REP_PREFIXES, prefixes, Type.STRINGS), new PrefixPattern(prefixes));
 
+        List<String> itemNames = ImmutableList.of("abc", "jcr:primaryType");
+        map.put(PropertyStates.createProperty(REP_ITEM_NAMES, itemNames, Type.NAMES), new ItemNamePattern(itemNames));
+
         NodeUtil tree = new NodeUtil(root.getTree("/")).getOrAddTree("testPath", JcrConstants.NT_UNSTRUCTURED);
         Tree restrictions = tree.addChild(REP_RESTRICTIONS, NT_REP_RESTRICTIONS).getTree();
 

Modified: jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/accesscontrol/restriction.md
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/accesscontrol/restriction.md?rev=1705841&r1=1705840&r2=1705841&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/accesscontrol/restriction.md (original)
+++ jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/accesscontrol/restriction.md Tue Sep 29 12:04:44 2015
@@ -95,7 +95,7 @@ as follows:
 - supports multi-valued restrictions
 - validation of the restrictions is delegated to a dedicated commit hook
 - restriction `rep:glob` limits the number of wildcard characters to 20
-- new restrictions `rep:ntNames` and `rep:prefixes`
+- new restrictions `rep:ntNames`, `rep:prefixes` and `rep:itemNames`
 
 #### Built-in Restrictions
 
@@ -105,6 +105,7 @@ Oak 1.0 access control management:
 * `rep:glob`: single name or path pattern with '*' wildcard(s).
 * `rep:ntNames`: multivalued restriction for primary node type names (no inheritence, since Oak 1.0)
 * `rep:prefixes`: multivalued restriction for namespace prefixes (session level remapping not respected, since Oak 1.0)
+* `rep:itemNames`: multivalued restriction for property or node names (since Oak 1.3.8)
 
 
 ### Pluggability