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/03/22 09:45:53 UTC

svn commit: r1459665 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/security/authorization/permission/ main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/ test/java/org/apache/jackrabbit/oak/security/authoriza...

Author: angela
Date: Fri Mar 22 08:45:53 2013
New Revision: 1459665

URL: http://svn.apache.org/r1459665
Log:
OAK-527: permissions (wip)

Added:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java
    jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java?rev=1459665&r1=1459664&r2=1459665&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java Fri Mar 22 08:45:53 2013
@@ -20,6 +20,7 @@ import java.util.Set;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 
+import com.google.common.base.Objects;
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 import org.apache.jackrabbit.JcrConstants;
@@ -82,7 +83,7 @@ public class PermissionHook implements P
         ntMgr = ReadOnlyNodeTypeManager.getInstance(before);
         bitsProvider = new PrivilegeBitsProvider(new ImmutableRoot(before, workspaceName));
 
-        after.compareAgainstBaseState(before, new Diff(new BeforeNode(before), new Node(rootAfter)));
+        after.compareAgainstBaseState(before, new Diff(new BeforeNode(before), new AfterNode(rootAfter)));
         return rootAfter.getNodeState();
     }
 
@@ -102,11 +103,20 @@ public class PermissionHook implements P
         return permissionRoot;
     }
 
+    @CheckForNull
+    private NodeBuilder getPrincipalRoot(String principalName) {
+        if (permissionRoot.hasChildNode(principalName)) {
+            return permissionRoot.child(principalName);
+        } else {
+            return null;
+        }
+    }
+
     private static Tree getTree(String name, NodeState nodeState) {
         return new ImmutableTree(ImmutableTree.ParentProvider.UNSUPPORTED, name, nodeState, ImmutableTree.TypeProvider.EMPTY);
     }
 
-    private static String getAccessControlledPath(BaseNode aclNode) {
+    private static String getAccessControlledPath(Node aclNode) {
         if (REP_REPO_POLICY.equals(aclNode.getName())) {
             return "";
         } else {
@@ -114,27 +124,21 @@ public class PermissionHook implements P
         }
     }
 
-    private static int getAceIndex(BaseNode aclNode, String aceName) {
+    private static int getAceIndex(Node aclNode, String aceName) {
         PropertyState ordering = checkNotNull(aclNode.getNodeState().getProperty(TreeImpl.OAK_CHILD_ORDER));
         return Lists.newArrayList(ordering.getValue(Type.STRINGS)).indexOf(aceName);
     }
 
-    private static String generateName(NodeBuilder principalRoot, PermissionEntry entry) {
-        StringBuilder name = new StringBuilder();
-        name.append((entry.isAllow) ? PREFIX_ALLOW : PREFIX_DENY).append('-').append(principalRoot.getChildNodeCount());
-        return name.toString();
-    }
-
     private Set<Restriction> getRestrictions(String accessControlledPath, Tree aceTree) {
         return restrictionProvider.readRestrictions(Strings.emptyToNull(accessControlledPath), aceTree);
     }
 
     private class Diff implements NodeStateDiff {
 
-        private final BeforeNode parentBefore;
-        private final Node parentAfter;
+        private final Node parentBefore;
+        private final AfterNode parentAfter;
 
-        private Diff(@Nonnull BeforeNode parentBefore, @Nonnull Node parentAfter) {
+        private Diff(@Nonnull Node parentBefore, @Nonnull AfterNode parentAfter) {
             this.parentBefore = parentBefore;
             this.parentAfter = parentAfter;
         }
@@ -162,9 +166,11 @@ public class PermissionHook implements P
                 // ignore hidden nodes
             } else if (isACE(name, after)) {
                 addEntry(name, after);
+            } else if (REP_RESTRICTIONS.equals(name)) {
+                updateEntry(parentAfter.getName(), parentBefore.getNodeState(), parentAfter.getNodeState());
             } else {
-                BeforeNode before = new BeforeNode(parentBefore.getPath(), name, EMPTY_NODE);
-                Node node = new Node(parentAfter, name);
+                Node before = new BeforeNode(parentBefore.getPath(), name, EMPTY_NODE);
+                AfterNode node = new AfterNode(parentAfter, name);
                 after.compareAgainstBaseState(before.getNodeState(), new Diff(before, node));
             }
         }
@@ -179,7 +185,7 @@ public class PermissionHook implements P
                 updateEntry(parentAfter.getName(), parentBefore.getNodeState(), parentAfter.getNodeState());
             } else {
                 BeforeNode nodeBefore = new BeforeNode(parentBefore.getPath(), name, before);
-                Node nodeAfter = new Node(parentAfter, name);
+                AfterNode nodeAfter = new AfterNode(parentAfter, name);
                 after.compareAgainstBaseState(before, new Diff(nodeBefore, nodeAfter));
             }
         }
