Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java (revision 1853004) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStore.java (date 1549029959000) @@ -28,8 +28,6 @@ */ interface PermissionStore { - long DYNAMIC_ALL_BITS = -1; - /** * Loads the permission entries for the given principal and path. If no * entries can be found for the given principal or path, {@code null} is returned. Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java (revision 1853004) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreEditor.java (date 1549372641000) @@ -23,19 +23,17 @@ import com.google.common.base.Objects; import com.google.common.base.Strings; import com.google.common.collect.Maps; -import com.google.common.primitives.Longs; import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.Type; -import org.apache.jackrabbit.oak.plugins.memory.PropertyStates; import org.apache.jackrabbit.oak.plugins.nodetype.TypePredicate; import org.apache.jackrabbit.oak.plugins.tree.TreeProvider; 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.restriction.Restriction; import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider; +import org.apache.jackrabbit.oak.spi.security.privilege.JcrAllUtil; 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.oak.spi.state.NodeBuilder; import org.apache.jackrabbit.oak.spi.state.NodeState; import org.apache.jackrabbit.util.Text; @@ -56,6 +54,7 @@ private final String nodeName; private final Map> entries = Maps.newHashMap(); private final NodeBuilder permissionRoot; + private final PrivilegeBitsProvider bitsProvider; PermissionStoreEditor(@NotNull String aclPath, @NotNull String name, @NotNull NodeState node, @NotNull NodeBuilder permissionRoot, @@ -64,6 +63,7 @@ @NotNull RestrictionProvider restrictionProvider, @NotNull TreeProvider treeProvider) { this.permissionRoot = permissionRoot; + this.bitsProvider = bitsProvider; if (name.equals(REP_REPO_POLICY)) { accessControlledPath = ""; } else { @@ -77,7 +77,6 @@ addAll(orderedChildNames, node.getChildNodeNames()); } - PrivilegeBits jcrAll = bitsProvider.getBits(PrivilegeConstants.JCR_ALL); int index = 0; for (String childName : orderedChildNames) { NodeState ace = node.getChildNode(childName); @@ -86,9 +85,7 @@ PrivilegeBits privilegeBits = bitsProvider.getBits(ace.getNames(REP_PRIVILEGES)); Set restrictions = restrictionProvider.readRestrictions(Strings.emptyToNull(accessControlledPath), treeProvider.createReadOnlyTree(ace)); - AcEntry entry = (privilegeBits.equals(jcrAll)) ? - new JcrAllAcEntry(ace, accessControlledPath, index, isAllow, privilegeBits, restrictions) : - new AcEntry(ace, accessControlledPath, index, isAllow, privilegeBits, restrictions); + AcEntry entry = new AcEntry(ace, accessControlledPath, index, isAllow, privilegeBits, restrictions); List list = entries.computeIfAbsent(entry.principalName, k -> new ArrayList<>()); list.add(entry); index++; @@ -247,22 +244,6 @@ } } - private final class JcrAllAcEntry extends AcEntry { - - private JcrAllAcEntry(@NotNull NodeState node, - @NotNull String accessControlledPath, - int index, boolean isAllow, - @NotNull PrivilegeBits privilegeBits, - @NotNull Set restrictions) { - super(node, accessControlledPath, index, isAllow, privilegeBits, restrictions); - } - - @Override - protected PropertyState getPrivilegeBitsProperty() { - return PropertyStates.createProperty(REP_PRIVILEGE_BITS, Longs.asList(PermissionStore.DYNAMIC_ALL_BITS), Type.LONGS); - } - } - private class AcEntry { private final String accessControlledPath; @@ -296,7 +277,7 @@ } PropertyState getPrivilegeBitsProperty() { - return privilegeBits.asPropertyState(REP_PRIVILEGE_BITS); + return JcrAllUtil.getPropertyState(REP_PRIVILEGE_BITS, privilegeBits, bitsProvider); } //-------------------------------------------------------------< Object >--- Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java (revision 1853004) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionStoreImpl.java (date 1549372641000) @@ -23,13 +23,12 @@ 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.plugins.tree.TreeUtil; import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants; import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider; +import org.apache.jackrabbit.oak.spi.security.privilege.JcrAllUtil; 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.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -52,7 +51,7 @@ private final Map principalTreeMap = new HashMap<>(); private Tree permissionsTree; - private PrivilegeBits allBits; + private PrivilegeBitsProvider bitsProvider; PermissionStoreImpl(Root root, String permissionRootName, RestrictionProvider restrictionProvider) { this.permissionRootName = permissionRootName; @@ -68,7 +67,7 @@ private void reset(@NotNull Root root) { permissionsTree = PermissionUtil.getPermissionsRoot(root, permissionRootName); - allBits = new PrivilegeBitsProvider(root).getBits(PrivilegeConstants.JCR_ALL); + bitsProvider = new PrivilegeBitsProvider(root); } //----------------------------------------------------< PermissionStore >--- @@ -171,7 +170,7 @@ } private Collection loadPermissionEntries(@NotNull String path, - @NotNull Tree tree) { + @NotNull Tree tree) { Collection ret = new TreeSet<>(); for (Tree ace : tree.getChildren()) { if (ace.getName().charAt(0) != 'c') { @@ -185,7 +184,7 @@ private PermissionEntry createPermissionEntry(@NotNull String path, @NotNull Tree entryTree) { PropertyState ps = entryTree.getProperty(REP_PRIVILEGE_BITS); - PrivilegeBits bits = (isJcrAll(ps)) ? allBits : PrivilegeBits.getInstance(ps); + PrivilegeBits bits = JcrAllUtil.getPrivilegeBits(ps, bitsProvider); boolean isAllow = TreeUtil.getBoolean(entryTree, REP_IS_ALLOW); return new PermissionEntry(path, isAllow, @@ -193,8 +192,4 @@ bits, restrictionProvider.getPattern(path, entryTree)); } - - private static boolean isJcrAll(@Nullable PropertyState property) { - return property != null && property.count() == 1 && property.getValue(Type.LONG, 0) == DYNAMIC_ALL_BITS; - } } Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/JcrAllUtil.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/JcrAllUtil.java (date 1549372641000) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/JcrAllUtil.java (date 1549372641000) @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.spi.security.privilege; + +import com.google.common.primitives.Longs; +import org.apache.jackrabbit.oak.api.PropertyState; +import org.apache.jackrabbit.oak.api.Type; +import org.apache.jackrabbit.oak.plugins.memory.PropertyStates; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; + +public final class JcrAllUtil { + + private JcrAllUtil() {} + + public static final long DYNAMIC_JCR_ALL_VALUE = -1; + + /** + * Get or create an instance of privilege bits for the given property state. In contrast to + * {@link PrivilegeBits#getInstance(PropertyState)} this implementation will respect the special marker used to + * reflect the dynamic nature of the {@link PrivilegeConstants#JCR_ALL} privilege. + * + * @param propertyState A property storing privilege bits as {@link Type#LONGS} representation or the + * dynamic {@link #DYNAMIC_JCR_ALL_VALUE marker} for {@code jcr:all}. + * @param provider An instanceof {@link PrivilegeBitsProvider} to compute the bits for the {@link PrivilegeConstants#JCR_ALL}, when + * the given property contains the dynamic {@link #DYNAMIC_JCR_ALL_VALUE marker} for {@code jcr:all}. + * @return an instance of {@code PrivilegeBits} + * @see #getPropertyState(String, PrivilegeBits, PrivilegeBitsProvider) + */ + public static PrivilegeBits getPrivilegeBits(@Nullable PropertyState propertyState, @NotNull PrivilegeBitsProvider provider) { + return (denotesDynamicJcrAll(propertyState)) ? getAllBits(provider) : PrivilegeBits.getInstance(propertyState); + } + + /** + * Returns a new multi-valued {@link PropertyState} of type {@link Type#LONGS} with the given {@code name} and the + * long representation of the given {@code bits} as values. If the bits present include {@code jcr:all} the value + * will be {@link #DYNAMIC_JCR_ALL_VALUE} instead to mark the dynamic nature of the {@code jcr:all} privilege. + * For any other bits this method is equivalent to {@link PrivilegeBits#asPropertyState(String)}. + * + * @param name The name of the property to be created. + * @param bits The privilege bits from which the values will be retrieved. + * @param provider The {@link PrivilegeBitsProvider} needed to check if the given bits include {@code jcr:all}. + * @return The property state equivalent to {@link PrivilegeBits#asPropertyState(String)} or a state with the + * {@link #DYNAMIC_JCR_ALL_VALUE dynamic value marker} in case the given bits represent {@code jcr:all}. + */ + public static PropertyState getPropertyState(@NotNull String name, @NotNull PrivilegeBits bits, @NotNull PrivilegeBitsProvider provider) { + if (!bits.isBuiltin() && bits.includes(getAllBits(provider))) { + return PropertyStates.createProperty(name, Longs.asList(DYNAMIC_JCR_ALL_VALUE), Type.LONGS); + } else { + return bits.asPropertyState(name); + } + } + + public static boolean denotesDynamicJcrAll(@Nullable PropertyState property) { + return property != null && Type.LONGS == property.getType() && property.count() == 1 && property.getValue(Type.LONG, 0) == DYNAMIC_JCR_ALL_VALUE; + } + + private static PrivilegeBits getAllBits(@NotNull PrivilegeBitsProvider provider) { + return provider.getBits(Collections.singleton(PrivilegeConstants.JCR_ALL)); + } +} \ No newline at end of file Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/package-info.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/package-info.java (revision 1853004) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/package-info.java (date 1549029443000) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("1.2.1") +@Version("1.3.0") package org.apache.jackrabbit.oak.spi.security.privilege; import org.osgi.annotation.versioning.Version; Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBits.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBits.java (revision 1853004) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBits.java (date 1549029443000) @@ -418,6 +418,14 @@ return d.includes(otherBits.d); } + /** + * @return {@code true} if this instance represents one of the built-in privilege + * @see #BUILT_IN + */ + public boolean isBuiltin() { + return d.isSimple() && BUILT_IN_BITS.containsKey(d.longValue()); + } + /** * Adds the other privilege bits to this instance. * @@ -493,7 +501,7 @@ } @NotNull - public PropertyState asPropertyState(String name) { + public PropertyState asPropertyState(@NotNull String name) { return PropertyStates.createProperty(name, Longs.asList(d.longValues()), Type.LONGS); } Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBitsProvider.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBitsProvider.java (revision 1853004) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBitsProvider.java (date 1549032608000) @@ -22,7 +22,6 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import javax.jcr.RepositoryException; import javax.jcr.security.Privilege; import com.google.common.base.Function; @@ -49,6 +48,7 @@ private static final Logger log = LoggerFactory.getLogger(PrivilegeBitsProvider.class); private final Map> bitsToNames = new HashMap<>(); + private final Map nameToBits = new HashMap<>(); private final Map> aggregation = new HashMap<>(); private final Root root; @@ -99,13 +99,17 @@ PrivilegeBits builtIn = PrivilegeBits.BUILT_IN.get(privilegeName); if (builtIn != null) { bits.add(builtIn); - } else { + } else if (nameToBits.containsKey(privilegeName)) { + bits.add(nameToBits.get(privilegeName)); + } else { if (privilegesTree == null) { privilegesTree = getPrivilegesTree(); } if (privilegesTree.exists() && privilegesTree.hasChild(privilegeName)) { Tree defTree = privilegesTree.getChild(privilegeName); - bits.add(PrivilegeBits.getInstance(defTree)); + PrivilegeBits bitsFromDefTree = PrivilegeBits.getInstance(defTree); + nameToBits.put(privilegeName, bitsFromDefTree); + bits.add(bitsFromDefTree); } else { log.debug("Ignoring privilege name " + privilegeName); }