You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:47:48 UTC

[sling-org-apache-sling-jcr-jackrabbit-usermanager] 02/13: SLING-875: New Bundle for a ResourceProvider and Sling Post Operations for interacting with the jackrabbit UserManager https://issues.apache.org/jira/browse/SLING-875

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

rombert pushed a commit to annotated tag org.apache.sling.jcr.jackrabbit.usermanager-2.0.2-incubator
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-jackrabbit-usermanager.git

commit 854533dccdb1e5a87f014716f594dbb8d9ec68fb
Author: Juan Vazquez <jv...@apache.org>
AuthorDate: Thu Mar 19 20:53:24 2009 +0000

    SLING-875: New Bundle for a ResourceProvider and Sling Post Operations for interacting with the jackrabbit UserManager
    https://issues.apache.org/jira/browse/SLING-875
    
    git-svn-id: https://svn.apache.org/repos/asf/incubator/sling/trunk/bundles/jcr/jackrabbit-usermanager@756191 13f79535-47bb-0310-9956-ffa450edef68
---
 ...n.java => AbstractAuthorizablePostServlet.java} | 411 +++++++++++++--------
 .../usermanager/post/AbstractGroupPostServlet.java |  95 +++++
 .../usermanager/post/AbstractUserPostServlet.java  |  81 ++++
 ...eration.java => ChangeUserPasswordServlet.java} |  22 +-
 ...GroupOperation.java => CreateGroupServlet.java} |  33 +-
 ...teUserOperation.java => CreateUserServlet.java} |  30 +-
 .../post/DeleteAuthorizableOperation.java          |  73 ----
 .../post/DeleteAuthorizableServlet.java            | 159 ++++++++
 ...zableOperation.java => UpdateGroupServlet.java} |  24 +-
 ...izableOperation.java => UpdateUserServlet.java} |  30 +-
 10 files changed, 662 insertions(+), 296 deletions(-)

diff --git a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/AbstractAuthorizableOperation.java b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/AbstractAuthorizablePostServlet.java
similarity index 65%
rename from src/main/java/org/apache/sling/jackrabbit/usermanager/post/AbstractAuthorizableOperation.java
rename to src/main/java/org/apache/sling/jackrabbit/usermanager/post/AbstractAuthorizablePostServlet.java
index 06f6577..ab1d5cf 100644
--- a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/AbstractAuthorizableOperation.java
+++ b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/AbstractAuthorizablePostServlet.java
@@ -16,15 +16,14 @@
  */
 package org.apache.sling.jackrabbit.usermanager.post;
 
-import java.io.UnsupportedEncodingException;
-import java.security.NoSuchAlgorithmException;
+import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Dictionary;
+import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.NoSuchElementException;
 
 import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
@@ -32,30 +31,39 @@ import javax.jcr.Session;
 import javax.jcr.Value;
 import javax.jcr.ValueFactory;
 import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import org.apache.jackrabbit.api.security.user.Authorizable;
-import org.apache.jackrabbit.api.security.user.Group;
-import org.apache.jackrabbit.util.Text;
 import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
 import org.apache.sling.api.request.RequestParameter;
-import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceNotFoundException;
+import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.servlets.HtmlResponse;
+import org.apache.sling.api.servlets.SlingAllMethodsServlet;
+import org.apache.sling.api.wrappers.SlingRequestPaths;
 import org.apache.sling.commons.osgi.OsgiUtil;
 import org.apache.sling.jackrabbit.usermanager.post.impl.DateParser;
 import org.apache.sling.jackrabbit.usermanager.post.impl.RequestProperty;
 import org.apache.sling.jackrabbit.usermanager.resource.AuthorizableResourceProvider;
-import org.apache.sling.servlets.post.AbstractSlingPostOperation;
 import org.apache.sling.servlets.post.Modification;
 import org.apache.sling.servlets.post.SlingPostConstants;
 import org.osgi.service.component.ComponentContext;
-
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * Base class for operations that do work on authorizable resources
+ * Base class for all the POST servlets for the UserManager operations 
  */
