Index: oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/AbortEvaluationAndTest.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/AbortEvaluationAndTest.java (date 1557315086000) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/AbortEvaluationAndTest.java (date 1557315086000) @@ -0,0 +1,590 @@ +/* + * 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 com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import org.apache.jackrabbit.oak.AbstractSecurityTest; +import org.apache.jackrabbit.oak.api.PropertyState; +import org.apache.jackrabbit.oak.api.Tree; +import org.apache.jackrabbit.oak.commons.PathUtils; +import org.apache.jackrabbit.oak.plugins.tree.TreeLocation; +import org.apache.jackrabbit.oak.plugins.tree.TreeType; +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.authorization.permission.TreePermission; +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.junit.Before; +import org.junit.Test; + +import javax.jcr.Session; + +import static org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_ADD_CHILD_NODES; +import static org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_NODE_TYPE_DEFINITION_MANAGEMENT; +import static org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_WRITE; +import static org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_ADD_PROPERTIES; +import static org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_PRIVILEGE_MANAGEMENT; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.withSettings; + +public class AbortEvaluationAndTest extends AbstractSecurityTest { + + AggregatedPermissionProvider app1; + AggregatedPermissionProvider app2; + AggregatedPermissionProvider app3; + + CompositePermissionProvider composite; + + @Before + public void before() throws Exception { + super.before(); + + app1 = createAggregatedProvider(false); + app2 = createAggregatedProvider(true); + app3 = createAggregatedProvider(false); + + composite = createComposite(app1, app2, app3); + } + + private static AggregatedPermissionProvider createAggregatedProvider(boolean doAbort) { + return when(mock(AggregatedPermissionProvider.class).abortEvaluation()).thenReturn(doAbort).getMock(); + } + + CompositePermissionProvider createComposite(AggregatedPermissionProvider... aggregated) { + return new CompositePermissionProviderAnd(root, ImmutableList.copyOf(aggregated), mock(Context.class), getRootProvider(), getTreeProvider()); + } + + boolean isGranted() { + return true; + } + + @Test + public void testRefresh() { + composite.refresh(); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + verify(app, times(1)).refresh(); + } + } + + @Test + public void testSupportedPrivileges() { + PrivilegeBits readBits = PrivilegeBits.BUILT_IN.get(PrivilegeConstants.JCR_READ); + PrivilegeBits wspBits = PrivilegeBits.BUILT_IN.get(PrivilegeConstants.JCR_WORKSPACE_MANAGEMENT); + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + when(app.supportedPrivileges(t, readBits)).thenReturn(readBits); + when(app.supportedPrivileges(null, wspBits)).thenReturn(wspBits); + } + + composite.supportedPrivileges(t, readBits); + composite.supportedPrivileges(null, wspBits); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2}) { + verify(app, times(1)).supportedPrivileges(t, readBits); + verify(app, times(1)).supportedPrivileges(null, wspBits); + } + verify(app3, never()).supportedPrivileges(t, readBits); + verify(app3, never()).supportedPrivileges(null, wspBits); + } + + @Test + public void testSupportedPermissions() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + when(app.supportedPermissions(t, null, Permissions.READ)).thenReturn(Permissions.READ); + } + composite.supportedPermissions(t, null, Permissions.READ); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2}) { + verify(app, times(1)).supportedPermissions(t, null, Permissions.READ); + } + verify(app3, never()).supportedPermissions(t, null, Permissions.READ); + } + + @Test + public void testSupportedPermissionsMissingEvaluation() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + long supported = (app == app2) ? Permissions.NO_PERMISSION : Permissions.READ; + when(app.supportedPermissions(t, null, Permissions.READ)).thenReturn(supported); + } + + composite.supportedPermissions(t, null, Permissions.READ); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app3}) { + verify(app, times(1)).supportedPermissions(t, null, Permissions.READ); + verify(app, times(1)).abortEvaluation(); + } + verify(app2, times(1)).supportedPermissions(t, null, Permissions.READ); + verify(app2, never()).abortEvaluation(); + } + + @Test + public void testSupportedPermissionsTreeLocation() { + TreeLocation tl = TreeLocation.create(getRootProvider().createReadOnlyRoot(root)).getChild("nonExisting"); + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + when(app.supportedPermissions(tl, Permissions.READ)).thenReturn(Permissions.READ); + } + + composite.supportedPermissions(tl, Permissions.READ); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2}) { + verify(app, times(1)).supportedPermissions(tl, Permissions.READ); + verify(app, times(1)).abortEvaluation(); + } + verify(app3, never()).supportedPermissions(tl, Permissions.READ); + verify(app3, never()).abortEvaluation(); + } + + @Test + public void testSupportedPermissionsTreeLocationMissingEvaluation() { + TreeLocation tl = TreeLocation.create(getRootProvider().createReadOnlyRoot(root)).getChild("nonExisting"); + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + long supported = (app == app2) ? Permissions.NO_PERMISSION : Permissions.READ; + when(app.supportedPermissions(tl, Permissions.READ)).thenReturn(supported); + } + + composite.supportedPermissions(tl, Permissions.READ); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app3}) { + verify(app, times(1)).supportedPermissions(tl, Permissions.READ); + verify(app, times(1)).abortEvaluation(); + } + verify(app2, times(1)).supportedPermissions(tl, Permissions.READ); + verify(app2, never()).abortEvaluation(); + } + + @Test + public void testSupportedPermissionsTreePermission() { + TreePermission tp = mock(TreePermission.class); + PropertyState prop = mock(PropertyState.class); + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + when(app.supportedPermissions(tp, prop, Permissions.READ_PROPERTY)).thenReturn(Permissions.READ_PROPERTY); + } + + composite.supportedPermissions(tp, prop, Permissions.READ_PROPERTY); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2}) { + verify(app, times(1)).supportedPermissions(tp, prop, Permissions.READ_PROPERTY); + verify(app, times(1)).abortEvaluation(); + } + verify(app3, never()).supportedPermissions(tp, prop, Permissions.READ_PROPERTY); + verify(app3, never()).abortEvaluation(); + } + + @Test + public void testSupportedPermissionsTreePermissionMissingEvaluation() { + TreePermission tp = mock(TreePermission.class); + PropertyState prop = mock(PropertyState.class); + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + long supported = (app == app2) ? Permissions.NO_PERMISSION : Permissions.READ; + when(app.supportedPermissions(tp, prop, Permissions.READ)).thenReturn(supported); + } + + composite.supportedPermissions(tp, prop, Permissions.READ); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app3}) { + verify(app, times(1)).supportedPermissions(tp, prop, Permissions.READ); + verify(app, times(1)).abortEvaluation(); + } + verify(app2, times(1)).supportedPermissions(tp, prop, Permissions.READ); + verify(app2, never()).abortEvaluation(); + } + + @Test + public void testHasPrivileges() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + + PrivilegeBits addBits = new PrivilegeBitsProvider(root).getBits(REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES); + PrivilegeBits privBits = PrivilegeBits.BUILT_IN.get(REP_PRIVILEGE_MANAGEMENT); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + when(app.supportedPrivileges(t, addBits)).thenReturn(addBits); + when(app.supportedPrivileges(null, privBits)).thenReturn(privBits); + + when(app.hasPrivileges(t, REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES)).thenReturn(isGranted()); + when(app.hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT)).thenReturn(isGranted()); + } + + composite.hasPrivileges(t, REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES); + composite.hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2}) { + verify(app, times(1)).hasPrivileges(t, REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES); + verify(app, times(1)).hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT); + verify(app, times(2)).abortEvaluation(); + } + verify(app3, never()).hasPrivileges(t, REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES); + verify(app3, never()).hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT); + verify(app3, never()).abortEvaluation(); + } + + @Test + public void testHasPrivilegesMissingEvaluation() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + + PrivilegeBits addBits = new PrivilegeBitsProvider(root).getBits(REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES); + PrivilegeBits privBits = PrivilegeBits.BUILT_IN.get(REP_PRIVILEGE_MANAGEMENT); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + PrivilegeBits supported = (app == app2) ? PrivilegeBits.EMPTY : addBits; + when(app.supportedPrivileges(t, addBits)).thenReturn(supported); + supported = (app == app2) ? PrivilegeBits.EMPTY : privBits; + when(app.supportedPrivileges(null, privBits)).thenReturn(supported); + + when(app.hasPrivileges(t, REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES)).thenReturn(isGranted()); + when(app.hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT)).thenReturn(isGranted()); + } + + composite.hasPrivileges(t, REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES); + composite.hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app3}) { + verify(app, times(1)).hasPrivileges(t, REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES); + verify(app, times(1)).hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT); + verify(app, times(2)).abortEvaluation(); + } + verify(app2, never()).hasPrivileges(t, REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES); + verify(app2, never()).hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT); + verify(app2, never()).abortEvaluation(); + } + + @Test + public void testGetPrivileges() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + when(app.supportedPrivileges(t, null)).thenReturn(PrivilegeBits.BUILT_IN.get(JCR_WRITE)); + when(app.supportedPrivileges(null, null)).thenReturn(PrivilegeBits.BUILT_IN.get(JCR_NODE_TYPE_DEFINITION_MANAGEMENT)); + + when(app.getPrivileges(t)).thenReturn(ImmutableSet.of(JCR_WRITE)); + when(app.getPrivileges(null)).thenReturn(ImmutableSet.of(PrivilegeConstants.JCR_NODE_TYPE_DEFINITION_MANAGEMENT)); + } + + composite.getPrivileges(t); + composite.getPrivileges(null); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2}) { + verify(app, times(1)).getPrivileges(t); + verify(app, times(1)).getPrivileges(null); + verify(app, times(2)).abortEvaluation(); + } + verify(app3, never()).getPrivileges(t); + verify(app3, never()).getPrivileges(null); + verify(app3, never()).abortEvaluation(); + } + + @Test + public void testGetPrivilegesMissingEvaluation() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + PrivilegeBits supported = (app == app2) ? PrivilegeBits.EMPTY : PrivilegeBits.BUILT_IN.get(JCR_WRITE); + when(app.supportedPrivileges(t, null)).thenReturn(supported); + supported = (app == app2) ? PrivilegeBits.EMPTY : PrivilegeBits.BUILT_IN.get(JCR_NODE_TYPE_DEFINITION_MANAGEMENT); + when(app.supportedPrivileges(null, null)).thenReturn(supported); + + when(app.getPrivileges(t)).thenReturn(ImmutableSet.of(JCR_WRITE)); + when(app.getPrivileges(null)).thenReturn(ImmutableSet.of(PrivilegeConstants.JCR_NODE_TYPE_DEFINITION_MANAGEMENT)); + } + + composite.getPrivileges(t); + composite.getPrivileges(null); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app3}) { + verify(app, times(1)).getPrivileges(t); + verify(app, times(1)).getPrivileges(null); + verify(app, times(2)).abortEvaluation(); + } + verify(app2, never()).getPrivileges(t); + verify(app2, never()).getPrivileges(null); + verify(app2, never()).abortEvaluation(); + } + + @Test + public void testIsGrantedTreeLocation() { + TreeLocation tl = TreeLocation.create(getRootProvider().createReadOnlyRoot(root)).getChild("nonExisting"); + long permissions = Permissions.READ; + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + when(app.supportedPermissions(tl, permissions)).thenReturn(permissions); + when(app.isGranted(tl, permissions)).thenReturn(isGranted()); + } + + composite.isGranted(tl, permissions); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2}) { + verify(app, times(1)).isGranted(tl, permissions); + verify(app, times(1)).abortEvaluation(); + } + verify(app3, never()).isGranted(tl, permissions); + verify(app3, never()).abortEvaluation(); + } + + @Test + public void testIsGrantedTreeLocationMissingEvaluation() { + TreeLocation tl = TreeLocation.create(getRootProvider().createReadOnlyRoot(root)).getChild("nonExisting"); + long permissions = Permissions.READ; + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + // since do-abort is only triggered if permissions are evaluated, app2 is ignored and do-abort has no effect + long supportedPermissions = (app == app2) ? Permissions.NO_PERMISSION : permissions; + when(app.supportedPermissions(tl, permissions)).thenReturn(supportedPermissions); + when(app.isGranted(tl, permissions)).thenReturn(isGranted()); + } + + composite.isGranted(tl, permissions); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app3}) { + verify(app, times(1)).isGranted(tl, permissions); + verify(app, times(1)).abortEvaluation(); + } + verify(app2, never()).isGranted(tl, permissions); + verify(app2, never()).abortEvaluation(); + } + + @Test + public void testIsGrantedPath() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + long permissions = Permissions.ADD_PROPERTY; + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + when(app.supportedPermissions(t, null, permissions)).thenReturn(permissions); + when(app.isGranted(t, null, permissions)).thenReturn(isGranted()); + } + + composite.isGranted(PathUtils.ROOT_PATH, Session.ACTION_SET_PROPERTY); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2}) { + verify(app, never()).isGranted(PathUtils.ROOT_PATH, Session.ACTION_SET_PROPERTY); + verify(app, times(1)).isGranted(t, null, permissions); + verify(app, times(1)).abortEvaluation(); + } + verify(app3, never()).isGranted(PathUtils.ROOT_PATH, Session.ACTION_SET_PROPERTY); + verify(app3, never()).isGranted(t, null, permissions); + verify(app3, never()).abortEvaluation(); + } + + @Test + public void testIsGrantedPathMissingEvaluation() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + long permissions = Permissions.ADD_PROPERTY; + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + // since do-abort is only triggered if permissions are evaluated, app2 is ignored and do-abort has no effect + long supportedPermissions = (app == app2) ? Permissions.NO_PERMISSION : permissions; + when(app.supportedPermissions(t, null, permissions)).thenReturn(supportedPermissions); + when(app.isGranted(t, null, permissions)).thenReturn(isGranted()); + } + + composite.isGranted(PathUtils.ROOT_PATH, Session.ACTION_SET_PROPERTY); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app3}) { + verify(app, never()).isGranted(PathUtils.ROOT_PATH, Session.ACTION_SET_PROPERTY); + verify(app, times(1)).isGranted(t, null, permissions); + verify(app, times(1)).abortEvaluation(); + } + verify(app2, never()).isGranted(PathUtils.ROOT_PATH, Session.ACTION_SET_PROPERTY); + verify(app2, never()).isGranted(t, null, permissions); + verify(app2, never()).abortEvaluation(); + } + + @Test + public void testIsGrantedTree() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + PropertyState propertyState = mock(PropertyState.class); + long permissions = Permissions.READ_ACCESS_CONTROL|Permissions.MODIFY_ACCESS_CONTROL; + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + when(app.supportedPermissions(t, propertyState, permissions)).thenReturn(permissions); + when(app.isGranted(t, propertyState, permissions)).thenReturn(isGranted()); + } + + composite.isGranted(t, propertyState, permissions); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2}) { + verify(app, times(1)).isGranted(t, propertyState, permissions); + verify(app, times(1)).abortEvaluation(); + } + verify(app3, never()).isGranted(t, propertyState, permissions); + verify(app3, never()).abortEvaluation(); + + } + + @Test + public void testIsGrantedTreeMissingEvaluation() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + PropertyState propertyState = mock(PropertyState.class); + long permissions = Permissions.READ_ACCESS_CONTROL|Permissions.MODIFY_ACCESS_CONTROL; + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + // since do-abort is only triggered if permissions are evaluated, app2 is ignored and do-abort has no effect + long supportedPermissions = (app == app2) ? Permissions.NO_PERMISSION : permissions; + when(app.supportedPermissions(t, propertyState, permissions)).thenReturn(supportedPermissions); + when(app.isGranted(t, propertyState, permissions)).thenReturn(isGranted()); + } + + composite.isGranted(t, propertyState, permissions); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app3}) { + verify(app, times(1)).isGranted(t, propertyState, permissions); + verify(app, times(1)).abortEvaluation(); + } + verify(app2, never()).isGranted(t, propertyState, permissions); + verify(app2, never()).abortEvaluation(); + } + + @Test + public void testGetRepositoryPermission() { + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + RepositoryPermission rp = mock(RepositoryPermission.class, withSettings().defaultAnswer(invocationOnMock -> Boolean.TRUE)); + when(app.getRepositoryPermission()).thenReturn(rp); + when(app.supportedPermissions((Tree)null, null, Permissions.WORKSPACE_MANAGEMENT)).thenReturn(Permissions.WORKSPACE_MANAGEMENT); + } + composite.getRepositoryPermission().isGranted(Permissions.WORKSPACE_MANAGEMENT); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2}) { + verify(app, times(1)).getRepositoryPermission(); + verify(app, times(1)).abortEvaluation(); + } + verify(app3, never()).getRepositoryPermission(); + verify(app3, never()).abortEvaluation(); + } + + @Test + public void testGetRepositoryPermissionMissingEvaluation() { + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + RepositoryPermission rp = mock(RepositoryPermission.class, withSettings().defaultAnswer(invocationOnMock -> Boolean.TRUE)); + when(app.getRepositoryPermission()).thenReturn(rp); + // since do-abort is only triggered if permissions are evaluated, app2 is ignored and do-abort has no effect + long supportedPermissions = (app == app2) ? Permissions.NO_PERMISSION : Permissions.WORKSPACE_MANAGEMENT; + when(app.supportedPermissions((Tree)null, null, Permissions.WORKSPACE_MANAGEMENT)).thenReturn(supportedPermissions); + } + composite.getRepositoryPermission().isGranted(Permissions.WORKSPACE_MANAGEMENT); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app3}) { + verify(app, times(1)).getRepositoryPermission(); + verify(app, times(1)).abortEvaluation(); + } + verify(app2, never()).getRepositoryPermission(); + verify(app2, never()).abortEvaluation(); + } + + @Test + public void testGetTreePermissionWithType() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + + composite.getTreePermission(t, TreeType.DEFAULT, TreePermission.EMPTY); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + verify(app, times(1)).getTreePermission(t, TreeType.DEFAULT, TreePermission.EMPTY); + } + } + + @Test + public void testGetTreePermission() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + + composite.getTreePermission(t, TreePermission.EMPTY); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + verify(app, times(1)).getTreePermission(t, TreeType.DEFAULT, TreePermission.EMPTY); + } + } + + @Test + public void testTreePermissionCanRead() { + TreePermission mock = getMockTreePermission(Permissions.ALL); + getCompositeTreePermission().canRead(); + + // only 2 of the 3 treepermissions in the composite gets called. + verify(mock, times(2)).canRead(); + } + + + @Test + public void testTreePermissionCanReadProperty() { + TreePermission mock = getMockTreePermission(Permissions.ALL); + when(mock.canReadProperties()).thenReturn(false); + + PropertyState prop = mock(PropertyState.class); + getCompositeTreePermission().canRead(prop); + + // only 2 of the 3 treepermissions in the composite gets called. + verify(mock, times(2)).canRead(prop); + } + + + @Test + public void testTreePermissionCanReadProperties() { + TreePermission mock = getMockTreePermission(Permissions.ALL); + getCompositeTreePermission().canReadProperties(); + + // only 2 of the 3 treepermissions in the composite gets called. + verify(mock, times(2)).canReadProperties(); + } + + @Test + public void testTreePermissionCanReadAll() { + TreePermission mock = getMockTreePermission(Permissions.ALL); + getCompositeTreePermission().canReadAll(); + + verify(mock, never()).canReadAll(); + } + + + @Test + public void testTreePermissionIsGranted() { + TreePermission mock = getMockTreePermission(Permissions.LOCK_MANAGEMENT); + getCompositeTreePermission().isGranted(Permissions.LOCK_MANAGEMENT); + + // only 2 of the 3 treepermissions in the composite gets called. + verify(mock, times(2)).isGranted(Permissions.LOCK_MANAGEMENT); + } + + private TreePermission getMockTreePermission(long supportedPermissions) { + TreePermission tp = mock(TreePermission.class, withSettings().defaultAnswer(invocationOnMock -> isGranted())); + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + when(app.getTreePermission(any(Tree.class), any(TreeType.class), any(TreePermission.class))).thenReturn(tp); + when(app.supportedPermissions(any(TreePermission.class), any(PropertyState.class), anyLong())).thenReturn(supportedPermissions); + when(app.supportedPermissions(any(TreePermission.class), isNull(), anyLong())).thenReturn(supportedPermissions); + } + return tp; + } + + private TreePermission getCompositeTreePermission() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + TreePermission compositeTp = composite.getTreePermission(t, TreeType.DEFAULT, TreePermission.EMPTY); + assertTrue(compositeTp instanceof CompositeTreePermission); + return compositeTp; + } +} \ No newline at end of file Index: oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/AbortEvaluationOrTest.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/AbortEvaluationOrTest.java (date 1557308892000) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/AbortEvaluationOrTest.java (date 1557308892000) @@ -0,0 +1,202 @@ +/* + * 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 com.google.common.collect.ImmutableList; +import org.apache.jackrabbit.oak.api.PropertyState; +import org.apache.jackrabbit.oak.api.Tree; +import org.apache.jackrabbit.oak.commons.PathUtils; +import org.apache.jackrabbit.oak.plugins.tree.TreeLocation; +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.privilege.PrivilegeBits; +import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider; +import org.junit.Test; + +import static org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_ADD_CHILD_NODES; +import static org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_ADD_PROPERTIES; +import static org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_PRIVILEGE_MANAGEMENT; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class AbortEvaluationOrTest extends AbortEvaluationAndTest { + + @Override + CompositePermissionProvider createComposite(AggregatedPermissionProvider... aggregated) { + return new CompositePermissionProviderOr(root, ImmutableList.copyOf(aggregated), mock(Context.class), getRootProvider(), getTreeProvider()); + } + + boolean isGranted() { + return false; + } + + @Test + public void testHasPrivileges() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + + PrivilegeBits addBits = new PrivilegeBitsProvider(root).getBits(REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES); + PrivilegeBits privBits = PrivilegeBits.BUILT_IN.get(REP_PRIVILEGE_MANAGEMENT); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + when(app.supportedPrivileges(t, addBits)).thenReturn(addBits); + when(app.supportedPrivileges(null, privBits)).thenReturn(privBits); + + when(app.hasPrivileges(t, REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES)).thenReturn(isGranted()); + when(app.hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT)).thenReturn(isGranted()); + } + + composite.hasPrivileges(t, REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES); + composite.hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2}) { + verify(app, times(1)).hasPrivileges(t, REP_ADD_PROPERTIES); + verify(app, times(1)).hasPrivileges(t, JCR_ADD_CHILD_NODES); + verify(app, times(1)).hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT); + verify(app, times(2)).abortEvaluation(); + } + verify(app3, never()).hasPrivileges(t, REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES); + verify(app3, never()).hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT); + verify(app3, never()).abortEvaluation(); + } + + @Test + public void testHasPrivilegesMissingEvaluation() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + + PrivilegeBits addBits = new PrivilegeBitsProvider(root).getBits(REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES); + PrivilegeBits privBits = PrivilegeBits.BUILT_IN.get(REP_PRIVILEGE_MANAGEMENT); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + PrivilegeBits supported = (app == app2) ? PrivilegeBits.EMPTY : addBits; + when(app.supportedPrivileges(t, addBits)).thenReturn(supported); + supported = (app == app2) ? PrivilegeBits.EMPTY : privBits; + when(app.supportedPrivileges(null, privBits)).thenReturn(supported); + + when(app.hasPrivileges(t, REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES)).thenReturn(isGranted()); + when(app.hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT)).thenReturn(isGranted()); + } + + composite.hasPrivileges(t, REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES); + composite.hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app3}) { + verify(app, times(1)).hasPrivileges(t, REP_ADD_PROPERTIES); + verify(app, times(1)).hasPrivileges(t, JCR_ADD_CHILD_NODES); + verify(app, times(1)).hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT); + verify(app, times(2)).abortEvaluation(); + } + verify(app2, never()).hasPrivileges(t, REP_ADD_PROPERTIES, JCR_ADD_CHILD_NODES); + verify(app2, never()).hasPrivileges(null, REP_PRIVILEGE_MANAGEMENT); + verify(app2, never()).abortEvaluation(); + } + + @Test + public void testIsGrantedTree() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + PropertyState propertyState = mock(PropertyState.class); + long permissions = Permissions.READ_ACCESS_CONTROL|Permissions.MODIFY_ACCESS_CONTROL; + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + when(app.supportedPermissions(t, propertyState, permissions)).thenReturn(permissions); + when(app.isGranted(t, propertyState, permissions)).thenReturn(isGranted()); + } + + composite.isGranted(t, propertyState, permissions); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2}) { + for (long aggr : Permissions.aggregates(permissions)) { + verify(app, times(1)).isGranted(t, propertyState, aggr); + } + } + verify(app3, never()).isGranted(t, propertyState, permissions); + } + + @Test + public void testIsGrantedTreeMissingEvaluation() { + Tree t = getRootProvider().createReadOnlyRoot(root).getTree(PathUtils.ROOT_PATH); + PropertyState propertyState = mock(PropertyState.class); + long permissions = Permissions.READ_ACCESS_CONTROL|Permissions.MODIFY_ACCESS_CONTROL; + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + // since do-abort is only triggered if permissions are evaluated, app2 is ignored and do-abort has no effect + long supportedPermissions = (app == app2) ? Permissions.NO_PERMISSION : permissions; + when(app.supportedPermissions(t, propertyState, permissions)).thenReturn(supportedPermissions); + when(app.isGranted(t, propertyState, permissions)).thenReturn(isGranted()); + } + + composite.isGranted(t, propertyState, permissions); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app3}) { + for (long aggr : Permissions.aggregates(permissions)) { + verify(app, times(1)).isGranted(t, propertyState, aggr); + } + verify(app, times(1)).abortEvaluation(); + } + verify(app2, never()).isGranted(t, propertyState, permissions); + verify(app2, never()).abortEvaluation(); + } + + @Test + public void testIsGrantedTreeLocation() { + TreeLocation tl = TreeLocation.create(getRootProvider().createReadOnlyRoot(root)).getChild("nonExisting"); + long permissions = Permissions.READ; + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + when(app.supportedPermissions(tl, permissions)).thenReturn(permissions); + when(app.isGranted(tl, permissions)).thenReturn(isGranted()); + } + + composite.isGranted(tl, permissions); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2}) { + for (long aggr : Permissions.aggregates(permissions)) { + verify(app, times(1)).isGranted(tl, aggr); + } + verify(app, times(1)).abortEvaluation(); + } + verify(app3, never()).isGranted(tl, permissions); + verify(app3, never()).abortEvaluation(); + } + + @Test + public void testIsGrantedTreeLocationMissingEvaluation() { + TreeLocation tl = TreeLocation.create(getRootProvider().createReadOnlyRoot(root)).getChild("nonExisting"); + long permissions = Permissions.READ; + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app2, app3}) { + // since do-abort is only triggered if permissions are evaluated, app2 is ignored and do-abort has no effect + long supportedPermissions = (app == app2) ? Permissions.NO_PERMISSION : permissions; + when(app.supportedPermissions(tl, permissions)).thenReturn(supportedPermissions); + when(app.isGranted(tl, permissions)).thenReturn(isGranted()); + } + + composite.isGranted(tl, permissions); + + for (AggregatedPermissionProvider app : new AggregatedPermissionProvider[] {app1, app3}) { + for (long aggr : Permissions.aggregates(permissions)) { + verify(app, times(1)).isGranted(tl, aggr); + } + verify(app, times(1)).abortEvaluation(); + } + verify(app2, never()).isGranted(tl, permissions); + verify(app2, never()).abortEvaluation(); + } +} \ No newline at end of file