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 2018/12/16 21:58:21 UTC

[sling-org-apache-sling-jcr-jackrabbit-accessmanager] branch master updated: SLING-8117 Add support to read/write ACE restrictions from REST

This is an automated email from the ASF dual-hosted git repository.

enorman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-jackrabbit-accessmanager.git


The following commit(s) were added to refs/heads/master by this push:
     new 3dc7c2f  SLING-8117 Add support to read/write ACE restrictions from REST
3dc7c2f is described below

commit 3dc7c2fb05926e60f3699a0c2f0c337264a82637
Author: Eric Norman <en...@apache.org>
AuthorDate: Sun Dec 16 13:58:12 2018 -0800

    SLING-8117 Add support to read/write ACE restrictions from REST
---
 pom.xml                                            |  33 +++++-
 .../jcr/jackrabbit/accessmanager/ModifyAce.java    |  50 +++++++-
 .../jackrabbit/accessmanager/PrivilegesInfo.java   |  55 +++++++++
 .../jcr/jackrabbit/accessmanager/package-info.java |   2 +-
 .../accessmanager/post/AbstractGetAclServlet.java  |  87 +++++++++++---
 .../accessmanager/post/ModifyAceServlet.java       | 126 ++++++++++++++++++---
 .../accessmanager/post/package-info.java           |   2 +-
 7 files changed, 316 insertions(+), 39 deletions(-)

diff --git a/pom.xml b/pom.xml
index 57d5626..43e1abf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,7 +40,10 @@
         <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-jackrabbit-accessmanager.git</developerConnection>
         <url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-jcr-jackrabbit-accessmanager.git</url>
       <tag>HEAD</tag>
-  </scm>
+    </scm>
+    <properties>
+        <sling.java.version>8</sling.java.version>
+    </properties>
 
     <build>
         <plugins>
@@ -68,6 +71,18 @@
 
     <dependencies>
         <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.cmpn</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+            
+        <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
         </dependency>
@@ -97,7 +112,13 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.jcr.base</artifactId>
-            <version>2.1.0</version>
+            <version>3.0.6</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>oak-security-spi</artifactId>
+            <version>1.8.0</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
@@ -116,8 +137,14 @@
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.testing.sling-mock</artifactId>
+            <version>2.3.4</version>
+            <scope>test</scope>
+        </dependency>        
+        <dependency>
+            <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.testing.sling-mock-oak</artifactId>
-            <version>2.0.2</version>
+            <version>2.1.2</version>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/ModifyAce.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/ModifyAce.java
index 06c7964..6ad8095 100644
--- a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/ModifyAce.java
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/ModifyAce.java
@@ -19,9 +19,12 @@
 package org.apache.sling.jcr.jackrabbit.accessmanager;
 
 import java.util.Map;
