in src/main/java/org/apache/sling/jcr/base/util/AccessControlUtil.java [418:612]
public static void replaceAccessControlEntry(Session session, String resourcePath, Principal principal,
String[] grantedPrivilegeNames, String[] deniedPrivilegeNames, String[] removedPrivilegeNames,
String order,
Map<String, Value> restrictions,
Map<String, Value[]> mvRestrictions,
Set<String> removedRestrictionNames)
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);
//make a copy since we may need to merge and change the map before applying them
Map<String, Value> newRestrictions = new HashMap<>();
Map<String, Value[]> newMvRestrictions = new HashMap<>();
if (restrictions != null) {
Set<Entry<String, Value>> entrySet = restrictions.entrySet();
for (Entry<String, Value> entry : entrySet) {
String key = entry.getKey();
if (removedRestrictionNames != null && removedRestrictionNames.contains(key)) {
// new restriction is also in the removed set, so no need to try to remove it
removedRestrictionNames.remove(key);
}
newRestrictions.put(key, entry.getValue());
}
}
if (mvRestrictions != null) {
Set<Entry<String, Value[]>> entrySet = mvRestrictions.entrySet();
for (Entry<String, Value[]> entry : entrySet) {
String key = entry.getKey();
if (removedRestrictionNames != null && removedRestrictionNames.contains(key)) {
// new restriction is also in the removed set, so no need to try to remove it
removedRestrictionNames.remove(key);
}
newMvRestrictions.put(key, entry.getValue());
}
}
// 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 (int i=0; i < accessControlEntries.length; i++) {
AccessControlEntry ace = accessControlEntries[i];
if (principal.equals(ace.getPrincipal())) {
if (log.isDebugEnabled()) {
log.debug("Found Existing ACE for principal {} on resource {}", new Object[] {principal.getName(), resourcePath});
}
if (order == null || order.length() == 0) {
//order not specified, so keep track of the original ACE position.
order = String.valueOf(i);
}
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);
}
}
}
// If there is any existing restrictions that are not specified with the newly specified arguments,
// then maintain the original restriction values as they were.
if (ace instanceof JackrabbitAccessControlEntry) {
JackrabbitAccessControlEntry jace = (JackrabbitAccessControlEntry)ace;
String[] restrictionNames = jace.getRestrictionNames();
if (restrictionNames != null) {
for (String rname : restrictionNames) {
if (!(newRestrictions.containsKey(rname) || newMvRestrictions.containsKey(rname))) {
// the restriction doesn't have a new value, so remember the old value
try {
Value restriction = jace.getRestriction(rname);
newRestrictions.put(rname, restriction);
} catch (Exception vfe) {
if (vfe instanceof ValueFormatException) {
//try multival variant (only valid for jackrabbit-api 2.8.0 or later)
Value[] rvalue = safeInvokeRepoMethod(ace, METHOD_JACKRABBIT_ACE_GET_RESTRICTIONS, Value[].class,
new Object[] {rname}, new Class[] {String.class});
newMvRestrictions.put(rname, rvalue);
} else {
//some other exception, so just re-throw the original
throw vfe;
}
}
}
}
}
}
// Remove the old ACE.
acl.removeAccessControlEntry(ace);
}
}
//remove the map entry for any restrictions were requested to be removed and no new value was
// supplied
if (removedRestrictionNames != null) {
for (String rname : removedRestrictionNames) {
// remove if a new value was not also supplied
if (!((restrictions != null && restrictions.containsKey(rname)) ||
(mvRestrictions != null && mvRestrictions.containsKey(rname)))) {
newRestrictions.remove(rname);
newMvRestrictions.remove(rname);
}
}
}
//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) {
addEntry(acl, principal, grantedPrivilegeList.toArray(new Privilege[grantedPrivilegeList.size()]), true,
newRestrictions, newMvRestrictions);
}
//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,
newRestrictions, newMvRestrictions);
}
//order the ACL
reorderAccessControlEntries(acl, principal, order);
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 principalName {} for resource {} from grants {}, denies {} to grants {}, denies {}", new Object [] {
principal.getName(), resourcePath, oldGrantedNames, oldDeniedNames, newGrantedPrivilegeNames, newDeniedPrivilegeNames
});
}
}