jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r1532771 [1/2] - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/core/ main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/ main/java/org/apache/jackrabbit/oak/security/authorization/permissio...
Date Wed, 16 Oct 2013 14:00:52 GMT
Author: angela
Date: Wed Oct 16 14:00:51 2013
New Revision: 1532771

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

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/AbstractEntryIterator.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/EntryPredicate.java
    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/spi/security/authorization/permission/RepositoryPermission.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/TreePermission.java
Removed:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/ReadStatus.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImplTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/ReadStatusTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecurityContext.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/AllPermissions.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissions.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/NoPermissions.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionHook.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionUtil.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/spi/security/authorization/permission/OpenPermissionProvider.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionProvider.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBits.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/AllPermissionsTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImplTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBitsTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecurityContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecurityContext.java?rev=1532771&r1=1532770&r2=1532771&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecurityContext.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecurityContext.java Wed Oct 16 14:00:51 2013
@@ -21,11 +21,9 @@ import javax.annotation.Nonnull;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.spi.security.Context;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
-import org.apache.jackrabbit.oak.spi.security.authorization.permission.ReadStatus;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 /**
  * The security context encapsulates all the information needed to make
  * read permission checks within a specific subtree.
@@ -47,64 +45,41 @@ class SecurityContext {
 
     private final Context acContext;
 
-    private ReadStatus readStatus;
+    private TreePermission treePermission;
 
-    SecurityContext(
-            @Nonnull NodeState rootState,
-            @Nonnull PermissionProvider permissionProvider,
-            @Nonnull Context acContext) {
-        this.root = checkNotNull(rootState);
-        this.base = new ImmutableTree(rootState, new TreeTypeProviderImpl(acContext));
+    SecurityContext(@Nonnull NodeState rootState,
+                    @Nonnull PermissionProvider permissionProvider,
+                    @Nonnull Context acContext) {
+        root = rootState;
+        base = new ImmutableTree(rootState, new TreeTypeProviderImpl(acContext));
         this.permissionProvider = permissionProvider;
         this.acContext = acContext;
-        // calculate the readstatus for the root
-        this.readStatus = permissionProvider.getReadStatus(base, null);
-    }
-
-    private SecurityContext(
-            @Nonnull SecurityContext parent,
-            @Nonnull String name, @Nonnull NodeState nodeState) {
-        this.root = checkNotNull(parent).root;
-        this.base = new ImmutableTree(parent.base, name, nodeState);
-        this.permissionProvider = parent.permissionProvider;
-        this.acContext = parent.acContext;
-        if (base.getType() == parent.base.getType()) {
-            readStatus = ReadStatus.getChildStatus(parent.readStatus);
-        } else {
-            readStatus = null;
-        }
+        treePermission = permissionProvider.getTreePermission(base, TreePermission.EMPTY);
     }
 
-    private synchronized ReadStatus getReadStatus() {
-        if (readStatus == null) {
-            readStatus = permissionProvider.getReadStatus(base, null);
-        }
-        return readStatus;
+    private SecurityContext(@Nonnull SecurityContext parent,
+                            @Nonnull String name, @Nonnull NodeState nodeState) {
+        root = parent.root;
+        base = new ImmutableTree(parent.base, name, nodeState);
+        permissionProvider = parent.permissionProvider;
+        acContext = parent.acContext;
+        treePermission = permissionProvider.getTreePermission(base, parent.treePermission);
     }
 
     boolean canReadThisNode() {
-        return getReadStatus().includes(ReadStatus.ALLOW_THIS);
+        return treePermission.canRead();
     }
 
     boolean canReadAllProperties() {
-        ReadStatus rs = getReadStatus();
-        return rs.includes(ReadStatus.ALLOW_PROPERTIES);
+        return treePermission.canReadProperties();
     }
 
     boolean canReadProperty(PropertyState property) {
-        ReadStatus rs = getReadStatus();
-        if (rs.includes(ReadStatus.ALLOW_PROPERTIES)) {
-            return true;
-        } else if (rs.appliesToThis()) {
-            rs = permissionProvider.getReadStatus(base, property);
-            return rs.isAllow();
-        } else {
-            return false;
-        }
+        return treePermission.canRead(property);
     }
 
     boolean canReadAll() {
-        return readStatus != null && readStatus.includes(ReadStatus.ALLOW_ALL);
+        return treePermission.canReadAll();
     }
 
     SecurityContext getChildContext(String name, NodeState state) {
@@ -134,5 +109,4 @@ class SecurityContext {
     public int hashCode() {
         return 0;
     }
-
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImpl.java?rev=1532771&r1=1532770&r2=1532771&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImpl.java Wed Oct 16 14:00:51 2013
@@ -472,7 +472,7 @@ public class AccessControlManagerImpl im
     private void checkPermissions(@Nullable Tree tree, long permissions) throws AccessDeniedException {
         boolean isGranted;
         if (tree == null) {
-            isGranted = getPermissionProvider().isGranted(permissions);
+            isGranted = getPermissionProvider().getRepositoryPermission().isGranted(permissions);
         } else {
             isGranted = getPermissionProvider().isGranted(tree, null, permissions);
         }
@@ -636,16 +636,6 @@ public class AccessControlManagerImpl im
     }
 
     @Nonnull
-    private Set<Privilege> getPrivileges(@Nonnull Tree aceTree) throws RepositoryException {
-        Iterable<String> privNames = checkNotNull(TreeUtil.getStrings(aceTree, REP_PRIVILEGES));
-        Set<Privilege> privileges = new HashSet<Privilege>();
-        for (String name : privNames) {
-            privileges.add(privilegeManager.getPrivilege(name));
-        }
-        return privileges;
-    }
-
-    @Nonnull
     private Privilege[] getPrivileges(@Nullable String absPath, @Nonnull PermissionProvider provider,
                                       long permissions) throws RepositoryException {
         Tree tree;

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/AbstractEntryIterator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/AbstractEntryIterator.java?rev=1532771&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/AbstractEntryIterator.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/AbstractEntryIterator.java Wed Oct 16 14:00:51 2013
@@ -0,0 +1,66 @@
+/*
+ * 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.util.Iterator;
+import java.util.NoSuchElementException;
+import javax.annotation.CheckForNull;
+
+import com.google.common.collect.Iterators;
+
+/**
+ * EntryIterator... TODO
+ */
+abstract class AbstractEntryIterator implements Iterator<PermissionEntry> {
+
+    // the ordered permission entries at a given path in the hierarchy
+    protected Iterator<PermissionEntry> nextEntries;
+
+    // the next permission entry
+    protected PermissionEntry next;
+
+    @Override
+    public boolean hasNext() {
+        if (next == null) {
+            // lazy initialization
+            if (nextEntries == null) {
+                nextEntries = Iterators.emptyIterator();
+                seekNext();
+            }
+        }
+        return next != null;
+    }
+
+    @Override
+    public PermissionEntry next() {
+        if (next == null) {
+            throw new NoSuchElementException();
+        }
+
+        PermissionEntry pe = next;
+        seekNext();
+        return pe;
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+    @CheckForNull
+    protected abstract void seekNext();
+}

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/AllPermissions.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/AllPermissions.java?rev=1532771&r1=1532770&r2=1532771&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/AllPermissions.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/AllPermissions.java Wed Oct 16 14:00:51 2013
@@ -18,15 +18,14 @@ package org.apache.jackrabbit.oak.securi
 
 import java.util.Collections;
 import java.util.Set;
-
 import javax.annotation.Nonnull;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.core.ImmutableTree;
-import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.RepositoryPermission;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
-import org.apache.jackrabbit.oak.spi.security.authorization.permission.ReadStatus;
 
 /**
  * Implementation of the {@code CompiledPermissions} interface that grants full
@@ -44,18 +43,18 @@ public final class AllPermissions implem
     }
 
     @Override
-    public void refresh(@Nonnull ImmutableTree permissionsTree, @Nonnull PrivilegeBitsProvider bitsProvider) {
+    public void refresh(@Nonnull ImmutableRoot root, @Nonnull String workspaceName) {
         // nop
     }
 
     @Override
-    public ReadStatus getReadStatus(Tree tree, PropertyState property) {
-        return ReadStatus.ALLOW_ALL;
+    public RepositoryPermission getRepositoryPermission() {
+        return RepositoryPermission.ALL;
     }
 
     @Override
-    public boolean isGranted(long permissions) {
-        return true;
+    public TreePermission getTreePermission(@Nonnull Tree tree, @Nonnull TreePermission parentPermission) {
+        return TreePermission.ALL;
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java?rev=1532771&r1=1532770&r2=1532771&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissionImpl.java Wed Oct 16 14:00:51 2013
@@ -18,55 +18,84 @@ package org.apache.jackrabbit.oak.securi
 
 import java.security.Principal;
 import java.security.acl.Group;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
+import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterators;
+import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
 import org.apache.jackrabbit.oak.core.ImmutableTree;
+import org.apache.jackrabbit.oak.core.TreeTypeProvider;
+import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager;
+import org.apache.jackrabbit.oak.plugins.version.VersionConstants;
+import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions;
-import org.apache.jackrabbit.oak.spi.security.authorization.permission.ReadStatus;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.RepositoryPermission;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
 import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
-import org.apache.jackrabbit.util.Text;
-
-import com.google.common.collect.Iterators;
+import org.apache.jackrabbit.oak.util.TreeLocation;
+import org.apache.jackrabbit.oak.util.TreeUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterators.concat;
 
 /**
  * TODO: WIP
+ * FIXME: decide on where to filter out hidden items (OAK-753)
  */
 class CompiledPermissionImpl implements CompiledPermissions, PermissionConstants {
 
+    private static final Logger log = LoggerFactory.getLogger(CompiledPermissionImpl.class);
+
+    private static final Map<Long, PrivilegeBits> READ_BITS = ImmutableMap.of(
+            Permissions.READ_NODE, PrivilegeBits.BUILT_IN.get(PrivilegeConstants.REP_READ_NODES),
+            Permissions.READ_PROPERTY, PrivilegeBits.BUILT_IN.get(PrivilegeConstants.REP_READ_PROPERTIES),
+            Permissions.READ_ACCESS_CONTROL, PrivilegeBits.BUILT_IN.get(PrivilegeConstants.JCR_READ_ACCESS_CONTROL));
+
     private final Set<Principal> principals;
+    private ImmutableRoot root;
+    private final String workspaceName;
 
     private final Map<String, Tree> userTrees;
     private final Map<String, Tree> groupTrees;
 
     private final String[] readPathsCheckList;
 
-    private PrivilegeBitsProvider bitsProvider;
-
     private final PermissionStore userStore;
     private final PermissionStore groupStore;
 
-    CompiledPermissionImpl(@Nonnull Set<Principal> principals,
-                           @Nonnull ImmutableTree permissionsTree,
-                           @Nonnull PrivilegeBitsProvider bitsProvider,
-                           @Nonnull RestrictionProvider restrictionProvider,
-                           @Nonnull Set<String> readPaths) {
-        checkArgument(!principals.isEmpty());
+    private PrivilegeBitsProvider bitsProvider;
+
+    private CompiledPermissionImpl(@Nonnull Set<Principal> principals,
+                                   @Nonnull ImmutableRoot root, @Nonnull String workspaceName,
+                                   @Nonnull ImmutableTree permissionsTree,
+                                   @Nonnull RestrictionProvider restrictionProvider,
+                                   @Nonnull Set<String> readPaths) {
         this.principals = principals;
-        this.bitsProvider = bitsProvider;
+        this.root = root;
+        this.workspaceName = workspaceName;
+
+        bitsProvider = new PrivilegeBitsProvider(root);
         readPathsCheckList = new String[readPaths.size() * 2];
         int i = 0;
         for (String p : readPaths) {
@@ -78,8 +107,8 @@ class CompiledPermissionImpl implements 
         groupTrees = new HashMap<String, Tree>(principals.size());
         if (permissionsTree.exists()) {
             for (Principal principal : principals) {
-                Tree t = getPrincipalRoot(permissionsTree, principal);
-                Map<String, Tree> target = getTargetMap(principal);
+                Tree t = PermissionUtil.getPrincipalRoot(permissionsTree, principal);
+                Map<String, Tree> target = (principal instanceof Group) ? groupTrees : userTrees;
                 if (t.exists()) {
                     target.put(principal.getName(), t);
                 } else {
@@ -88,65 +117,156 @@ class CompiledPermissionImpl implements 
             }
         }
 
-        userStore = new PermissionStore(userTrees, restrictionProvider);
-        groupStore = new PermissionStore(groupTrees, restrictionProvider);
+        userStore = PermissionStore.create(userTrees, restrictionProvider);
+        groupStore = PermissionStore.create(groupTrees, restrictionProvider);
+    }
+
+    static CompiledPermissions create(@Nonnull ImmutableRoot root, @Nonnull String workspaceName,
+                                      @Nonnull Set<Principal> principals,
+                                      @Nonnull AuthorizationConfiguration acConfig) {
+        ImmutableTree permissionsTree = PermissionUtil.getPermissionsRoot(root, workspaceName);
+        if (!permissionsTree.exists() || principals.isEmpty()) {
+            return NoPermissions.getInstance();
+        } else {
+            String[] readPaths = acConfig.getParameters().getConfigValue(PARAM_READ_PATHS, DEFAULT_READ_PATHS);
+            return new CompiledPermissionImpl(principals, root, workspaceName,
+                    permissionsTree, acConfig.getRestrictionProvider(),
+                    ImmutableSet.copyOf(readPaths));
+        }
     }
 
     //------------------------------------------------< CompiledPermissions >---
     @Override
-    public void refresh(@Nonnull ImmutableTree permissionsTree,
-                        @Nonnull PrivilegeBitsProvider bitsProvider) {
-        this.bitsProvider = bitsProvider;
+    public void refresh(@Nonnull ImmutableRoot root, @Nonnull String workspaceName) {
+        this.root = root;
+        this.bitsProvider = new PrivilegeBitsProvider(root);
         // test if a permission has been added for those principals that didn't have one before
+
+        ImmutableTree permissionsTree = PermissionUtil.getPermissionsRoot(root, workspaceName);
+        boolean flushUserStore = false;
+        boolean flushGroupStore = false;
         for (Principal principal : principals) {
-            Map<String, Tree> target = getTargetMap(principal);
-            Tree principalRoot = getPrincipalRoot(permissionsTree, principal);
+            boolean isGroup = (principal instanceof Group);
+            Map<String, Tree> target = isGroup ? groupTrees : userTrees;
+            Tree principalRoot = PermissionUtil.getPrincipalRoot(permissionsTree, principal);
             String pName = principal.getName();
+
             if (principalRoot.exists()) {
                 if (!target.containsKey(pName) || !principalRoot.equals(target.get(pName))) {
                     target.put(pName, principalRoot);
+                    if (isGroup) {
+                        flushGroupStore = true;
+                    } else {
+                        flushUserStore = true;
+                    }
+                }
+            } else if (target.remove(pName) != null) {
+                if (isGroup) {
+                    flushGroupStore = true;
+                } else {
+                    flushUserStore = true;
                 }
-            } else {
-                target.remove(pName);
             }
         }
-        // todo, improve flush stores
-        userStore.flush();
-        groupStore.flush();
+        if (flushUserStore) {
+            userStore.flush();
+        }
+        if (flushGroupStore) {
+            groupStore.flush();
+        }
     }
 
     @Override
-    public ReadStatus getReadStatus(@Nonnull Tree tree, @Nullable PropertyState property) {
-        if (isReadablePath(tree, null)) {
-            return ReadStatus.ALLOW_ALL_REGULAR;
-        }
-        long permission = (property == null) ? Permissions.READ_NODE : Permissions.READ_PROPERTY;
-        Iterator<PermissionStore.PermissionEntry> it = getEntryIterator(new PermissionStore.EntryPredicate(tree, property));
-        while (it.hasNext()) {
-            PermissionStore.PermissionEntry entry = it.next();
-            if (entry.readStatus != null) {
-                return entry.readStatus;
-            } else if (entry.privilegeBits.includesRead(permission)) {
-                return (entry.isAllow) ? ReadStatus.ALLOW_THIS : ReadStatus.DENY_THIS;
+    public RepositoryPermission getRepositoryPermission() {
+        return new RepositoryPermission() {
+            @Override
+            public boolean isGranted(long repositoryPermissions) {
+                return hasPermissions(getEntryIterator(new EntryPredicate()), repositoryPermissions, null, null);
             }
-        }
-        return ReadStatus.DENY_THIS;
+        };
     }
 
     @Override
-    public boolean isGranted(long permissions) {
-        return hasPermissions(getEntryIterator(new PermissionStore.EntryPredicate()), permissions, null, null);
+    public TreePermission getTreePermission(@Nonnull Tree tree, @Nonnull TreePermission parentPermission) {
+        if (tree.isRoot()) {
+            return new TreePermissionImpl(tree, TreeTypeProvider.TYPE_DEFAULT, TreePermission.EMPTY);
+        }
+        int type = PermissionUtil.getType(tree, null);
+        switch (type) {
+            case TreeTypeProvider.TYPE_HIDDEN:
+                // TODO: OAK-753 decide on where to filter out hidden items.
+                return TreePermission.ALL;
+            case TreeTypeProvider.TYPE_VERSION:
+                String ntName = checkNotNull(TreeUtil.getPrimaryTypeName(tree));
+                if (VersionConstants.VERSION_STORE_NT_NAMES.contains(ntName) || VersionConstants.NT_ACTIVITY.equals(ntName)) {
+                    return new TreePermissionImpl(tree, TreeTypeProvider.TYPE_VERSION, parentPermission);
+                } else {
+                    TreeLocation tl = getLocation(tree, null);
+                    if (tl == null) {
+                        return TreePermission.EMPTY;
+                    } else {
+                        // TODO: may return wrong results in case of restrictions
+                        // TODO that would match the path of the versionable node
+                        // TODO (or item in the subtree) but that item no longer exists
+                        // TODO -> evaluation by path would be more accurate (-> see #isGranted)
+                        while (!tl.exists()) {
+                            tl = tl.getParent();
+                        }
+                        Tree versionableTree = tl.getTree();
+                        TreePermission pp = getParentPermission(versionableTree);
+                        return new TreePermissionImpl(versionableTree, TreeTypeProvider.TYPE_VERSION, pp);
+                    }
+                }
+            default:
+                return new TreePermissionImpl(tree, type, parentPermission);
+        }
+    }
+
+    @Nonnull
+    private TreePermission getParentPermission(@Nonnull Tree tree) {
+        List<Tree> trees = new ArrayList();
+        while (!tree.isRoot()) {
+            tree = tree.getParent();
+            if (tree.exists()) {
+                trees.add(0, tree);
+            }
+        }
+        TreePermission pp = TreePermission.EMPTY;
+        for (Tree tr : trees) {
+            pp = new TreePermissionImpl(tr, PermissionUtil.getType(tree, null), pp);
+        }
+        return pp;
     }
 
     @Override
     public boolean isGranted(@Nonnull Tree tree, @Nullable PropertyState property, long permissions) {
-        Iterator<PermissionStore.PermissionEntry> it = getEntryIterator(new PermissionStore.EntryPredicate(tree, property));
-        return hasPermissions(it, permissions, tree, null);
+        int type = PermissionUtil.getType(tree, property);
+        switch (type) {
+            case TreeTypeProvider.TYPE_HIDDEN:
+                // TODO: OAK-753 decide on where to filter out hidden items.
+                return true;
+            case TreeTypeProvider.TYPE_VERSION:
+                TreeLocation location = getLocation(tree, property);
+                if (location == null) {
+                    // unable to determine the location of the versionable item -> deny access.
+                    return false;
+                }
+                Tree versionableTree = (property == null) ? location.getTree() : location.getParent().getTree();
+                if (versionableTree != null) {
+                    return internalIsGranted(versionableTree, property, permissions);
+                } else {
+                    // versionable node does not exist (anymore) in this workspace;
+                    // use best effort calculation based on the item path.
+                    return isGranted(location.getPath(), permissions);
+                }
+            default:
+                return internalIsGranted(tree, property, permissions);
+        }
     }
 
     @Override
     public boolean isGranted(@Nonnull String path, long permissions) {
-        Iterator<PermissionStore.PermissionEntry> it = getEntryIterator(new PermissionStore.EntryPredicate(path));
+        Iterator<PermissionEntry> it = getEntryIterator(new EntryPredicate(path));
         return hasPermissions(it, permissions, null, path);
     }
 
@@ -161,20 +281,16 @@ class CompiledPermissionImpl implements 
     }
 
     //------------------------------------------------------------< private >---
-    @Nonnull
-    private static Tree getPrincipalRoot(Tree permissionsTree, Principal principal) {
-        return permissionsTree.getChild(Text.escapeIllegalJcrChars(principal.getName()));
-    }
 
-    @Nonnull
-    private Map<String, Tree> getTargetMap(Principal principal) {
-        return (principal instanceof Group) ? groupTrees : userTrees;
+    private boolean internalIsGranted(@Nonnull Tree tree, @Nullable PropertyState property, long permissions) {
+        Iterator<PermissionEntry> it = getEntryIterator(new EntryPredicate(tree, property));
+        return hasPermissions(it, permissions, tree, null);
     }
 
-    private boolean hasPermissions(@Nonnull Iterator<PermissionStore.PermissionEntry> entries,
+    private boolean hasPermissions(@Nonnull Iterator<PermissionEntry> entries,
                                    long permissions, @Nullable Tree tree, @Nullable String path) {
         // calculate readable paths if the given permissions includes any read permission.
-        boolean isReadable = Permissions.diff(Permissions.READ, permissions) != Permissions.READ && isReadablePath(tree, path);
+        boolean isReadable = Permissions.diff(Permissions.READ, permissions) != Permissions.READ && isReadablePath(tree, path, false);
         if (!entries.hasNext() && !isReadable) {
             return false;
         }
@@ -207,7 +323,7 @@ class CompiledPermissionImpl implements 
         }
 
         while (entries.hasNext()) {
-            PermissionStore.PermissionEntry entry = entries.next();
+            PermissionEntry entry = entries.next();
             if (respectParent && (parentPath != null)) {
                 boolean matchesParent = entry.matchesParent(parentPath);
                 if (matchesParent) {
@@ -241,16 +357,16 @@ class CompiledPermissionImpl implements 
 
     @Nonnull
     private PrivilegeBits getPrivilegeBits(@Nullable Tree tree) {
-        PermissionStore.EntryPredicate pred = (tree == null)
-                ? new PermissionStore.EntryPredicate()
-                : new PermissionStore.EntryPredicate(tree, null);
-        Iterator<PermissionStore.PermissionEntry> entries = getEntryIterator(pred);
+        EntryPredicate pred = (tree == null)
+                ? new EntryPredicate()
+                : new EntryPredicate(tree, null);
+        Iterator<PermissionEntry> entries = getEntryIterator(pred);
 
         PrivilegeBits allowBits = PrivilegeBits.getInstance();
         PrivilegeBits denyBits = PrivilegeBits.getInstance();
 
         while (entries.hasNext()) {
-            PermissionStore.PermissionEntry entry = entries.next();
+            PermissionEntry entry = entries.next();
             if (entry.isAllow) {
                 allowBits.addDifference(entry.privilegeBits, denyBits);
             } else {
@@ -259,20 +375,20 @@ class CompiledPermissionImpl implements 
         }
 
         // special handling for paths that are always readable
-        if (isReadablePath(tree, null)) {
+        if (isReadablePath(tree, null, false)) {
             allowBits.add(bitsProvider.getBits(PrivilegeConstants.JCR_READ));
         }
         return allowBits;
     }
 
     @Nonnull
-    private Iterator<PermissionStore.PermissionEntry> getEntryIterator(@Nonnull PermissionStore.EntryPredicate predicate) {
-        Iterator<PermissionStore.PermissionEntry> userEntries = userStore.getEntryIterator(predicate);
-        Iterator<PermissionStore.PermissionEntry> groupEntries = groupStore.getEntryIterator(predicate);
-        return Iterators.concat(userEntries, groupEntries);
+    private Iterator<PermissionEntry> getEntryIterator(@Nonnull EntryPredicate predicate) {
+        Iterator<PermissionEntry> userEntries = userStore.getEntryIterator(predicate);
+        Iterator<PermissionEntry> groupEntries = groupStore.getEntryIterator(predicate);
+        return concat(userEntries, groupEntries);
     }
 
-    private boolean isReadablePath(@Nullable Tree tree, @Nullable String treePath) {
+    private boolean isReadablePath(@Nullable Tree tree, @Nullable String treePath, boolean exactMatch) {
         if (readPathsCheckList.length > 0) {
             String targetPath = (tree != null) ? tree.getPath() : treePath;
             if (targetPath != null) {
@@ -280,7 +396,7 @@ class CompiledPermissionImpl implements 
                     if (targetPath.equals(readPathsCheckList[i++])) {
                         return true;
                     }
-                    if (targetPath.startsWith(readPathsCheckList[i])) {
+                    if (!exactMatch && targetPath.startsWith(readPathsCheckList[i])) {
                         return true;
                     }
                 }
@@ -289,5 +405,167 @@ class CompiledPermissionImpl implements 
         return false;
     }
 
+    @CheckForNull
+    private TreeLocation getLocation(@Nonnull Tree versionStoreTree, @Nullable PropertyState property) {
+        String relPath = "";
+        String propName = (property == null) ? "" : property.getName();
+        String versionablePath = null;
+        Tree t = versionStoreTree;
+        while (t.exists() && !t.isRoot() && !VersionConstants.VERSION_STORE_ROOT_NAMES.contains(t.getName())) {
+            String ntName = checkNotNull(TreeUtil.getPrimaryTypeName(t));
+            if (VersionConstants.JCR_FROZENNODE.equals(t.getName()) && t != versionStoreTree) {
+                relPath = PathUtils.relativize(t.getPath(), versionStoreTree.getPath());
+            } else if (JcrConstants.NT_VERSIONHISTORY.equals(ntName)) {
+                PropertyState prop = t.getProperty(workspaceName);
+                if (prop != null) {
+                    versionablePath = PathUtils.concat(prop.getValue(Type.PATH), relPath, propName);
+                }
+                return PermissionUtil.createLocation(root, versionablePath);
+            } else if (VersionConstants.NT_CONFIGURATION.equals(ntName)) {
+                String rootId = TreeUtil.getString(t, VersionConstants.JCR_ROOT);
+                if (rootId != null) {
+                    versionablePath = new IdentifierManager(root).getPath(rootId);
+                    return PermissionUtil.createLocation(root, versionablePath);
+                } else {
+                    log.error("Missing mandatory property jcr:root with configuration node.");
+                    return null;
+                }
+            } else if (VersionConstants.NT_ACTIVITY.equals(ntName)) {
+                return PermissionUtil.createLocation(versionStoreTree, property);
+            }
+            t = t.getParent();
+        }
 
+        // intermediate node in the version, configuration or activity store that
+        // matches none of the special conditions checked above -> regular permission eval.
+        return PermissionUtil.createLocation(versionStoreTree, property);
+    }
+
+    private final class TreePermissionImpl implements TreePermission {
+
+        private final Tree tree;
+        private final TreePermissionImpl parent;
+
+        private final boolean isAcTree;
+        private final boolean readableTree;
+
+        private Collection<PermissionEntry> userEntries;
+        private Collection<PermissionEntry> groupEntries;
+
+        // FIXME: use proper readstatus
+        private Boolean canReadThis;
+
+        private TreePermissionImpl(Tree tree, int treeType, TreePermission parentPermission) {
+            this.tree = tree;
+            if (parentPermission instanceof TreePermissionImpl) {
+                parent = (TreePermissionImpl) parentPermission;
+            } else {
+                parent = null;
+            }
+            isAcTree = (treeType == TreeTypeProvider.TYPE_AC);
+            readableTree = (parent != null && parent.readableTree) || isReadablePath(tree, null, true);
+        }
+
+        @Override
+        public boolean canRead() {
+            if (!isAcTree && readableTree) {
+                return true;
+            }
+            if (canReadThis == null) {
+                canReadThis = false;
+                long permission = (isAcTree) ? Permissions.READ_ACCESS_CONTROL : Permissions.READ_NODE;
+                Iterator<PermissionEntry> it = getIterator(null);
+                while (it.hasNext()) {
+                    PermissionEntry entry = it.next();
+                    if (entry.privilegeBits.includes(READ_BITS.get(permission))) {
+                        canReadThis = (entry.isAllow);
+                        break;
+                    }
+                }
+            }
+            return canReadThis;
+        }
+
+        @Override
+        public boolean canRead(@Nonnull PropertyState property) {
+            if (!isAcTree && readableTree) {
+                return true;
+            }
+            long permission = (isAcTree) ? Permissions.READ_ACCESS_CONTROL : Permissions.READ_PROPERTY;
+            Iterator<PermissionEntry> it = getIterator(property);
+            while (it.hasNext()) {
+                PermissionEntry entry = it.next();
+                if (entry.privilegeBits.includes(READ_BITS.get(permission))) {
+                    return (entry.isAllow);
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public boolean canReadAll() {
+            return false;  // TODO: best effort approach to detect full read-access within a given tree.
+        }
+
+        @Override
+        public boolean canReadProperties() {
+            return false;  // TODO: best effort approach to detect full read-property permission
+        }
+
+        @Override
+        public boolean isGranted(long permissions) {
+            return hasPermissions(getIterator(null), permissions, tree, null);
+        }
+
+        @Override
+        public boolean isGranted(long permissions, @Nonnull PropertyState property) {
+            return hasPermissions(getIterator(property), permissions, tree, null);
+        }
+
+        private Iterator<PermissionEntry> getIterator(@Nullable PropertyState property) {
+            return Iterators.filter(
+                    concat(new LazyIterator(this, true), new LazyIterator(this, false)),
+                    new EntryPredicate(tree, property));
+        }
+
+        private Iterator<PermissionEntry> getUserEntries() {
+            if (userEntries == null) {
+                userEntries = userStore.getEntries(tree);
+            }
+            return userEntries.iterator();
+        }
+
+        private Iterator<PermissionEntry> getGroupEntries() {
+            if (groupEntries == null) {
+                groupEntries = groupStore.getEntries(tree);
+            }
+            return groupEntries.iterator();
+        }
+    }
+
+    private static final class LazyIterator extends AbstractEntryIterator {
+
+        private boolean isUser;
+        private TreePermissionImpl tp;
+
+        private LazyIterator(@Nonnull TreePermissionImpl tp, boolean isUser) {
+            this.tp = tp;
+            this.isUser = isUser;
+        }
+
+        @CheckForNull
+        protected void seekNext() {
+            for (next = null; next == null; ) {
+                if (nextEntries.hasNext()) {
+                    next = nextEntries.next();
+                } else {
+                    if (tp == null) {
+                        break;
+                    }
+                    nextEntries = (isUser) ? tp.getUserEntries() : tp.getGroupEntries();
+                    tp = tp.parent;
+                }
+            }
+        }
+    }
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissions.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissions.java?rev=1532771&r1=1532770&r2=1532771&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissions.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/CompiledPermissions.java Wed Oct 16 14:00:51 2013
@@ -22,33 +22,20 @@ import javax.annotation.Nullable;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.core.ImmutableTree;
-import org.apache.jackrabbit.oak.spi.security.authorization.permission.ReadStatus;
-import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.RepositoryPermission;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission;
 
 /**
  * CompiledPermissions... TODO
  */
 public interface CompiledPermissions {
 
-    void refresh(@Nonnull ImmutableTree permissionsTree,
-                 @Nonnull PrivilegeBitsProvider bitsProvider);
+    void refresh(@Nonnull ImmutableRoot root, @Nonnull String workspaceName);
 
-    /**
-     *
-     * @param tree
-     * @param property
-     * @return
-     */
-    @Nonnull
-    ReadStatus getReadStatus(@Nonnull Tree tree, @Nullable PropertyState property);
+    RepositoryPermission getRepositoryPermission();
 
-    /**
-     *
-     * @param permissions
-     * @return
-     */
-    boolean isGranted(long permissions);
+    TreePermission getTreePermission(@Nonnull Tree tree, @Nonnull TreePermission parentPermission);
 
     /**
      *

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/EntryPredicate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/EntryPredicate.java?rev=1532771&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/EntryPredicate.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/EntryPredicate.java Wed Oct 16 14:00:51 2013
@@ -0,0 +1,72 @@
+/*
+ * 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 javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.google.common.base.Predicate;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * EntryPredicate... TODO
+ */
+final class EntryPredicate implements Predicate<PermissionEntry> {
+
+    private final Tree tree;
+    private final PropertyState property;
+    private final String path;
+
+    public EntryPredicate(@Nonnull Tree tree, @Nullable PropertyState property) {
+        this.tree = tree;
+        this.property = property;
+        this.path = tree.getPath();
+    }
+
+    public EntryPredicate(@Nonnull String path) {
+        this.tree = null;
+        this.property = null;
+        this.path = path;
+    }
+
+    public EntryPredicate() {
+        this.tree = null;
+        this.property = null;
+        this.path = null;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    @Override
+    public boolean apply(@Nullable PermissionEntry entry) {
+        if (entry == null) {
+            return false;
+        }
+        if (tree != null) {
+            return entry.matches(tree, property);
+        } else if (path != null) {
+            return entry.matches(path);
+        } else {
+            return entry.matches();
+        }
+    }
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/NoPermissions.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/NoPermissions.java?rev=1532771&r1=1532770&r2=1532771&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/NoPermissions.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/NoPermissions.java Wed Oct 16 14:00:51 2013
@@ -23,9 +23,9 @@ import javax.annotation.Nullable;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.core.ImmutableTree;
-import org.apache.jackrabbit.oak.spi.security.authorization.permission.ReadStatus;
-import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.RepositoryPermission;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission;
 
 /**
  * Implementation of the {@code CompiledPermission} interface that denies all permissions.
@@ -42,18 +42,18 @@ public final class NoPermissions impleme
     }
 
     @Override
-    public void refresh(@Nonnull ImmutableTree permissionsTree, @Nonnull PrivilegeBitsProvider bitsProvider) {
+    public void refresh(@Nonnull ImmutableRoot root, @Nonnull String workspaceName) {
         // nop
     }
 
     @Override
-    public ReadStatus getReadStatus(@Nonnull Tree tree, @Nullable PropertyState property) {
-        return ReadStatus.DENY_ALL;
+    public RepositoryPermission getRepositoryPermission() {
+        return RepositoryPermission.EMPTY;
     }
 
     @Override
-    public boolean isGranted(long permissions) {
-        return false;
+    public TreePermission getTreePermission(@Nonnull Tree tree, @Nonnull TreePermission parentPermission) {
+        return TreePermission.EMPTY;
     }
 
     @Override

Added: 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=1532771&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntry.java Wed Oct 16 14:00:51 2013
@@ -0,0 +1,128 @@
+/*
+ * 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 javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.google.common.base.Objects;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
+import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionPattern;
+import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
+import org.apache.jackrabbit.util.Text;
+
+/**
+ * PermissionEntry... TODO
+ */
+final class PermissionEntry implements Comparable<PermissionEntry>, PermissionConstants {
+
+    /**
+     * flag controls if this is an allow or deny entry
+     */
+    final boolean isAllow;
+
+    /**
+     * the privilege bits
+     */
+    final PrivilegeBits privilegeBits;
+
+    /**
+     * the index (order) of the original ACE in the ACL.
+     */
+    private final int index;
+
+    /**
+     * the access controlled (node) path
+     */
+    private final String path;
+
+    /**
+     * the restriction pattern for this entry
+     */
+    private final RestrictionPattern restriction;
+
+    PermissionEntry(String path, Tree entryTree, RestrictionProvider restrictionsProvider) {
+        this.path = path;
+        isAllow = entryTree.getProperty(REP_IS_ALLOW).getValue(Type.BOOLEAN);
+        privilegeBits = PrivilegeBits.getInstance(entryTree.getProperty(REP_PRIVILEGE_BITS));
+        index = entryTree.getProperty(REP_INDEX).getValue(Type.LONG).intValue();
+        restriction = restrictionsProvider.getPattern(path, entryTree);
+    }
+
+    public boolean matches(@Nonnull Tree tree, @Nullable PropertyState property) {
+        return restriction == RestrictionPattern.EMPTY || restriction.matches(tree, property);
+    }
+
+    public boolean matches(@Nonnull String treePath) {
+        return restriction == RestrictionPattern.EMPTY || restriction.matches(treePath);
+    }
+
+    public boolean matches() {
+        return restriction == RestrictionPattern.EMPTY || restriction.matches();
+    }
+
+    public boolean matchesParent(@Nonnull String parentPath) {
+        return Text.isDescendantOrEqual(path, parentPath) && (restriction == RestrictionPattern.EMPTY || restriction.matches(parentPath));
+    }
+
+    @Override
+    public int compareTo(PermissionEntry pe) {
+        if (Objects.equal(path, pe.path)) {
+            // reverse order
+            if (index == pe.index) {
+                return 0;
+            } else if (index < pe.index) {
+                return 1;
+            } else {
+                return -1;
+            }
+        } else {
+            int depth = PathUtils.getDepth(path);
+            int otherDepth = PathUtils.getDepth(pe.path);
+            if (PathUtils.getDepth(path) == otherDepth) {
+                return path.compareTo(pe.path);
+            } else {
+                return (depth < otherDepth) ? 1 : -1;
+            }
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o instanceof PermissionEntry) {
+            PermissionEntry that = (PermissionEntry) o;
+
+            return index == that.index && isAllow == that.isAllow
+                    && privilegeBits.equals(that.privilegeBits)
+                    && path.equals(that.path) && restriction.equals(that.restriction);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(privilegeBits, index, path, isAllow, restriction);
+    }
+}
\ No newline at end of file

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=1532771&r1=1532770&r2=1532771&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 Wed Oct 16 14:00:51 2013
@@ -262,7 +262,7 @@ public class PermissionHook implements P
         }
     }
 
-    private class Acl {
+    private final class Acl {
 
         private final String accessControlledPath;
 
@@ -373,7 +373,7 @@ public class PermissionHook implements P
                             idx++;
                         }
                         while (child == null) {
-                            String name = "c" + String.valueOf(idx++);
+                            String name = 'c' + String.valueOf(idx++);
                             child = parent.getChildNode(name);
                             if (child.exists()) {
                                 child = null;
@@ -413,7 +413,7 @@ public class PermissionHook implements P
         }
     }
 
-    private class AcEntry {
+    private final class AcEntry {
 
         private final String accessControlledPath;
         private final String principalName;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java?rev=1532771&r1=1532770&r2=1532771&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java Wed Oct 16 14:00:51 2013
@@ -18,7 +18,6 @@ package org.apache.jackrabbit.oak.securi
 
 import java.security.Principal;
 import java.util.Set;
-import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
@@ -27,12 +26,7 @@ import org.apache.jackrabbit.JcrConstant
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager;
 import org.apache.jackrabbit.oak.core.ImmutableRoot;
-import org.apache.jackrabbit.oak.core.ImmutableTree;
-import org.apache.jackrabbit.oak.core.TreeTypeProvider;
 import org.apache.jackrabbit.oak.core.TreeTypeProviderImpl;
 import org.apache.jackrabbit.oak.plugins.version.VersionConstants;
 import org.apache.jackrabbit.oak.spi.security.SecurityConfiguration;
@@ -42,26 +36,17 @@ import org.apache.jackrabbit.oak.spi.sec
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions;
-import org.apache.jackrabbit.oak.spi.security.authorization.permission.ReadStatus;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.RepositoryPermission;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission;
 import org.apache.jackrabbit.oak.spi.security.principal.AdminPrincipal;
 import org.apache.jackrabbit.oak.spi.security.principal.SystemPrincipal;
-import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
 import org.apache.jackrabbit.oak.util.TreeLocation;
-import org.apache.jackrabbit.oak.util.TreeUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * PermissionProviderImpl... TODO
- * <p/>
- * FIXME: decide on where to filter out hidden items (OAK-753)
  */
 public class PermissionProviderImpl implements PermissionProvider, AccessControlConstants, PermissionConstants {
 
-    private static final Logger log = LoggerFactory.getLogger(PermissionProviderImpl.class);
-
     private final Root root;
 
     private final String workspaceName;
@@ -83,23 +68,14 @@ public class PermissionProviderImpl impl
         if (principals.contains(SystemPrincipal.INSTANCE) || isAdmin(principals)) {
             compiledPermissions = AllPermissions.getInstance();
         } else {
-            ImmutableTree permissionsTree = getPermissionsRoot();
-            if (!permissionsTree.exists() || principals.isEmpty()) {
-                compiledPermissions = NoPermissions.getInstance();
-            } else {
-                String[] readPaths = acConfig.getParameters().getConfigValue(PARAM_READ_PATHS, DEFAULT_READ_PATHS);
-                compiledPermissions = new CompiledPermissionImpl(principals,
-                        permissionsTree, getBitsProvider(),
-                        acConfig.getRestrictionProvider(),
-                        ImmutableSet.copyOf(readPaths));
-            }
+            compiledPermissions = CompiledPermissionImpl.create(immutableRoot, workspaceName, principals, acConfig);
         }
     }
 
     @Override
     public void refresh() {
         immutableRoot = getImmutableRoot(root, acConfig);
-        compiledPermissions.refresh(getPermissionsRoot(), getBitsProvider());
+        compiledPermissions.refresh(immutableRoot, workspaceName);
     }
 
     @Nonnull
@@ -114,52 +90,18 @@ public class PermissionProviderImpl impl
     }
 
     @Override
-    public ReadStatus getReadStatus(@Nonnull Tree tree, @Nullable PropertyState property) {
-        int type = getType(tree, property);
-        switch (type) {
-            case TreeTypeProvider.TYPE_HIDDEN:
-                // TODO: OAK-753 decide on where to filter out hidden items.
-                return ReadStatus.ALLOW_ALL;
-            case TreeTypeProvider.TYPE_AC:
-                // TODO: review if read-ac permission is never fine-granular
-                // TODO: replace by calling #getReadStatus
-                return canReadAccessControlContent(tree, null) ? ReadStatus.ALLOW_ALL : ReadStatus.DENY_ALL;
-            case TreeTypeProvider.TYPE_VERSION:
-                return getVersionContentReadStatus(tree, property);
-            default:
-                return compiledPermissions.getReadStatus(tree, property);
-        }
+    public RepositoryPermission getRepositoryPermission() {
+        return compiledPermissions.getRepositoryPermission();
     }
 
     @Override
-    public boolean isGranted(long repositoryPermissions) {
-        return compiledPermissions.isGranted(repositoryPermissions);
+    public TreePermission getTreePermission(@Nonnull Tree tree, @Nonnull TreePermission parentPermission) {
+        return compiledPermissions.getTreePermission(tree, parentPermission);
     }
 
     @Override
     public boolean isGranted(@Nonnull Tree tree, @Nullable PropertyState property, long permissions) {
-        int type = getType(tree, property);
-        switch (type) {
-            case TreeTypeProvider.TYPE_HIDDEN:
-                // TODO: OAK-753 decide on where to filter out hidden items.
-                return true;
-            case TreeTypeProvider.TYPE_VERSION:
-                TreeLocation location = getLocation(tree, property);
-                if (location == null) {
-                    // unable to determine the location of the versionable item -> deny access.
-                    return false;
-                }
-                Tree versionableTree = (property == null) ? location.getTree() : location.getParent().getTree();
-                if (versionableTree != null) {
-                    return compiledPermissions.isGranted(versionableTree, property, permissions);
-                } else {
-                    // versionable node does not exist (anymore) in this workspace;
-                    // use best effort calculation based on the item path.
-                    return compiledPermissions.isGranted(location.getPath(), permissions);
-                }
-            default:
-                return compiledPermissions.isGranted(tree, property, permissions);
-        }
+        return compiledPermissions.isGranted(tree, property, permissions);
     }
 
     @Override
@@ -199,76 +141,6 @@ public class PermissionProviderImpl impl
         }
     }
 
-    @Nonnull
-    private ImmutableTree getPermissionsRoot() {
-        return immutableRoot.getTree(PERMISSIONS_STORE_PATH + '/' + workspaceName);
-    }
-
-    @Nonnull
-    private PrivilegeBitsProvider getBitsProvider() {
-        return new PrivilegeBitsProvider(immutableRoot);
-    }
-
-    private static int getType(@Nonnull Tree tree, @Nullable PropertyState property) {
-        // TODO: OAK-753 decide on where to filter out hidden items.
-        // TODO: deal with hidden properties
-        return ImmutableTree.getType(tree);
-    }
-
-    private boolean canReadAccessControlContent(@Nonnull Tree acTree, @Nullable PropertyState acProperty) {
-        return compiledPermissions.isGranted(acTree, acProperty, Permissions.READ_ACCESS_CONTROL);
-    }
-
-    private ReadStatus getVersionContentReadStatus(@Nonnull Tree versionStoreTree, @Nullable PropertyState property) {
-        TreeLocation location = getLocation(versionStoreTree, property);
-        ReadStatus status = ReadStatus.DENY_THIS;
-        if (location != null) {
-            Tree tree = (property == null) ? location.getTree() : location.getParent().getTree();
-            if (tree != null) {
-                status = compiledPermissions.getReadStatus(tree, property);
-            } else {
-                // versionable node does not exist (anymore) in this workspace;
-                // use best effort calculation based on the item path.
-                long permission = (property == null) ? Permissions.READ_NODE : Permissions.READ_PROPERTY;
-                if (compiledPermissions.isGranted(location.getPath(), permission)) {
-                    status = ReadStatus.ALLOW_THIS;
-                }
-            }
-        }
-        return status;
-    }
-
-    @CheckForNull
-    private TreeLocation getLocation(@Nonnull Tree versionStoreTree, @Nullable PropertyState property) {
-        String relPath = "";
-        String propName = (property == null) ? "" : property.getName();
-        String versionablePath = null;
-        Tree t = versionStoreTree;
-        while (t.exists() && !t.isRoot() && !VersionConstants.VERSION_STORE_ROOT_NAMES.contains(t.getName())) {
-            String ntName = checkNotNull(TreeUtil.getPrimaryTypeName(t));
-            if (VersionConstants.JCR_FROZENNODE.equals(t.getName()) && t != versionStoreTree) {
-                relPath = PathUtils.relativize(t.getPath(), versionStoreTree.getPath());
-            } else if (JcrConstants.NT_VERSIONHISTORY.equals(ntName)) {
-                PropertyState prop = t.getProperty(workspaceName);
-                if (prop != null) {
-                    versionablePath = PathUtils.concat(prop.getValue(Type.PATH), relPath, propName);
-                }
-                return createLocation(versionablePath);
-            } else if (VersionConstants.NT_CONFIGURATION.equals(ntName)) {
-                String rootId = TreeUtil.getString(t, VersionConstants.JCR_ROOT);
-                versionablePath = new IdentifierManager(root).getPath(rootId);
-                return createLocation(versionablePath);
-            } else if (VersionConstants.NT_ACTIVITY.equals(ntName)) {
-                return createLocation(versionStoreTree, property);
-            }
-            t = t.getParent();
-        }
-
-        // intermediate node in the version, configuration or activity store that
-        // matches none of the special conditions checked above -> regular permission eval.
-        return createLocation(versionStoreTree, property);
-    }
-
     private static boolean isVersionStorePath(@Nonnull String oakPath) {
         if (oakPath.indexOf(JcrConstants.JCR_SYSTEM) == 1) {
             for (String p : VersionConstants.SYSTEM_PATHS) {
@@ -279,23 +151,4 @@ public class PermissionProviderImpl impl
         }
         return false;
     }
-
-    @CheckForNull
-    private TreeLocation createLocation(@Nullable String oakPath) {
-        if (oakPath != null && PathUtils.isAbsolute(oakPath)) {
-            return TreeLocation.create(immutableRoot, oakPath);
-        } else {
-            log.debug("Unable to create location for path " + oakPath);
-            return null;
-        }
-    }
-
-    @Nonnull
-    private static TreeLocation createLocation(@Nonnull Tree tree, @Nullable PropertyState property) {
-        if (property == null) {
-            return TreeLocation.create(tree);
-        } else {
-            return TreeLocation.create(tree, property);
-        }
-    }
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java?rev=1532771&r1=1532770&r2=1532771&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java Wed Oct 16 14:00:51 2013
@@ -17,61 +17,100 @@
 package org.apache.jackrabbit.oak.security.authorization.permission;
 
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.NoSuchElementException;
 import java.util.TreeSet;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 
-import com.google.common.base.Predicate;
 import com.google.common.base.Strings;
 import com.google.common.collect.Iterators;
-import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
-import org.apache.jackrabbit.oak.spi.security.authorization.permission.ReadStatus;
-import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionPattern;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
-import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
-import org.apache.jackrabbit.util.Text;
-
-import static com.google.common.base.Preconditions.checkNotNull;
+import org.apache.jackrabbit.oak.util.TreeUtil;
 
 /**
- * The Permission store reads the principal based access control permissions. One store is currently used to handle
- * 1 set of principal trees (so the compiled permissions use 2 stores, one for the user principals and one for the
- * group principals)
- * <p/>
- * TODO: implement caching
+ * The Permission store reads the principal based access control permissions.
+ * One store is currently used to handle 1 set of principal trees (so the compiled
+ * permissions use 2 stores, one for the user principals and one for the
+ * group principals).
  */
 class PermissionStore implements PermissionConstants {
 
-    private final Map<String, Tree> principalTrees;
+    private static final long MAX_SIZE = 250;
 
+    private final Map<String, Tree> principalTrees;
     private final RestrictionProvider restrictionProvider;
+    private Map<String, Collection<PermissionEntry>> pathEntryMap;
 
-    PermissionStore(Map<String, Tree> principalTrees, RestrictionProvider restrictionProvider) {
+    private PermissionStore(@Nonnull Map<String, Tree> principalTrees,
+                            @Nonnull RestrictionProvider restrictionProvider,
+                            boolean doCreateMap) {
         this.principalTrees = principalTrees;
         this.restrictionProvider = restrictionProvider;
+        this.pathEntryMap = (doCreateMap) ?
+                createMap(principalTrees.values(), restrictionProvider) : null;
+    }
+
+    static PermissionStore create(@Nonnull Map<String, Tree> principalTrees,
+                                  @Nonnull RestrictionProvider restrictionProvider) {
+        long cnt = 0;
+        if (!principalTrees.isEmpty()) {
+            Iterator<Tree> treeItr = principalTrees.values().iterator();
+            while (treeItr.hasNext() && cnt < MAX_SIZE) {
+                Tree t = treeItr.next();
+                cnt += t.getChildrenCount(MAX_SIZE);
+            }
+        }
+        return new PermissionStore(principalTrees, restrictionProvider, (cnt < MAX_SIZE));
+    }
+
+    public void flush() {
+        if (pathEntryMap != null) {
+            pathEntryMap = createMap(principalTrees.values(), restrictionProvider);
+        }
+    }
+
+    public Iterator<PermissionEntry> getEntryIterator(@Nonnull EntryPredicate predicate) {
+        if (principalTrees.isEmpty()) {
+            return Iterators.emptyIterator();
+        } else {
+            return new EntryIterator(predicate);
+        }
+    }
+
+    public Collection<PermissionEntry> getEntries(@Nonnull Tree tree) {
+        if (principalTrees.isEmpty()) {
+            return Collections.emptyList();
+        } else if (pathEntryMap != null) {
+            Collection<PermissionEntry> entries = pathEntryMap.get(tree.getPath());
+            return (entries != null) ? entries : Collections.<PermissionEntry>emptyList();
+        } else {
+            return (tree.hasChild(AccessControlConstants.REP_POLICY)) ?
+                    getEntries(tree.getPath()) :
+                    Collections.<PermissionEntry>emptyList();
+        }
     }
 
     @Nonnull
-    private Collection<PermissionEntry> getEntries(String path) {
+    private Collection<PermissionEntry> getEntries(@Nonnull String path) {
         Collection<PermissionEntry> ret = new TreeSet<PermissionEntry>();
         String name = PermissionUtil.getEntryName(path);
         for (Map.Entry<String, Tree> principalRoot : principalTrees.entrySet()) {
-            Tree child = principalRoot.getValue().getChild(name);
-            if (child.exists()) {
+            Tree parent = principalRoot.getValue();
+            if (parent.hasChild(name)) {
+                Tree child = parent.getChild(name);
                 if (PermissionUtil.checkACLPath(child, path)) {
-                    loadPermissionsFromNode(path, ret, child);
+                    loadPermissionsFromTree(path, ret, child, restrictionProvider);
                 } else {
                     // check for child node
                     for (Tree node : child.getChildren()) {
                         if (PermissionUtil.checkACLPath(node, path)) {
-                            loadPermissionsFromNode(path, ret, node);
+                            loadPermissionsFromTree(path, ret, node, restrictionProvider);
                         }
                     }
                 }
@@ -80,73 +119,60 @@ class PermissionStore implements Permiss
         return ret;
     }
 
-    private void loadPermissionsFromNode(String path, Collection<PermissionEntry> ret, Tree node) {
-        for (Tree ace : node.getChildren()) {
-            if (ace.getName().charAt(0) != 'c') {
-                ret.add(new PermissionEntry(path, ace, restrictionProvider));
+    private static Map<String, Collection<PermissionEntry>> createMap(@Nonnull Collection<Tree> principalTrees,
+                                                                      @Nonnull RestrictionProvider restrictionProvider) {
+        Map<String, Collection<PermissionEntry>> pathEntryMap = new HashMap<String, Collection<PermissionEntry>>();
+        for (Tree principalTree : principalTrees) {
+            for (Tree entryTree : principalTree.getChildren()) {
+                loadPermissionEntries(entryTree, pathEntryMap, restrictionProvider);
+            }
+        }
+        return pathEntryMap;
+    }
+
+    private static void loadPermissionEntries(@Nonnull Tree tree,
+                                              @Nonnull Map<String, Collection<PermissionEntry>> pathEntryMap,
+                                              @Nonnull RestrictionProvider restrictionProvider) {
+        String path = TreeUtil.getString(tree, REP_ACCESS_CONTROLLED_PATH);
+        Collection<PermissionEntry> entries = pathEntryMap.get(path);
+        if (entries == null) {
+            entries = new TreeSet<PermissionEntry>();
+            pathEntryMap.put(path, entries);
+        }
+        for (Tree child : tree.getChildren()) {
+            if (child.getName().charAt(0) == 'c') {
+                loadPermissionEntries(child, pathEntryMap, restrictionProvider);
+            } else {
+                entries.add(new PermissionEntry(path, child, restrictionProvider));
             }
         }
     }
 
-    public Iterator<PermissionEntry> getEntryIterator(@Nonnull EntryPredicate predicate) {
-        if (principalTrees.isEmpty()) {
-            return Iterators.emptyIterator();
+    private static void loadPermissionsFromTree(@Nonnull String path,
+                                                @Nonnull Collection<PermissionEntry> ret,
+                                                @Nonnull Tree tree,
+                                                @Nonnull RestrictionProvider restrictionProvider) {
+        for (Tree ace : tree.getChildren()) {
+            if (ace.getName().charAt(0) != 'c') {
+                ret.add(new PermissionEntry(path, ace, restrictionProvider));
+            }
         }
-        return new EntryIterator(predicate);
-    }
-
-    public void flush() {
-        // TODO clear cache
     }
 
-    private class EntryIterator implements Iterator<PermissionEntry> {
+    private final class EntryIterator extends AbstractEntryIterator {
 
         private final EntryPredicate predicate;
 
         // the next oak path for which to retrieve permission entries
         private String path;
 
-        // the ordered permission entries at a given path in the hierarchy
-        private Iterator<PermissionEntry> nextEntries;
-
-        // the next permission entry
-        private PermissionEntry next;
-
         private EntryIterator(@Nonnull EntryPredicate predicate) {
             this.predicate = predicate;
-            this.path = Strings.nullToEmpty(predicate.path);
-        }
-
-        @Override
-        public boolean hasNext() {
-            if (next == null) {
-                // lazy initialization
-                if (nextEntries == null) {
-                    nextEntries = Iterators.emptyIterator();
-                    seekNext();
-                }
-            }
-            return next != null;
-        }
-
-        @Override
-        public PermissionEntry next() {
-            if (next == null) {
-                throw new NoSuchElementException();
-            }
-
-            PermissionEntry pe = next;
-            seekNext();
-            return pe;
-        }
-
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
+            this.path = Strings.nullToEmpty(predicate.getPath());
         }
 
         @CheckForNull
-        private void seekNext() {
+        protected void seekNext() {
             for (next = null; next == null; ) {
                 if (nextEntries.hasNext()) {
                     PermissionEntry pe = nextEntries.next();
@@ -163,124 +189,4 @@ class PermissionStore implements Permiss
             }
         }
     }
-
-    public static final class EntryPredicate implements Predicate<PermissionEntry> {
-
-        private final Tree tree;
-        private final PropertyState property;
-        private final String path;
-
-        public EntryPredicate(@Nonnull Tree tree, @Nullable PropertyState property) {
-            this.tree = tree;
-            this.property = property;
-            this.path = tree.getPath();
-        }
-
-        public EntryPredicate(@Nonnull String path) {
-            this.tree = null;
-            this.property = null;
-            this.path = path;
-        }
-
-        public EntryPredicate() {
-            this.tree = null;
-            this.property = null;
-            this.path = null;
-        }
-
-        @Override
-        public boolean apply(@Nullable PermissionEntry entry) {
-            if (entry == null) {
-                return false;
-            }
-            if (tree != null) {
-                return entry.matches(tree, property);
-            } else if (path != null) {
-                return entry.matches(path);
-            } else {
-                return entry.matches();
-            }
-        }
-    }
-
-    public static final class PermissionEntry implements Comparable<PermissionEntry> {
-
-        /**
-         * flag controls if this is an allow or deny entry
-         */
-        public final boolean isAllow;
-
-        /**
-         * the privilege bits
-         */
-        public final PrivilegeBits privilegeBits;
-
-        /**
-         * the index (order) of the original ACE in the ACL.
-         */
-        public final int index;
-
-        /**
-         * the access controlled (node) path
-         */
-        public final String path;
-
-        /**
-         * the restriction pattern for this entry
-         */
-        public final RestrictionPattern restriction;
-
-        /**
-         * pre-evaluated read status
-         */
-        public ReadStatus readStatus = null; // TODO
-
-        private PermissionEntry(String path, Tree entryTree, RestrictionProvider restrictionsProvider) {
-            this.path = path;
-            isAllow = entryTree.getProperty(REP_IS_ALLOW).getValue(Type.BOOLEAN);
-            privilegeBits = PrivilegeBits.getInstance(entryTree.getProperty(REP_PRIVILEGE_BITS));
-            index = (int) (long) checkNotNull(entryTree.getProperty(REP_INDEX).getValue(Type.LONG));
-            restriction = restrictionsProvider.getPattern(path, entryTree);
-        }
-
-        public boolean matches(@Nonnull Tree tree, @Nullable PropertyState property) {
-            return restriction == RestrictionPattern.EMPTY || restriction.matches(tree, property);
-        }
-
-        public boolean matches(@Nonnull String treePath) {
-            return restriction == RestrictionPattern.EMPTY || restriction.matches(treePath);
-        }
-
-        public boolean matches() {
-            return restriction == RestrictionPattern.EMPTY || restriction.matches();
-        }
-
-        public boolean matchesParent(@Nonnull String parentPath) {
-            return Text.isDescendantOrEqual(path, parentPath) && (restriction == RestrictionPattern.EMPTY || restriction.matches(parentPath));
-        }
-
-        @Override
-        public int compareTo(PermissionEntry o) {
-            final int anotherVal = o.index;
-            // reverse order
-            return (index < anotherVal ? 1 : (index == anotherVal ? 0 : -1));
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            if (o == null || getClass() != o.getClass()) {
-                return false;
-            }
-            PermissionEntry that = (PermissionEntry) o;
-            return index == that.index;
-        }
-
-        @Override
-        public int hashCode() {
-            return index;
-        }
-    }
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionUtil.java?rev=1532771&r1=1532770&r2=1532771&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionUtil.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionUtil.java Wed Oct 16 14:00:51 2013
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.oak.security.authorization.permission;
 
+import java.security.Principal;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -23,16 +24,25 @@ import javax.annotation.Nullable;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.core.ImmutableTree;
 import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 
 import com.google.common.base.Strings;
+import org.apache.jackrabbit.oak.util.TreeLocation;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * PermissionUtil... TODO
  */
 public final class PermissionUtil implements PermissionConstants {
 
+    private static final Logger log = LoggerFactory.getLogger(PermissionUtil.class);
+
     private PermissionUtil() {}
 
     @CheckForNull
@@ -55,13 +65,48 @@ public final class PermissionUtil implem
         return String.valueOf(path.hashCode());
     }
 
-    public static boolean checkACLPath(NodeBuilder node, String path) {
+    public static boolean checkACLPath(@Nonnull NodeBuilder node, @Nonnull String path) {
         PropertyState property = node.getProperty(REP_ACCESS_CONTROLLED_PATH);
         return property != null && path.equals(property.getValue(Type.STRING));
     }
 
-    public static boolean checkACLPath(Tree node, String path) {
+    public static boolean checkACLPath(@Nonnull Tree node, @Nonnull String path) {
         PropertyState property = node.getProperty(REP_ACCESS_CONTROLLED_PATH);
         return property != null && path.equals(property.getValue(Type.STRING));
     }
+
+    @Nonnull
+    public static ImmutableTree getPermissionsRoot(ImmutableRoot immutableRoot, String workspaceName) {
+        return immutableRoot.getTree(PERMISSIONS_STORE_PATH + '/' + workspaceName);
+    }
+
+    @Nonnull
+    public static Tree getPrincipalRoot(Tree permissionsTree, Principal principal) {
+        return permissionsTree.getChild(Text.escapeIllegalJcrChars(principal.getName()));
+    }
+
+    public static int getType(@Nonnull Tree tree, @Nullable PropertyState property) {
+        // TODO: OAK-753 decide on where to filter out hidden items.
+        // TODO: deal with hidden properties
+        return ImmutableTree.getType(tree);
+    }
+
+    @CheckForNull
+    public static TreeLocation createLocation(@Nonnull ImmutableRoot immutableRoot, @Nullable String oakPath) {
+        if (oakPath != null && PathUtils.isAbsolute(oakPath)) {
+            return TreeLocation.create(immutableRoot, oakPath);
+        } else {
+            log.debug("Unable to create location for path " + oakPath);
+            return null;
+        }
+    }
+
+    @Nonnull
+    public static TreeLocation createLocation(@Nonnull Tree tree, @Nullable PropertyState property) {
+        if (property == null) {
+            return TreeLocation.create(tree);
+        } else {
+            return TreeLocation.create(tree, property);
+        }
+    }
 }
\ No newline at end of file



Mime
View raw message