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>privil...@*</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("privil...@jcr:addChildNodes", "denied")); //add a new privilege
- postParams2.add(new
NameValuePair("privil...@jcr:removeChildNodes", "denied")); //add a new
privilege
- postParams2.add(new
NameValuePair("privil...@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("privil...@jcr:write",
"denied")); //add a new privilege
assertAuthenticatedPostStatus(creds, postUrl,
HttpServletResponse.SC_OK, postParams2, null);