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 2011/05/04 17:11:26 UTC

svn commit: r1099482 - in /sling/trunk: bundles/jcr/jackrabbit-usermanager/src/main/java/org/apache/sling/jackrabbit/usermanager/impl/post/ launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/ samples...

Author: enorman
Date: Wed May  4 15:11:25 2011
New Revision: 1099482

URL: http://svn.apache.org/viewvc?rev=1099482&view=rev
Log:
SLING-2069 PW reset through administrator is not possible.  
Following the jackrabbit model, members of the UserAdmin group can set the password of other users.

Modified:
    sling/trunk/bundles/jcr/jackrabbit-usermanager/src/main/java/org/apache/sling/jackrabbit/usermanager/impl/post/ChangeUserPasswordServlet.java
    sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/UpdateUserTest.java
    sling/trunk/samples/usermanager-ui/src/main/resources/libs/sling/user/update_body.html.esp

Modified: sling/trunk/bundles/jcr/jackrabbit-usermanager/src/main/java/org/apache/sling/jackrabbit/usermanager/impl/post/ChangeUserPasswordServlet.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/jackrabbit-usermanager/src/main/java/org/apache/sling/jackrabbit/usermanager/impl/post/ChangeUserPasswordServlet.java?rev=1099482&r1=1099481&r2=1099482&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/jackrabbit-usermanager/src/main/java/org/apache/sling/jackrabbit/usermanager/impl/post/ChangeUserPasswordServlet.java (original)
+++ sling/trunk/bundles/jcr/jackrabbit-usermanager/src/main/java/org/apache/sling/jackrabbit/usermanager/impl/post/ChangeUserPasswordServlet.java Wed May  4 15:11:25 2011
@@ -17,6 +17,7 @@
 package org.apache.sling.jackrabbit.usermanager.impl.post;
 
 import java.lang.reflect.Method;
+import java.util.Dictionary;
 import java.util.List;
 
 import javax.jcr.Credentials;
@@ -24,12 +25,19 @@ import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.SimpleCredentials;
 import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
 import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.sling.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.commons.osgi.OsgiUtil;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
 import org.apache.sling.servlets.post.Modification;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * <p>
@@ -45,7 +53,7 @@ import org.apache.sling.servlets.post.Mo
  * <h4>Post Parameters</h4>
  * <dl>
  * <dt>oldPwd</dt>
- * <dd>The current password for the user (required)</dd>
+ * <dd>The current password for the user (required for non-administrators)</dd>
  * <dt>newPwd</dt>
  * <dd>The new password for the user (required)</dd>
  * <dt>newPwdConfirm</dt>
@@ -63,13 +71,13 @@ import org.apache.sling.servlets.post.Mo
  * <h4>Example</h4>
  *
  * <code>
- * curl -FoldPwd=oldpassword -FnewPwd=newpassword =FnewPwdConfirm=newpassword http://localhost:8080/system/userManager/user/ieb.changePassword.html
+ * curl -FoldPwd=oldpassword -FnewPwd=newpassword -FnewPwdConfirm=newpassword http://localhost:8080/system/userManager/user/ieb.changePassword.html
  * </code>
  *
  * <h4>Notes</h4>
  *
  *
- * @scr.component metatype="no" immediate="true"
+ * @scr.component immediate="true"
  * @scr.service interface="javax.servlet.Servlet"
  * @scr.property name="sling.servlet.resourceTypes" value="sling/user"
  * @scr.property name="sling.servlet.methods" value="POST"
