You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by en...@apache.org on 2010/02/27 03:02:09 UTC
svn commit: r916893 - in /sling/trunk:
bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/util/
bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/
bundles/jcr/jackrabbit-accessmanager/src/main/java/org/apache/sli...
Author: enorman
Date: Sat Feb 27 02:02:09 2010
New Revision: 916893
URL: http://svn.apache.org/viewvc?rev=916893&view=rev
Log:
SLING-1411 Add replaceAccessControlEntry method to AccessControlUtil
Thanks to Ray Davis for the contribution.
Modified:
sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/util/AccessControlUtil.java
sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
sling/trunk/bundles/jcr/jackrabbit-accessmanager/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java
sling/trunk/launchpad/testing/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/accessManager/ModifyAceTest.java
Modified: sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/util/AccessControlUtil.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/util/AccessControlUtil.java?rev=916893&r1=916892&r2=916893&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/util/AccessControlUtil.java (original)
+++ sling/trunk/bundles/jcr/base/src/main/java/org/apache/sling/jcr/base/util/AccessControlUtil.java Sat Feb 27 02:02:09 2010
@@ -18,10 +18,22 @@
*/
package org.apache.sling.jcr.base.util;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
import javax.jcr.AccessDeniedException;
import javax.jcr.RepositoryException;
@@ -31,12 +43,10 @@
import javax.jcr.security.AccessControlException;
import javax.jcr.security.AccessControlList;
import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.AccessControlPolicyIterator;
import javax.jcr.security.Privilege;
-import org.apache.jackrabbit.api.JackrabbitSession;
-import org.apache.jackrabbit.api.security.principal.PrincipalManager;
-import org.apache.jackrabbit.api.security.user.UserManager;
-
/**
* A simple utility class providing utilities with respect to
* access control over repositories.
@@ -60,7 +70,7 @@
// the name of the JackrabbitAccessControlEntry method
private static final String METHOD_JACKRABBIT_ACE_IS_ALLOW = "isAllow";
-
+ private static final Logger log = LoggerFactory.getLogger(AccessControlUtil.class);
// ---------- SessionImpl methods -----------------------------------------------------
@@ -201,6 +211,141 @@
Class[] types = new Class[] {Principal.class, Privilege[].class, boolean.class, Map.class};
return safeInvokeRepoMethod(acl, METHOD_JACKRABBIT_ACL_ADD_ENTRY, Boolean.class, args, types);
}
+
+ /**
+ * Replaces existing access control entries in the ACL for the specified
+ * <code>principal</code> and <code>resourcePath</code>. Any existing granted
+ * or denied privileges which do not conflict with the specified privileges
+ * are maintained. Where conflicts exist, existing privileges are dropped.
+ * The end result will be at most two ACEs for the principal: one for grants
+ * and one for denies. Aggregate privileges are disaggregated before checking
+ * for conflicts.
+ * @param session
+ * @param resourcePath
+ * @param principal
+ * @param grantedPrivilegeNames
+ * @param deniedPrivilegeNames
+ * @param removedPrivilegeNames privileges which, if they exist, should be
+ * removed for this principal and resource
+ * @throws RepositoryException
+ */
+ public static void replaceAccessControlEntry(Session session, String resourcePath, Principal principal,
+ String[] grantedPrivilegeNames, String[] deniedPrivilegeNames, String[] removedPrivilegeNames)
+ throws RepositoryException {
+ AccessControlManager accessControlManager = getAccessControlManager(session);
+ Set<String> specifiedPrivilegeNames = new HashSet<String>();
+ Set<String> newGrantedPrivilegeNames = disaggregateToPrivilegeNames(accessControlManager, grantedPrivilegeNames, specifiedPrivilegeNames);
+ Set<String> newDeniedPrivilegeNames = disaggregateToPrivilegeNames(accessControlManager, deniedPrivilegeNames, specifiedPrivilegeNames);
+ disaggregateToPrivilegeNames(accessControlManager, removedPrivilegeNames, specifiedPrivilegeNames);
+
+ // Get or create the ACL for the node.
+ AccessControlList acl = null;
+ AccessControlPolicy[] policies = accessControlManager.getPolicies(resourcePath);
+ for (AccessControlPolicy policy : policies) {
+ if (policy instanceof AccessControlList) {
+ acl = (AccessControlList) policy;
+ break;
+ }
+ }
+ if (acl == null) {
+ AccessControlPolicyIterator applicablePolicies = accessControlManager.getApplicablePolicies(resourcePath);
+ while (applicablePolicies.hasNext()) {
+ AccessControlPolicy policy = applicablePolicies.nextAccessControlPolicy();
+ if (policy instanceof AccessControlList) {
+ acl = (AccessControlList) policy;
+ break;
+ }
+ }
+ }
+ if (acl == null) {
+ throw new RepositoryException("Could not obtain ACL for resource " + resourcePath);
+ }
+ // Used only for logging.
+ Set<Privilege> oldGrants = null;
+ Set<Privilege> oldDenies = null;
+ if (log.isDebugEnabled()) {
+ oldGrants = new HashSet<Privilege>();
+ oldDenies = new HashSet<Privilege>();
+ }
+
+ // Combine all existing ACEs for the target principal.
+ AccessControlEntry[] accessControlEntries = acl.getAccessControlEntries();
+ for (AccessControlEntry ace : accessControlEntries) {
+ if (principal.equals(ace.getPrincipal())) {
+ if (log.isDebugEnabled()) {
+ log.debug("Found Existing ACE for principal {} on resource {}", new Object[] {principal.getName(), resourcePath});
+ }
+ boolean isAllow = isAllow(ace);
+ Privilege[] privileges = ace.getPrivileges();
+ if (log.isDebugEnabled()) {
+ if (isAllow) {
+ oldGrants.addAll(Arrays.asList(privileges));
+ } else {
+ oldDenies.addAll(Arrays.asList(privileges));
+ }
+ }
+ for (Privilege privilege : privileges) {
+ Set<String> maintainedPrivileges = disaggregateToPrivilegeNames(privilege);
+ // If there is any overlap with the newly specified privileges, then
+ // break the existing privilege down; otherwise, maintain as is.
+ if (!maintainedPrivileges.removeAll(specifiedPrivilegeNames)) {
+ // No conflicts, so preserve the original.
+ maintainedPrivileges.clear();
+ maintainedPrivileges.add(privilege.getName());
+ }
+ if (!maintainedPrivileges.isEmpty()) {
+ if (isAllow) {
+ newGrantedPrivilegeNames.addAll(maintainedPrivileges);
+ } else {
+ newDeniedPrivilegeNames.addAll(maintainedPrivileges);
+ }
+ }
+ }
+ // Remove the old ACE.
+ acl.removeAccessControlEntry(ace);
+ }
+ }
+
+ //add a fresh ACE with the granted privileges
+ List<Privilege> grantedPrivilegeList = new ArrayList<Privilege>();
+ for (String name : newGrantedPrivilegeNames) {
+ Privilege privilege = accessControlManager.privilegeFromName(name);
+ grantedPrivilegeList.add(privilege);
+ }
+ if (grantedPrivilegeList.size() > 0) {
+ acl.addAccessControlEntry(principal, grantedPrivilegeList.toArray(new Privilege[grantedPrivilegeList.size()]));
+ }
+
+ //if the authorizable is a user (not a group) process any denied privileges
+ UserManager userManager = getUserManager(session);
+ Authorizable authorizable = userManager.getAuthorizable(principal);
+ if (!authorizable.isGroup()) {
+ //add a fresh ACE with the denied privileges
+ List<Privilege> deniedPrivilegeList = new ArrayList<Privilege>();
+ for (String name : newDeniedPrivilegeNames) {
+ Privilege privilege = accessControlManager.privilegeFromName(name);
+ deniedPrivilegeList.add(privilege);
+ }
+ if (deniedPrivilegeList.size() > 0) {
+ addEntry(acl, principal, deniedPrivilegeList.toArray(new Privilege[deniedPrivilegeList.size()]), false);
+ }
+ }
+
+ accessControlManager.setPolicy(resourcePath, acl);
+ if (log.isDebugEnabled()) {
+ List<String> oldGrantedNames = new ArrayList<String>(oldGrants.size());
+ for (Privilege privilege : oldGrants) {
+ oldGrantedNames.add(privilege.getName());
+ }
+ List<String> oldDeniedNames = new ArrayList<String>(oldDenies.size());
+ for (Privilege privilege : oldDenies) {
+ oldDeniedNames.add(privilege.getName());
+ }
+ log.debug("Updated ACE for principalId {} for resource {} from grants {}, denies {} to grants {}, denies {}", new Object [] {
+ authorizable.getID(), resourcePath, oldGrantedNames, oldDeniedNames, newGrantedPrivilegeNames, newDeniedPrivilegeNames
+ });
+ }
+ }
// ---------- AccessControlEntry methods -----------------------------------------------
@@ -264,4 +409,40 @@
else
return null;
}
+
+ /**
+ * Helper routine to transform an input array of privilege names into a set in
+ * a null-safe way while also adding its disaggregated privileges to an input set.
+ */
+ private static Set<String> disaggregateToPrivilegeNames(AccessControlManager accessControlManager,
+ String[] privilegeNames, Set<String> disaggregatedPrivilegeNames)
+ throws RepositoryException {
+ Set<String> originalPrivilegeNames = new HashSet<String>();
+ if (privilegeNames != null) {
+ for (String privilegeName : privilegeNames) {
+ originalPrivilegeNames.add(privilegeName);
+ Privilege privilege = accessControlManager.privilegeFromName(privilegeName);
+ disaggregatedPrivilegeNames.addAll(disaggregateToPrivilegeNames(privilege));
+ }
+ }
+ return originalPrivilegeNames;
+ }
+
+ /**
+ * Transform an aggregated privilege into a set of disaggregated privilege
+ * names. If the privilege is not an aggregate, the set will contain the
+ * original name.
+ */
+ private static Set<String> disaggregateToPrivilegeNames(Privilege privilege) {
+ Set<String> disaggregatedPrivilegeNames = new HashSet<String>();
+ if (privilege.isAggregate()) {
+ Privilege[] privileges = privilege.getAggregatePrivileges();
+ for (Privilege disaggregate : privileges) {
+ disaggregatedPrivilegeNames.add(disaggregate.getName());
+ }
+ } else {
+ disaggregatedPrivilegeNames.add(privilege.getName());
+ }
+ return disaggregatedPrivilegeNames;
+ }
}
Modified: sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java?rev=916893&r1=916892&r2=916893&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java (original)
+++ sling/trunk/bundles/jcr/contentloader/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java Sat Feb 27 02:02:09 2010
@@ -18,6 +18,13 @@
*/
package org.apache.sling.jcr.contentloader.internal;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
+
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
@@ -26,11 +33,9 @@
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -47,18 +52,6 @@
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
-import javax.jcr.security.AccessControlEntry;
-import javax.jcr.security.AccessControlList;
-import javax.jcr.security.AccessControlManager;
-import javax.jcr.security.AccessControlPolicy;
-import javax.jcr.security.AccessControlPolicyIterator;
-import javax.jcr.security.Privilege;
-
-import org.apache.jackrabbit.api.security.user.Authorizable;
-import org.apache.jackrabbit.api.security.user.Group;
-import org.apache.jackrabbit.api.security.user.User;
-import org.apache.jackrabbit.api.security.user.UserManager;
-import org.apache.sling.jcr.base.util.AccessControlUtil;
/**
* The <code>ContentLoader</code> creates the nodes and properties.
@@ -810,120 +803,17 @@
throws RepositoryException {
final Node parentNode = this.parentNodeStack.peek();
Session session = parentNode.getSession();
-
- UserManager userManager = AccessControlUtil.getUserManager(session);
- Authorizable authorizable = userManager.getAuthorizable(principalId);
- if (authorizable == null) {
+ PrincipalManager principalManager = AccessControlUtil.getPrincipalManager(session);
+ Principal principal = principalManager.getPrincipal(principalId);
+ if (principal == null) {
throw new RepositoryException("No principal found for id: " + principalId);
}
-
String resourcePath = parentNode.getPath();
- AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
- AccessControlList updatedAcl = null;
- AccessControlPolicy[] policies = accessControlManager.getPolicies(resourcePath);
- for (AccessControlPolicy policy : policies) {
- if (policy instanceof AccessControlList) {
- updatedAcl = (AccessControlList)policy;
- break;
- }
- }
- if (updatedAcl == null) {
- AccessControlPolicyIterator applicablePolicies = accessControlManager.getApplicablePolicies(resourcePath);
- while (applicablePolicies.hasNext()) {
- AccessControlPolicy policy = applicablePolicies.nextAccessControlPolicy();
- if (policy instanceof AccessControlList) {
- updatedAcl = (AccessControlList)policy;
- }
- }
- }
- if (updatedAcl == null) {
- throw new RepositoryException("Unable to find or create an access control policy to update for " + resourcePath);
- }
-
- Set<String> postedPrivilegeNames = new HashSet<String>();
- if (grantedPrivilegeNames != null) {
- postedPrivilegeNames.addAll(Arrays.asList(grantedPrivilegeNames));
+ if ((grantedPrivilegeNames != null) || (deniedPrivilegeNames != null)) {
+ AccessControlUtil.replaceAccessControlEntry(session, resourcePath, principal,
+ grantedPrivilegeNames, deniedPrivilegeNames, null);
}
- if (deniedPrivilegeNames != null) {
- postedPrivilegeNames.addAll(Arrays.asList(deniedPrivilegeNames));
- }
-
- List<Privilege> preserveGrantedPrivileges = new ArrayList<Privilege>();
- List<Privilege> preserveDeniedPrivileges = new ArrayList<Privilege>();
-
- //keep track of the existing Aces for the target principal
- AccessControlEntry[] accessControlEntries = updatedAcl.getAccessControlEntries();
- List<AccessControlEntry> oldAces = new ArrayList<AccessControlEntry>();
- for (AccessControlEntry ace : accessControlEntries) {
- if (principalId.equals(ace.getPrincipal().getName())) {
- oldAces.add(ace);
-
- boolean isAllow = AccessControlUtil.isAllow(ace);
- Privilege[] privileges = ace.getPrivileges();
- for (Privilege privilege : privileges) {
- String privilegeName = privilege.getName();
- if (!postedPrivilegeNames.contains(privilegeName)) {
- //this privilege was not posted, so record the existing state to be
- // preserved when the ACE is re-created below
- if (isAllow) {
- preserveGrantedPrivileges.add(privilege);
- } else {
- preserveDeniedPrivileges.add(privilege);
- }
- }
- }
- }
- }
-
- //remove the old aces
- if (!oldAces.isEmpty()) {
- for (AccessControlEntry ace : oldAces) {
- updatedAcl.removeAccessControlEntry(ace);
- }
- }
-
- //add a fresh ACE with the granted privileges
- List<Privilege> grantedPrivilegeList = new ArrayList<Privilege>();
- if (grantedPrivilegeNames != null) {
- for (String name : grantedPrivilegeNames) {
- if (name.length() == 0) {
- continue; //empty, skip it.
- }
- Privilege privilege = accessControlManager.privilegeFromName(name);
- grantedPrivilegeList.add(privilege);
- }
- }
- //add the privileges that should be preserved
- grantedPrivilegeList.addAll(preserveGrantedPrivileges);
-
- if (grantedPrivilegeList.size() > 0) {
- Principal principal = authorizable.getPrincipal();
- updatedAcl.addAccessControlEntry(principal, grantedPrivilegeList.toArray(new Privilege[grantedPrivilegeList.size()]));
- }
-
- //if the authorizable is a user (not a group) process any denied privileges
- if (!authorizable.isGroup()) {
- //add a fresh ACE with the denied privileges
- List<Privilege> deniedPrivilegeList = new ArrayList<Privilege>();
- if (deniedPrivilegeNames != null) {
- for (String name : deniedPrivilegeNames) {
- if (name.length() == 0) {
- continue; //empty, skip it.
- }
- Privilege privilege = accessControlManager.privilegeFromName(name);
- deniedPrivilegeList.add(privilege);
- }
- }
- //add the privileges that should be preserved
- deniedPrivilegeList.addAll(preserveDeniedPrivileges);
- if (deniedPrivilegeList.size() > 0) {
- Principal principal = authorizable.getPrincipal();
- AccessControlUtil.addEntry(updatedAcl, principal, deniedPrivilegeList.toArray(new Privilege[deniedPrivilegeList.size()]), false);
- }
- }
-
- accessControlManager.setPolicy(resourcePath, updatedAcl);
}
/**
Modified: sling/trunk/bundles/jcr/jackrabbit-accessmanager/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/jackrabbit-accessmanager/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java?rev=916893&r1=916892&r2=916893&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/jackrabbit-accessmanager/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java (original)
+++ sling/trunk/bundles/jcr/jackrabbit-accessmanager/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java Sat Feb 27 02:02:09 2010
@@ -16,8 +16,15 @@
*/
package org.apache.sling.jcr.jackrabbit.accessmanager.post;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceNotFoundException;
+import org.apache.sling.api.servlets.HtmlResponse;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
+import org.apache.sling.servlets.post.Modification;
+
import java.security.Principal;
-import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
@@ -26,31 +33,16 @@
import javax.jcr.Item;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
-import javax.jcr.security.AccessControlEntry;
-import javax.jcr.security.AccessControlList;
-import javax.jcr.security.AccessControlManager;
-import javax.jcr.security.Privilege;
-
-import org.apache.jackrabbit.api.security.user.Authorizable;
-import org.apache.jackrabbit.api.security.user.UserManager;
-import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceNotFoundException;
-import org.apache.sling.api.servlets.HtmlResponse;
-import org.apache.sling.jcr.base.util.AccessControlUtil;
-import org.apache.sling.servlets.post.Modification;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* <p>
- * Sling Post Servlet implementation for modifying the ACE for a principal on a JCR
+ * Sling Post Servlet implementation for modifying the ACEs for a principal on a JCR
* resource.
* </p>
* <h2>Rest Service Description</h2>
* <p>
- * Delete a set of Ace's from a node, the node is identified as a resource by the request
- * url >resource<.modifyAce.html
+ * Modify a principal's ACEs for the node identified as a resource by the request
+ * URL >resource<.modifyAce.html
* </p>
* <h4>Methods</h4>
* <ul>
@@ -59,11 +51,11 @@
* <h4>Post Parameters</h4>
* <dl>
* <dt>principalId</dt>
- * <dd>The principal of the Ace to modify in the ACL specified by the path.</dd>
+ * <dd>The principal of the ACEs to modify in the ACL specified by the path.</dd>
* <dt>privilege@*</dt>
- * <dd>One of more privileges, either granted or denied, where set the permission in the
- * stored ACE is modified to match the request. Any permissions that are present in the
- * stored ACE, but are not in the request are left untouched.</dd>
+ * <dd>One or more privileges, either granted or denied or none, which will be applied
+ * to (or removed from) the node ACL. Any permissions that are present in an
+ * existing ACE for the principal but not in the request are left untouched.</dd>
* </dl>
*
* <h4>Response</h4>
@@ -92,11 +84,6 @@
public class ModifyAceServlet extends AbstractAccessPostServlet {
private static final long serialVersionUID = -9182485466670280437L;
- /**
- * default log
- */
- private final Logger log = LoggerFactory.getLogger(getClass());
-
/* (non-Javadoc)
* @see org.apache.sling.jackrabbit.accessmanager.post.AbstractAccessPostServlet#handleOperation(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
*/
@@ -113,88 +100,25 @@
if (principalId == null) {
throw new RepositoryException("principalId was not submitted.");
}
- UserManager userManager = AccessControlUtil.getUserManager(session);
- Authorizable authorizable = userManager.getAuthorizable(principalId);
- if (authorizable == null) {
- throw new RepositoryException("No principal found for id: " + principalId);
- }
-
- String resourcePath = null;
- Resource resource = request.getResource();
- if (resource == null) {
+ PrincipalManager principalManager = AccessControlUtil.getPrincipalManager(session);
+ Principal principal = principalManager.getPrincipal(principalId);
+ String resourcePath = null;
+ Resource resource = request.getResource();
+ if (resource == null) {
throw new ResourceNotFoundException("Resource not found.");
- } else {
- Item item = resource.adaptTo(Item.class);
- if (item != null) {
- resourcePath = item.getPath();
- } else {
- throw new ResourceNotFoundException("Resource is not a JCR Node");
- }
- }
-
- try {
- AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
-
- //SLING-997: keep track of the privilege names that were posted, so the others can be preserved
- PrivilegesState privilegesInfo = new PrivilegesState(log.isDebugEnabled());
-
- //calculate which privileges were POSTed.
- collectPostedPrivilegeNames(request,
- accessControlManager,
- privilegesInfo);
-
- //find the existing ACL
- AccessControlList updatedAcl = getAccessControlList(accessControlManager, resourcePath, true);
-
- //keep track of the existing ACEs for the target principal
- List<AccessControlEntry> oldAces = processExistingAccessControlEntries(resourcePath,
- authorizable,
- accessControlManager,
- updatedAcl,
- privilegesInfo);
-
- //remove the old ACEs. Re-created below.
- if (!oldAces.isEmpty()) {
- for (AccessControlEntry ace : oldAces) {
- updatedAcl.removeAccessControlEntry(ace);
- }
+ } else {
+ Item item = resource.adaptTo(Item.class);
+ if (item != null) {
+ resourcePath = item.getPath();
+ } else {
+ throw new ResourceNotFoundException("Resource is not a JCR Node");
}
-
- //re-aggregate the granted/denied privileges into the best matched aggregate privilege
- reaggregatePrivileges(resourcePath,
- accessControlManager,
- privilegesInfo);
-
- //add fresh ACEs with the granted privileges
- buildFreshAccessControlEntries(authorizable,
- accessControlManager,
- updatedAcl,
- privilegesInfo);
-
- //store the updated ACL
- accessControlManager.setPolicy(resourcePath, updatedAcl);
- if (session.hasPendingChanges()) {
- session.save();
- }
-
- if (log.isDebugEnabled()) {
- log.debug("Updated ACE for principalId {0} for resource {1) from {2} to {3}", new Object [] {
- authorizable.getID(), resourcePath, privilegesInfo.oldPrivileges.toString(), privilegesInfo.newPrivileges.toString()
- });
- }
- } catch (RepositoryException re) {
- throw new RepositoryException("Failed to create ace.", re);
}
- }
-
-
- /**
- * Collect the privileges to assign from the http request.
- */
- private void collectPostedPrivilegeNames(SlingHttpServletRequest request,
- AccessControlManager accessControlManager,
- PrivilegesState privilegesInfo) throws RepositoryException {
-
+
+ // Collect the modified privileges from the request.
+ Set<String> grantedPrivilegeNames = new HashSet<String>();
+ Set<String> deniedPrivilegeNames = new HashSet<String>();
+ Set<String> removedPrivilegeNames = new HashSet<String>();
Enumeration<?> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
Object nextElement = parameterNames.nextElement();
@@ -202,237 +126,31 @@
String paramName = (String)nextElement;
if (paramName.startsWith("privilege@")) {
String privilegeName = paramName.substring(10);
- //keep track of which privileges should be changed
- privilegesInfo.postedPrivilegeNames.add(privilegeName);
-
String parameterValue = request.getParameter(paramName);
if (parameterValue != null && parameterValue.length() > 0) {
if ("granted".equals(parameterValue)) {
- Privilege privilege = accessControlManager.privilegeFromName(privilegeName);
- if (privilege.isAggregate()) {
- Privilege[] aggregatePrivileges = privilege.getAggregatePrivileges();
- for (Privilege privilege2 : aggregatePrivileges) {
- privilegesInfo.grantedPrivilegeNames.add(privilege2.getName());
- }
- } else {
- privilegesInfo.grantedPrivilegeNames.add(privilegeName);
- }
+ grantedPrivilegeNames.add(privilegeName);
} else if ("denied".equals(parameterValue)) {
- Privilege privilege = accessControlManager.privilegeFromName(privilegeName);
- if (privilege.isAggregate()) {
- Privilege[] aggregatePrivileges = privilege.getAggregatePrivileges();
- for (Privilege privilege2 : aggregatePrivileges) {
- privilegesInfo.deniedPrivilegeNames.add(privilege2.getName());
- }
- } else {
- privilegesInfo.deniedPrivilegeNames.add(privilegeName);
- }
- }
- }
- }
- }
- }
- }
-
- /**
- * Process the existing ACL to determine which privileges to preserve.
- */
- private List<AccessControlEntry> processExistingAccessControlEntries(
- String resourcePath,
- Authorizable authorizable,
- AccessControlManager accessControlManager,
- AccessControlList updatedAcl,
- PrivilegesState privilegesInfo) throws RepositoryException {
-
- String principalId = authorizable.getPrincipal().getName();
- AccessControlEntry[] accessControlEntries = updatedAcl.getAccessControlEntries();
- List<AccessControlEntry> oldAces = new ArrayList<AccessControlEntry>();
- for (AccessControlEntry ace : accessControlEntries) {
- if (principalId.equals(ace.getPrincipal().getName())) {
- if (log.isDebugEnabled()) {
- log.debug("Found Existing ACE for principal {0} on resource: ", new Object[] {principalId, resourcePath});
- }
- oldAces.add(ace);
-
- boolean isAllow = AccessControlUtil.isAllow(ace);
- Privilege[] privileges = ace.getPrivileges();
-
- //build a list of (merged and expanded) privileges
- Set<Privilege> mergedExistingPrivileges = new HashSet<Privilege>();
- for (Privilege privilege : privileges) {
- if (privilege.isAggregate()) {
- Privilege[] aggregatePrivileges = privilege.getAggregatePrivileges();
- for (Privilege privilege2 : aggregatePrivileges) {
- mergedExistingPrivileges.add(privilege2);
- }
- } else {
- mergedExistingPrivileges.add(privilege);
- }
- }
-
- //now process the merged privileges set
- for (Privilege privilege : mergedExistingPrivileges) {
- String privilegeName = privilege.getName();
- if (!privilegesInfo.postedPrivilegeNames.contains(privilegeName)) {
- //this privilege was not posted, so record the existing state to be
- // preserved when the ACE is re-created below
- if (isAllow) {
- privilegesInfo.grantedPrivilegeNames.add(privilegeName);
- } else {
- privilegesInfo.deniedPrivilegeNames.add(privilegeName);
- }
- }
-
- if (log.isDebugEnabled()) {
- //collect the information for debug logging
- if (privilegesInfo.oldPrivileges.length() > 0) {
- privilegesInfo.oldPrivileges.append(", "); //separate entries by commas
- }
- if (isAllow) {
- privilegesInfo.oldPrivileges.append("granted=");
+ deniedPrivilegeNames.add(privilegeName);
} else {
- privilegesInfo.oldPrivileges.append("denied=");
+ removedPrivilegeNames.add(privilegeName);
}
- privilegesInfo.oldPrivileges.append(privilege.getName());
- }
- }
- }
- }
-
- return oldAces;
- }
-
- /**
- * Given the set of granted/denied privileges, try to combine them
- * into the best aggregate Privilege that contains them all.
- */
- private void reaggregatePrivileges(
- String resourcePath,
- AccessControlManager accessControlManager,
- PrivilegesState privilegesInfo) throws RepositoryException {
- Privilege[] supportedPrivileges = accessControlManager.getSupportedPrivileges(resourcePath);
- for (Privilege privilege : supportedPrivileges) {
- if (privilege.isAggregate()) {
- boolean grantedAggregatePrivilege = true;
- boolean deniedAggregatePrivilege = true;
- Privilege[] aggregatePrivileges = privilege.getAggregatePrivileges();
- for (Privilege privilege2 : aggregatePrivileges) {
- String name = privilege2.getName();
- if (!privilegesInfo.grantedPrivilegeNames.contains(name)) {
- grantedAggregatePrivilege = false;
- }
- if (!privilegesInfo.deniedPrivilegeNames.contains(name)) {
- deniedAggregatePrivilege = false;
- }
- }
-
- if (grantedAggregatePrivilege) {
- //add the aggregate privilege and remove the containing parts
- privilegesInfo.grantedPrivilegeNames.add(privilege.getName());
- for (Privilege privilege2 : aggregatePrivileges) {
- String name = privilege2.getName();
- privilegesInfo.grantedPrivilegeNames.remove(name);
- }
- }
-
- if (deniedAggregatePrivilege) {
- //add the aggregate privilege and remove the containing parts
- privilegesInfo.deniedPrivilegeNames.add(privilege.getName());
- for (Privilege privilege2 : aggregatePrivileges) {
- String name = privilege2.getName();
- privilegesInfo.deniedPrivilegeNames.remove(name);
- }
- }
- }
- }
- }
-
- /**
- * Create new ACE for the granted and denied privileges.
- */
- private void buildFreshAccessControlEntries(
- Authorizable authorizable,
- AccessControlManager accessControlManager,
- AccessControlList updatedAcl,
- PrivilegesState privilegesInfo) throws RepositoryException {
- List<Privilege> grantedPrivilegeList = new ArrayList<Privilege>();
- for (String name : privilegesInfo.grantedPrivilegeNames) {
- if (name.length() == 0) {
- continue; //empty, skip it.
- }
- Privilege privilege = accessControlManager.privilegeFromName(name);
- grantedPrivilegeList.add(privilege);
- }
-
- if (log.isDebugEnabled()) {
- for (Privilege privilege : grantedPrivilegeList) {
- if (privilegesInfo.newPrivileges.length() > 0) {
- privilegesInfo.newPrivileges.append(", "); //separate entries by commas
- }
- privilegesInfo.newPrivileges.append("granted=");
- privilegesInfo.newPrivileges.append(privilege.getName());
- }
- }
-
- if (grantedPrivilegeList.size() > 0) {
- Principal principal = authorizable.getPrincipal();
- updatedAcl.addAccessControlEntry(principal, grantedPrivilegeList.toArray(new Privilege[grantedPrivilegeList.size()]));
- }
-
- //if the authorizable is a user (not a group) process any denied privileges
- if (!authorizable.isGroup()) {
- //add a fresh ACE with the denied privileges
- List<Privilege> deniedPrivilegeList = new ArrayList<Privilege>();
- for (String name : privilegesInfo.deniedPrivilegeNames) {
- if (name.length() == 0) {
- continue; //empty, skip it.
- }
- Privilege privilege = accessControlManager.privilegeFromName(name);
- deniedPrivilegeList.add(privilege);
- }
-
- if (log.isDebugEnabled()) {
- for (Privilege privilege : deniedPrivilegeList) {
- if (privilegesInfo.newPrivileges.length() > 0) {
- privilegesInfo.newPrivileges.append(", "); //separate entries by commas
}
- privilegesInfo.newPrivileges.append("denied=");
- privilegesInfo.newPrivileges.append(privilege.getName());
}
}
-
- if (deniedPrivilegeList.size() > 0) {
- Principal principal = authorizable.getPrincipal();
- AccessControlUtil.addEntry(updatedAcl, principal, deniedPrivilegeList.toArray(new Privilege[deniedPrivilegeList.size()]), false);
- }
}
- }
-
- /**
- * Contains the information about the privilege state as it
- * progresses through the update process.
- */
- private static class PrivilegesState {
- //stores the names of the privileges that were POSTed
- Set<String> postedPrivilegeNames = new HashSet<String>();
-
- //stores the names of the privileges to be granted
- Set<String> grantedPrivilegeNames = new HashSet<String>();
-
- //stores the names of the privileges to be denied
- Set<String> deniedPrivilegeNames = new HashSet<String>();
-
- //collects debug information about the previous privileges
- StringBuilder oldPrivileges = null;
-
- //collects debug information about the new privileges
- StringBuilder newPrivileges = null;
- public PrivilegesState(boolean isDebugEnabled) {
- if (isDebugEnabled) {
- oldPrivileges = new StringBuilder();
- newPrivileges = new StringBuilder();
+ // Make the actual changes.
+ try {
+ AccessControlUtil.replaceAccessControlEntry(session, resourcePath, principal,
+ grantedPrivilegeNames.toArray(new String[grantedPrivilegeNames.size()]),
+ deniedPrivilegeNames.toArray(new String[deniedPrivilegeNames.size()]),
+ removedPrivilegeNames.toArray(new String[removedPrivilegeNames.size()]));
+ if (session.hasPendingChanges()) {
+ session.save();
}
+ } catch (RepositoryException re) {
+ throw new RepositoryException("Failed to create ace.", re);
}
}
}
Modified: sling/trunk/launchpad/testing/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/accessManager/ModifyAceTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/testing/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/accessManager/ModifyAceTest.java?rev=916893&r1=916892&r2=916893&view=diff
==============================================================================
--- sling/trunk/launchpad/testing/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/accessManager/ModifyAceTest.java (original)
+++ sling/trunk/launchpad/testing/src/test/java/org/apache/sling/launchpad/webapp/integrationtest/accessManager/ModifyAceTest.java Sat Feb 27 02:02:09 2010
@@ -398,10 +398,9 @@
postParams2.add(new NameValuePair("principalId", testUserId));
//jcr:read is not posted, so it should remain in the granted ACE
- //post the remaining privileges that when combined, correspond to the jcr:write aggregate privilege
- postParams2.add(new NameValuePair("privilege@jcr:addChildNodes", "denied")); //add a new privilege
- postParams2.add(new NameValuePair("privilege@jcr:removeChildNodes", "denied")); //add a new privilege
- postParams2.add(new NameValuePair("privilege@jcr:modifyProperties", "denied")); //add a new privilege
+ //deny the full jcr:write aggregate privilege, which should merge with the
+ //existing part.
+ postParams2.add(new NameValuePair("privilege@jcr:write", "denied")); //add a new privilege
assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams2, null);