@@ -190,9 +196,11 @@ public class PermissionHook implements P
                 // ignore hidden nodes
             } else if (isACE(name, before)) {
                 removeEntry(name, before);
+            } else if (REP_RESTRICTIONS.equals(name)) {
+                updateEntry(parentAfter.getName(), parentBefore.getNodeState(), parentAfter.getNodeState());
             } else {
                 BeforeNode nodeBefore = new BeforeNode(parentBefore.getPath(), name, before);
-                Node after = new Node(parentAfter.getPath(), name, EMPTY_NODE);
+                AfterNode after = new AfterNode(parentAfter.getPath(), name, EMPTY_NODE);
                 after.getNodeState().compareAgainstBaseState(before, new Diff(nodeBefore, after));
             }
         }
@@ -208,16 +216,14 @@ public class PermissionHook implements P
 
         private void addEntry(String name, NodeState ace) {
             PermissionEntry entry = createPermissionEntry(name, ace, parentAfter);
-            if (getExistingPermissionNodeName(entry) == null) {
-                entry.writeTo(permissionRoot);
-            }
+            entry.writeTo(permissionRoot);
         }
 
         private void removeEntry(String name, NodeState ace) {
             PermissionEntry entry = createPermissionEntry(name, ace, parentBefore);
-            String permissionName = getExistingPermissionNodeName(entry);
-            if (permissionName != null) {
-                permissionRoot.child(entry.principalName).removeNode(permissionName);
+            NodeBuilder principalRoot = getPrincipalRoot(entry.principalName);
+            if (principalRoot != null) {
+                principalRoot.removeNode(entry.nodeName);
             }
         }
 
@@ -226,28 +232,8 @@ public class PermissionHook implements P
             addEntry(name, after);
         }
 
-        @CheckForNull
-        private String getExistingPermissionNodeName(PermissionEntry permissionEntry) {
-            if (permissionRoot.hasChildNode(permissionEntry.principalName)) {
-                NodeBuilder principalRoot = permissionRoot.child(permissionEntry.principalName);
-                for (String childName : principalRoot.getChildNodeNames()) {
-                    NodeState state = principalRoot.child(childName).getNodeState();
-                    if (permissionEntry.isSame(childName, state)) {
-                        log.debug("Found existing permission entry for " + permissionEntry);
-                        return childName;
-                    }
-                }
-                log.warn("No permission entry for " + permissionEntry);
-            } else {
-                // inconsistency: removing an ACE that doesn't have a corresponding
-                // entry in the permission store.
-                log.warn("Missing permission node for principal " + permissionEntry.principalName);
-            }
-            return null;
-        }
-
         @Nonnull
-        private PermissionEntry createPermissionEntry(String name, NodeState ace, BaseNode acl) {
+        private PermissionEntry createPermissionEntry(String name, NodeState ace, Node acl) {
             Tree aceTree = getTree(name, ace);
             String accessControlledPath = getAccessControlledPath(acl);
             String principalName = checkNotNull(TreeUtil.getString(aceTree, REP_PRINCIPAL_NAME));
@@ -259,15 +245,15 @@ public class PermissionHook implements P
         }
     }
 