@@ -78,6 +86,46 @@ import org.apache.sling.servlets.post.Mo
 public class ChangeUserPasswordServlet extends AbstractUserPostServlet {
     private static final long serialVersionUID = 1923614318474654502L;
 
+    /**
+     * default log
+     */
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    /**
+     * The name of the configuration parameter providing the 
+     * name of the group whose members are allowed to reset the password
+     * of a user without the 'oldPwd' value.
+     *
+     * @scr.property valueRef="DEFAULT_USER_ADMIN_GROUP_NAME"
+     */
+    private static final String PAR_USER_ADMIN_GROUP_NAME = "user.admin.group.name";
+
+    /**
+     * The default 'User administrator' group name
+     *
+     * @see #PAR_USER_ADMIN_GROUP_NAME
+     */
+    private static final String DEFAULT_USER_ADMIN_GROUP_NAME = "UserAdmin";
+ 
+    private String userAdminGroupName = DEFAULT_USER_ADMIN_GROUP_NAME;
+    
+    // ---------- SCR integration ---------------------------------------------
+
+    /**
+     * Activates this component.
+     *
+     * @param componentContext The OSGi <code>ComponentContext</code> of this
+     *            component.
+     */
+    protected void activate(ComponentContext componentContext) {
+        super.activate(componentContext);
+        Dictionary<?, ?> props = componentContext.getProperties();
+        
+        this.userAdminGroupName = OsgiUtil.toString(props.get(PAR_USER_ADMIN_GROUP_NAME),
+        		DEFAULT_USER_ADMIN_GROUP_NAME);
+        log.info("User Admin Group Name {}", this.userAdminGroupName);
+    }
+    
     /*
      * (non-Javadoc)
      * @see
@@ -111,10 +159,37 @@ public class ChangeUserPasswordServlet e
             throw new RepositoryException("JCR Session not found");
         }
 
+    	//SLING-2069: if the current user is an administrator, then a missing oldPwd is ok,
+    	// otherwise the oldPwd must be supplied.
+        boolean administrator = false;
+
         // check that the submitted parameter values have valid values.
         String oldPwd = request.getParameter("oldPwd");
         if (oldPwd == null || oldPwd.length() == 0) {
-            throw new RepositoryException("Old Password was not submitted");
+            try {
+                Session currentSession = request.getResourceResolver().adaptTo(Session.class);
+                UserManager um = AccessControlUtil.getUserManager(currentSession);
+                User currentUser = (User) um.getAuthorizable(currentSession.getUserID());
+                administrator = currentUser.isAdmin();
+                
+                if (!administrator) {
+    				//check if the user is a member of the 'User administrator' group
+    				Authorizable userAdmin = um.getAuthorizable(this.userAdminGroupName);
+    				if (userAdmin instanceof Group) {
+    					boolean isMember = ((Group)userAdmin).isMember(currentUser);
+    					if (isMember) {
+    						administrator = true;
+    					}
+    				}
+                	
+                }
+            } catch ( Exception ex ) {
+                log.warn("Failed to determine if the user is an admin, assuming not. Cause: "+ex.getMessage());
+                administrator = false;
+            }
+            if (!administrator) {
+            	throw new RepositoryException("Old Password was not submitted");
+            }
         }
         String newPwd = request.getParameter("newPwd");
         if (newPwd == null || newPwd.length() == 0) {
@@ -126,8 +201,10 @@ public class ChangeUserPasswordServlet e
                 "New Password does not match the confirmation password");
         }
 
-        // verify old password
-        checkPassword(authorizable, oldPwd);
+        if (oldPwd != null && oldPwd.length() > 0) {
+            // verify old password
+            checkPassword(authorizable, oldPwd);
+        }
 
         try {
             ((User) authorizable).changePassword(digestPassword(newPwd));

Modified: sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/UpdateUserTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/UpdateUserTest.java?rev=1099482&r1=1099481&r2=1099482&view=diff
==============================================================================
--- sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/UpdateUserTest.java (original)
+++ sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/userManager/UpdateUserTest.java Wed May  4 15:11:25 2011
@@ -131,4 +131,41 @@ public class UpdateUserTest extends Abst
 		JSONObject jsonObj = new JSONObject(json);
 		assertNotNull(jsonObj);
 	}	
+	
+
+	/**
+	 * Test for SLING-2069
+	 * @throws IOException
+	 */
+	public void testChangeUserPasswordAsAdministratorWithoutOldPwd() throws IOException {
+		testUserId = createTestUser();
+		
+        String postUrl = HTTP_BASE_URL + "/system/userManager/user/" + testUserId + ".changePassword.html";
+
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair("newPwd", "testNewPwd"));
+		postParams.add(new NameValuePair("newPwdConfirm", "testNewPwd"));
+		
+		Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+	}
+
+	/**
+	 * Test for SLING-2069
+	 * @throws IOException
+	 */
+	public void testChangeUserPasswordAsUserAdminMemberWithoutOldPwd() throws IOException {
+		testUserId = createTestUser();
+		addUserToUserAdminGroup(testUserId);
+		
+        String postUrl = HTTP_BASE_URL + "/system/userManager/user/" + testUserId + ".changePassword.html";
+
+		List<NameValuePair> postParams = new ArrayList<NameValuePair>();
+		postParams.add(new NameValuePair("newPwd", "testNewPwd"));
+		postParams.add(new NameValuePair("newPwdConfirm", "testNewPwd"));
+		
+		Credentials creds = new UsernamePasswordCredentials(testUserId, "testPwd");
+		assertAuthenticatedPostStatus(creds, postUrl, HttpServletResponse.SC_OK, postParams, null);
+	}
+	
 }

