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 1859230) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeAuthorizationConfiguration.java (date 1557900480000) @@ -30,6 +30,7 @@ import org.apache.jackrabbit.oak.spi.security.SecurityProvider; import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration; import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregationFilter; import org.apache.jackrabbit.oak.spi.security.authorization.permission.EmptyPermissionProvider; import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider; import org.apache.jackrabbit.oak.spi.security.authorization.restriction.CompositeRestrictionProvider; @@ -112,6 +113,8 @@ private CompositionType compositionType = CompositionType.AND; + private AggregationFilter aggregationFilter = AggregationFilter.DEFAULT; + public CompositeAuthorizationConfiguration() { super(AuthorizationConfiguration.NAME); } @@ -124,6 +127,10 @@ this.compositionType = CompositionType.fromString(ct); } + public void withAggregationFilter(@NotNull AggregationFilter aggregationFilter) { + this.aggregationFilter = aggregationFilter; + } + @NotNull @Override public AccessControlManager getAccessControlManager(@NotNull final Root root, @@ -172,7 +179,11 @@ for (AuthorizationConfiguration conf : configurations) { PermissionProvider pProvider = conf.getPermissionProvider(root, workspaceName, principals); if (pProvider instanceof AggregatedPermissionProvider) { - aggrPermissionProviders.add((AggregatedPermissionProvider) pProvider); + AggregatedPermissionProvider aggrProvider = (AggregatedPermissionProvider) pProvider; + aggrPermissionProviders.add(aggrProvider); + if (aggregationFilter.stop(aggrProvider, principals)) { + break; + } } else { log.debug("Ignoring permission provider of '{}': Not an AggregatedPermissionProvider", conf.getClass().getName()); } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/internal/SecurityProviderRegistration.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/internal/SecurityProviderRegistration.java (revision 1859230) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/internal/SecurityProviderRegistration.java (date 1557900480000) @@ -49,6 +49,7 @@ import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenConfiguration; import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration; import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregationFilter; import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider; import org.apache.jackrabbit.oak.spi.security.principal.CompositePrincipalConfiguration; import org.apache.jackrabbit.oak.spi.security.principal.PrincipalConfiguration; @@ -156,6 +157,7 @@ private final SortedMap authorizableActionProviders = Collections.synchronizedSortedMap(new TreeMap<>()); private final SortedMap restrictionProviders = Collections.synchronizedSortedMap(new TreeMap<>()); private final SortedMap userAuthenticationFactories = Collections.synchronizedSortedMap(new TreeMap<>()); + private final SortedMap aggregationFilters = Collections.synchronizedSortedMap(new TreeMap<>()); private RootProvider rootProvider; private TreeProvider treeProvider; @@ -421,6 +423,26 @@ removeCandidate(serviceReference); } + maybeUnregister(); + } + + @Reference( + name = "aggregationFilters", service = AggregationFilter.class, + cardinality = ReferenceCardinality.MULTIPLE, + policy = ReferencePolicy.DYNAMIC) + public void bindAggregationFilter(@NotNull ServiceReference serviceReference, @NotNull AggregationFilter aggregationFilter) { + synchronized (this) { + aggregationFilters.put(serviceReference, aggregationFilter); + addCandidate(serviceReference); + } + maybeRegister(); + } + + public void unbindAggregationFilter(@NotNull ServiceReference serviceReference, @NotNull AggregationFilter aggregationFilter) { + synchronized (this) { + aggregationFilters.remove(serviceReference); + removeCandidate(serviceReference); + } maybeUnregister(); } @@ -557,6 +579,7 @@ ConfigurationParameters authorizationParams = ConfigurationParameters .of(AccessControlConstants.PARAM_RESTRICTION_PROVIDER, createWhiteboardRestrictionProvider()); + authorizationConfiguration.withAggregationFilter(createAggregationFilter()); return SecurityProviderBuilder.newBuilder().withRootProvider(rootProvider).withTreeProvider(treeProvider) .with(authenticationConfiguration, EMPTY, privilegeConfiguration, EMPTY, userConfiguration, userParams, @@ -621,6 +644,25 @@ }; } + private AggregationFilter createAggregationFilter() { + List filters; + synchronized (aggregationFilters) { + filters = newArrayList(aggregationFilters.values()); + } + switch (filters.size()) { + case 0: return AggregationFilter.DEFAULT; + case 1: return filters.get(0); + default: return (permissionProvider, principals) -> { + for (AggregationFilter f : filters) { + if (f.stop(permissionProvider, principals)) { + return true; + } + } + return false; + }; + } + } + private void addCandidate(Map properties) { String pidOrName = getServicePidOrComponentName(properties); Index: oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeAuthorizationConfigurationTest.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/CompositeAuthorizationConfigurationTest.java (revision 1859230) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/composite/CompositeAuthorizationConfigurationTest.java (date 1557900480000) @@ -16,31 +16,42 @@ */ package org.apache.jackrabbit.oak.security.authorization.composite; -import java.security.Principal; -import java.util.Collections; - -import javax.jcr.RepositoryException; -import javax.jcr.security.AccessControlManager; - +import com.google.common.collect.ImmutableSet; import org.apache.jackrabbit.oak.AbstractSecurityTest; +import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.namepath.NamePathMapper; import org.apache.jackrabbit.oak.security.authorization.AuthorizationConfigurationImpl; import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters; +import org.apache.jackrabbit.oak.spi.security.Context; import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration; import org.apache.jackrabbit.oak.spi.security.authorization.OpenAuthorizationConfiguration; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregationFilter; import org.apache.jackrabbit.oak.spi.security.authorization.permission.EmptyPermissionProvider; import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider; import org.apache.jackrabbit.oak.spi.security.authorization.restriction.CompositeRestrictionProvider; import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider; +import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal; import org.jetbrains.annotations.NotNull; import org.junit.Test; -import org.mockito.Mockito; + +import javax.jcr.RepositoryException; +import javax.jcr.security.AccessControlManager; +import java.security.Principal; +import java.util.Collections; +import java.util.Set; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +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 CompositeAuthorizationConfigurationTest extends AbstractSecurityTest { @@ -146,8 +157,8 @@ public void testMultipleRestrictionProvider() { // 2 authorization configuration with different RestrictionProvider AuthorizationConfiguration ac = createAuthorizationConfigurationImpl(); - AuthorizationConfiguration ac2 = Mockito.mock(AuthorizationConfiguration.class); - when(ac2.getRestrictionProvider()).thenReturn(Mockito.mock(RestrictionProvider.class)); + AuthorizationConfiguration ac2 = mock(AuthorizationConfiguration.class); + when(ac2.getRestrictionProvider()).thenReturn(mock(RestrictionProvider.class)); when(ac2.getParameters()).thenReturn(ConfigurationParameters.EMPTY); CompositeAuthorizationConfiguration cc = getCompositeConfiguration(ac, ac2); @@ -160,7 +171,7 @@ public void testRedundantRestrictionProvider() { // 2 authorization configuration sharing the same RestrictionProvider AuthorizationConfiguration ac = createAuthorizationConfigurationImpl(); - AuthorizationConfiguration ac2 = Mockito.mock(AuthorizationConfiguration.class); + AuthorizationConfiguration ac2 = mock(AuthorizationConfiguration.class); when(ac2.getRestrictionProvider()).thenReturn(ac.getRestrictionProvider()); when(ac2.getParameters()).thenReturn(ConfigurationParameters.EMPTY); @@ -204,4 +215,47 @@ assertFalse(rp instanceof CompositeRestrictionProvider); assertSame(RestrictionProvider.EMPTY, rp); } + + @Test + public void testDefaultEvaluationFilter() { + PermissionProvider pp = mock(PermissionProvider.class, withSettings().extraInterfaces(AggregatedPermissionProvider.class)); + AuthorizationConfiguration ac1 = mock(AuthorizationConfiguration.class); + AuthorizationConfiguration ac2 = mock(AuthorizationConfiguration.class); + for (AuthorizationConfiguration ac : new AuthorizationConfiguration[] {ac1, ac2}) { + when(ac.getPermissionProvider(any(Root.class), anyString(), any(Set.class))).thenReturn(pp); + when(ac.getParameters()).thenReturn(ConfigurationParameters.EMPTY); + when(ac.getContext()).thenReturn(Context.DEFAULT); + } + CompositeAuthorizationConfiguration cc = getCompositeConfiguration(ac1, ac2); + PermissionProvider permissionProvider = cc.getPermissionProvider(root, adminSession.getWorkspaceName(), ImmutableSet.of(EveryonePrincipal.getInstance())); + permissionProvider.refresh(); + + verify(pp, times(2)).refresh(); + } + + @Test + public void testAbortigEvaluationFilter() { + Set principalSet = ImmutableSet.of(EveryonePrincipal.getInstance()); + AggregatedPermissionProvider pp = mock(AggregatedPermissionProvider.class); + AggregationFilter filter = when(mock(AggregationFilter.class).stop(pp, principalSet)).thenReturn(true).getMock(); + + AuthorizationConfiguration ac1 = mock(AuthorizationConfiguration.class); + AuthorizationConfiguration ac2 = mock(AuthorizationConfiguration.class); + for (AuthorizationConfiguration ac : new AuthorizationConfiguration[] {ac1, ac2}) { + when(ac.getPermissionProvider(any(Root.class), anyString(), any(Set.class))).thenReturn(pp); + when(ac.getParameters()).thenReturn(ConfigurationParameters.EMPTY); + when(ac.getContext()).thenReturn(Context.DEFAULT); + } + CompositeAuthorizationConfiguration cc = getCompositeConfiguration(ac1, ac2); + cc.withAggregationFilter(filter); + + PermissionProvider permissionProvider = cc.getPermissionProvider(root, adminSession.getWorkspaceName(), principalSet); + permissionProvider.refresh(); + + Set nonMatchingSet = adminSession.getAuthInfo().getPrincipals(); + permissionProvider = cc.getPermissionProvider(root, adminSession.getWorkspaceName(), nonMatchingSet); + permissionProvider.refresh(); + + verify(pp, times(3)).refresh(); + } } Index: oak-core/src/test/java/org/apache/jackrabbit/oak/security/internal/SecurityProviderRegistrationTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/security/internal/SecurityProviderRegistrationTest.java (revision 1859230) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/security/internal/SecurityProviderRegistrationTest.java (date 1557849263000) @@ -19,8 +19,10 @@ import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import org.apache.jackrabbit.oak.AbstractSecurityTest; +import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.plugins.memory.PropertyStates; import org.apache.jackrabbit.oak.plugins.tree.RootProvider; @@ -48,6 +50,9 @@ import org.apache.jackrabbit.oak.spi.security.authentication.token.CompositeTokenConfiguration; import org.apache.jackrabbit.oak.spi.security.authentication.token.TokenConfiguration; import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregationFilter; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider; import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider; import org.apache.jackrabbit.oak.spi.security.principal.CompositePrincipalConfiguration; import org.apache.jackrabbit.oak.spi.security.principal.PrincipalConfiguration; @@ -72,6 +77,7 @@ import java.util.Hashtable; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.SortedMap; import static org.apache.jackrabbit.oak.spi.security.RegistrationConstants.OAK_SECURITY_NAME; @@ -82,12 +88,15 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; 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; import static org.osgi.framework.Constants.SERVICE_PID; +import static org.osgi.framework.Constants.SERVICE_RANKING; public class SecurityProviderRegistrationTest extends AbstractSecurityTest { @@ -850,4 +859,131 @@ registration.unbindTreeProvider(tp); assertNull(f.get(registration)); } + + @Test + public void testBindEvaluationFilter() { + registration.activate(context.bundleContext(), configWithRequiredServiceIds("filterId", "a1", "a2")); + + AggregationFilter filter = mock(AggregationFilter.class, withSettings().defaultAnswer(invocationOnMock -> Boolean.TRUE)); + ServiceRegistration sr = context.bundleContext().registerService(AggregationFilter.class.getName(), filter, new Hashtable(ImmutableMap.of(SERVICE_PID, "filterId"))); + registration.bindAggregationFilter(sr.getReference(), filter); + + AggregatedPermissionProvider pp = mock(AggregatedPermissionProvider.class); + AuthorizationConfiguration ac1 = mock(AuthorizationConfiguration.class); + AuthorizationConfiguration ac2 = mock(AuthorizationConfiguration.class); + for (AuthorizationConfiguration ac : new AuthorizationConfiguration[]{ac1, ac2}) { + when(ac.getPermissionProvider(any(Root.class), anyString(), any(Set.class))).thenReturn(pp); + when(ac.getParameters()).thenReturn(ConfigurationParameters.EMPTY); + when(ac.getContext()).thenReturn(Context.DEFAULT); + } + + registration.bindAuthorizationConfiguration(ac1, new Hashtable(ImmutableMap.of(SERVICE_PID, "a1"))); + registration.bindAuthorizationConfiguration(ac2, new Hashtable(ImmutableMap.of(SERVICE_PID, "a2"))); + + SecurityProvider service = context.getService(SecurityProvider.class); + + AuthorizationConfiguration ac = service.getConfiguration(AuthorizationConfiguration.class); + assertTrue(ac instanceof CompositeAuthorizationConfiguration); + + PermissionProvider permissionProvider = ac.getPermissionProvider(root, adminSession.getWorkspaceName(), ImmutableSet.of()); + assertSame(pp, permissionProvider); + verify(filter, times(1)).stop(pp, ImmutableSet.of()); + } + + @Test + public void testUnbindEvaluationFilter() { + registration.activate(context.bundleContext(), configWithRequiredServiceIds("a1", "a2", "f1")); + + AggregationFilter filter = mock(AggregationFilter.class, withSettings().defaultAnswer(invocationOnMock -> Boolean.TRUE)); + ServiceRegistration sr = context.bundleContext().registerService(AggregationFilter.class.getName(), filter, new Hashtable(ImmutableMap.of(SERVICE_PID, "f1"))); + registration.bindAggregationFilter(sr.getReference(), filter); + + AggregatedPermissionProvider pp = mock(AggregatedPermissionProvider.class); + AuthorizationConfiguration ac1 = mock(AuthorizationConfiguration.class); + AuthorizationConfiguration ac2 = mock(AuthorizationConfiguration.class); + for (AuthorizationConfiguration ac : new AuthorizationConfiguration[]{ac1, ac2}) { + when(ac.getPermissionProvider(any(Root.class), anyString(), any(Set.class))).thenReturn(pp); + when(ac.getParameters()).thenReturn(ConfigurationParameters.EMPTY); + when(ac.getContext()).thenReturn(Context.DEFAULT); + } + + registration.bindAuthorizationConfiguration(ac1, new Hashtable(ImmutableMap.of(SERVICE_PID, "a1"))); + registration.bindAuthorizationConfiguration(ac2, new Hashtable(ImmutableMap.of(SERVICE_PID, "a2"))); + + AuthorizationConfiguration ac = context.getService(SecurityProvider.class).getConfiguration(AuthorizationConfiguration.class); + assertTrue(ac instanceof CompositeAuthorizationConfiguration); + + PermissionProvider permissionProvider = ac.getPermissionProvider(root, adminSession.getWorkspaceName(), ImmutableSet.of()); + assertSame(pp, permissionProvider); + verify(filter, times(1)).stop(pp, ImmutableSet.of()); + + registration.unbindAggregationFilter(sr.getReference(), filter); + assertNull(context.getService(SecurityProvider.class)); + + registration.modified(configWithRequiredServiceIds("a1", "a2")); + + context.getService(SecurityProvider.class).getConfiguration(AuthorizationConfiguration.class).getPermissionProvider(root, adminSession.getWorkspaceName(), ImmutableSet.of()); + // since unbind was called on filter -> no additional calls + verify(filter, times(1)).stop(pp, ImmutableSet.of()); + } + + @Test + public void testMultipleEvaluationFilterFalse() throws Exception { + registration.activate(context.bundleContext(), configWithRequiredServiceIds("f1", "f2", "ac1", "ac2")); + + AggregationFilter filter1 = mock(AggregationFilter.class, withSettings().defaultAnswer(invocationOnMock -> Boolean.FALSE)); + ServiceRegistration sr1 = context.bundleContext().registerService(AggregationFilter.class.getName(), filter1, new Hashtable(ImmutableMap.of(SERVICE_PID, "f1", SERVICE_RANKING, 100))); + registration.bindAggregationFilter(sr1.getReference(), filter1); + + AggregationFilter filter2 = mock(AggregationFilter.class, withSettings().defaultAnswer(invocationOnMock -> Boolean.FALSE)); + ServiceRegistration sr2 = context.bundleContext().registerService(AggregationFilter.class.getName(), filter2, new Hashtable(ImmutableMap.of(SERVICE_PID, "f2", SERVICE_RANKING, 200))); + registration.bindAggregationFilter(sr2.getReference(), filter2); + + AggregatedPermissionProvider pp = mock(AggregatedPermissionProvider.class); + AuthorizationConfiguration ac1 = mock(AuthorizationConfiguration.class); + AuthorizationConfiguration ac2 = mock(AuthorizationConfiguration.class); + for (AuthorizationConfiguration ac : new AuthorizationConfiguration[]{ac1, ac2}) { + when(ac.getPermissionProvider(any(Root.class), anyString(), any(Set.class))).thenReturn(pp); + when(ac.getParameters()).thenReturn(ConfigurationParameters.EMPTY); + when(ac.getContext()).thenReturn(Context.DEFAULT); + } + registration.bindAuthorizationConfiguration(ac1, new Hashtable(ImmutableMap.of(SERVICE_PID, "ac1"))); + registration.bindAuthorizationConfiguration(ac2, new Hashtable(ImmutableMap.of(SERVICE_PID, "ac2"))); + + AuthorizationConfiguration config = context.getService(SecurityProvider.class).getConfiguration(AuthorizationConfiguration.class); + PermissionProvider permissionProvider = config.getPermissionProvider(root, adminSession.getWorkspaceName(), ImmutableSet.of()); + + verify(filter1, times(2)).stop(pp, ImmutableSet.of()); + verify(filter2, times(2)).stop(pp, ImmutableSet.of()); + } + + @Test + public void testMultipleEvaluationFilterTrue() throws Exception { + registration.activate(context.bundleContext(), configWithRequiredServiceIds("f1", "f2", "ac1", "ac2")); + + AggregationFilter filter1 = mock(AggregationFilter.class, withSettings().defaultAnswer(invocationOnMock -> Boolean.TRUE)); + ServiceRegistration sr1 = context.bundleContext().registerService(AggregationFilter.class.getName(), filter1, new Hashtable(ImmutableMap.of(SERVICE_PID, "f1", SERVICE_RANKING, 200))); + registration.bindAggregationFilter(sr1.getReference(), filter1); + + AggregationFilter filter2 = mock(AggregationFilter.class, withSettings().defaultAnswer(invocationOnMock -> Boolean.TRUE)); + ServiceRegistration sr2 = context.bundleContext().registerService(AggregationFilter.class.getName(), filter2, new Hashtable(ImmutableMap.of(SERVICE_PID, "f2", SERVICE_RANKING, 100))); + registration.bindAggregationFilter(sr2.getReference(), filter2); + + AggregatedPermissionProvider pp = mock(AggregatedPermissionProvider.class); + AuthorizationConfiguration ac1 = mock(AuthorizationConfiguration.class); + AuthorizationConfiguration ac2 = mock(AuthorizationConfiguration.class); + for (AuthorizationConfiguration ac : new AuthorizationConfiguration[]{ac1, ac2}) { + when(ac.getPermissionProvider(any(Root.class), anyString(), any(Set.class))).thenReturn(pp); + when(ac.getParameters()).thenReturn(ConfigurationParameters.EMPTY); + when(ac.getContext()).thenReturn(Context.DEFAULT); + } + registration.bindAuthorizationConfiguration(ac1, new Hashtable(ImmutableMap.of(SERVICE_PID, "ac1"))); + registration.bindAuthorizationConfiguration(ac2, new Hashtable(ImmutableMap.of(SERVICE_PID, "ac2"))); + + AuthorizationConfiguration config = context.getService(SecurityProvider.class).getConfiguration(AuthorizationConfiguration.class); + PermissionProvider permissionProvider = config.getPermissionProvider(root, adminSession.getWorkspaceName(), ImmutableSet.of()); + + verify(filter1, never()).stop(pp, ImmutableSet.of()); + verify(filter2, times(1)).stop(pp, ImmutableSet.of()); + } } Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/AggregationFilter.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/authorization/permission/AggregationFilter.java (date 1557849357000) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/AggregationFilter.java (date 1557849357000) @@ -0,0 +1,40 @@ +/* + * 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.authorization.permission; + +import org.jetbrains.annotations.NotNull; + +import java.security.Principal; +import java.util.Set; + +public interface AggregationFilter { + + /** + * + * @param permissionProvider + * @param principals + * @return {@code true} if aggregation of permission providers should be stopped after the given {@code permissionProvider} + * created for the given set of {@code principals}. + */ + boolean stop(AggregatedPermissionProvider permissionProvider, @NotNull Set principals); + + /** + * Default implementation of the {@code AggregationFilter} interface that handles all combinations of permission + * providers and principals and never aborts the evaluation. + */ + AggregationFilter DEFAULT = (permissionProvider, principals) -> false; +} \ No newline at end of file Index: oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/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/authorization/permission/package-info.java (revision 1859230) +++ oak-security-spi/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/package-info.java (date 1557839761000) @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("4.1.0") +@Version("4.2.0") package org.apache.jackrabbit.oak.spi.security.authorization.permission; import org.osgi.annotation.versioning.Version;