public static void replaceAccessControlEntry()

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
    			});
    	}
	}