You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2014/07/30 17:38:27 UTC
svn commit: r1614686 - in /jackrabbit/oak/trunk/oak-core/src:
main/java/org/apache/jackrabbit/oak/core/
main/java/org/apache/jackrabbit/oak/security/authorization/
main/java/org/apache/jackrabbit/oak/security/authorization/permission/
main/java/org/apa...
Author: angela
Date: Wed Jul 30 15:38:27 2014
New Revision: 1614686
URL: http://svn.apache.org/r1614686
Log:
OAK-1268 : Add support for composite authorization setup (untested, wip)
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/CompositeAccessControlManager.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/AggregatedPermissionProvider.java (with props)
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/CompositePermissionProvider.java (with props)
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/ControlFlag.java (with props)
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/EmptyPermissionProvider.java
- copied, changed from r1603387, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/OpenPermissionProvider.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/CompositeConfigurationTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/CompositePermissionProviderTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableRoot.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/CompositeAuthorizationConfiguration.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/Permissions.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBits.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionsTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBitsTest.java
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableRoot.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableRoot.java?rev=1614686&r1=1614685&r2=1614686&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableRoot.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/ImmutableRoot.java Wed Jul 30 15:38:27 2014
@@ -67,6 +67,14 @@ public final class ImmutableRoot impleme
this.rootTree = rootTree;
}
+ public static ImmutableRoot getInstance(@Nonnull Root root) {
+ if (root instanceof ImmutableRoot) {
+ return (ImmutableRoot) root;
+ } else {
+ return new ImmutableRoot(root);
+ }
+ }
+
//---------------------------------------------------------------< Root >---
@Nonnull
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java?rev=1614686&r1=1614685&r2=1614686&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/AuthorizationConfigurationImpl.java Wed Jul 30 15:38:27 2014
@@ -48,6 +48,7 @@ import org.apache.jackrabbit.oak.spi.com
import org.apache.jackrabbit.oak.spi.commit.MoveTracker;
import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
import org.apache.jackrabbit.oak.spi.lifecycle.WorkspaceInitializer;
+import org.apache.jackrabbit.oak.spi.security.CompositeConfiguration;
import org.apache.jackrabbit.oak.spi.security.ConfigurationBase;
import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
import org.apache.jackrabbit.oak.spi.security.Context;
@@ -55,6 +56,8 @@ import org.apache.jackrabbit.oak.spi.sec
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.accesscontrol.AccessControlConstants;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.ControlFlag;
import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
@@ -95,7 +98,19 @@ import org.apache.jackrabbit.oak.spi.xml
@Property(name = PermissionConstants.PARAM_ADMINISTRATIVE_PRINCIPALS,
label = "Administrative Principals",
description = "Allows to specify principals that should be granted full permissions on the complete repository content.",
- cardinality = 10)
+ cardinality = 10),
+ @Property(name = CompositeConfiguration.PARAM_RANKING,
+ label = "Ranking",
+ description = "Ranking of this configuration in a setup with multiple authorization configurations.",
+ intValue = 100),
+ @Property(name = AggregatedPermissionProvider.PARAM_CONTROL_FLAG,
+ label = "Control Flag",
+ description = "Control flag defining if the permission provider is SUFFICIENT or REQUIRED.",
+ options = {
+ @PropertyOption(name = ControlFlag.SUFFICIENT_NAME, value = ControlFlag.SUFFICIENT_NAME),
+ @PropertyOption(name = ControlFlag.REQUISITE_NAME, value = ControlFlag.REQUISITE_NAME)
+ },
+ value = ControlFlag.REQUISITE_NAME)
})
public class AuthorizationConfigurationImpl extends ConfigurationBase implements AuthorizationConfiguration {
public AuthorizationConfigurationImpl() {
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java?rev=1614686&r1=1614685&r2=1614686&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionProviderImpl.java Wed Jul 30 15:38:27 2014
@@ -32,6 +32,8 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.plugins.version.VersionConstants;
import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.ControlFlag;
import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions;
@@ -40,7 +42,7 @@ import org.apache.jackrabbit.oak.spi.sec
import org.apache.jackrabbit.oak.spi.security.principal.AdminPrincipal;
import org.apache.jackrabbit.oak.spi.security.principal.SystemPrincipal;
-public class PermissionProviderImpl implements PermissionProvider, AccessControlConstants, PermissionConstants {
+public class PermissionProviderImpl implements PermissionProvider, AccessControlConstants, PermissionConstants, AggregatedPermissionProvider {
private final Root root;
@@ -52,6 +54,8 @@ public class PermissionProviderImpl impl
private ImmutableRoot immutableRoot;
+ private ControlFlag flag;
+
public PermissionProviderImpl(@Nonnull Root root, @Nonnull String workspaceName, @Nonnull Set<Principal> principals,
@Nonnull AuthorizationConfiguration acConfig) {
this.root = root;
@@ -65,6 +69,8 @@ public class PermissionProviderImpl impl
} else {
compiledPermissions = CompiledPermissionImpl.create(immutableRoot, workspaceName, principals, acConfig);
}
+
+ flag = ControlFlag.valueOf(acConfig.getParameters().getConfigValue(AggregatedPermissionProvider.PARAM_CONTROL_FLAG, ControlFlag.REQUISITE_NAME));
}
@Override
@@ -116,6 +122,37 @@ public class PermissionProviderImpl impl
return isGranted;
}
+ //---------------------------------------< AggregatedPermissionProvider >---
+ @Override
+ public ControlFlag getFlag() {
+ return flag;
+ }
+
+ @Override
+ public boolean handles(@Nonnull String path, @Nonnull String jcrAction) {
+ return true;
+ }
+
+ @Override
+ public boolean handles(@Nonnull Tree tree) {
+ return true;
+ }
+
+ @Override
+ public boolean handles(@Nonnull Tree tree, long permission) {
+ return true;
+ }
+
+ @Override
+ public boolean handles(@Nonnull TreePermission treePermission, long permission) {
+ return true;
+ }
+
+ @Override
+ public boolean handlesRepositoryPermissions() {
+ return true;
+ }
+
//--------------------------------------------------------------------------
private boolean isAdmin(Set<Principal> principals) {
@@ -137,11 +174,7 @@ public class PermissionProviderImpl impl
}
private static ImmutableRoot getImmutableRoot(@Nonnull Root base) {
- if (base instanceof ImmutableRoot) {
- return (ImmutableRoot) base;
- } else {
- return new ImmutableRoot(base);
- }
+ return ImmutableRoot.getInstance(base);
}
private static boolean isVersionStorePath(@Nonnull String oakPath) {
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java?rev=1614686&r1=1614685&r2=1614686&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java Wed Jul 30 15:38:27 2014
@@ -48,6 +48,19 @@ import org.apache.jackrabbit.oak.plugins
*/
public abstract class CompositeConfiguration<T extends SecurityConfiguration> implements SecurityConfiguration {
+ /**
+ * Parameter used to define the ranking of a given configuration compared to
+ * other registered configuration in this aggregate. If the ranking parameter
+ * is missing a new configuration will be added at the end of the list.
+ */
+ public static final String PARAM_RANKING = "configurationRanking";
+
+ /**
+ * Default ranking value used to insert a new configuration at the end of
+ * the list.
+ */
+ private static final int NO_RANKING = Integer.MIN_VALUE;
+
private final List<T> configurations = new CopyOnWriteArrayList<T>();
private final String name;
@@ -65,7 +78,21 @@ public abstract class CompositeConfigura
}
public void addConfiguration(@Nonnull T configuration) {
- configurations.add(configuration);
+ int ranking = configuration.getParameters().getConfigValue(PARAM_RANKING, NO_RANKING);
+ if (ranking == NO_RANKING || configurations.isEmpty()) {
+ configurations.add(configuration);
+ } else {
+ int i = 0;
+ for (T c : configurations) {
+ int r = c.getParameters().getConfigValue(PARAM_RANKING, NO_RANKING);
+ if (ranking > r) {
+ break;
+ } else {
+ i++;
+ }
+ }
+ configurations.add(i, configuration);
+ }
}
public void removeConfiguration(@Nonnull T configuration) {
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/CompositeAuthorizationConfiguration.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/CompositeAuthorizationConfiguration.java?rev=1614686&r1=1614685&r2=1614686&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/CompositeAuthorizationConfiguration.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/CompositeAuthorizationConfiguration.java Wed Jul 30 15:38:27 2014
@@ -20,26 +20,17 @@ import java.security.Principal;
import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;
-import javax.jcr.RepositoryException;
-import javax.jcr.security.AccessControlException;
import javax.jcr.security.AccessControlManager;
-import javax.jcr.security.AccessControlPolicy;
-import javax.jcr.security.AccessControlPolicyIterator;
-import javax.jcr.security.Privilege;
import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
-import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
-import org.apache.jackrabbit.api.security.JackrabbitAccessControlPolicy;
-import org.apache.jackrabbit.commons.iterator.AccessControlPolicyIteratorAdapter;
import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.namepath.NamePathMapper;
import org.apache.jackrabbit.oak.spi.security.CompositeConfiguration;
import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
-import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AbstractAccessControlManager;
-import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.PolicyOwner;
+import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.CompositeAccessControlManager;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.CompositePermissionProvider;
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;
@@ -60,13 +51,20 @@ public class CompositeAuthorizationConfi
@Override
public AccessControlManager getAccessControlManager(final @Nonnull Root root,
final @Nonnull NamePathMapper namePathMapper) {
- List<AccessControlManager> mgrs = Lists.transform(getConfigurations(), new Function<AuthorizationConfiguration, AccessControlManager>() {
- @Override
- public AccessControlManager apply(AuthorizationConfiguration authorizationConfiguration) {
- return authorizationConfiguration.getAccessControlManager(root, namePathMapper);
- }
- });
- return new CompositeAcMgr(root, namePathMapper, getSecurityProvider(), mgrs);
+ List<AuthorizationConfiguration> configurations = getConfigurations();
+ switch (configurations.size()) {
+ case 0: throw new IllegalArgumentException();
+ case 1: return configurations.get(0).getAccessControlManager(root, namePathMapper);
+ default:
+ List<AccessControlManager> mgrs = Lists.transform(configurations, new Function<AuthorizationConfiguration, AccessControlManager>() {
+ @Override
+ public AccessControlManager apply(AuthorizationConfiguration authorizationConfiguration) {
+ return authorizationConfiguration.getAccessControlManager(root, namePathMapper);
+ }
+ });
+ return new CompositeAccessControlManager(root, namePathMapper, getSecurityProvider(), mgrs);
+
+ }
}
@Nonnull
@@ -84,129 +82,22 @@ public class CompositeAuthorizationConfi
@Nonnull
@Override
- public PermissionProvider getPermissionProvider(@Nonnull Root root, @Nonnull String workspaceName, @Nonnull Set<Principal> principals) {
- // TODO OAK-1268
- throw new UnsupportedOperationException("not yet implemented (OAK-1268)");
- }
-
- /**
- * Access control manager that aggregates a list of different access control
- * manager implementations. Note, that the implementations *must* implement
- * the {@link org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.PolicyOwner}
- * interface in order to be able to set and remove individual access control
- * policies.
- */
- private static class CompositeAcMgr extends AbstractAccessControlManager {
-
- private final List<AccessControlManager> acMgrs;
-
- private CompositeAcMgr(@Nonnull Root root,
- @Nonnull NamePathMapper namePathMapper,
- @Nonnull SecurityProvider securityProvider,
- @Nonnull List<AccessControlManager> acMgrs) {
- super(root, namePathMapper, securityProvider);
- this.acMgrs = acMgrs;
- }
-
- //-------------------------------------------< AccessControlManager >---
- @Override
- public Privilege[] getSupportedPrivileges(String absPath) throws RepositoryException {
- ImmutableList.Builder<Privilege> privs = ImmutableList.builder();
- for (AccessControlManager acMgr : acMgrs) {
- privs.add(acMgr.getSupportedPrivileges(absPath));
- }
- List<Privilege> l = privs.build();
- return l.toArray(new Privilege[l.size()]);
- }
-
- @Override
- public AccessControlPolicy[] getPolicies(String absPath) throws RepositoryException {
- ImmutableList.Builder<AccessControlPolicy> policies = ImmutableList.builder();
- for (AccessControlManager acMgr : acMgrs) {
- policies.add(acMgr.getPolicies(absPath));
- }
- List<AccessControlPolicy> l = policies.build();
- return l.toArray(new AccessControlPolicy[l.size()]);
- }
-
- @Override
- public AccessControlPolicy[] getEffectivePolicies(String absPath) throws RepositoryException {
- ImmutableList.Builder<AccessControlPolicy> privs = ImmutableList.builder();
- for (AccessControlManager acMgr : acMgrs) {
- privs.add(acMgr.getEffectivePolicies(absPath));
- }
- List<AccessControlPolicy> l = privs.build();
- return l.toArray(new AccessControlPolicy[l.size()]);
- }
-
- @Override
- public AccessControlPolicyIterator getApplicablePolicies(String absPath) throws RepositoryException {
- List<AccessControlPolicyIterator> l = Lists.newArrayList();
- for (AccessControlManager acMgr : acMgrs) {
- if (acMgr instanceof PolicyOwner) {
- l.add(acMgr.getApplicablePolicies(absPath));
- }
- }
- return new AccessControlPolicyIteratorAdapter(Iterators.concat(l.toArray(new AccessControlPolicyIterator[l.size()])));
- }
-
- @Override
- public void setPolicy(String absPath, AccessControlPolicy policy) throws RepositoryException {
- for (AccessControlManager acMgr : acMgrs) {
- if (acMgr instanceof PolicyOwner && ((PolicyOwner) acMgr).defines(absPath, policy)) {
- acMgr.setPolicy(absPath, policy);
- return;
- }
- }
- throw new AccessControlException("Cannot set access control policy " + policy + "; no PolicyOwner found.");
- }
-
- @Override
- public void removePolicy(String absPath, AccessControlPolicy policy) throws RepositoryException {
- for (AccessControlManager acMgr : acMgrs) {
- if (acMgr instanceof PolicyOwner && ((PolicyOwner) acMgr).defines(absPath, policy)) {
- acMgr.removePolicy(absPath, policy);
- return;
- }
- }
- throw new AccessControlException("Cannot remove access control policy " + policy + "; no PolicyOwner found.");
- }
-
- //---------------------------------< JackrabbitAccessControlManager >---
- @Override
- public JackrabbitAccessControlPolicy[] getApplicablePolicies(Principal principal) throws RepositoryException {
- ImmutableList.Builder<JackrabbitAccessControlPolicy> policies = ImmutableList.builder();
- for (AccessControlManager acMgr : acMgrs) {
- if (acMgr instanceof JackrabbitAccessControlManager && acMgr instanceof PolicyOwner) {
- policies.add(((JackrabbitAccessControlManager) acMgr).getApplicablePolicies(principal));
- }
- }
- List<JackrabbitAccessControlPolicy> l = policies.build();
- return l.toArray(new JackrabbitAccessControlPolicy[l.size()]);
- }
-
- @Override
- public JackrabbitAccessControlPolicy[] getPolicies(Principal principal) throws RepositoryException {
- ImmutableList.Builder<JackrabbitAccessControlPolicy> privs = ImmutableList.builder();
- for (AccessControlManager acMgr : acMgrs) {
- if (acMgr instanceof JackrabbitAccessControlManager) {
- privs.add(((JackrabbitAccessControlManager) acMgr).getPolicies(principal));
- }
- }
- List<JackrabbitAccessControlPolicy> l = privs.build();
- return l.toArray(new JackrabbitAccessControlPolicy[l.size()]);
- }
-
- @Override
- public AccessControlPolicy[] getEffectivePolicies(Set<Principal> principals) throws RepositoryException {
- ImmutableList.Builder<AccessControlPolicy> privs = ImmutableList.builder();
- for (AccessControlManager acMgr : acMgrs) {
- if (acMgr instanceof JackrabbitAccessControlManager) {
- privs.add(((JackrabbitAccessControlManager) acMgr).getEffectivePolicies(principals));
+ public PermissionProvider getPermissionProvider(final @Nonnull Root root,
+ final @Nonnull String workspaceName,
+ final @Nonnull Set<Principal> principals) {
+ List<AuthorizationConfiguration> configurations = getConfigurations();
+ switch (configurations.size()) {
+ case 0: throw new IllegalArgumentException();
+ case 1: return configurations.get(0).getPermissionProvider(root, workspaceName, principals);
+ default:
+ List<AggregatedPermissionProvider> aggrPermissionProviders = Lists.newArrayListWithCapacity(configurations.size());
+ for (AuthorizationConfiguration conf : configurations) {
+ PermissionProvider pProvider = conf.getPermissionProvider(root, workspaceName, principals);
+ if (pProvider instanceof AggregatedPermissionProvider) {
+ aggrPermissionProviders.add((AggregatedPermissionProvider) pProvider);
+ }
}
- }
- List<AccessControlPolicy> l = privs.build();
- return l.toArray(new AccessControlPolicy[l.size()]);
+ return new CompositePermissionProvider(root, aggrPermissionProviders);
}
}
}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/CompositeAccessControlManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/CompositeAccessControlManager.java?rev=1614686&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/CompositeAccessControlManager.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/CompositeAccessControlManager.java Wed Jul 30 15:38:27 2014
@@ -0,0 +1,159 @@
+/*
+ * 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.accesscontrol;
+
+import java.security.Principal;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import javax.jcr.RepositoryException;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.AccessControlPolicyIterator;
+import javax.jcr.security.Privilege;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlPolicy;
+import org.apache.jackrabbit.commons.iterator.AccessControlPolicyIteratorAdapter;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
+
+/**
+ * Access control manager that aggregates a list of different access control
+ * manager implementations. Note, that the implementations *must* implement
+ * the {@link org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.PolicyOwner}
+ * interface in order to be able to set and remove individual access control
+ * policies.
+ */
+public class CompositeAccessControlManager extends AbstractAccessControlManager {
+
+ private final List<AccessControlManager> acMgrs;
+
+ public CompositeAccessControlManager(@Nonnull Root root,
+ @Nonnull NamePathMapper namePathMapper,
+ @Nonnull SecurityProvider securityProvider,
+ @Nonnull List<AccessControlManager> acMgrs) {
+ super(root, namePathMapper, securityProvider);
+ this.acMgrs = acMgrs;
+ }
+
+ //-----------------------------------------------< AccessControlManager >---
+ @Override
+ public Privilege[] getSupportedPrivileges(String absPath) throws RepositoryException {
+ ImmutableList.Builder<Privilege> privs = ImmutableList.builder();
+ for (AccessControlManager acMgr : acMgrs) {
+ privs.add(acMgr.getSupportedPrivileges(absPath));
+ }
+ List<Privilege> l = privs.build();
+ return l.toArray(new Privilege[l.size()]);
+ }
+
+ @Override
+ public AccessControlPolicy[] getPolicies(String absPath) throws RepositoryException {
+ ImmutableList.Builder<AccessControlPolicy> policies = ImmutableList.builder();
+ for (AccessControlManager acMgr : acMgrs) {
+ policies.add(acMgr.getPolicies(absPath));
+ }
+ List<AccessControlPolicy> l = policies.build();
+ return l.toArray(new AccessControlPolicy[l.size()]);
+ }
+
+ @Override
+ public AccessControlPolicy[] getEffectivePolicies(String absPath) throws RepositoryException {
+ ImmutableList.Builder<AccessControlPolicy> privs = ImmutableList.builder();
+ for (AccessControlManager acMgr : acMgrs) {
+ privs.add(acMgr.getEffectivePolicies(absPath));
+ }
+ List<AccessControlPolicy> l = privs.build();
+ return l.toArray(new AccessControlPolicy[l.size()]);
+ }
+
+ @Override
+ public AccessControlPolicyIterator getApplicablePolicies(String absPath) throws RepositoryException {
+ List<AccessControlPolicyIterator> l = Lists.newArrayList();
+ for (AccessControlManager acMgr : acMgrs) {
+ if (acMgr instanceof PolicyOwner) {
+ l.add(acMgr.getApplicablePolicies(absPath));
+ }
+ }
+ return new AccessControlPolicyIteratorAdapter(Iterators.concat(l.toArray(new AccessControlPolicyIterator[l.size()])));
+ }
+
+ @Override
+ public void setPolicy(String absPath, AccessControlPolicy policy) throws RepositoryException {
+ for (AccessControlManager acMgr : acMgrs) {
+ if (acMgr instanceof PolicyOwner && ((PolicyOwner) acMgr).defines(absPath, policy)) {
+ acMgr.setPolicy(absPath, policy);
+ return;
+ }
+ }
+ throw new AccessControlException("Cannot set access control policy " + policy + "; no PolicyOwner found.");
+ }
+
+ @Override
+ public void removePolicy(String absPath, AccessControlPolicy policy) throws RepositoryException {
+ for (AccessControlManager acMgr : acMgrs) {
+ if (acMgr instanceof PolicyOwner && ((PolicyOwner) acMgr).defines(absPath, policy)) {
+ acMgr.removePolicy(absPath, policy);
+ return;
+ }
+ }
+ throw new AccessControlException("Cannot remove access control policy " + policy + "; no PolicyOwner found.");
+ }
+
+ //-------------------------------------< JackrabbitAccessControlManager >---
+ @Override
+ public JackrabbitAccessControlPolicy[] getApplicablePolicies(Principal principal) throws RepositoryException {
+ ImmutableList.Builder<JackrabbitAccessControlPolicy> policies = ImmutableList.builder();
+ for (AccessControlManager acMgr : acMgrs) {
+ if (acMgr instanceof JackrabbitAccessControlManager && acMgr instanceof PolicyOwner) {
+ policies.add(((JackrabbitAccessControlManager) acMgr).getApplicablePolicies(principal));
+ }
+ }
+ List<JackrabbitAccessControlPolicy> l = policies.build();
+ return l.toArray(new JackrabbitAccessControlPolicy[l.size()]);
+ }
+
+ @Override
+ public JackrabbitAccessControlPolicy[] getPolicies(Principal principal) throws RepositoryException {
+ ImmutableList.Builder<JackrabbitAccessControlPolicy> privs = ImmutableList.builder();
+ for (AccessControlManager acMgr : acMgrs) {
+ if (acMgr instanceof JackrabbitAccessControlManager) {
+ privs.add(((JackrabbitAccessControlManager) acMgr).getPolicies(principal));
+ }
+ }
+ List<JackrabbitAccessControlPolicy> l = privs.build();
+ return l.toArray(new JackrabbitAccessControlPolicy[l.size()]);
+ }
+
+ @Override
+ public AccessControlPolicy[] getEffectivePolicies(Set<Principal> principals) throws RepositoryException {
+ ImmutableList.Builder<AccessControlPolicy> privs = ImmutableList.builder();
+ for (AccessControlManager acMgr : acMgrs) {
+ if (acMgr instanceof JackrabbitAccessControlManager) {
+ privs.add(((JackrabbitAccessControlManager) acMgr).getEffectivePolicies(principals));
+ }
+ }
+ List<AccessControlPolicy> l = privs.build();
+ return l.toArray(new AccessControlPolicy[l.size()]);
+ }
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/AggregatedPermissionProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/AggregatedPermissionProvider.java?rev=1614686&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/AggregatedPermissionProvider.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/AggregatedPermissionProvider.java Wed Jul 30 15:38:27 2014
@@ -0,0 +1,47 @@
+/*
+ * 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 javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.api.Tree;
+
+/**
+ * Extension of the {@link PermissionProvider} interface that allows it to be
+ * used in combination with other provider implementations.
+ */
+public interface AggregatedPermissionProvider extends PermissionProvider {
+
+ /**
+ * Name of the configuration option that specifies the {@link org.apache.jackrabbit.oak.spi.security.authorization.permission.ControlFlag}
+ * of this provider instance.
+ */
+ String PARAM_CONTROL_FLAG = "controlFlag";
+
+ @Nonnull
+ ControlFlag getFlag();
+
+ boolean handles(@Nonnull String path, @Nonnull String jcrAction);
+
+ boolean handles(@Nonnull Tree tree);
+
+ boolean handles(@Nonnull Tree tree, long permission);
+
+ boolean handles(@Nonnull TreePermission treePermission, long permission);
+
+ boolean handlesRepositoryPermissions();
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/AggregatedPermissionProvider.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/CompositePermissionProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/CompositePermissionProvider.java?rev=1614686&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/CompositePermissionProvider.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/CompositePermissionProvider.java Wed Jul 30 15:38:27 2014
@@ -0,0 +1,411 @@
+/*
+ * 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 java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+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.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.plugins.tree.ImmutableTree;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.util.Text;
+
+/**
+ * Permission provider implementation that aggregates a list of different
+ * provider implementations. Note, that the implementations *must* implement
+ * the {@link org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider}
+ * interface.
+ */
+public class CompositePermissionProvider implements PermissionProvider {
+
+ private final Root root;
+ private final List<AggregatedPermissionProvider> pps;
+ private final CompositeRepositoryPermission repositoryPermission;
+
+ private ImmutableRoot immutableRoot;
+ private PrivilegeBitsProvider pbp;
+
+ public CompositePermissionProvider(@Nonnull Root root, @Nonnull List<AggregatedPermissionProvider> pps) {
+ this.root = root;
+ this.pps = pps;
+
+ repositoryPermission = new CompositeRepositoryPermission();
+ immutableRoot = (root instanceof ImmutableRoot) ? (ImmutableRoot) root : new ImmutableRoot(root);
+ pbp = new PrivilegeBitsProvider(immutableRoot);
+ }
+
+ @Override
+ public void refresh() {
+ immutableRoot = (root instanceof ImmutableRoot) ? (ImmutableRoot) root : new ImmutableRoot(root);
+ pbp = new PrivilegeBitsProvider(immutableRoot);
+
+ for (PermissionProvider pp : pps) {
+ pp.refresh();
+ }
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getPrivileges(@Nullable Tree tree) {
+ return pbp.getPrivilegeNames(getPrivilegeBits(tree));
+ }
+
+ @Override
+ public boolean hasPrivileges(@Nullable Tree tree, @Nonnull String... privilegeNames) {
+ return getPrivilegeBits(tree).includes(pbp.getBits(privilegeNames));
+ }
+
+ @Override
+ public RepositoryPermission getRepositoryPermission() {
+ return repositoryPermission;
+ }
+
+ @Override
+ public TreePermission getTreePermission(@Nonnull Tree tree, @Nonnull TreePermission parentPermission) {
+ ImmutableTree immTree = (tree instanceof ImmutableTree) ? (ImmutableTree) tree : immutableRoot.getTree(tree.getPath());
+ if (tree.isRoot()) {
+ return new CompositeTreePermission(immTree, new CompositeTreePermission());
+ } else {
+ if (!(parentPermission instanceof CompositeTreePermission)) {
+ throw new IllegalArgumentException("Illegal parent permission instance. Expected CompositeTreePermission.");
+ }
+ return new CompositeTreePermission(immTree, (CompositeTreePermission) parentPermission);
+ }
+ }
+
+ @Override
+ public boolean isGranted(final @Nonnull Tree parent, @Nullable PropertyState property, final long permissions) {
+ if (Permissions.isAggregate(permissions)) {
+ for (final long permission : Permissions.aggregates(permissions)) {
+ Iterable<AggregatedPermissionProvider> providers = Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
+ @Override
+ public boolean apply(@Nullable AggregatedPermissionProvider pp) {
+ return pp != null && pp.handles(parent, permission);
+ }
+ });
+ if (!grantsPermission(parent, property, permission, providers)) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ Iterable<AggregatedPermissionProvider> providers = Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
+ @Override
+ public boolean apply(@Nullable AggregatedPermissionProvider pp) {
+ return pp != null && pp.handles(parent, permissions);
+ }
+ });
+ return grantsPermission(parent, property, permissions, providers);
+ }
+ }
+
+ @Override
+ public boolean isGranted(final @Nonnull String oakPath, final @Nonnull String jcrActions) {
+ String[] actions = Text.explode(jcrActions, ',', false);
+ switch (actions.length) {
+ case 0: return true;
+ case 1:
+ Iterable<AggregatedPermissionProvider> providers = Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
+ @Override
+ public boolean apply(@Nullable AggregatedPermissionProvider pp) {
+ return pp != null && pp.handles(oakPath, jcrActions);
+ }
+ });
+ return grantsAction(oakPath, actions[0], providers);
+ default:
+ for (final String action : actions) {
+ providers = Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
+ @Override
+ public boolean apply(@Nullable AggregatedPermissionProvider pp) {
+ return pp != null && pp.handles(oakPath, action);
+ }
+ });
+ if (!grantsAction(oakPath, action, providers)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ private PrivilegeBits getPrivilegeBits(@Nullable final Tree tree) {
+ PrivilegeBits sufficient = PrivilegeBits.getInstance();
+ PrivilegeBits required = null;
+
+ Iterable<AggregatedPermissionProvider> providers = Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
+ @Override
+ public boolean apply(@Nullable AggregatedPermissionProvider pp) {
+ return pp != null && ((tree == null) ? pp.handlesRepositoryPermissions() : pp.handles(tree));
+ }
+ });
+ for (AggregatedPermissionProvider pp : providers) {
+ PrivilegeBits privs = pbp.getBits(pp.getPrivileges(tree));
+ ControlFlag flag = pp.getFlag();
+ if (ControlFlag.SUFFICIENT == flag) {
+ sufficient.add(privs);
+ if (required != null) {
+ sufficient.retain(required);
+ }
+ } else if (ControlFlag.REQUISITE == flag) {
+ if (required == null) {
+ required = PrivilegeBits.getInstance();
+ required.add(privs);
+ } else {
+ required.retain(privs);
+ }
+ }
+ }
+ if (required != null) {
+ sufficient.add(required);
+ }
+ return sufficient;
+ }
+
+ private static boolean grantsPermission(@Nonnull final Tree parent,
+ @Nullable PropertyState property,
+ final long permission,
+ @Nonnull Iterable<AggregatedPermissionProvider> providers) {
+ Iterator<AggregatedPermissionProvider> it = providers.iterator();
+ while (it.hasNext()) {
+ AggregatedPermissionProvider pp = it.next();
+ boolean isGranted = pp.isGranted(parent, property, permission);
+ if (!it.hasNext() || evalComplete(isGranted, pp.getFlag())) {
+ return isGranted;
+ }
+ }
+ return false;
+ }
+
+ private static boolean grantsAction(@Nonnull final String oakPath,
+ @Nonnull final String action,
+ @Nonnull Iterable<AggregatedPermissionProvider> providers) {
+ Iterator<AggregatedPermissionProvider> it = providers.iterator();
+ while (it.hasNext()) {
+ AggregatedPermissionProvider pp = it.next();
+ boolean isGranted = pp.isGranted(oakPath, action);
+ if (!it.hasNext() || evalComplete(isGranted, pp.getFlag())) {
+ return isGranted;
+ }
+ }
+ return false;
+ }
+
+ private static boolean grantsRepoPermission(long permission, @Nonnull Iterable<AggregatedPermissionProvider> providers) {
+ Iterator<AggregatedPermissionProvider> it = providers.iterator();
+ while (it.hasNext()) {
+ AggregatedPermissionProvider pp = it.next();
+ boolean isGranted = pp.getRepositoryPermission().isGranted(permission);
+ if (!it.hasNext() || evalComplete(isGranted, pp.getFlag())) {
+ return isGranted;
+ }
+
+ }
+ return false;
+ }
+
+ private static boolean evalComplete(boolean isGranted, ControlFlag flag) {
+ switch (flag) {
+ case SUFFICIENT:
+ if (isGranted) {
+ return true;
+ }
+ break;
+ case REQUISITE:
+ if (!isGranted) {
+ return true;
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported PermissionProvider Control Flag " + flag);
+
+ }
+ return false;
+ }
+
+ //--------------------------------------------------------------------------
+
+ private class CompositeTreePermission implements TreePermission {
+
+ private final ImmutableTree tree;
+ private final CompositeTreePermission parentPermission;
+
+ private final Map<AggregatedPermissionProvider, TreePermission> map;
+
+ private Boolean canRead;
+
+ private CompositeTreePermission() {
+ tree = null;
+ parentPermission = null;
+
+ map = ImmutableMap.of();
+ }
+
+ private CompositeTreePermission(final @Nonnull ImmutableTree tree, @Nonnull CompositeTreePermission parentPermission) {
+ this.tree = tree;
+ this.parentPermission = parentPermission;
+
+ map = new LinkedHashMap<AggregatedPermissionProvider, TreePermission>(pps.size());
+ for (AggregatedPermissionProvider provider : pps) {
+ TreePermission tp = provider.getTreePermission(tree, getParentPermission(provider));
+ map.put(provider, tp);
+ }
+ }
+
+ @Override
+ public TreePermission getChildPermission(String childName, NodeState childState) {
+ ImmutableTree childTree = new ImmutableTree(tree, childName, childState);
+ return new CompositeTreePermission(childTree, this);
+ }
+
+ @Override
+ public boolean canRead() {
+ if (canRead == null) {
+ canRead = false;
+ Iterator<Map.Entry<AggregatedPermissionProvider, TreePermission>> it = map.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<AggregatedPermissionProvider, TreePermission> entry = it.next();
+ TreePermission tp = entry.getValue();
+ if (entry.getKey().handles(tp, Permissions.READ_NODE)) {
+ boolean isGranted = entry.getValue().canRead();
+ if (!it.hasNext() || evalComplete(isGranted, entry.getKey().getFlag())) {
+ this.canRead = isGranted;
+ break;
+ }
+ }
+ }
+ }
+ return canRead;
+ }
+
+ @Override
+ public boolean canRead(@Nonnull PropertyState property) {
+ Iterator<Map.Entry<AggregatedPermissionProvider, TreePermission>> it = map.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<AggregatedPermissionProvider, TreePermission> entry = it.next();
+ TreePermission tp = entry.getValue();
+ if (entry.getKey().handles(tp, Permissions.READ_PROPERTY)) {
+ boolean isGranted = entry.getValue().canRead(property);
+ if (!it.hasNext() || evalComplete(isGranted, entry.getKey().getFlag())) {
+ return isGranted;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean canReadAll() {
+ return false;
+ }
+
+ @Override
+ public boolean canReadProperties() {
+ return false;
+ }
+
+ @Override
+ public boolean isGranted(long permissions) {
+ if (Permissions.isAggregate(permissions)) {
+ for (long permission : Permissions.aggregates(permissions)) {
+ if (!grantsPermission(permission, null)) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return grantsPermission(permissions, null);
+ }
+ }
+
+ @Override
+ public boolean isGranted(long permissions, @Nonnull PropertyState property) {
+ if (Permissions.isAggregate(permissions)) {
+ for (long permission : Permissions.aggregates(permissions)) {
+ if (!grantsPermission(permission, property)) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return grantsPermission(permissions, property);
+ }
+ }
+
+ private boolean grantsPermission(long permission, @Nullable PropertyState property) {
+ Iterator<Map.Entry<AggregatedPermissionProvider, TreePermission>> it = map.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<AggregatedPermissionProvider, TreePermission> entry = it.next();
+ if (entry.getKey().handles(this, permission)) {
+ TreePermission tp = entry.getValue();
+ boolean isGranted = (property == null) ? tp.isGranted(permission) : tp.isGranted(permission, property);
+ if (!it.hasNext() || evalComplete(isGranted, entry.getKey().getFlag())) {
+ return isGranted;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Nonnull
+ private TreePermission getParentPermission(AggregatedPermissionProvider provider) {
+ TreePermission parent = null;
+ if (parentPermission != null) {
+ parent = parentPermission.map.get(provider);
+ }
+ return (parent == null) ? TreePermission.EMPTY : parent;
+ }
+
+
+ }
+
+ private class CompositeRepositoryPermission implements RepositoryPermission {
+
+ @Override
+ public boolean isGranted(long repositoryPermissions) {
+ Iterable<AggregatedPermissionProvider> providers = Iterables.filter(pps, new Predicate<AggregatedPermissionProvider>() {
+ @Override
+ public boolean apply(@Nullable AggregatedPermissionProvider provider) {
+ return provider != null && provider.handlesRepositoryPermissions();
+ }
+ });
+ if (Permissions.isAggregate(repositoryPermissions)) {
+ for (long permission : Permissions.aggregates(repositoryPermissions)) {
+ if (!grantsRepoPermission(permission, providers)) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return grantsRepoPermission(repositoryPermissions, providers);
+ }
+ }
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/CompositePermissionProvider.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/ControlFlag.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/ControlFlag.java?rev=1614686&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/ControlFlag.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/ControlFlag.java Wed Jul 30 15:38:27 2014
@@ -0,0 +1,59 @@
+/*
+ * 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 javax.annotation.Nonnull;
+
+/**
+ * This class is used to define the evaluation behavior of a given aggregated
+ * permission provider. It can be SUFFICIENT or REQUISITE.
+ */
+public enum ControlFlag {
+
+ /**
+ * The {@code AggregatedPermissionProvider} is not required to return {@code true}
+ * upon permission evaluation. If it does grant the permissions in question,
+ * control is immediately returned to the caller and the evaluation does
+ * not proceed down the list of {@code PermissionProvider}s. If it returns
+ * {@code false}, the evaluation continues down the list of {@code PermissionProvider}s.
+ */
+ SUFFICIENT("SUFFICIENT"),
+
+ /**
+ * The {@code AggregatedPermissionProvider} is required to return {@code true}
+ * upon permission evaluation. If it grants access the evaluation continues
+ * down the list of {@code PermissionProvider}s. However, if it returns
+ * {@code false} indicating that permissions are not granted, the evaluation
+ * is immediately stopped at this point control is returned to the caller
+ * without proceeding down the list of the {@code PermissionProvider}s.
+ */
+ REQUISITE("REQUISITE");
+
+ public static final String SUFFICIENT_NAME = "SUFFICIENT";
+ public static final String REQUISITE_NAME = "REQUISITE";
+
+ private final String name;
+
+ private ControlFlag(@Nonnull String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/ControlFlag.java
------------------------------------------------------------------------------
svn:eol-style = native
Copied: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/EmptyPermissionProvider.java (from r1603387, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/OpenPermissionProvider.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/EmptyPermissionProvider.java?p2=jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/EmptyPermissionProvider.java&p1=jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/OpenPermissionProvider.java&r1=1603387&r2=1614686&rev=1614686&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/OpenPermissionProvider.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/EmptyPermissionProvider.java Wed Jul 30 15:38:27 2014
@@ -23,16 +23,15 @@ import javax.annotation.Nullable;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
/**
- * Permission provider implementation that grants full access everywhere.
+ * Permission provider implementation that does not grant any permissions.
*/
-public final class OpenPermissionProvider implements PermissionProvider {
+public final class EmptyPermissionProvider implements PermissionProvider {
- private static final PermissionProvider INSTANCE = new OpenPermissionProvider();
+ private static final PermissionProvider INSTANCE = new EmptyPermissionProvider();
- private OpenPermissionProvider() {
+ private EmptyPermissionProvider() {
}
public static PermissionProvider getInstance() {
@@ -47,31 +46,31 @@ public final class OpenPermissionProvide
@Nonnull
@Override
public Set<String> getPrivileges(@Nullable Tree tree) {
- return Collections.singleton(PrivilegeConstants.JCR_ALL);
+ return Collections.emptySet();
}
@Override
public boolean hasPrivileges(@Nullable Tree tree, String... privilegeNames) {
- return true;
+ return false;
}
@Override
public RepositoryPermission getRepositoryPermission() {
- return RepositoryPermission.ALL;
+ return RepositoryPermission.EMPTY;
}
@Override
public TreePermission getTreePermission(@Nonnull Tree tree, @Nonnull TreePermission parentPermission) {
- return TreePermission.ALL;
+ return TreePermission.EMPTY;
}
@Override
public boolean isGranted(@Nonnull Tree tree, @Nullable PropertyState property, long permissions) {
- return true;
+ return false;
}
@Override
public boolean isGranted(@Nonnull String oakPath, @Nonnull String jcrActions) {
- return true;
+ return false;
}
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/Permissions.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/Permissions.java?rev=1614686&r1=1614685&r2=1614686&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/Permissions.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/Permissions.java Wed Jul 30 15:38:27 2014
@@ -26,13 +26,15 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.jcr.Session;
+import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import org.apache.jackrabbit.oak.plugins.name.NamespaceConstants;
import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.plugins.tree.TreeLocation;
import org.apache.jackrabbit.oak.plugins.version.VersionConstants;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
-import org.apache.jackrabbit.oak.plugins.tree.TreeLocation;
import org.apache.jackrabbit.util.Text;
/**
@@ -132,6 +134,29 @@ public final class Permissions {
| INDEX_DEFINITION_MANAGEMENT
);
+ private static final Set<Long> NON_AGGREGATES = ImmutableSet.of(
+ READ_NODE,
+ READ_PROPERTY,
+ ADD_PROPERTY,
+ MODIFY_PROPERTY,
+ REMOVE_PROPERTY,
+ ADD_NODE,
+ REMOVE_NODE,
+ MODIFY_CHILD_NODE_COLLECTION,
+ READ_ACCESS_CONTROL,
+ MODIFY_ACCESS_CONTROL,
+ NODE_TYPE_MANAGEMENT,
+ VERSION_MANAGEMENT,
+ LOCK_MANAGEMENT,
+ LIFECYCLE_MANAGEMENT,
+ RETENTION_MANAGEMENT,
+ NODE_TYPE_DEFINITION_MANAGEMENT,
+ NAMESPACE_MANAGEMENT,
+ WORKSPACE_MANAGEMENT,
+ PRIVILEGE_MANAGEMENT,
+ USER_MANAGEMENT,
+ INDEX_DEFINITION_MANAGEMENT);
+
public static final Map<Long, String> PERMISSION_NAMES = new LinkedHashMap<Long, String>();
static {
PERMISSION_NAMES.put(ALL, "ALL");
@@ -246,6 +271,23 @@ public final class Permissions {
permission == WORKSPACE_MANAGEMENT;
}
+ public static boolean isAggregate(long permission) {
+ return !NON_AGGREGATES.contains(permission);
+ }
+
+ public static Iterable<Long> aggregates(final long permissions) {
+ if (ALL == permissions) {
+ return NON_AGGREGATES;
+ } else {
+ return Iterables.filter(NON_AGGREGATES, new Predicate<Long>() {
+ @Override
+ public boolean apply(@Nullable Long permission) {
+ return permission != null && includes(permissions, permission);
+ }
+ });
+ }
+ }
+
public static boolean includes(long permissions, long permissionsToTest) {
return (permissions & permissionsToTest) == permissionsToTest;
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBits.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBits.java?rev=1614686&r1=1614685&r2=1614686&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBits.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBits.java Wed Jul 30 15:38:27 2014
@@ -425,6 +425,24 @@ public final class PrivilegeBits impleme
}
}
+ /**
+ * Retains the elements in this {@code PrivilegeBits} that are contained in
+ * the specified other {@code PrivilegeBits}.
+ *
+ * @param other Other privilege bits.
+ * @return This modifiable instance of privilege bits modified such it contains
+ * only privileges that were also contained in the {@code other} instance.
+ */
+ @Nonnull
+ public PrivilegeBits retain(@Nonnull PrivilegeBits other) {
+ if (d instanceof ModifiableData) {
+ ((ModifiableData) d).retain(other.d);
+ return this;
+ } else {
+ throw new UnsupportedOperationException("immutable privilege bits");
+ }
+ }
+
@Nonnull
public PropertyState asPropertyState(String name) {
return PropertyStates.createProperty(name, Longs.asList(d.longValues()), Type.LONGS);
@@ -753,6 +771,33 @@ public final class PrivilegeBits impleme
}
}
+ private void retain(Data other) {
+ if (isSimple()) {
+ bits[0] &= other.longValue();
+ } else {
+ long[] lvs = longValues();
+ long[] bLvs = other.longValues();
+
+ long[] res = (lvs.length <= bLvs.length) ? new long[lvs.length] : new long[bLvs.length];
+ int compactSize = -1;
+ for (int i = 0; i < res.length; i++) {
+ res[i] = (lvs[i] & bLvs[i]);
+ if (res[i] == 0) {
+ if (compactSize == -1) {
+ compactSize = i+1;
+ }
+ } else {
+ compactSize = -1;
+ }
+ }
+ if (compactSize != -1 && res.length > compactSize) {
+ bits = Arrays.copyOfRange(res, 0, compactSize);
+ } else {
+ bits = res;
+ }
+ }
+ }
+
private static long[] diff(long[] a, long[] b) {
int index = -1;
long[] res = new long[((a.length > b.length) ? a.length : b.length)];
Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/CompositeConfigurationTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/CompositeConfigurationTest.java?rev=1614686&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/CompositeConfigurationTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/CompositeConfigurationTest.java Wed Jul 30 15:38:27 2014
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+/**
+ * CompositeConfigurationTest... TODO
+ */
+public class CompositeConfigurationTest extends AbstractCompositeConfigurationTest {
+
+ // TODO
+
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/CompositePermissionProviderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/CompositePermissionProviderTest.java?rev=1614686&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/CompositePermissionProviderTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/CompositePermissionProviderTest.java Wed Jul 30 15:38:27 2014
@@ -0,0 +1,24 @@
+/*
+ * 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.apache.jackrabbit.oak.AbstractSecurityTest;
+
+public class CompositePermissionProviderTest extends AbstractSecurityTest {
+
+ // TODO
+}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionsTest.java?rev=1614686&r1=1614685&r2=1614686&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionsTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/permission/PermissionsTest.java Wed Jul 30 15:38:27 2014
@@ -73,4 +73,9 @@ public class PermissionsTest extends Abs
}
}
+ @Test
+ public void testAggregates() {
+ // TODO
+ }
+
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBitsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBitsTest.java?rev=1614686&r1=1614685&r2=1614686&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBitsTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/privilege/PrivilegeBitsTest.java Wed Jul 30 15:38:27 2014
@@ -16,9 +16,12 @@
*/
package org.apache.jackrabbit.oak.spi.security.privilege;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.Random;
import org.apache.jackrabbit.oak.AbstractSecurityTest;
import org.apache.jackrabbit.oak.api.PropertyState;
@@ -426,6 +429,100 @@ public class PrivilegeBitsTest extends A
}
@Test
+ public void testRetainUnmodifiable() {
+ PrivilegeBits unmodifiable = READ_NODES_PRIVILEGE_BITS;
+ try {
+ unmodifiable.retain(PrivilegeBits.getInstance());
+ fail();
+ } catch (UnsupportedOperationException e) {
+ // success
+ }
+ }
+
+ @Test
+ public void testRetainSimple() {
+ PrivilegeBits pb = PrivilegeBits.getInstance(READ_NODES_PRIVILEGE_BITS);
+ assertEquals(pb, pb.retain(pb));
+ assertEquals(pb, pb.retain(READ_NODES_PRIVILEGE_BITS));
+
+ pb = PrivilegeBits.getInstance(READ_NODES_PRIVILEGE_BITS);
+ pb.retain(PrivilegeBits.getInstance());
+ assertTrue(pb.isEmpty());
+
+ pb = PrivilegeBits.getInstance(READ_NODES_PRIVILEGE_BITS);
+ pb.retain(PrivilegeBits.EMPTY);
+ assertTrue(pb.isEmpty());
+
+ PrivilegeBits write = PrivilegeBits.BUILT_IN.get(PrivilegeBits.REP_WRITE);
+ pb = PrivilegeBits.getInstance().add(write);
+ assertEquals(pb, pb.retain(pb));
+ assertEquals(pb, pb.retain(write));
+
+ pb.retain(READ_NODES_PRIVILEGE_BITS);
+ assertTrue(pb.isEmpty());
+
+ pb.add(READ_NODES_PRIVILEGE_BITS).add(write);
+ pb.retain(write);
+ assertEquivalent(write, pb);
+ assertFalse(pb.includes(READ_NODES_PRIVILEGE_BITS));
+
+ PrivilegeBits lock = PrivilegeBits.BUILT_IN.get(PrivilegeBits.JCR_LOCK_MANAGEMENT);
+ PrivilegeBits lw = PrivilegeBits.getInstance(write, lock);
+
+ pb.add(READ_NODES_PRIVILEGE_BITS).add(write).add(lock);
+ pb.retain(lw);
+ assertEquivalent(lw, pb);
+ assertFalse(pb.includes(READ_NODES_PRIVILEGE_BITS));
+ }
+
+ @Test
+ public void testRetain() {
+ PrivilegeBits pb = READ_NODES_PRIVILEGE_BITS;
+ List<PrivilegeBits> pbs = new ArrayList<PrivilegeBits>();
+ pbs.add(pb);
+ Random random = new Random();
+
+ for (int i = 0; i < 100; i++) {
+ PrivilegeBits nxt = pb.nextBits();
+
+ PrivilegeBits mod = PrivilegeBits.getInstance(nxt, pb);
+ mod.retain(nxt);
+ assertEquivalent(nxt, mod);
+
+ mod = PrivilegeBits.getInstance(nxt);
+ mod.retain(pb);
+ assertTrue(nxt.toString(), mod.isEmpty());
+
+ mod = PrivilegeBits.getInstance(nxt);
+ mod.retain(READ_NODES_PRIVILEGE_BITS);
+ assertTrue(nxt.toString(), mod.isEmpty());
+
+ mod = PrivilegeBits.getInstance(nxt, READ_NODES_PRIVILEGE_BITS);
+ mod.retain(nxt);
+ assertEquivalent(nxt, mod);
+
+ mod = PrivilegeBits.getInstance(nxt, pb, READ_NODES_PRIVILEGE_BITS);
+ mod.retain(READ_NODES_PRIVILEGE_BITS);
+ assertEquivalent(READ_NODES_PRIVILEGE_BITS, mod);
+
+ mod = PrivilegeBits.getInstance(nxt);
+ PrivilegeBits other = PrivilegeBits.getInstance();
+ for (int j = 0; j < pbs.size()/2; j++) {
+ other.add(pbs.get(random.nextInt(pbs.size()-1)));
+ }
+ mod.add(other);
+ mod.retain(other);
+ assertEquivalent(other, mod);
+
+ other.retain(nxt);
+ assertTrue(other.isEmpty());
+
+ pbs.add(nxt);
+ pb = nxt;
+ }
+ }
+
+ @Test
public void testGetInstance() {
PrivilegeBits pb = PrivilegeBits.getInstance();
assertEquivalent(PrivilegeBits.EMPTY, pb);