-public abstract class AbstractAuthorizableOperation extends AbstractSlingPostOperation {
-	
+public abstract class AbstractAuthorizablePostServlet extends SlingAllMethodsServlet {
+	private static final long serialVersionUID = -5918670409789895333L;
+
+	/**
+     * default log
+     */
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
     /**
      * @scr.property values.0="EEE MMM dd yyyy HH:mm:ss 'GMT'Z"
      *               values.1="yyyy-MM-dd'T'HH:mm:ss.SSSZ"
@@ -65,17 +73,7 @@ public abstract class AbstractAuthorizableOperation extends AbstractSlingPostOpe
     private static final String PROP_DATE_FORMAT = "servlet.post.dateFormats";
 	
 	private DateParser dateParser;
-
-
-	/**
-     * To be used for the encryption. E.g. for passwords in
-     * {@link javax.jcr.SimpleCredentials#getPassword()}  SimpleCredentials} 
-     * @scr.property valueRef="DEFAULT_PASSWORD_DIGEST_ALGORITHM"
-     */
-    private static final String PROP_PASSWORD_DIGEST_ALGORITHM = "password.digest.algorithm";
-    private static final String DEFAULT_PASSWORD_DIGEST_ALGORITHM = "sha1";
-    private String passwordDigestAlgoritm = null;
-
+	
     // ---------- SCR Integration ----------------------------------------------
 
     protected void activate(ComponentContext context) {
@@ -86,90 +84,178 @@ public abstract class AbstractAuthorizableOperation extends AbstractSlingPostOpe
         for (String dateFormat : dateFormats) {
             dateParser.register(dateFormat);
         }
-        Object propValue = props.get(PROP_PASSWORD_DIGEST_ALGORITHM);
-        if (propValue instanceof String) {
-        	passwordDigestAlgoritm = (String)propValue;
-        } else {
-        	passwordDigestAlgoritm = DEFAULT_PASSWORD_DIGEST_ALGORITHM;
-        }
     }
 
     protected void deactivate(ComponentContext context) {
         dateParser = null;
-        passwordDigestAlgoritm = null;
     }
 	
-    protected String digestPassword(String pwd) throws IllegalArgumentException {
+    
+	/* (non-Javadoc)
+	 * @see org.apache.sling.api.servlets.SlingAllMethodsServlet#doPost(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.SlingHttpServletResponse)
+	 */
+	@Override
+	protected void doPost(SlingHttpServletRequest request,
+			SlingHttpServletResponse httpResponse) throws ServletException,
+			IOException {
+        // prepare the response
+        HtmlResponse htmlResponse = new HtmlResponse();
+        htmlResponse.setReferer(request.getHeader("referer"));
+
+        // calculate the paths
+        String path = getItemPath(request);
+        htmlResponse.setPath(path);
+
+        // location
+        htmlResponse.setLocation(externalizePath(request, path));
+
+        // parent location
+        path = ResourceUtil.getParent(path);
+        if (path != null) {
+        	htmlResponse.setParentLocation(externalizePath(request, path));
+        }
+
+        Session session = request.getResourceResolver().adaptTo(Session.class);
+
+        final List<Modification> changes = new ArrayList<Modification>();
+        
         try {
-            StringBuffer password = new StringBuffer();
-            password.append("{").append(passwordDigestAlgoritm).append("}");
-            password.append(Text.digest(passwordDigestAlgoritm, pwd.getBytes("UTF-8")));
-            return password.toString();
-        } catch (NoSuchAlgorithmException e) {
-            throw new IllegalArgumentException(e.toString());
-        } catch (UnsupportedEncodingException e) {
-            throw new IllegalArgumentException(e.toString());
+            handleOperation(request, htmlResponse, changes);
+            
+            //TODO: maybe handle SlingAuthorizablePostProcessor handlers here
+            
+            // set changes on html response
+            for(Modification change : changes) {
+                switch ( change.getType() ) {
+                    case MODIFY : htmlResponse.onModified(change.getSource()); break;
+                    case DELETE : htmlResponse.onDeleted(change.getSource()); break;
+                    case MOVE :   htmlResponse.onMoved(change.getSource(), change.getDestination()); break;
+                    case COPY :   htmlResponse.onCopied(change.getSource(), change.getDestination()); break;
+                    case CREATE : htmlResponse.onCreated(change.getSource()); break;
+                    case ORDER : htmlResponse.onChange("ordered", change.getSource(), change.getDestination()); break;
+                }
+            }
+            
+            if (session.hasPendingChanges()) {
+                session.save();
+            }
+        } catch (ResourceNotFoundException rnfe) {
+            htmlResponse.setStatus(HttpServletResponse.SC_NOT_FOUND,
+                rnfe.getMessage());
+        } catch (Throwable throwable) {
+            log.debug("Exception while handling POST "
+                + request.getResource().getPath() + " with "
+                + getClass().getName(), throwable);
+            htmlResponse.setError(throwable);
+        } finally {
+            try {
+                if (session.hasPendingChanges()) {
+                    session.refresh(false);
+                }
+            } catch (RepositoryException e) {
+                log.warn("RepositoryException in finally block: {}",
+                    e.getMessage(), e);
+            }
         }
-    }
-	
+        
+        // check for redirect URL if processing succeeded
+        if (htmlResponse.isSuccessful()) {
+            String redirect = getRedirectUrl(request, htmlResponse);
+            if (redirect != null) {
+                httpResponse.sendRedirect(redirect);
+                return;
+            }
+        }
+
+        // create a html response and send if unsuccessful or no redirect
+        htmlResponse.send(httpResponse, isSetStatus(request));
+	}
 
+	/**
+	 * Extending Servlet should implement this operation to do the work
+	 * 
+	 * @param request the sling http request to process
+	 * @param htmlResponse the response 
+	 * @param changes 
+	 */
+	abstract protected void handleOperation(SlingHttpServletRequest request,
+			HtmlResponse htmlResponse, List<Modification> changes) throws RepositoryException;
+	
+	
     /**
-     * Update the group membership based on the ":member" request
-     * parameters.  If the ":member" value ends with @Delete it is removed
-     * from the group membership, otherwise it is added to the group membership.
-     * 
-     * @param request
-     * @param authorizable
-     * @throws RepositoryException
+     * compute redirect URL (SLING-126)
+     *
+     * @param ctx the post processor
+     * @return the redirect location or <code>null</code>
      */
-	protected void updateGroupMembership(SlingHttpServletRequest request,
-			Authorizable authorizable, List<Modification> changes) throws RepositoryException {
-		if (authorizable.isGroup()) {
-			Group group = ((Group)authorizable);
-    		String groupPath = AuthorizableResourceProvider.SYSTEM_USER_MANAGER_GROUP_PREFIX + group.getID(); 
-
-	    	ResourceResolver resolver = request.getResourceResolver();
-	    	Resource baseResource = request.getResource();
-	    	boolean changed = false;
-
-	    	//first remove any members posted as ":member@Delete"
-	    	String[] membersToDelete = request.getParameterValues(SlingPostConstants.RP_PREFIX + "member" + SlingPostConstants.SUFFIX_DELETE);
-	    	if (membersToDelete != null) {
-				for (String member : membersToDelete) {
-	                Resource res = resolver.getResource(baseResource, member);
-	                if (res != null) {
-	                	Authorizable memberAuthorizable = res.adaptTo(Authorizable.class);
-	                	if (memberAuthorizable != null) {
-	                		group.removeMember(memberAuthorizable);
-	                		changed = true;
-	                	}
-	                }
-					
-				}
-	    	}
-	    	
-	    	//second add any members posted as ":member"
-	    	String[] membersToAdd = request.getParameterValues(SlingPostConstants.RP_PREFIX + "member");
-	    	if (membersToAdd != null) {
-				for (String member : membersToAdd) {
-	                Resource res = resolver.getResource(baseResource, member);
-	                if (res != null) {
-	                	Authorizable memberAuthorizable = res.adaptTo(Authorizable.class);
-	                	if (memberAuthorizable != null) {
-	                		group.addMember(memberAuthorizable);
-	                		changed = true;
-	                	}
-	                }
-				}
-	    	}
-
-	    	if (changed) {
-        		//add an entry to the changes list to record the membership change
-        		changes.add(Modification.onModified(groupPath + "/members"));
-	    	}
-		}
-	}
-    
+    protected String getRedirectUrl(HttpServletRequest request, HtmlResponse ctx) {
+        // redirect param has priority (but see below, magic star)
+        String result = request.getParameter(SlingPostConstants.RP_REDIRECT_TO);
+        if (result != null && ctx.getPath() != null) {
+
+            // redirect to created/modified Resource
+            int star = result.indexOf('*');
+            if (star >= 0) {
+                StringBuffer buf = new StringBuffer();
+
+                // anything before the star
+                if (star > 0) {
+                    buf.append(result.substring(0, star));
+                }
+
+                // append the name of the manipulated node
+                buf.append(ResourceUtil.getName(ctx.getPath()));
+
+                // anything after the star
+                if (star < result.length() - 1) {
+                    buf.append(result.substring(star + 1));
+                }
+
+                // use the created path as the redirect result
+                result = buf.toString();
+
+            } else if (result.endsWith(SlingPostConstants.DEFAULT_CREATE_SUFFIX)) {
+                // if the redirect has a trailing slash, append modified node
+                // name
+                result = result.concat(ResourceUtil.getName(ctx.getPath()));
+            }
+
+            if (log.isDebugEnabled()) {
+                log.debug("Will redirect to " + result);
+            }
+        }
+        return result;
+    }
+
+    protected boolean isSetStatus(SlingHttpServletRequest request) {
+        String statusParam = request.getParameter(SlingPostConstants.RP_STATUS);
+        if (statusParam == null) {
+            log.debug(
+                "getStatusMode: Parameter {} not set, assuming standard status code",
+                SlingPostConstants.RP_STATUS);
+            return true;
+        }
+
+        if (SlingPostConstants.STATUS_VALUE_BROWSER.equals(statusParam)) {
+            log.debug(
+                "getStatusMode: Parameter {} asks for user-friendly status code",
+                SlingPostConstants.RP_STATUS);
+            return false;
+        }
+
+        if (SlingPostConstants.STATUS_VALUE_STANDARD.equals(statusParam)) {
+            log.debug(
+                "getStatusMode: Parameter {} asks for standard status code",
+                SlingPostConstants.RP_STATUS);
+            return true;
+        }
+
+        log.debug(
+            "getStatusMode: Parameter {} set to unknown value {}, assuming standard status code",
+            SlingPostConstants.RP_STATUS);
+        return true;
+    }
+	
     
     
     // ------ The methods below are based on the private methods from the ModifyOperation class -----
@@ -553,82 +639,79 @@ public abstract class AbstractAuthorizableOperation extends AbstractSlingPostOpe
 	}
 
 	
+	// ------ These methods were copied from AbstractSlingPostOperation ------
+
     /**
-     * Returns an iterator on <code>Resource</code> instances addressed in the
-     * {@link SlingPostConstants#RP_APPLY_TO} request parameter. If the request
-     * parameter is not set, <code>null</code> is returned. If the parameter
-     * is set with valid resources an empty iterator is returned. Any resources
-     * addressed in the {@link SlingPostConstants#RP_APPLY_TO} parameter is
-     * ignored.
-     *
-     * @param request The <code>SlingHttpServletRequest</code> object used to
-     *            get the {@link SlingPostConstants#RP_APPLY_TO} parameter.
-     * @return The iterator of resources listed in the parameter or
-     *         <code>null</code> if the parameter is not set in the request.
+     * Returns the path of the resource of the request as the item path.
+     * <p>
+     * This method may be overwritten by extension if the operation has
+     * different requirements on path processing.
      */
-    protected Iterator<Resource> getApplyToResources(
-            SlingHttpServletRequest request) {
-
-        String[] applyTo = request.getParameterValues(SlingPostConstants.RP_APPLY_TO);
-        if (applyTo == null) {
-            return null;
-        }
-
-        return new ApplyToIterator(request, applyTo);
+    protected String getItemPath(SlingHttpServletRequest request) {
+        return request.getResource().getPath();
     }
 
-    private static class ApplyToIterator implements Iterator<Resource> {
-
-        private final ResourceResolver resolver;
-        private final Resource baseResource;
-        private final String[] paths;
-
-        private int pathIndex;
-
-        private Resource nextResource;
-
-        ApplyToIterator(SlingHttpServletRequest request, String[] paths) {
-            this.resolver = request.getResourceResolver();
-            this.baseResource = request.getResource();
-            this.paths = paths;
-            this.pathIndex = 0;
-
-            nextResource = seek();
-        }
-
-        public boolean hasNext() {
-            return nextResource != null;
-        }
-
-        public Resource next() {
-            if (!hasNext()) {
-                throw new NoSuchElementException();
+    /**
+     * Returns an external form of the given path prepending the context path
+     * and appending a display extension.
+     *
+     * @param path the path to externalize
+     * @return the url
+     */
+    protected final String externalizePath(SlingHttpServletRequest request,
+            String path) {
+        StringBuffer ret = new StringBuffer();
+        ret.append(SlingRequestPaths.getContextPath(request));
+        ret.append(request.getResourceResolver().map(path));
+
+        // append optional extension
+        String ext = request.getParameter(SlingPostConstants.RP_DISPLAY_EXTENSION);
+        if (ext != null && ext.length() > 0) {
+            if (ext.charAt(0) != '.') {
+                ret.append('.');
             }
-
-            Resource result = nextResource;
-            nextResource = seek();
-
-            return result;
-        }
-
-        public void remove() {
-            throw new UnsupportedOperationException();
+            ret.append(ext);
         }
 
-        private Resource seek() {
-            while (pathIndex < paths.length) {
-                String path = paths[pathIndex];
-                pathIndex++;
+        return ret.toString();
+    }
+	
+    /**
+     * Returns <code>true</code> if the <code>name</code> starts with either
+     * of the prefixes
+     * {@link SlingPostConstants#ITEM_PREFIX_RELATIVE_CURRENT <code>./</code>},
+     * {@link SlingPostConstants#ITEM_PREFIX_RELATIVE_PARENT <code>../</code>}
+     * and {@link SlingPostConstants#ITEM_PREFIX_ABSOLUTE <code>/</code>}.
+     */
+    protected boolean hasItemPathPrefix(String name) {
+        return name.startsWith(SlingPostConstants.ITEM_PREFIX_ABSOLUTE)
+            || name.startsWith(SlingPostConstants.ITEM_PREFIX_RELATIVE_CURRENT)
+            || name.startsWith(SlingPostConstants.ITEM_PREFIX_RELATIVE_PARENT);
+    }
+    
+    /**
+     * Returns true if any of the request parameters starts with
+     * {@link SlingPostConstants#ITEM_PREFIX_RELATIVE_CURRENT <code>./</code>}.
+     * In this case only parameters starting with either of the prefixes
+     * {@link SlingPostConstants#ITEM_PREFIX_RELATIVE_CURRENT <code>./</code>},
+     * {@link SlingPostConstants#ITEM_PREFIX_RELATIVE_PARENT <code>../</code>}
+     * and {@link SlingPostConstants#ITEM_PREFIX_ABSOLUTE <code>/</code>} are
+     * considered as providing content to be stored. Otherwise all parameters
+     * not starting with the command prefix <code>:</code> are considered as
+     * parameters to be stored.
+     */
+    protected final boolean requireItemPathPrefix(
+            SlingHttpServletRequest request) {
 
-                Resource res = resolver.getResource(baseResource, path);
-                if (res != null) {
-                    return res;
-                }
-            }
+        boolean requirePrefix = false;
 
-            // no more elements in the array
-            return null;
+        Enumeration<?> names = request.getParameterNames();
+        while (names.hasMoreElements() && !requirePrefix) {
+            String name = (String) names.nextElement();
+            requirePrefix = name.startsWith(SlingPostConstants.ITEM_PREFIX_RELATIVE_CURRENT);
         }
+
+        return requirePrefix;
     }
-	
+    
 }
diff --git a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/AbstractGroupPostServlet.java b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/AbstractGroupPostServlet.java
new file mode 100644
index 0000000..675aeb8
--- /dev/null
+++ b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/AbstractGroupPostServlet.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.jackrabbit.usermanager.post;
+
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.jackrabbit.usermanager.resource.AuthorizableResourceProvider;
+import org.apache.sling.servlets.post.Modification;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/**
+ * Base class for servlets manipulating groups
+ */
+public abstract class AbstractGroupPostServlet extends AbstractAuthorizablePostServlet {
+	private static final long serialVersionUID = 1159063041816944076L;
+
+	/**
+     * Update the group membership based on the ":member" request
+     * parameters.  If the ":member" value ends with @Delete it is removed
+     * from the group membership, otherwise it is added to the group membership.
+     * 
+     * @param request
+     * @param authorizable
+     * @throws RepositoryException
+     */
+	protected void updateGroupMembership(SlingHttpServletRequest request,
+			Authorizable authorizable, List<Modification> changes) throws RepositoryException {
+		if (authorizable.isGroup()) {
+			Group group = ((Group)authorizable);
+    		String groupPath = AuthorizableResourceProvider.SYSTEM_USER_MANAGER_GROUP_PREFIX + group.getID(); 
+
+	    	ResourceResolver resolver = request.getResourceResolver();
+	    	Resource baseResource = request.getResource();
+	    	boolean changed = false;
+
+	    	//first remove any members posted as ":member@Delete"
+	    	String[] membersToDelete = request.getParameterValues(SlingPostConstants.RP_PREFIX + "member" + SlingPostConstants.SUFFIX_DELETE);
+	    	if (membersToDelete != null) {
+				for (String member : membersToDelete) {
+	                Resource res = resolver.getResource(baseResource, member);
+	                if (res != null) {
+	                	Authorizable memberAuthorizable = res.adaptTo(Authorizable.class);
+	                	if (memberAuthorizable != null) {
+	                		group.removeMember(memberAuthorizable);
+	                		changed = true;
+	                	}
+	                }
+					
+				}
+	    	}
+	    	
+	    	//second add any members posted as ":member"
+	    	String[] membersToAdd = request.getParameterValues(SlingPostConstants.RP_PREFIX + "member");
+	    	if (membersToAdd != null) {
+				for (String member : membersToAdd) {
+	                Resource res = resolver.getResource(baseResource, member);
+	                if (res != null) {
+	                	Authorizable memberAuthorizable = res.adaptTo(Authorizable.class);
+	                	if (memberAuthorizable != null) {
+	                		group.addMember(memberAuthorizable);
+	                		changed = true;
+	                	}
+	                }
+				}
+	    	}
+
+	    	if (changed) {
+        		//add an entry to the changes list to record the membership change
+        		changes.add(Modification.onModified(groupPath + "/members"));
+	    	}
+		}
+	}
+	
+}
diff --git a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/AbstractUserPostServlet.java b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/AbstractUserPostServlet.java
new file mode 100644
index 0000000..8e32ae9
--- /dev/null
+++ b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/AbstractUserPostServlet.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.jackrabbit.usermanager.post;
+
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Dictionary;
+
+import org.apache.jackrabbit.util.Text;
+import org.osgi.service.component.ComponentContext;
+
+/**
+ * Base class for servlets manipulating users
+ */
+public abstract class AbstractUserPostServlet extends AbstractAuthorizablePostServlet {
+	private static final long serialVersionUID = -8401210711297654453L;
+
+	/**
+     * To be used for the encryption. E.g. for passwords in
+     * {@link javax.jcr.SimpleCredentials#getPassword()}  SimpleCredentials} 
+     * @scr.property valueRef="DEFAULT_PASSWORD_DIGEST_ALGORITHM"
+     */
+    private static final String PROP_PASSWORD_DIGEST_ALGORITHM = "password.digest.algorithm";
+    private static final String DEFAULT_PASSWORD_DIGEST_ALGORITHM = "sha1";
+    private String passwordDigestAlgoritm = null;
+
+    // ---------- SCR Integration ----------------------------------------------
+
+    protected void activate(ComponentContext context) {
+        super.activate(context);
+        
+        Dictionary<?, ?> props = context.getProperties();
+
+        Object propValue = props.get(PROP_PASSWORD_DIGEST_ALGORITHM);
+        if (propValue instanceof String) {
+        	passwordDigestAlgoritm = (String)propValue;
+        } else {
+        	passwordDigestAlgoritm = DEFAULT_PASSWORD_DIGEST_ALGORITHM;
+        }
+    }
+
+    protected void deactivate(ComponentContext context) {
+        super.deactivate(context);
+        passwordDigestAlgoritm = null;
+    }
+    
+    /**
+     * Digest the given password using the configured digest algorithm
+     * 
+     * @param pwd the value to digest
+     * @return the digested value
+     * @throws IllegalArgumentException
+     */
+    protected String digestPassword(String pwd) throws IllegalArgumentException {
+        try {
+            StringBuffer password = new StringBuffer();
+            password.append("{").append(passwordDigestAlgoritm).append("}");
+            password.append(Text.digest(passwordDigestAlgoritm, pwd.getBytes("UTF-8")));
+            return password.toString();
+        } catch (NoSuchAlgorithmException e) {
+            throw new IllegalArgumentException(e.toString());
+        } catch (UnsupportedEncodingException e) {
+            throw new IllegalArgumentException(e.toString());
+        }
+    }
+    
+}
diff --git a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/ChangePasswordOperation.java b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/ChangeUserPasswordServlet.java
similarity index 78%
rename from src/main/java/org/apache/sling/jackrabbit/usermanager/post/ChangePasswordOperation.java
rename to src/main/java/org/apache/sling/jackrabbit/usermanager/post/ChangeUserPasswordServlet.java
index 9972ede..9feddec 100644
--- a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/ChangePasswordOperation.java
+++ b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/ChangeUserPasswordServlet.java
@@ -26,25 +26,29 @@ import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.User;
 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.servlets.post.Modification;
 
 /**
- * Sling Post Operation implementation for updating the password of
- * a user in the jackrabbit UserManager.
+ * Sling Post Operation implementation for updating the password of a user in the 
+ * jackrabbit UserManager.
  * 
  * @scr.component metatype="no" immediate="true"
- * @scr.service interface="org.apache.sling.servlets.post.SlingPostOperation"
- * @scr.property name="sling.post.operation" value="changePassword"
+ * @scr.service interface="javax.servlet.Servlet"
+ * @scr.property name="sling.servlet.resourceTypes" value="sling/user"
+ * @scr.property name="sling.servlet.methods" value="POST" 
+ * @scr.property name="sling.servlet.selectors" value="changePassword" 
  */
-public class ChangePasswordOperation extends AbstractAuthorizableOperation {
+public class ChangeUserPasswordServlet extends AbstractUserPostServlet {
+	private static final long serialVersionUID = 1923614318474654502L;
 
 	/* (non-Javadoc)
-	 * @see org.apache.sling.servlets.post.AbstractSlingPostOperation#doRun(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
+	 * @see org.apache.sling.jackrabbit.usermanager.post.AbstractAuthorizablePostServlet#handleOperation(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
 	 */
 	@Override
-	protected void doRun(SlingHttpServletRequest request,
-			HtmlResponse response, List<Modification> changes)
+	protected void handleOperation(SlingHttpServletRequest request,
+			HtmlResponse htmlResponse, List<Modification> changes)
 			throws RepositoryException {
 		Authorizable authorizable = null;
 		Resource resource = request.getResource();
@@ -54,7 +58,7 @@ public class ChangePasswordOperation extends AbstractAuthorizableOperation {
 		
 		//check that the user was located.
 		if (authorizable == null || authorizable.isGroup()) {
-			throw new RepositoryException("User to update could not be determined.");
+			throw new ResourceNotFoundException("User to update could not be determined.");
 		}
 
 		if ("anonymous".equals(authorizable.getID())) {
diff --git a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/CreateGroupOperation.java b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/CreateGroupServlet.java
similarity index 79%
rename from src/main/java/org/apache/sling/jackrabbit/usermanager/post/CreateGroupOperation.java
rename to src/main/java/org/apache/sling/jackrabbit/usermanager/post/CreateGroupServlet.java
index 08e2456..a7e162b 100644
--- a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/CreateGroupOperation.java
+++ b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/CreateGroupServlet.java
@@ -35,33 +35,36 @@ import org.apache.sling.servlets.post.Modification;
 import org.apache.sling.servlets.post.SlingPostConstants;
 
 /**
- * Sling Post Operation implementation for creating a group in the jackrabbit
+ * Sling Post Servlet implementation for creating a group in the jackrabbit
  * UserManager.
- *
- * @scr.component metatype="no" immediate="true"
- * @scr.service interface="org.apache.sling.servlets.post.SlingPostOperation"
- * @scr.property name="sling.post.operation" value="createGroup"
+ * 
+ * @scr.component immediate="true" 
+ * @scr.service interface="javax.servlet.Servlet"
+ * @scr.property name="sling.servlet.resourceTypes" value="sling/groups"
+ * @scr.property name="sling.servlet.methods" value="POST" 
+ * @scr.property name="sling.servlet.selectors" value="create" 
  */
-public class CreateGroupOperation extends AbstractAuthorizableOperation {
+public class CreateGroupServlet extends AbstractGroupPostServlet {
+	private static final long serialVersionUID = -1084915263933901466L;
 
 	/* (non-Javadoc)
-	 * @see org.apache.sling.servlets.post.AbstractSlingPostOperation#doRun(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
+	 * @see org.apache.sling.jackrabbit.usermanager.post.AbstractAuthorizablePostServlet#handleOperation(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
 	 */
 	@Override
-	protected void doRun(SlingHttpServletRequest request,
-			HtmlResponse response, List<Modification> changes)
-			throws RepositoryException {
-		Session session = request.getResourceResolver().adaptTo(Session.class);
-		if (session == null) {
-			throw new RepositoryException("JCR Session not found");
-		}
+	protected void handleOperation(SlingHttpServletRequest request,
+			HtmlResponse response, List<Modification> changes) throws RepositoryException {
 		
 		//check that the submitted parameter values have valid values.
 		final String principalName = request.getParameter(SlingPostConstants.RP_NODE_NAME);
 		if (principalName == null) {
 			throw new RepositoryException("Group name was not submitted");
 		}
-		
+
+		Session session = request.getResourceResolver().adaptTo(Session.class);
+		if (session == null) {
+			throw new RepositoryException("JCR Session not found");
+		}
+
 		try {
 			UserManager userManager = AccessControlUtil.getUserManager(session);
 			Authorizable authorizable = userManager.getAuthorizable(principalName);
diff --git a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/CreateUserOperation.java b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/CreateUserServlet.java
similarity index 86%
rename from src/main/java/org/apache/sling/jackrabbit/usermanager/post/CreateUserOperation.java
rename to src/main/java/org/apache/sling/jackrabbit/usermanager/post/CreateUserServlet.java
index c0e385f..c8259dc 100644
--- a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/CreateUserOperation.java
+++ b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/CreateUserServlet.java
@@ -35,17 +35,27 @@ import org.apache.sling.jcr.base.util.AccessControlUtil;
 import org.apache.sling.servlets.post.Modification;
 import org.apache.sling.servlets.post.SlingPostConstants;
 import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * Sling Post Operation implementation for creating a user in the jackrabbit
+ * Sling Post Servlet implementation for creating a user in the jackrabbit
  * UserManager.
  * 
  * @scr.component immediate="true" label="%createUser.post.operation.name"
  *                description="%createUser.post.operation.description"
- * @scr.service interface="org.apache.sling.servlets.post.SlingPostOperation"
- * @scr.property name="sling.post.operation" value="createUser"
+ * @scr.service interface="javax.servlet.Servlet"
+ * @scr.property name="sling.servlet.resourceTypes" value="sling/users"
+ * @scr.property name="sling.servlet.methods" value="POST" 
+ * @scr.property name="sling.servlet.selectors" value="create" 
  */
-public class CreateUserOperation extends AbstractAuthorizableOperation {
+public class CreateUserServlet extends AbstractUserPostServlet {
+	private static final long serialVersionUID = 6871481922737658675L;
+
+	/**
+     * default log
+     */
+    private final Logger log = LoggerFactory.getLogger(getClass());
 
     /** @scr.property label="%self.registration.enabled.name" 
      * 					description="%self.registration.enabled.description" 
@@ -87,7 +97,6 @@ public class CreateUserOperation extends AbstractAuthorizableOperation {
             }
         }
     }
-    
 
     // ---------- SCR integration ---------------------------------------------
 
@@ -107,15 +116,15 @@ public class CreateUserOperation extends AbstractAuthorizableOperation {
         	selfRegistrationEnabled = DEFAULT_SELF_REGISTRATION_ENABLED;
         }
     }
+
     
+
 	/* (non-Javadoc)
-	 * @see org.apache.sling.servlets.post.AbstractSlingPostOperation#doRun(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
+	 * @see org.apache.sling.jackrabbit.usermanager.post.AbstractAuthorizablePostServlet#handleOperation(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
 	 */
 	@Override
-	protected void doRun(SlingHttpServletRequest request,
-			HtmlResponse response, List<Modification> changes)
-			throws RepositoryException {
-
+	protected void handleOperation(SlingHttpServletRequest request,
+			HtmlResponse response, List<Modification> changes) throws RepositoryException {
 		//make sure user self-registration is enabled
 		if (!selfRegistrationEnabled) {
 			throw new RepositoryException("Sorry, registration of new users is not currently enabled.  Please try again later.");
@@ -155,6 +164,7 @@ public class CreateUserOperation extends AbstractAuthorizableOperation {
 
 				User user = userManager.createUser(principalName, digestPassword(pwd));
 				String userPath = AuthorizableResourceProvider.SYSTEM_USER_MANAGER_USER_PREFIX + user.getID();
+				
 				response.setPath(userPath);
 				response.setLocation(externalizePath(request, userPath));
 				response.setParentLocation(externalizePath(request, AuthorizableResourceProvider.SYSTEM_USER_MANAGER_USER_PATH));
diff --git a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/DeleteAuthorizableOperation.java b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/DeleteAuthorizableOperation.java
deleted file mode 100644
index 991cee0..0000000
--- a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/DeleteAuthorizableOperation.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sling.jackrabbit.usermanager.post;
-
-import java.util.Iterator;
-import java.util.List;
-
-import javax.jcr.RepositoryException;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.jackrabbit.api.security.user.Authorizable;
-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.servlets.post.Modification;
-
-/**
- * Sling Post Operation implementation for deleting users and/or groups from the 
- * jackrabbit UserManager.
- * 
- * @scr.component metatype="no" immediate="true"
- * @scr.service interface="org.apache.sling.servlets.post.SlingPostOperation"
- * @scr.property name="sling.post.operation" value="deleteAuthorizable"
- */
-public class DeleteAuthorizableOperation extends AbstractAuthorizableOperation {
-
-	/* (non-Javadoc)
-	 * @see org.apache.sling.servlets.post.AbstractSlingPostOperation#doRun(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
-	 */
-	@Override
-	protected void doRun(SlingHttpServletRequest request,
-			HtmlResponse response, List<Modification> changes)
-			throws RepositoryException {
-
-        Iterator<Resource> res = getApplyToResources(request);
-        if (res == null) {
-            Resource resource = request.getResource();
-            Authorizable item = resource.adaptTo(Authorizable.class);
-            if (item == null) {
-  	            String msg = "Missing source " + resource.getPath() + " for delete";
-                response.setStatus(HttpServletResponse.SC_NOT_FOUND, msg);
-               	throw new ResourceNotFoundException(msg);
-            }
-
-            item.remove();
-            changes.add(Modification.onDeleted(resource.getPath()));
-        } else {
-            while (res.hasNext()) {
-                Resource resource = res.next();
-                Authorizable item = resource.adaptTo(Authorizable.class);
-                if (item != null) {
-                    item.remove();
-                    changes.add(Modification.onDeleted(resource.getPath()));
-                }
-            }
-        }
-	}
-}
diff --git a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/DeleteAuthorizableServlet.java b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/DeleteAuthorizableServlet.java
new file mode 100644
index 0000000..39ac672
--- /dev/null
+++ b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/DeleteAuthorizableServlet.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.jackrabbit.usermanager.post;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import javax.jcr.RepositoryException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+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.resource.ResourceResolver;
+import org.apache.sling.api.servlets.HtmlResponse;
+import org.apache.sling.servlets.post.Modification;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/**
+ * Sling Post Operation implementation for deleting one or more users and/or groups from the 
+ * jackrabbit UserManager.
+ * 
+ * @scr.component metatype="no" immediate="true"
+ * @scr.service interface="javax.servlet.Servlet"
+ * @scr.property name="sling.servlet.resourceTypes" values.0="sling/user" values.1="sling/group" values.2="sling/userManager"
+ * @scr.property name="sling.servlet.methods" value="POST" 
+ * @scr.property name="sling.servlet.selectors" value="delete" 
+ */
+public class DeleteAuthorizableServlet extends AbstractAuthorizablePostServlet {
+	private static final long serialVersionUID = 5874621724096106496L;
+
+	/* (non-Javadoc)
+	 * @see org.apache.sling.jackrabbit.usermanager.post.AbstractAuthorizablePostServlet#handleOperation(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
+	 */
+	@Override
+	protected void handleOperation(SlingHttpServletRequest request,
+			HtmlResponse htmlResponse, List<Modification> changes)
+			throws RepositoryException {
+
+        Iterator<Resource> res = getApplyToResources(request);
+        if (res == null) {
+            Resource resource = request.getResource();
+            Authorizable item = resource.adaptTo(Authorizable.class);
+            if (item == null) {
+  	            String msg = "Missing source " + resource.getPath() + " for delete";
+  	            htmlResponse.setStatus(HttpServletResponse.SC_NOT_FOUND, msg);
+               	throw new ResourceNotFoundException(msg);
+            }
+
+            item.remove();
+            changes.add(Modification.onDeleted(resource.getPath()));
+        } else {
+            while (res.hasNext()) {
+                Resource resource = res.next();
+                Authorizable item = resource.adaptTo(Authorizable.class);
+                if (item != null) {
+                    item.remove();
+                    changes.add(Modification.onDeleted(resource.getPath()));
+                }
+            }
+        }
+	}
+	
+	
+    /**
+     * Returns an iterator on <code>Resource</code> instances addressed in the
+     * {@link SlingPostConstants#RP_APPLY_TO} request parameter. If the request
+     * parameter is not set, <code>null</code> is returned. If the parameter
+     * is set with valid resources an empty iterator is returned. Any resources
+     * addressed in the {@link SlingPostConstants#RP_APPLY_TO} parameter is
+     * ignored.
+     *
+     * @param request The <code>SlingHttpServletRequest</code> object used to
+     *            get the {@link SlingPostConstants#RP_APPLY_TO} parameter.
+     * @return The iterator of resources listed in the parameter or
+     *         <code>null</code> if the parameter is not set in the request.
+     */
+    protected Iterator<Resource> getApplyToResources(
+            SlingHttpServletRequest request) {
+
+        String[] applyTo = request.getParameterValues(SlingPostConstants.RP_APPLY_TO);
+        if (applyTo == null) {
+            return null;
+        }
+
+        return new ApplyToIterator(request, applyTo);
+    }
+
+    private static class ApplyToIterator implements Iterator<Resource> {
+
+        private final ResourceResolver resolver;
+        private final Resource baseResource;
+        private final String[] paths;
+
+        private int pathIndex;
+
+        private Resource nextResource;
+
+        ApplyToIterator(SlingHttpServletRequest request, String[] paths) {
+            this.resolver = request.getResourceResolver();
+            this.baseResource = request.getResource();
+            this.paths = paths;
+            this.pathIndex = 0;
+
+            nextResource = seek();
+        }
+
+        public boolean hasNext() {
+            return nextResource != null;
+        }
+
+        public Resource next() {
+            if (!hasNext()) {
+                throw new NoSuchElementException();
+            }
+
+            Resource result = nextResource;
+            nextResource = seek();
+
+            return result;
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        private Resource seek() {
+            while (pathIndex < paths.length) {
+                String path = paths[pathIndex];
+                pathIndex++;
+
+                Resource res = resolver.getResource(baseResource, path);
+                if (res != null) {
+                    return res;
+                }
+            }
+
+            // no more elements in the array
+            return null;
+        }
+    }
+	
+}
diff --git a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/UpdateAuthorizableOperation.java b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/UpdateGroupServlet.java
similarity index 70%
copy from src/main/java/org/apache/sling/jackrabbit/usermanager/post/UpdateAuthorizableOperation.java
copy to src/main/java/org/apache/sling/jackrabbit/usermanager/post/UpdateGroupServlet.java
index c88be1c..4e433a8 100644
--- a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/UpdateAuthorizableOperation.java
+++ b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/UpdateGroupServlet.java
@@ -25,26 +25,30 @@ import javax.jcr.Session;
 import org.apache.jackrabbit.api.security.user.Authorizable;
 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.jackrabbit.usermanager.post.impl.RequestProperty;
 import org.apache.sling.servlets.post.Modification;
 
 /**
- * Sling Post Operation implementation for updating a user or group in the 
+ * Sling Post Operation implementation for updating a group in the 
  * jackrabbit UserManager.
  * 
  * @scr.component metatype="no" immediate="true"
- * @scr.service interface="org.apache.sling.servlets.post.SlingPostOperation"
- * @scr.property name="sling.post.operation" value="updateAuthorizable"
+ * @scr.service interface="javax.servlet.Servlet"
+ * @scr.property name="sling.servlet.resourceTypes" values="sling/group"
+ * @scr.property name="sling.servlet.methods" value="POST" 
+ * @scr.property name="sling.servlet.selectors" value="update" 
  */
-public class UpdateAuthorizableOperation extends AbstractAuthorizableOperation {
+public class UpdateGroupServlet extends AbstractGroupPostServlet {
+	private static final long serialVersionUID = -8292054361992488797L;
 
 	/* (non-Javadoc)
-	 * @see org.apache.sling.servlets.post.AbstractSlingPostOperation#doRun(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
+	 * @see org.apache.sling.jackrabbit.usermanager.post.AbstractAuthorizablePostServlet#handleOperation(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
 	 */
 	@Override
-	protected void doRun(SlingHttpServletRequest request,
-			HtmlResponse response, List<Modification> changes)
+	protected void handleOperation(SlingHttpServletRequest request,
+			HtmlResponse htmlResponse, List<Modification> changes)
 			throws RepositoryException {
 		Authorizable authorizable = null;
 		Resource resource = request.getResource();
@@ -54,7 +58,7 @@ public class UpdateAuthorizableOperation extends AbstractAuthorizableOperation {
 		
 		//check that the group was located.
 		if (authorizable == null) {
-			throw new RepositoryException("Authorizable to update could not be determined");
+			throw new ResourceNotFoundException("Group to update could not be determined");
 		}
 
 		Session session = request.getResourceResolver().adaptTo(Session.class);
@@ -62,7 +66,7 @@ public class UpdateAuthorizableOperation extends AbstractAuthorizableOperation {
 			throw new RepositoryException("JCR Session not found");
 		}
 
-		Map<String, RequestProperty> reqProperties = collectContent(request, response);
+		Map<String, RequestProperty> reqProperties = collectContent(request, htmlResponse);
 		try {
 	        // cleanup any old content (@Delete parameters)
 	        processDeletes(authorizable, reqProperties, changes);
@@ -75,7 +79,7 @@ public class UpdateAuthorizableOperation extends AbstractAuthorizableOperation {
 		        updateGroupMembership(request, authorizable, changes);
 			}
 		} catch (RepositoryException re) {
-			throw new RepositoryException("Failed to update authorizable.", re);
+			throw new RepositoryException("Failed to update group.", re);
 		}
 	}
 }
diff --git a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/UpdateAuthorizableOperation.java b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/UpdateUserServlet.java
similarity index 68%
rename from src/main/java/org/apache/sling/jackrabbit/usermanager/post/UpdateAuthorizableOperation.java
rename to src/main/java/org/apache/sling/jackrabbit/usermanager/post/UpdateUserServlet.java
index c88be1c..d0245c6 100644
--- a/src/main/java/org/apache/sling/jackrabbit/usermanager/post/UpdateAuthorizableOperation.java
+++ b/src/main/java/org/apache/sling/jackrabbit/usermanager/post/UpdateUserServlet.java
@@ -25,26 +25,30 @@ import javax.jcr.Session;
 import org.apache.jackrabbit.api.security.user.Authorizable;
 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.jackrabbit.usermanager.post.impl.RequestProperty;
 import org.apache.sling.servlets.post.Modification;
 
 /**
- * Sling Post Operation implementation for updating a user or group in the 
+ * Sling Post Operation implementation for updating a user in the 
  * jackrabbit UserManager.
  * 
  * @scr.component metatype="no" immediate="true"
- * @scr.service interface="org.apache.sling.servlets.post.SlingPostOperation"
- * @scr.property name="sling.post.operation" value="updateAuthorizable"
+ * @scr.service interface="javax.servlet.Servlet"
+ * @scr.property name="sling.servlet.resourceTypes" value="sling/user"
+ * @scr.property name="sling.servlet.methods" value="POST" 
+ * @scr.property name="sling.servlet.selectors" value="update" 
  */
-public class UpdateAuthorizableOperation extends AbstractAuthorizableOperation {
+public class UpdateUserServlet extends AbstractUserPostServlet {
+	private static final long serialVersionUID = 5874621724096106496L;
 
 	/* (non-Javadoc)
-	 * @see org.apache.sling.servlets.post.AbstractSlingPostOperation#doRun(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
+	 * @see org.apache.sling.jackrabbit.usermanager.post.AbstractAuthorizablePostServlet#handleOperation(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
 	 */
 	@Override
-	protected void doRun(SlingHttpServletRequest request,
-			HtmlResponse response, List<Modification> changes)
+	protected void handleOperation(SlingHttpServletRequest request,
+			HtmlResponse htmlResponse, List<Modification> changes)
 			throws RepositoryException {
 		Authorizable authorizable = null;
 		Resource resource = request.getResource();
@@ -54,7 +58,7 @@ public class UpdateAuthorizableOperation extends AbstractAuthorizableOperation {
 		
 		//check that the group was located.
 		if (authorizable == null) {
-			throw new RepositoryException("Authorizable to update could not be determined");
+			throw new ResourceNotFoundException("User to update could not be determined");
 		}
 
 		Session session = request.getResourceResolver().adaptTo(Session.class);
@@ -62,20 +66,16 @@ public class UpdateAuthorizableOperation extends AbstractAuthorizableOperation {
 			throw new RepositoryException("JCR Session not found");
 		}
 
-		Map<String, RequestProperty> reqProperties = collectContent(request, response);
+		Map<String, RequestProperty> reqProperties = collectContent(request, htmlResponse);
 		try {
 	        // cleanup any old content (@Delete parameters)
 	        processDeletes(authorizable, reqProperties, changes);
 				
 	        // write content from form
 	        writeContent(session, authorizable, reqProperties, changes);
-	        
-	        //update the group memberships
-			if (authorizable.isGroup()) {
-		        updateGroupMembership(request, authorizable, changes);
-			}
+
 		} catch (RepositoryException re) {
-			throw new RepositoryException("Failed to update authorizable.", re);
+			throw new RepositoryException("Failed to update user.", re);
 		}
 	}
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.