-    private static abstract class BaseNode {
+    private static abstract class Node {
 
         private final String path;
 
-        private BaseNode(String path) {
+        private Node(String path) {
             this.path = path;
         }
 
-        private BaseNode(String parentPath, String name) {
+        private Node(String parentPath, String name) {
             this.path = PathUtils.concat(parentPath, new String[]{name});
         }
 
@@ -282,7 +268,7 @@ public class PermissionHook implements P
         abstract NodeState getNodeState();
     }
 
-    private static final class BeforeNode extends BaseNode {
+    private static final class BeforeNode extends Node {
 
         private final NodeState nodeState;
 
@@ -303,21 +289,21 @@ public class PermissionHook implements P
         }
     }
 
-    private static final class Node extends BaseNode {
+    private static final class AfterNode extends Node {
 
         private final NodeBuilder builder;
 
-        private Node(NodeBuilder rootBuilder) {
+        private AfterNode(NodeBuilder rootBuilder) {
             super("/");
             this.builder = rootBuilder;
         }
 
-        private Node(String parentPath, String name, NodeState state) {
+        private AfterNode(String parentPath, String name, NodeState state) {
             super(parentPath, name);
             this.builder = state.builder();
         }
 
-        private Node(Node parent, String name) {
+        private AfterNode(AfterNode parent, String name) {
             super(parent.getPath(), name);
             this.builder = parent.builder.child(name);
         }
@@ -331,12 +317,13 @@ public class PermissionHook implements P
 
         private final String accessControlledPath;
         private final int index;
-
         private final String principalName;
         private final PrivilegeBits privilegeBits;
         private final boolean isAllow;
         private final Set<Restriction> restrictions;
 
+        private final String nodeName;
+
         private PermissionEntry(@Nonnull String accessControlledPath,
                       int index,
                       @Nonnull String principalName,
@@ -349,6 +336,12 @@ public class PermissionHook implements P
             this.privilegeBits = privilegeBits;
             this.isAllow = isAllow;
             this.restrictions = restrictions;
+
+            // create node name from ace definition (excluding the index)
+            StringBuilder name = new StringBuilder();
+            name.append((isAllow) ? PREFIX_ALLOW : PREFIX_DENY).append('-');
+            name.append(Objects.hashCode(accessControlledPath, principalName, privilegeBits, isAllow, restrictions));
+            nodeName = name.toString();
         }
 
         private void writeTo(NodeBuilder permissionRoot) {
@@ -356,8 +349,7 @@ public class PermissionHook implements P
             if (principalRoot.getProperty(JCR_PRIMARYTYPE) == null) {
                 principalRoot.setProperty(JCR_PRIMARYTYPE, NT_REP_PERMISSION_STORE, Type.NAME);
             }
-            String entryName = generateName(principalRoot, this);
-            NodeBuilder entry = principalRoot.child(entryName)
+            NodeBuilder entry = principalRoot.child(nodeName)
                     .setProperty(JCR_PRIMARYTYPE, NT_REP_PERMISSIONS, Type.NAME)
                     .setProperty(REP_ACCESS_CONTROLLED_PATH, accessControlledPath)
                     .setProperty(REP_INDEX, index)
@@ -367,27 +359,10 @@ public class PermissionHook implements P
             }
         }
 
-        private boolean isSame(String name, NodeState node) {
-            Tree entry = getTree(name, node);
-
-            if (isAllow != (name.charAt(0) == PREFIX_ALLOW)) {
-                return false;
-            }
-            if (!privilegeBits.equals(PrivilegeBits.getInstance(node.getProperty(REP_PRIVILEGES)))) {
-                return false;
-            }
-            if (index != entry.getProperty(REP_INDEX).getValue(Type.LONG)) {
-                return false;
-            }
-            if (!accessControlledPath.equals(TreeUtil.getString(entry, REP_ACCESS_CONTROLLED_PATH))) {
-                return false;
-            }
-            return restrictions.equals(getRestrictions(accessControlledPath, entry));
-        }
-
         public String toString() {
             StringBuilder sb = new StringBuilder();
             sb.append("permission entry: ").append(accessControlledPath);
+            sb.append(';').append(index);
             sb.append(';').append(principalName);
             sb.append(';').append(isAllow ? "allow" : "deny");
             sb.append(';').append(privilegeBits);

Modified: jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd?rev=1459665&r1=1459664&r2=1459665&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd Fri Mar 22 08:45:53 2013
@@ -637,10 +637,8 @@
  * @since oak 1.0
  */
 [rep:Permissions]
-  - rep:accessControlledPath (PATH) protected mandatory
-  - rep:privileges (LONG) protected multiple mandatory
-  - rep:index (LONG) protected mandatory
   - * (UNDEFINED) protected
+  - * (UNDEFINED) protected multiple
 
 // -----------------------------------------------------------------------------
 // Principal based AC

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java?rev=1459665&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHookTest.java Fri Mar 22 08:45:53 2013
@@ -0,0 +1,121 @@
+/*
+ * 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.permission;
+
+import java.security.Principal;
+import javax.jcr.RepositoryException;
+import javax.jcr.security.AccessControlManager;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.oak.security.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.oak.spi.security.authorization.AbstractAccessControlTest;
+import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
+import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * PermissionHookTest... TODO
+ */
+public class PermissionHookTest extends AbstractAccessControlTest implements PermissionConstants {
+
+    private AccessControlManager acMgr;
+    @Override
+    @Before
+    public void before() throws Exception {
+        super.before();
+
+        NodeUtil rootNode = new NodeUtil(root.getTree("/"), namePathMapper);
+        rootNode.addChild("testName", JcrConstants.NT_UNSTRUCTURED);
+        root.commit();
+
+        acMgr = getAccessControlManager(root);
+    }
+
+    @After
+    public void after() throws Exception {
+        root.refresh();
+        root.getTree("/testName").remove();
+        root.commit();
+    }
+
+    private Tree getEntry(String principalName, String accessControlledPath) throws Exception {
+        Tree permissionTree = root.getTree(PERMISSIONS_STORE_PATH).getChild(adminSession.getWorkspaceName()).getChild(principalName);
+        for (Tree entry : permissionTree.getChildren()) {
+            if (accessControlledPath.equals(entry.getProperty(REP_ACCESS_CONTROLLED_PATH).getValue(Type.STRING))) {
+                return entry;
+            }
+        }
+        throw new RepositoryException("no such entry");
+    }
+
+    @Test
+    public void testAddDuplicateAce() {
+        // TODO
+    }
+
+    @Test
+    public void testRemoveDuplicateAce() {
+        // TODO
+    }
+
+    @Test
+    public void testAddRestrictionNode() {
+        // TODO add restriction node on oak-api
+    }
+
+    @Test
+    public void testRemoveRestrictionNode() {
+        // TODO
+    }
+
+    @Test
+    public void testModifyRestrictions() {
+        // TODO
+    }
+
+    @Ignore("PermissionHook#propertyChanged without corresponding child node modifications")
+    @Test
+    public void testReorderAce() throws Exception {
+        Principal testPrincipal = new PrincipalImpl("admin");
+        JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, "/testName");
+        acl.addAccessControlEntry(testPrincipal, privilegesFromNames(PrivilegeConstants.JCR_ADD_CHILD_NODES));
+        acl.addAccessControlEntry(EveryonePrincipal.getInstance(), privilegesFromNames(PrivilegeConstants.JCR_READ));
+        acMgr.setPolicy("/testName", acl);
+        root.commit();
+
+        Tree entry = getEntry("admin", "/testName");
+        assertEquals(0, entry.getProperty(REP_INDEX).getValue(Type.LONG).longValue());
+
+        Tree aclTree = root.getTree("/testName/rep:policy");
+        aclTree.getChildren().iterator().next().orderBefore(null);
+
+        root.commit();
+
+        entry = getEntry("admin", "/testName");
+        assertEquals(1, entry.getProperty(REP_INDEX).getValue(Type.LONG).longValue());
+    }
+}
\ No newline at end of file