+import java.util.Set;
 
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
 
 /**
  * The <code>ModifyAce</code> service api.
@@ -40,8 +43,16 @@ public interface ModifyAce {
 	 * @param resourcePath The absolute path of the resource to apply the ACE to (required)
 	 * @param principalId The name of the user/group to provision (required)
 	 * @param privileges Map of privileges to apply. (optional)
-     * @param changes The list of changes for this operation (optional)
-     * @return the user that was updated or null if not found 
+     * @param order where the access control entry should go in the list.
+     *         Value should be one of these:
+     *         <table>
+     *          <tr><td>null</td><td>If the ACE for the principal doesn't exist add at the end, otherwise leave the ACE at it's current position.</td></tr>
+     * 			<tr><td>first</td><td>Place the target ACE as the first amongst its siblings</td></tr>
+	 *			<tr><td>last</td><td>Place the target ACE as the last amongst its siblings</td></tr>
+	 * 			<tr><td>before xyz</td><td>Place the target ACE immediately before the sibling whose name is xyz</td></tr>
+	 * 			<tr><td>after xyz</td><td>Place the target ACE immediately after the sibling whose name is xyz</td></tr>
+	 * 			<tr><td>numeric</td><td>Place the target ACE at the specified numeric index</td></tr>
+	 *         </table>
 	 * @throws RepositoryException
 	 */
 	void modifyAce(Session jcrSession,
@@ -51,4 +62,39 @@ public interface ModifyAce {
 							String order
 				) throws RepositoryException;
 	
+	/**
+	 * Add or modify the access control entry for the specified user 
+	 * or group.
+	 * 
+	 * @param jcrSession the JCR session of the user updating the user
+	 * @param resourcePath The absolute path of the resource to apply the ACE to (required)
+	 * @param principalId The name of the user/group to provision (required)
+	 * @param privileges Map of privileges to apply. (optional)
+     * @param order where the access control entry should go in the list.
+     *         Value should be one of these:
+     *         <table>
+     *          <tr><td>null</td><td>If the ACE for the principal doesn't exist add at the end, otherwise leave the ACE at it's current position.</td></tr>
+     * 			<tr><td>first</td><td>Place the target ACE as the first amongst its siblings</td></tr>
+	 *			<tr><td>last</td><td>Place the target ACE as the last amongst its siblings</td></tr>
+	 * 			<tr><td>before xyz</td><td>Place the target ACE immediately before the sibling whose name is xyz</td></tr>
+	 * 			<tr><td>after xyz</td><td>Place the target ACE immediately after the sibling whose name is xyz</td></tr>
+	 * 			<tr><td>numeric</td><td>Place the target ACE at the specified numeric index</td></tr>
+	 *         </table>
+	 * @param restrictions Map of single-value restrictions to apply. (optional)
+	 * @param mvRestrictions Map of multi-value restrictions to apply. (optional)
+	 * @param removeRestrictionNames Set of existing restriction names to remove (optional)
+	 * @throws RepositoryException
+	 */
+	default void modifyAce(Session jcrSession,
+							String resourcePath,
+							String principalId,
+							Map<String, String> privileges,
+							String order,
+							Map<String, Value> restrictions,
+							Map<String, Value[]> mvRestrictions,
+							Set<String> removeRestrictionNames
+				) throws RepositoryException {
+		throw new UnsupportedRepositoryOperationException();
+	}
+
 }
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/PrivilegesInfo.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/PrivilegesInfo.java
index 0232e2f..b4f7744 100644
--- a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/PrivilegesInfo.java
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/PrivilegesInfo.java
@@ -31,12 +31,15 @@ import java.util.Set;
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
 import javax.jcr.security.AccessControlEntry;
 import javax.jcr.security.AccessControlList;
 import javax.jcr.security.AccessControlManager;
 import javax.jcr.security.AccessControlPolicy;
 import javax.jcr.security.Privilege;
 
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
 import org.apache.sling.jcr.base.util.AccessControlUtil;
 
 /**
@@ -241,6 +244,58 @@ public class PrivilegesInfo {
 		return rights;
 	}
 	
+	/**
+	 * Returns the restrictions for the specified path.
+	 * 
+	 * @param node the node to inspect
+	 * @param principalId the principalId to get the access rights for
+	 * @return map of restrictions (key is restriction name, value is Value or Value[])
+	 * @throws RepositoryException
+	 */
+	public Map<String, Object> getDeclaredRestrictionsForPrincipal(Node node, String principalId) throws RepositoryException {
+		return getDeclaredRestrictionsForPrincipal(node.getSession(), node.getPath(), principalId);
+	}
+	
+	/**
+	 * Returns the restrictions for the specified path.
+	 * 
+	 * @param session the session for the current user
+	 * @param absPath the path to get the privileges for
+	 * @param principalId the principalId to get the access rights for
+	 * @return map of restrictions (key is restriction name, value is Value or Value[])
+	 * @throws RepositoryException
+	 */
+	public Map<String, Object> getDeclaredRestrictionsForPrincipal(Session session, String absPath, String principalId) throws RepositoryException {
+		Map<String, Object> restrictions = new LinkedHashMap<>();
+		AccessControlEntry[] entries = getDeclaredAccessControlEntries(session, absPath);
+		if (entries != null) {
+			for (AccessControlEntry ace : entries) {
+				if (principalId.equals(ace.getPrincipal().getName())) {
+					if (ace instanceof JackrabbitAccessControlEntry) {
+						JackrabbitAccessControlEntry jace = (JackrabbitAccessControlEntry)ace;
+						String[] restrictionNames = jace.getRestrictionNames();
+						if (restrictionNames != null) {
+							for (String name : restrictionNames) {
+								try {
+									Value value = jace.getRestriction(name);
+									if (value != null) {
+										restrictions.put(name, value);
+									}									
+								} catch (ValueFormatException vfe) {
+									//try multi-value restriction
+									Value[] values = jace.getRestrictions(name);
+									if (values != null && values.length > 0) {
+										restrictions.put(name,  values);
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		return restrictions;
+	}
 
 	
 	
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/package-info.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/package-info.java
index 5119ee5..e46171e 100644
--- a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/package-info.java
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/package-info.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@org.osgi.annotation.versioning.Version("3.0.0")
+@org.osgi.annotation.versioning.Version("3.1.0")
 package org.apache.sling.jcr.jackrabbit.accessmanager;
 
 
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAclServlet.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAclServlet.java
index 9ee88f6..72c9e19 100644
--- a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAclServlet.java
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAclServlet.java
@@ -17,6 +17,7 @@
 package org.apache.sling.jcr.jackrabbit.accessmanager.post;
 
 import java.io.IOException;
+import java.lang.reflect.Array;
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -31,6 +32,8 @@ import javax.jcr.AccessDeniedException;
 import javax.jcr.Item;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
 import javax.jcr.security.AccessControlEntry;
 import javax.jcr.security.Privilege;
 import javax.json.Json;
@@ -41,6 +44,7 @@ import javax.json.stream.JsonGenerator;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.SlingHttpServletResponse;
 import org.apache.sling.api.resource.ResourceNotFoundException;
@@ -120,6 +124,7 @@ public abstract class AbstractGetAclServlet extends SlingAllMethodsServlet {
 
         AccessControlEntry[] declaredAccessControlEntries = getAccessControlEntries(jcrSession, resourcePath);
         Map<String, Map<String, Object>> aclMap = new LinkedHashMap<String, Map<String,Object>>();
+        Map<String, Map<String, Object>> restrictionMap = new LinkedHashMap<String, Map<String,Object>>();
         int sequence = 0;
 
         for (AccessControlEntry ace : declaredAccessControlEntries) {
@@ -134,8 +139,31 @@ public abstract class AbstractGetAclServlet extends SlingAllMethodsServlet {
         //evaluate these in reverse order so the most entries with highest specificity are last
         for (int i = declaredAccessControlEntries.length - 1; i >= 0; i--) {
 			AccessControlEntry ace = declaredAccessControlEntries[i];
-
 			Principal principal = ace.getPrincipal();
+
+			if (ace instanceof JackrabbitAccessControlEntry) {
+				JackrabbitAccessControlEntry jace = (JackrabbitAccessControlEntry)ace;
+				String[] restrictionNames = jace.getRestrictionNames();
+				if (restrictionNames != null) {
+					Map<String, Object> restrictions = restrictionMap.get(principal.getName());
+					if (restrictions == null) {
+						restrictions = new HashMap<>();
+						restrictionMap.put(principal.getName(), restrictions);
+					}
+					for (String rname : restrictionNames) {
+						try {
+							//try as a single-value restriction
+							Value value = jace.getRestriction(rname);
+							restrictions.put(rname, value);
+						} catch (ValueFormatException vfe) {
+							//try as a multi-value restriction
+							Value[] values = jace.getRestrictions(rname);
+							restrictions.put(rname, values);
+						}
+					}
+				}
+			}
+			
             Map<String, Object> map = aclMap.get(principal.getName());
 
             Set<Privilege> grantedSet = (Set<Privilege>) map.get("granted");
@@ -196,6 +224,30 @@ public abstract class AbstractGetAclServlet extends SlingAllMethodsServlet {
                 aceObject.add("denied", arrayBuilder);
             }
             aceObject.add("order", (Integer) value.get("order"));
+
+            Map<String, Object> restrictions = restrictionMap.get(principalName);
+            if (restrictions != null && !restrictions.isEmpty()) {
+            	Set<Entry<String, Object>> entrySet2 = restrictions.entrySet();
+            	JsonObjectBuilder jsonRestrictions = Json.createObjectBuilder();
+            	for (Entry<String, Object> entry2 : entrySet2) {
+    				Object rvalue = entry2.getValue();
+    				if (rvalue != null) {
+    					if (rvalue.getClass().isArray()) {
+    		                JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();
+    		                int length = Array.getLength(rvalue);
+    		                for (int i= 0; i  < length; i++) {
+    		                	Object object = Array.get(rvalue, i);
+    		                	addTo(arrayBuilder, object);
+    		                }
+    		                jsonRestrictions.add(entry2.getKey(), arrayBuilder);
+    					} else {
+    						addTo(jsonRestrictions, entry2.getKey(), rvalue);
+    					}
+    				}
+    			}
+            	aceObject.add("restrictions", jsonRestrictions);
+            }
+            
             aclList.add(aceObject.build());
         }
         JsonObjectBuilder jsonAclMap = Json.createObjectBuilder();
@@ -208,6 +260,7 @@ public abstract class AbstractGetAclServlet extends SlingAllMethodsServlet {
             }
             jsonAclMap.add(entry.getKey(), builder);
         }
+
         for (JsonObject jsonObj : aclList) {
             jsonAclMap.add(jsonObj.getString("principal"), jsonObj);
         }
@@ -216,31 +269,35 @@ public abstract class AbstractGetAclServlet extends SlingAllMethodsServlet {
     }
     
     private JsonObjectBuilder addTo(JsonObjectBuilder builder, String key, Object value) {
-        if (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long)
-        {
+        if (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long) {
             builder.add(key, ((Number) value).longValue());
-        }
-        else if (value instanceof Float || value instanceof Double)
-        {
+        } else if (value instanceof Float || value instanceof Double) {
             builder.add(key, ((Number) value).doubleValue());
-        }
-        else if (value instanceof Privilege)
-        {
+        } else if (value instanceof Privilege) {
             JsonObjectBuilder privilegeBuilder = Json.createObjectBuilder();
             privilegeBuilder.add("name", ((Privilege) value).getName());
             builder.add(key, privilegeBuilder);
-        }
-        else if (value instanceof String)
-        {
+        } else if (value instanceof String) {
             builder.add(key, (String) value);
-        }
-        else
-        {
+        } else {
             builder.add(key, value.toString());
         }
         return builder;
     }
 
+    private JsonArrayBuilder addTo(JsonArrayBuilder builder, Object value) {
+        if (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long) {
+            builder.add(((Number) value).longValue());
+        } else if (value instanceof Float || value instanceof Double) {
+            builder.add(((Number) value).doubleValue());
+        } else if (value instanceof String) {
+            builder.add((String) value);
+        } else {
+            builder.add(value.toString());
+        }
+        return builder;
+    }
+
     protected abstract AccessControlEntry[] getAccessControlEntries(Session session, String absPath) throws RepositoryException;
 
 }
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java
index c11f85c..1282299 100644
--- a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java
@@ -28,9 +28,13 @@ import java.util.Set;
 import javax.jcr.Item;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
 import javax.servlet.Servlet;
 
 import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionDefinition;
+import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.ResourceNotFoundException;
 import org.apache.sling.jcr.base.util.AccessControlUtil;
@@ -42,6 +46,7 @@ import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.component.annotations.ReferenceCardinality;
 import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
 
 /**
  * <p>
@@ -66,6 +71,12 @@ import org.osgi.service.component.annotations.ReferencePolicy;
  * 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>
+ * <dt>restriction@*</dt>
+ * <dd>One or more restrictions which will be applied to the ACE</dd>
+ * </dl>
+ * <dt>restriction@*@Delete</dt>
+ * <dd>One or more restrictions which will be removed from the ACE</dd>
+ * </dl>
  *
  * <h4>Response</h4>
  * <dl>
@@ -94,6 +105,19 @@ property= {
 public class ModifyAceServlet extends AbstractAccessPostServlet implements ModifyAce {
 	private static final long serialVersionUID = -9182485466670280437L;
 
+	private RestrictionProvider restrictionProvider = null;
+
+	// NOTE: the @Reference annotation is not inherited, so subclasses will need to override the #bindRestrictionProvider 
+	// and #unbindRestrictionProvider methods to provide the @Reference annotation.     
+	//
+    @Reference(cardinality=ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC, policyOption=ReferencePolicyOption.GREEDY)
+    protected void bindRestrictionProvider(RestrictionProvider rp) {
+    	this.restrictionProvider = rp;
+    }
+    protected void unbindRestrictionProvider(RestrictionProvider rp) {
+    	this.restrictionProvider = null;
+    }
+    
     /**
      * Overridden since the @Reference annotation is not inherited from the super method
      *  
@@ -126,7 +150,15 @@ public class ModifyAceServlet extends AbstractAccessPostServlet implements Modif
 		Session session = request.getResourceResolver().adaptTo(Session.class);
     	String resourcePath = request.getResource().getPath();
 		String principalId = request.getParameter("principalId");
-		Map<String, String> privileges = new HashMap<String, String>();
+		Map<String, String> privileges = new HashMap<>();
+		Map<String, Value> restrictions = new HashMap<>();
+		Map<String, Value[]> mvRestrictions = new HashMap<>();
+		Set<String> removeRestrictionNames = new HashSet<>();
+
+		//lazy initialized map for quick lookup when processing POSTed restrictions
+		Map<String, RestrictionDefinition> supportedRestrictionsMap = null;
+		ValueFactory factory = session.getValueFactory();
+
 		Enumeration<?> parameterNames = request.getParameterNames();
 		while (parameterNames.hasMoreElements()) {
 			Object nextElement = parameterNames.nextElement();
@@ -136,19 +168,74 @@ public class ModifyAceServlet extends AbstractAccessPostServlet implements Modif
 					String privilegeName = paramName.substring(10);
 					String parameterValue = request.getParameter(paramName);
 					privileges.put(privilegeName, parameterValue);
+				} else if (paramName.startsWith("restriction@")) {
+					if (restrictionProvider == null) {
+						throw new IllegalArgumentException("No restriction provider is available so unable to process POSTed restriction values");
+					}
+					if (supportedRestrictionsMap == null) {
+						supportedRestrictionsMap = new HashMap<>();
+
+						//populate the map for quick lookup below
+						Set<RestrictionDefinition> supportedRestrictions = restrictionProvider.getSupportedRestrictions(resourcePath);
+						for (RestrictionDefinition restrictionDefinition : supportedRestrictions) {
+							supportedRestrictionsMap.put(restrictionDefinition.getName(), restrictionDefinition);
+						}
+					}
+					
+					if (paramName.endsWith("@Delete")) {
+						String restrictionName = paramName.substring(12, paramName.length() - 7);
+						removeRestrictionNames.add(restrictionName);
+					} else {
+						String restrictionName = paramName.substring(12);
+						String[] parameterValues = request.getParameterValues(paramName);
+						if (parameterValues != null) {
+							RestrictionDefinition rd = supportedRestrictionsMap.get(restrictionName);
+							if (rd == null) {
+								//illegal restriction name?
+								throw new IllegalArgumentException("Invalid or not supported restriction name was supplied");
+							}
+							
+							boolean multival = rd.getRequiredType().isArray();
+							int restrictionType = rd.getRequiredType().tag();
+							
+							if (multival) {
+								Value [] v = new Value[parameterValues.length];
+								for (int j = 0; j < parameterValues.length; j++) {
+									String string = parameterValues[j];
+									v[j] = factory.createValue(string, restrictionType);
+								}
+
+								mvRestrictions.put(restrictionName, v);
+							} else if (parameterValues.length > 0) {
+								Value v = factory.createValue(parameterValues[0], restrictionType);
+								restrictions.put(restrictionName, v);
+							}
+						}
+					}
 				}
 			}
 		}
 		String order = request.getParameter("order");
-    	modifyAce(session, resourcePath, principalId, privileges, order);
+    	modifyAce(session, resourcePath, principalId, privileges, order, restrictions, mvRestrictions, 
+    			removeRestrictionNames);
 	}
 	
+
 	/* (non-Javadoc)
 	 * @see org.apache.sling.jcr.jackrabbit.accessmanager.ModifyAce#modifyAce(javax.jcr.Session, java.lang.String, java.lang.String, java.util.Map, java.lang.String)
 	 */
 	public void modifyAce(Session jcrSession, String resourcePath,
 			String principalId, Map<String, String> privileges, String order)
 			throws RepositoryException {
+		modifyAce(jcrSession, resourcePath, principalId, privileges, order, null, null, null);
+	}
+	/* (non-Javadoc)
+	 * @see org.apache.sling.jcr.jackrabbit.accessmanager.ModifyAce#modifyAce(javax.jcr.Session, java.lang.String, java.lang.String, java.util.Map, java.lang.String, java.util.Map, java.util.Map, java.util.Set)
+	 */
+	@Override
+	public void modifyAce(Session jcrSession, String resourcePath, String principalId, Map<String, String> privileges,
+			String order, Map<String, Value> restrictions, Map<String, Value[]> mvRestrictions,
+			Set<String> removeRestrictionNames) throws RepositoryException {
 		if (jcrSession == null) {
 			throw new RepositoryException("JCR Session not found");
 		}
@@ -174,20 +261,22 @@ public class ModifyAceServlet extends AbstractAccessPostServlet implements Modif
 		Set<String> grantedPrivilegeNames = new HashSet<String>();
 		Set<String> deniedPrivilegeNames = new HashSet<String>();
 		Set<String> removedPrivilegeNames = new HashSet<String>();
-		Set<Entry<String, String>> entrySet = privileges.entrySet();
-		for (Entry<String, String> entry : entrySet) {
-			String privilegeName = entry.getKey();
-			if (privilegeName.startsWith("privilege@")) {
-				privilegeName = privilegeName.substring(10);
-			}
-			String parameterValue = entry.getValue();
-			if (parameterValue != null && parameterValue.length() > 0) {
-				if ("granted".equals(parameterValue)) {
-					grantedPrivilegeNames.add(privilegeName);
-				} else if ("denied".equals(parameterValue)) {
-					deniedPrivilegeNames.add(privilegeName);
-				} else if ("none".equals(parameterValue)){
-					removedPrivilegeNames.add(privilegeName);
+		if (privileges != null) {
+			Set<Entry<String, String>> entrySet = privileges.entrySet();
+			for (Entry<String, String> entry : entrySet) {
+				String privilegeName = entry.getKey();
+				if (privilegeName.startsWith("privilege@")) {
+					privilegeName = privilegeName.substring(10);
+				}
+				String parameterValue = entry.getValue();
+				if (parameterValue != null && parameterValue.length() > 0) {
+					if ("granted".equals(parameterValue)) {
+						grantedPrivilegeNames.add(privilegeName);
+					} else if ("denied".equals(parameterValue)) {
+						deniedPrivilegeNames.add(privilegeName);
+					} else if ("none".equals(parameterValue)){
+						removedPrivilegeNames.add(privilegeName);
+					}
 				}
 			}
 		}
@@ -198,7 +287,10 @@ public class ModifyAceServlet extends AbstractAccessPostServlet implements Modif
 					grantedPrivilegeNames.toArray(new String[grantedPrivilegeNames.size()]),
 					deniedPrivilegeNames.toArray(new String[deniedPrivilegeNames.size()]),
 					removedPrivilegeNames.toArray(new String[removedPrivilegeNames.size()]),
-					order);
+					order,
+					restrictions,
+					mvRestrictions,
+					removeRestrictionNames);
 			if (jcrSession.hasPendingChanges()) {
 				jcrSession.save();
 			}
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/package-info.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/package-info.java
index 79406f4..839033a 100644
--- a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/package-info.java
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/package-info.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@org.osgi.annotation.versioning.Version("3.1.0")
+@org.osgi.annotation.versioning.Version("3.2.0")
 package org.apache.sling.jcr.jackrabbit.accessmanager.post;