Modified: sling/trunk/samples/usermanager-ui/src/main/resources/libs/sling/user/update_body.html.esp
URL: http://svn.apache.org/viewvc/sling/trunk/samples/usermanager-ui/src/main/resources/libs/sling/user/update_body.html.esp?rev=1099482&r1=1099481&r2=1099482&view=diff
==============================================================================
--- sling/trunk/samples/usermanager-ui/src/main/resources/libs/sling/user/update_body.html.esp (original)
+++ sling/trunk/samples/usermanager-ui/src/main/resources/libs/sling/user/update_body.html.esp Wed May  4 15:11:25 2011
@@ -22,7 +22,6 @@ var canEdit = privilegesInfo.canUpdatePr
 var canRemove = privilegesInfo.canRemove(currentSession, authorizable.getID()); 
 var canUpdateMembers = privilegesInfo.canUpdateGroupMembers(currentSession, authorizable.getID());
 var valueMap = resource.adaptTo(Packages.org.apache.sling.api.resource.ValueMap);
-var isMe = authorizable.getID().equals(request.getRemoteUser());
 
 var rb = request.getResourceBundle("org.apache.sling.usermgr.Resources", null);
 
@@ -158,7 +157,30 @@ function displayName(path) {
 </div>
 <% } /*endif(canRemove) */ %>
 
-<% if (isMe) { %>
+<% 
+var canChangePwd = false;
+if (canEdit) {
+	var isMe = authorizable.getID().equals(request.getRemoteUser());
+	if (isMe) {
+	    //a user can always change their own password
+	    canChangePwd = true;
+	} else {
+		if ("admin".equals(request.getRemoteUser())) {
+			canChangePwd = true;
+		} else {
+	        //if the current user is a member of the UserAdmin group, then allow changing the password of other users.
+	        var currentUserRes = request.getResourceResolver().resolve("/system/userManager/user/" + request.getRemoteUser());  
+	        var currentUserAuthorizable = currentUserRes.adaptTo(Packages.org.apache.jackrabbit.api.security.user.Authorizable);
+
+	        var userAdminRes = request.getResourceResolver().resolve("/system/userManager/group/UserAdmin");
+	        var group = userAdminRes.adaptTo(Packages.org.apache.jackrabbit.api.security.user.Group);
+	        if (group) {
+	            canChangePwd = group.isMember(currentUserAuthorizable);
+	        }
+		}
+	}
+}
+if (canChangePwd) { %>
 <div class="ui-widget ui-widget-content ui-corner-all usermgmt-body" id="update-password-body" >
     <h3 class="ui-widget-header ui-corner-all usermgmt-header"><%=rb.getString("header.change.password")%></h3>
     
@@ -177,11 +199,12 @@ function displayName(path) {
         <fieldset>
             <input type="hidden" value="UTF-8" name="_charset_" />
             <input id="pwdRedirect" type="hidden" name=":redirect" value="<%=request.contextPath%><%=resource.path %>.html" />
-
+            <% if (isMe) { %>
             <div class="prop-line ui-helper-clearfix">
                 <label for="oldPwd" accesskey="o"><%=propLabel("oldPwd")%>:</label>
                 <input id="oldPwd" type="password" name="oldPwd" value=''/>
             </div>
+            <% } %>
 
             <div class="prop-line ui-helper-clearfix">
                 <label for="newPwd" accesskey="p"><%=propLabel("newPwd")%>:</label>                
@@ -200,4 +223,4 @@ function displayName(path) {
         </fieldset>
     </form>
 </div>
-<% } /*endif (isme)*/ %>
+<% } /*endif (canChangePwd)*/ %>