Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeAuthorizationConfiguration.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/composite/CompositeAuthorizationConfiguration.java (revision 1858190) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeAuthorizationConfiguration.java (date 1556278133000) @@ -186,7 +186,7 @@ pp = aggrPermissionProviders.get(0); break; default : - pp = new CompositePermissionProvider(root, aggrPermissionProviders, getContext(), compositionType, getRootProvider(), getTreeProvider()); + pp = CompositePermissionProvider.create(root, aggrPermissionProviders, getContext(), compositionType, getRootProvider(), getTreeProvider()); } return pp; } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositePermissionProvider.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/composite/CompositePermissionProvider.java (revision 1858190) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositePermissionProvider.java (date 1556278111000) @@ -16,9 +16,6 @@ */ package org.apache.jackrabbit.oak.security.authorization.composite; -import java.util.List; -import java.util.Set; -import java.util.function.Function; import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.api.Tree; @@ -40,7 +37,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import static org.apache.jackrabbit.oak.security.authorization.composite.CompositeAuthorizationConfiguration.CompositionType.AND; +import java.util.List; +import java.util.function.Function; /** * Permission provider implementation that aggregates a list of different @@ -49,12 +47,11 @@ * {@link org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider} * interface. */ -class CompositePermissionProvider implements AggregatedPermissionProvider { +abstract class CompositePermissionProvider implements AggregatedPermissionProvider { private final Root root; private final AggregatedPermissionProvider[] pps; private final Context ctx; - private final CompositionType compositionType; private final RootProvider rootProvider; private final TreeProvider treeProvider; @@ -65,21 +62,50 @@ private TreeTypeProvider typeProvider; CompositePermissionProvider(@NotNull Root root, @NotNull List pps, - @NotNull Context acContext, @NotNull CompositionType compositionType, - @NotNull RootProvider rootProvider, @NotNull TreeProvider treeProvider) { + @NotNull Context acContext, @NotNull RootProvider rootProvider, @NotNull TreeProvider treeProvider) { this.root = root; this.pps = pps.toArray(new AggregatedPermissionProvider[0]); this.ctx = acContext; - this.compositionType = compositionType; this.rootProvider = rootProvider; this.treeProvider = treeProvider; - repositoryPermission = new CompositeRepositoryPermission(this.pps, this.compositionType); + repositoryPermission = createRepositoryPermission(); immutableRoot = rootProvider.createReadOnlyRoot(root); privilegeBitsProvider = new PrivilegeBitsProvider(immutableRoot); typeProvider = new TreeTypeProvider(ctx); } + static CompositePermissionProvider create(@NotNull Root root, @NotNull List pps, + @NotNull Context acContext, @NotNull CompositionType compositionType, + @NotNull RootProvider rootProvider, @NotNull TreeProvider treeProvider) { + if (compositionType == CompositionType.AND) { + return new CompositePermissionProviderAnd(root, pps, acContext, rootProvider, treeProvider); + } else { + return new CompositePermissionProviderOr(root, pps, acContext, rootProvider, treeProvider); + } + } + + @NotNull + abstract CompositionType getCompositeType(); + + @NotNull + abstract RepositoryPermission createRepositoryPermission(); + + @NotNull + Root getImmutableRoot() { + return immutableRoot; + } + + @NotNull + PrivilegeBitsProvider getBitsProvider() { + return privilegeBitsProvider; + } + + @NotNull + AggregatedPermissionProvider[] getPermissionProviders() { + return pps; + } + //-------------------------------------------------< PermissionProvider >--- @Override public void refresh() { @@ -91,75 +117,6 @@ } } - @NotNull - @Override - public Set getPrivileges(@Nullable Tree tree) { - Tree immutableTree = PermissionUtil.getReadOnlyTreeOrNull(tree, immutableRoot); - - PrivilegeBits result = PrivilegeBits.getInstance(); - PrivilegeBits denied = PrivilegeBits.getInstance(); - - for (AggregatedPermissionProvider aggregatedPermissionProvider : pps) { - PrivilegeBits supported = aggregatedPermissionProvider.supportedPrivileges(immutableTree, null).modifiable(); - if (doEvaluate(supported)) { - PrivilegeBits granted = privilegeBitsProvider.getBits(aggregatedPermissionProvider.getPrivileges(immutableTree)); - // add the granted privileges to the result - if (!granted.isEmpty()) { - result.add(granted); - } - if (compositionType == AND) { - // update the set of denied privs by comparing the granted privs - // with the complete set of supported privileges - denied.add(supported.diff(granted)); - } - } - } - // subtract all denied privileges from the result - if (!denied.isEmpty()) { - result.diff(denied); - } - return privilegeBitsProvider.getPrivilegeNames(result); - } - - @Override - public boolean hasPrivileges(@Nullable Tree tree, @NotNull String... privilegeNames) { - Tree immutableTree = PermissionUtil.getReadOnlyTreeOrNull(tree, immutableRoot); - PrivilegeBits privilegeBits = privilegeBitsProvider.getBits(privilegeNames); - if (privilegeBits.isEmpty()) { - return true; - } - - boolean hasPrivileges = false; - PrivilegeBits coveredPrivs = PrivilegeBits.getInstance(); - - for (AggregatedPermissionProvider aggregatedPermissionProvider : pps) { - PrivilegeBits supported = aggregatedPermissionProvider.supportedPrivileges(immutableTree, privilegeBits); - if (doEvaluate(supported)) { - Set supportedNames = privilegeBitsProvider.getPrivilegeNames(supported); - if (compositionType == AND) { - hasPrivileges = aggregatedPermissionProvider.hasPrivileges(immutableTree, - supportedNames.toArray(new String[0])); - if (!hasPrivileges) { - return false; - } - coveredPrivs.add(supported); - - } else { - // evaluate one by one so we can aggregate fragments of - // supported privileges - for (String p : supportedNames) { - if (aggregatedPermissionProvider.hasPrivileges(immutableTree, p)) { - PrivilegeBits granted = privilegeBitsProvider.getBits(p); - coveredPrivs.add(granted); - hasPrivileges = true; - } - } - } - } - } - return hasPrivileges && coveredPrivs.includes(privilegeBits); - } - @NotNull @Override public RepositoryPermission getRepositoryPermission() { @@ -171,7 +128,7 @@ public TreePermission getTreePermission(@NotNull Tree tree, @NotNull TreePermission parentPermission) { Tree readOnlyTree = PermissionUtil.getReadOnlyTree(tree, immutableRoot); if (tree.isRoot()) { - return CompositeTreePermission.create(readOnlyTree, treeProvider, typeProvider, pps, compositionType); + return CompositeTreePermission.create(readOnlyTree, treeProvider, typeProvider, pps, getCompositeType()); } else if (parentPermission instanceof CompositeTreePermission) { return CompositeTreePermission.create(readOnlyTree, treeProvider, ((CompositeTreePermission) parentPermission)); } else { @@ -179,34 +136,6 @@ } } - @Override - public boolean isGranted(@NotNull Tree parent, @Nullable PropertyState property, long permissions) { - Tree immParent = PermissionUtil.getReadOnlyTree(parent, immutableRoot); - - boolean isGranted = false; - long coveredPermissions = Permissions.NO_PERMISSION; - for (AggregatedPermissionProvider aggregatedPermissionProvider : pps) { - long supportedPermissions = aggregatedPermissionProvider.supportedPermissions(immParent, property, permissions); - if (doEvaluate(supportedPermissions)) { - if (compositionType == AND) { - isGranted = aggregatedPermissionProvider.isGranted(immParent, property, supportedPermissions); - if (!isGranted) { - return false; - } - coveredPermissions |= supportedPermissions; - } else { - for (long p : Permissions.aggregates(permissions)) { - if (aggregatedPermissionProvider.isGranted(immParent, property, p)) { - coveredPermissions |= p; - isGranted = true; - } - } - } - } - } - return isGranted && coveredPermissions == permissions; - } - @Override public boolean isGranted(@NotNull String oakPath, @NotNull String jcrActions) { TreeLocation location = TreeLocation.create(immutableRoot, oakPath); @@ -216,61 +145,6 @@ return isGranted(location, permissions); } - //------------------------------------------------------------< private >--- - - private static boolean doEvaluate(long supportedPermissions) { - return supportedPermissions != Permissions.NO_PERMISSION; - } - - private static boolean doEvaluate(PrivilegeBits supportedPrivileges) { - return !supportedPrivileges.isEmpty(); - } - - //-----------------------------------------------< RepositoryPermission >--- - /** - * {@code RepositoryPermission} implementation that wraps multiple implementations. - */ - private final static class CompositeRepositoryPermission implements RepositoryPermission { - - private final AggregatedPermissionProvider[] pps; - - private final CompositionType compositionType; - - CompositeRepositoryPermission(@NotNull AggregatedPermissionProvider[] pps, - @NotNull CompositionType compositionType) { - this.pps = pps; - this.compositionType = compositionType; - } - - @Override - public boolean isGranted(long repositoryPermissions) { - boolean isGranted = false; - long coveredPermissions = Permissions.NO_PERMISSION; - - for (AggregatedPermissionProvider aggregatedPermissionProvider : pps) { - long supportedPermissions = aggregatedPermissionProvider.supportedPermissions((Tree) null, null, repositoryPermissions); - if (doEvaluate(supportedPermissions)) { - RepositoryPermission rp = aggregatedPermissionProvider.getRepositoryPermission(); - if (compositionType == AND) { - isGranted = rp.isGranted(supportedPermissions); - if (!isGranted) { - return false; - } - coveredPermissions |= supportedPermissions; - } else { - for (long p : Permissions.aggregates(repositoryPermissions)) { - if (rp.isGranted(p)) { - coveredPermissions |= p; - isGranted = true; - } - } - } - } - } - return isGranted && coveredPermissions == repositoryPermissions; - } - } - //---------------------------------------< AggregatedPermissionProvider >--- @NotNull @@ -311,47 +185,13 @@ return coveredPermissions; } - @Override - public boolean isGranted(@NotNull TreeLocation location, long permissions) { - PropertyState property = location.getProperty(); - Tree tree = (property == null) ? location.getTree() : location.getParent().getTree(); - - if (tree != null) { - return isGranted(tree, property, permissions); - } else { - boolean isGranted = false; - long coveredPermissions = Permissions.NO_PERMISSION; - - for (AggregatedPermissionProvider aggregatedPermissionProvider : pps) { - long supportedPermissions = aggregatedPermissionProvider.supportedPermissions(location, permissions); - if (doEvaluate(supportedPermissions)) { - if (compositionType == AND) { - isGranted = aggregatedPermissionProvider.isGranted(location, supportedPermissions); - if (!isGranted) { - return false; - } - coveredPermissions |= supportedPermissions; - } else { - for (long p : Permissions.aggregates(permissions)) { - if (aggregatedPermissionProvider.isGranted(location, p)) { - coveredPermissions |= p; - isGranted = true; - } - } - } - } - } - return isGranted && coveredPermissions == permissions; - } - } - @NotNull @Override public TreePermission getTreePermission(@NotNull Tree tree, @NotNull TreeType type, @NotNull TreePermission parentPermission) { Tree immutableTree = PermissionUtil.getReadOnlyTree(tree, immutableRoot); if (tree.isRoot()) { - return CompositeTreePermission.create(immutableTree, treeProvider, typeProvider, pps, compositionType); + return CompositeTreePermission.create(immutableTree, treeProvider, typeProvider, pps, getCompositeType()); } else if (parentPermission instanceof CompositeTreePermission) { return CompositeTreePermission.create(immutableTree, treeProvider, ((CompositeTreePermission) parentPermission), type); } else { Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositePermissionProviderAnd.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/composite/CompositePermissionProviderAnd.java (date 1556111918000) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositePermissionProviderAnd.java (date 1556111918000) @@ -0,0 +1,196 @@ +/* + * 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.composite; + +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.plugins.tree.RootProvider; +import org.apache.jackrabbit.oak.plugins.tree.TreeLocation; +import org.apache.jackrabbit.oak.plugins.tree.TreeProvider; +import org.apache.jackrabbit.oak.security.authorization.composite.CompositeAuthorizationConfiguration.CompositionType; +import org.apache.jackrabbit.oak.security.authorization.permission.PermissionUtil; +import org.apache.jackrabbit.oak.spi.security.Context; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.RepositoryPermission; +import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits; +import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Set; + +import static org.apache.jackrabbit.oak.security.authorization.composite.CompositeAuthorizationConfiguration.CompositionType.AND; + +/** + * Permission provider implementation that aggregates a list of different + * provider implementations. Note, that the aggregated provider implementations + * *must* implement the + * {@link AggregatedPermissionProvider} + * interface. + */ +final class CompositePermissionProviderAnd extends CompositePermissionProvider { + + CompositePermissionProviderAnd(@NotNull Root root, @NotNull List pps, + @NotNull Context acContext, + @NotNull RootProvider rootProvider, @NotNull TreeProvider treeProvider) { + super(root, pps, acContext, rootProvider, treeProvider); + } + + @NotNull + CompositionType getCompositeType() { + return AND; + } + + @NotNull + RepositoryPermission createRepositoryPermission() { + return new CompositeRepositoryPermission(); + } + + //-------------------------------------------------< PermissionProvider >--- + + @NotNull + @Override + public Set getPrivileges(@Nullable Tree tree) { + Tree immutableTree = PermissionUtil.getReadOnlyTreeOrNull(tree, getImmutableRoot()); + + PrivilegeBits result = PrivilegeBits.getInstance(); + PrivilegeBits denied = PrivilegeBits.getInstance(); + + PrivilegeBitsProvider bitsProvider = getBitsProvider(); + for (AggregatedPermissionProvider aggregatedPermissionProvider : getPermissionProviders()) { + PrivilegeBits supported = aggregatedPermissionProvider.supportedPrivileges(immutableTree, null).modifiable(); + if (Util.doEvaluate(supported)) { + PrivilegeBits granted = bitsProvider.getBits(aggregatedPermissionProvider.getPrivileges(immutableTree)); + // add the granted privileges to the result + if (!granted.isEmpty()) { + result.add(granted); + } + // update the set of denied privs by comparing the granted privs + // with the complete set of supported privileges + denied.add(supported.diff(granted)); + } + } + // subtract all denied privileges from the result + if (!denied.isEmpty()) { + result.diff(denied); + } + return bitsProvider.getPrivilegeNames(result); + } + + @Override + public boolean hasPrivileges(@Nullable Tree tree, @NotNull String... privilegeNames) { + Tree immutableTree = PermissionUtil.getReadOnlyTreeOrNull(tree, getImmutableRoot()); + PrivilegeBitsProvider bitsProvider = getBitsProvider(); + + PrivilegeBits privilegeBits = bitsProvider.getBits(privilegeNames); + if (privilegeBits.isEmpty()) { + return true; + } + + boolean hasPrivileges = false; + PrivilegeBits coveredPrivs = PrivilegeBits.getInstance(); + + for (AggregatedPermissionProvider aggregatedPermissionProvider : getPermissionProviders()) { + PrivilegeBits supported = aggregatedPermissionProvider.supportedPrivileges(immutableTree, privilegeBits); + if (Util.doEvaluate(supported)) { + Set supportedNames = bitsProvider.getPrivilegeNames(supported); + hasPrivileges = aggregatedPermissionProvider.hasPrivileges(immutableTree, + supportedNames.toArray(new String[0])); + if (!hasPrivileges) { + return false; + } + coveredPrivs.add(supported); + } + } + return hasPrivileges && coveredPrivs.includes(privilegeBits); + } + + @Override + public boolean isGranted(@NotNull Tree parent, @Nullable PropertyState property, long permissions) { + Tree immParent = PermissionUtil.getReadOnlyTree(parent, getImmutableRoot()); + + boolean isGranted = false; + long coveredPermissions = Permissions.NO_PERMISSION; + for (AggregatedPermissionProvider aggregatedPermissionProvider : getPermissionProviders()) { + long supportedPermissions = aggregatedPermissionProvider.supportedPermissions(immParent, property, permissions); + if (Util.doEvaluate(supportedPermissions)) { + isGranted = aggregatedPermissionProvider.isGranted(immParent, property, supportedPermissions); + if (!isGranted) { + return false; + } + coveredPermissions |= supportedPermissions; + } + } + return isGranted && coveredPermissions == permissions; + } + + //---------------------------------------< AggregatedPermissionProvider >--- + + @Override + public boolean isGranted(@NotNull TreeLocation location, long permissions) { + PropertyState property = location.getProperty(); + Tree tree = (property == null) ? location.getTree() : location.getParent().getTree(); + + if (tree != null) { + return isGranted(tree, property, permissions); + } else { + boolean isGranted = false; + long coveredPermissions = Permissions.NO_PERMISSION; + + for (AggregatedPermissionProvider aggregatedPermissionProvider : getPermissionProviders()) { + long supportedPermissions = aggregatedPermissionProvider.supportedPermissions(location, permissions); + if (Util.doEvaluate(supportedPermissions)) { + isGranted = aggregatedPermissionProvider.isGranted(location, supportedPermissions); + if (!isGranted) { + return false; + } + coveredPermissions |= supportedPermissions; + } + } + return isGranted && coveredPermissions == permissions; + } + } + + //-----------------------------------------------< RepositoryPermission >--- + /** + * {@code RepositoryPermission} implementation that wraps multiple implementations. + */ + private final class CompositeRepositoryPermission implements RepositoryPermission { + + @Override + public boolean isGranted(long repositoryPermissions) { + boolean isGranted = false; + long coveredPermissions = Permissions.NO_PERMISSION; + + for (AggregatedPermissionProvider aggregatedPermissionProvider : getPermissionProviders()) { + long supportedPermissions = aggregatedPermissionProvider.supportedPermissions((Tree) null, null, repositoryPermissions); + if (Util.doEvaluate(supportedPermissions)) { + RepositoryPermission rp = aggregatedPermissionProvider.getRepositoryPermission(); + isGranted = rp.isGranted(supportedPermissions); + if (!isGranted) { + return false; + } + coveredPermissions |= supportedPermissions; + } + } + return isGranted && coveredPermissions == repositoryPermissions; + } + } +} Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositePermissionProviderOr.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/composite/CompositePermissionProviderOr.java (date 1556111918000) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositePermissionProviderOr.java (date 1556111918000) @@ -0,0 +1,201 @@ +/* + * 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.composite; + +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.plugins.tree.RootProvider; +import org.apache.jackrabbit.oak.plugins.tree.TreeLocation; +import org.apache.jackrabbit.oak.plugins.tree.TreeProvider; +import org.apache.jackrabbit.oak.security.authorization.composite.CompositeAuthorizationConfiguration.CompositionType; +import org.apache.jackrabbit.oak.security.authorization.permission.PermissionUtil; +import org.apache.jackrabbit.oak.spi.security.Context; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.RepositoryPermission; +import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits; +import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Set; + +import static org.apache.jackrabbit.oak.security.authorization.composite.CompositeAuthorizationConfiguration.CompositionType.OR; + +/** + * Permission provider implementation that aggregates a list of different + * provider implementations. Note, that the aggregated provider implementations + * *must* implement the + * {@link AggregatedPermissionProvider} + * interface. + */ +final class CompositePermissionProviderOr extends CompositePermissionProvider { + + CompositePermissionProviderOr(@NotNull Root root, @NotNull List pps, + @NotNull Context acContext, @NotNull RootProvider rootProvider, + @NotNull TreeProvider treeProvider) { + super(root, pps, acContext, rootProvider, treeProvider); + } + + @NotNull + @Override + CompositionType getCompositeType() { + return OR; + } + + @NotNull + @Override + RepositoryPermission createRepositoryPermission() { + return new CompositeRepositoryPermission(); + } + + //-------------------------------------------------< PermissionProvider >--- + + @NotNull + @Override + public Set getPrivileges(@Nullable Tree tree) { + Tree immutableTree = PermissionUtil.getReadOnlyTreeOrNull(tree, getImmutableRoot()); + + PrivilegeBits result = PrivilegeBits.getInstance(); + PrivilegeBits denied = PrivilegeBits.getInstance(); + + PrivilegeBitsProvider bitsProvider = getBitsProvider(); + for (AggregatedPermissionProvider aggregatedPermissionProvider : getPermissionProviders()) { + PrivilegeBits supported = aggregatedPermissionProvider.supportedPrivileges(immutableTree, null).modifiable(); + if (Util.doEvaluate(supported)) { + PrivilegeBits granted = bitsProvider.getBits(aggregatedPermissionProvider.getPrivileges(immutableTree)); + // add the granted privileges to the result + if (!granted.isEmpty()) { + result.add(granted); + } + } + } + // subtract all denied privileges from the result + if (!denied.isEmpty()) { + result.diff(denied); + } + return getBitsProvider().getPrivilegeNames(result); + } + + @Override + public boolean hasPrivileges(@Nullable Tree tree, @NotNull String... privilegeNames) { + Tree immutableTree = PermissionUtil.getReadOnlyTreeOrNull(tree, getImmutableRoot()); + PrivilegeBitsProvider bitsProvider = getBitsProvider(); + + PrivilegeBits privilegeBits = bitsProvider.getBits(privilegeNames); + if (privilegeBits.isEmpty()) { + return true; + } + + boolean hasPrivileges = false; + PrivilegeBits coveredPrivs = PrivilegeBits.getInstance(); + + for (AggregatedPermissionProvider aggregatedPermissionProvider : getPermissionProviders()) { + PrivilegeBits supported = aggregatedPermissionProvider.supportedPrivileges(immutableTree, privilegeBits); + if (Util.doEvaluate(supported)) { + Set supportedNames = bitsProvider.getPrivilegeNames(supported); + // evaluate one by one so we can aggregate fragments of + // supported privileges + for (String p : supportedNames) { + if (aggregatedPermissionProvider.hasPrivileges(immutableTree, p)) { + PrivilegeBits granted = bitsProvider.getBits(p); + coveredPrivs.add(granted); + hasPrivileges = true; + } + } + } + } + return hasPrivileges && coveredPrivs.includes(privilegeBits); + } + + @Override + public boolean isGranted(@NotNull Tree parent, @Nullable PropertyState property, long permissions) { + Tree immParent = PermissionUtil.getReadOnlyTree(parent, getImmutableRoot()); + + boolean isGranted = false; + long coveredPermissions = Permissions.NO_PERMISSION; + for (AggregatedPermissionProvider aggregatedPermissionProvider : getPermissionProviders()) { + long supportedPermissions = aggregatedPermissionProvider.supportedPermissions(immParent, property, permissions); + if (Util.doEvaluate(supportedPermissions)) { + for (long p : Permissions.aggregates(permissions)) { + if (aggregatedPermissionProvider.isGranted(immParent, property, p)) { + coveredPermissions |= p; + isGranted = true; + } + } + } + } + return isGranted && coveredPermissions == permissions; + } + + //---------------------------------------< AggregatedPermissionProvider >--- + + @Override + public boolean isGranted(@NotNull TreeLocation location, long permissions) { + PropertyState property = location.getProperty(); + Tree tree = (property == null) ? location.getTree() : location.getParent().getTree(); + + if (tree != null) { + return isGranted(tree, property, permissions); + } else { + boolean isGranted = false; + long coveredPermissions = Permissions.NO_PERMISSION; + + for (AggregatedPermissionProvider aggregatedPermissionProvider : getPermissionProviders()) { + long supportedPermissions = aggregatedPermissionProvider.supportedPermissions(location, permissions); + if (Util.doEvaluate(supportedPermissions)) { + for (long p : Permissions.aggregates(permissions)) { + if (aggregatedPermissionProvider.isGranted(location, p)) { + coveredPermissions |= p; + isGranted = true; + } + } + } + } + return isGranted && coveredPermissions == permissions; + } + } + + //-----------------------------------------------< RepositoryPermission >--- + /** + * {@code RepositoryPermission} implementation that wraps multiple implementations. + */ + private final class CompositeRepositoryPermission implements RepositoryPermission { + + @Override + public boolean isGranted(long repositoryPermissions) { + boolean isGranted = false; + long coveredPermissions = Permissions.NO_PERMISSION; + + for (AggregatedPermissionProvider aggregatedPermissionProvider : getPermissionProviders()) { + long supportedPermissions = aggregatedPermissionProvider.supportedPermissions((Tree) null, null, repositoryPermissions); + if (Util.doEvaluate(supportedPermissions)) { + RepositoryPermission rp = aggregatedPermissionProvider.getRepositoryPermission(); + for (long p : Permissions.aggregates(repositoryPermissions)) { + if (rp.isGranted(p)) { + coveredPermissions |= p; + isGranted = true; + } + } + } + } + return isGranted && coveredPermissions == repositoryPermissions; + } + } +} Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeTreePermission.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/composite/CompositeTreePermission.java (revision 1858190) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeTreePermission.java (date 1556279479000) @@ -32,16 +32,16 @@ import static org.apache.jackrabbit.oak.security.authorization.composite.CompositeAuthorizationConfiguration.CompositionType.AND; import static org.apache.jackrabbit.oak.security.authorization.composite.CompositeAuthorizationConfiguration.CompositionType.OR; +import static org.apache.jackrabbit.oak.security.authorization.composite.Util.doEvaluate; /** * {@code TreePermission} implementation that combines multiple {@code TreePermission} * implementations. */ -final class CompositeTreePermission implements TreePermission { +abstract class CompositeTreePermission implements TreePermission { private final Tree tree; private final TreeType type; - private final CompositionType compositionType; private final TreeProvider treeProvider; private final TreeTypeProvider typeProvider; @@ -53,9 +53,10 @@ private Boolean canReadProperties; private CompositeTreePermission(@NotNull Tree tree, @NotNull TreeType type, - @NotNull TreeProvider treeProvider, - @NotNull TreeTypeProvider typeProvider, @NotNull AggregatedPermissionProvider[] providers, - @NotNull TreePermission[] treePermissions, int cnt, @NotNull CompositionType compositionType) { + @NotNull TreeProvider treeProvider, + @NotNull TreeTypeProvider typeProvider, + @NotNull AggregatedPermissionProvider[] providers, + @NotNull TreePermission[] treePermissions, int cnt) { this.tree = tree; this.type = type; @@ -64,7 +65,6 @@ this.providers = providers; this.treePermissions = treePermissions; this.childSize = providers.length - cnt; - this.compositionType = compositionType; } static TreePermission create(@NotNull Tree rootTree, @@ -85,8 +85,11 @@ } treePermissions[i] = tp; } - return new CompositeTreePermission(rootTree, TreeType.DEFAULT, treeProvider, typeProvider, providers, treePermissions, - cnt, compositionType); + if (compositionType == AND) { + return new CompositeTreePermissionAnd(rootTree, TreeType.DEFAULT, treeProvider, typeProvider, providers, treePermissions, cnt); + } else { + return new CompositeTreePermissionOr(rootTree, TreeType.DEFAULT, treeProvider, typeProvider, providers, treePermissions, cnt); + } } } @@ -108,11 +111,11 @@ case 1: TreePermission parent = null; for (TreePermission tp : parentPermission.treePermissions) { - if (isValid(tp)) { - parent = tp; - break; - } - } + if (isValid(tp)) { + parent = tp; + break; + } + } return (parent == null) ? TreePermission.EMPTY : parent.getChildPermission(childName, childState); default: Tree tree = lazyTree.get(); @@ -139,8 +142,11 @@ j++; } } - return new CompositeTreePermission(tree, type, parentPermission.treeProvider, parentPermission.typeProvider, pvds, tps, cnt, - parentPermission.compositionType); + if (parentPermission.getCompositionType() == AND) { + return new CompositeTreePermissionAnd(tree, type, parentPermission.treeProvider, parentPermission.typeProvider, pvds, tps, cnt); + } else { + return new CompositeTreePermissionOr(tree, type, parentPermission.treeProvider, parentPermission.typeProvider, pvds, tps, cnt); + } } } @@ -172,21 +178,7 @@ @Override public boolean canReadProperties() { if (canReadProperties == null) { - boolean readable = false; - for (int i = 0; i < providers.length; i++) { - TreePermission tp = treePermissions[i]; - long supported = providers[i].supportedPermissions(tp, null, Permissions.READ_PROPERTY); - if (doEvaluate(supported)) { - readable = tp.canReadProperties(); - if (!readable && compositionType == AND) { - break; - } - if (readable && compositionType == OR) { - break; - } - } - } - canReadProperties = readable; + canReadProperties = grantsReadProperties(); } return canReadProperties; } @@ -201,23 +193,65 @@ return grantsPermission(permissions, property); } + //--------------------------------------------------------------------------- + @NotNull + abstract CompositionType getCompositionType(); + + abstract boolean grantsPermission(long permissions, @Nullable PropertyState property); + + abstract boolean grantsRead(@Nullable PropertyState property); + + abstract boolean grantsReadProperties(); + + //--------------------------------------------------------------------------- + + int length() { + return providers.length; + } + + @NotNull + AggregatedPermissionProvider provider(int index) { + return providers[index]; + } + + @NotNull + TreePermission treePermission(int index) { + return treePermissions[index]; + } + //------------------------------------------------------------< private >--- - private boolean grantsPermission(long permissions, @Nullable PropertyState property) { - boolean isGranted = false; - long coveredPermissions = Permissions.NO_PERMISSION; + private static boolean isValid(@NotNull TreePermission tp) { + return NO_RECOURSE != tp; + } + + private static TreeType getType(@NotNull Tree tree, @NotNull CompositeTreePermission parent) { + return parent.typeProvider.getType(tree, parent.type); + } + + //---< OR >----------------------------------------------------------------- + + private static final class CompositeTreePermissionOr extends CompositeTreePermission { + + private CompositeTreePermissionOr(@NotNull Tree tree, @NotNull TreeType type, @NotNull TreeProvider treeProvider, @NotNull TreeTypeProvider typeProvider, @NotNull AggregatedPermissionProvider[] providers, @NotNull TreePermission[] treePermissions, int cnt) { + super(tree, type, treeProvider, typeProvider, providers, treePermissions, cnt); + } + + @NotNull + @Override + CompositionType getCompositionType() { + return OR; + } + + @Override + boolean grantsPermission(long permissions, @Nullable PropertyState property) { + boolean isGranted = false; + long coveredPermissions = Permissions.NO_PERMISSION; - for (int i = 0; i < providers.length; i++) { - TreePermission tp = treePermissions[i]; - long supported = providers[i].supportedPermissions(tp, property, permissions); - if (doEvaluate(supported)) { - if (compositionType == AND) { - isGranted = (property == null) ? tp.isGranted(supported) : tp.isGranted(supported, property); - if (!isGranted) { - return false; - } - coveredPermissions |= supported; - } else { + for (int i = 0; i < length(); i++) { + TreePermission tp = treePermission(i); + long supported = provider(i).supportedPermissions(tp, property, permissions); + if (doEvaluate(supported)) { for (long p : Permissions.aggregates(supported)) { boolean aGrant = (property == null) ? tp.isGranted(p) : tp.isGranted(p, property); if (aGrant) { @@ -227,40 +261,110 @@ } } } - } - return isGranted && coveredPermissions == permissions; - } + return isGranted && coveredPermissions == permissions; + } - private boolean grantsRead(@Nullable PropertyState property) { - if (property != null && canReadProperties()) { - return true; - } - boolean readable = false; - for (int i = 0; i < providers.length; i++) { - TreePermission tp = treePermissions[i]; - long supported = providers[i].supportedPermissions(tp, property, (property == null) ? Permissions.READ_NODE : Permissions.READ_PROPERTY); - if (doEvaluate(supported)) { - readable = (property == null) ? tp.canRead() : tp.canRead(property); - if (!readable && compositionType == AND) { - return false; + @Override + boolean grantsRead(@Nullable PropertyState property) { + if (property != null && canReadProperties()) { + return true; + } + boolean readable = false; + for (int i = 0; i < length(); i++) { + TreePermission tp = treePermission(i); + long supported = provider(i).supportedPermissions(tp, property, (property == null) ? Permissions.READ_NODE : Permissions.READ_PROPERTY); + if (doEvaluate(supported)) { + readable = (property == null) ? tp.canRead() : tp.canRead(property); + if (readable) { + return true; + } + } + } + return readable; + } + + @Override + boolean grantsReadProperties() { + boolean readable = false; + for (int i = 0; i < length(); i++) { + TreePermission tp = treePermission(i); + long supported = provider(i).supportedPermissions(tp, null, Permissions.READ_PROPERTY); + if (doEvaluate(supported)) { + readable = tp.canReadProperties(); + if (readable) { + break; + } + } + } + return readable; + } + } + + //---< AND >---------------------------------------------------------------- + + private static final class CompositeTreePermissionAnd extends CompositeTreePermission { + + private CompositeTreePermissionAnd(@NotNull Tree tree, @NotNull TreeType type, + @NotNull TreeProvider treeProvider, + @NotNull TreeTypeProvider typeProvider, @NotNull AggregatedPermissionProvider[] providers, + @NotNull TreePermission[] treePermissions, int cnt) { + super(tree, type, treeProvider, typeProvider, providers, treePermissions, cnt); + } + + @NotNull + CompositeAuthorizationConfiguration.CompositionType getCompositionType() { + return AND; + } + + boolean grantsPermission(long permissions, @Nullable PropertyState property) { + boolean isGranted = false; + long coveredPermissions = Permissions.NO_PERMISSION; + + for (int i = 0; i < length(); i++) { + TreePermission tp = treePermission(i); + long supported = provider(i).supportedPermissions(tp, property, permissions); + if (doEvaluate(supported)) { + isGranted = (property == null) ? tp.isGranted(supported) : tp.isGranted(supported, property); + if (!isGranted) { + return false; + } + coveredPermissions |= supported; } - if (readable && compositionType == OR) { - return true; - } - } - } - return readable; - } + } + return isGranted && coveredPermissions == permissions; + } + + boolean grantsRead(@Nullable PropertyState property) { + if (property != null && canReadProperties()) { + return true; + } + boolean readable = false; + for (int i = 0; i < length(); i++) { + TreePermission tp = treePermission(i); + long supported = provider(i).supportedPermissions(tp, property, (property == null) ? Permissions.READ_NODE : Permissions.READ_PROPERTY); + if (doEvaluate(supported)) { + readable = (property == null) ? tp.canRead() : tp.canRead(property); + if (!readable) { + return false; + } + } + } + return readable; + } - private static boolean doEvaluate(long supportedPermissions) { - return supportedPermissions != Permissions.NO_PERMISSION; - } - - private static boolean isValid(@NotNull TreePermission tp) { - return NO_RECOURSE != tp; - } - - private static TreeType getType(@NotNull Tree tree, @NotNull CompositeTreePermission parent) { - return parent.typeProvider.getType(tree, parent.type); + boolean grantsReadProperties() { + boolean readable = false; + for (int i = 0; i < length(); i++) { + TreePermission tp = treePermission(i); + long supported = provider(i).supportedPermissions(tp, null, Permissions.READ_PROPERTY); + if (doEvaluate(supported)) { + readable = tp.canReadProperties(); + if (!readable) { + break; + } + } + } + return readable; + } } } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/Util.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/composite/Util.java (date 1556098069000) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/Util.java (date 1556098069000) @@ -0,0 +1,38 @@ +/* + * 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.composite; + +import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions; +import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class Util { + + private static final Logger log = LoggerFactory.getLogger(Util.class); + + private Util() {} + + static boolean doEvaluate(long supportedPermissions) { + return supportedPermissions != Permissions.NO_PERMISSION; + } + + static boolean doEvaluate(@NotNull PrivilegeBits supportedPrivileges) { + return !supportedPrivileges.isEmpty(); + } +} \ No newline at end of file Index: oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/AbstractCompositeProviderTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/AbstractCompositeProviderTest.java (revision 1858190) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/AbstractCompositeProviderTest.java (date 1556279479000) @@ -30,7 +30,6 @@ import org.apache.jackrabbit.oak.commons.PathUtils; import org.apache.jackrabbit.oak.plugins.memory.PropertyStates; import org.apache.jackrabbit.oak.plugins.tree.TreeUtil; -import org.apache.jackrabbit.oak.security.authorization.composite.CompositeAuthorizationConfiguration.CompositionType; import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants; import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration; import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider; @@ -252,8 +251,8 @@ CompositePermissionProvider createPermissionProvider(Set principals) { String workspaceName = root.getContentSession().getWorkspaceName(); AuthorizationConfiguration config = getConfig(AuthorizationConfiguration.class); - return new CompositePermissionProvider(root, getAggregatedProviders(workspaceName, config, principals), - config.getContext(), CompositionType.AND, getRootProvider(), getTreeProvider()); + return new CompositePermissionProviderAnd(root, getAggregatedProviders(workspaceName, config, principals), + config.getContext(), getRootProvider(), getTreeProvider()); } CompositePermissionProvider createPermissionProviderOR(Principal... principals) { @@ -263,8 +262,8 @@ CompositePermissionProvider createPermissionProviderOR(Set principals) { String workspaceName = root.getContentSession().getWorkspaceName(); AuthorizationConfiguration config = getConfig(AuthorizationConfiguration.class); - return new CompositePermissionProvider(root, getAggregatedProviders(workspaceName, config, principals), - config.getContext(), CompositionType.OR, getRootProvider(), getTreeProvider()); + return new CompositePermissionProviderOr(root, getAggregatedProviders(workspaceName, config, principals), + config.getContext(), getRootProvider(), getTreeProvider()); } @Test Index: oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeProviderCustomMixTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeProviderCustomMixTest.java (revision 1858190) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeProviderCustomMixTest.java (date 1556279479000) @@ -234,7 +234,7 @@ AuthorizationConfiguration config = getConfig(AuthorizationConfiguration.class); List composite = ImmutableList.of(a1, a2); - return new CompositePermissionProvider(root, composite, config.getContext(), type, getRootProvider(), getTreeProvider()); + return CompositePermissionProvider.create(root, composite, config.getContext(), type, getRootProvider(), getTreeProvider()); } private static class CustomProvider implements AggregatedPermissionProvider { Index: oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeProviderGetTreePermissionTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeProviderGetTreePermissionTest.java (revision 1858190) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeProviderGetTreePermissionTest.java (date 1556280114000) @@ -47,7 +47,7 @@ private CompositePermissionProvider createProvider(@NotNull CompositeAuthorizationConfiguration.CompositionType compositionType, @NotNull AggregatedPermissionProvider... providers) { - return new CompositePermissionProvider(root, ImmutableList.copyOf(providers), Context.DEFAULT, compositionType, getRootProvider(), getTreeProvider()); + return CompositePermissionProvider.create(root, ImmutableList.copyOf(providers), Context.DEFAULT, compositionType, getRootProvider(), getTreeProvider()); } @Test Index: oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeProviderSupportedTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeProviderSupportedTest.java (revision 1858190) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeProviderSupportedTest.java (date 1556280086000) @@ -89,7 +89,7 @@ } private CompositePermissionProvider createProvider(@NotNull CompositeAuthorizationConfiguration.CompositionType compositionType, @NotNull AggregatedPermissionProvider... aggregated) { - return new CompositePermissionProvider(root, ImmutableList.copyOf(aggregated), Context.DEFAULT, compositionType, getRootProvider(), getTreeProvider()); + return CompositePermissionProvider.create(root, ImmutableList.copyOf(aggregated), Context.DEFAULT, compositionType, getRootProvider(), getTreeProvider()); } @Test