You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by GitBox <gi...@apache.org> on 2018/05/02 12:19:08 UTC

[GitHub] rafaelweingartner closed pull request #2574: [CLOUDSTACK-5235] ask users current password when they are executing a password update

rafaelweingartner closed pull request #2574: [CLOUDSTACK-5235] ask users current password when they are executing a password update
URL: https://github.com/apache/cloudstack/pull/2574
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/api/src/main/java/com/cloud/user/AccountService.java b/api/src/main/java/com/cloud/user/AccountService.java
index 9683d9fa330..060861d1809 100644
--- a/api/src/main/java/com/cloud/user/AccountService.java
+++ b/api/src/main/java/com/cloud/user/AccountService.java
@@ -23,53 +23,28 @@
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
 import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd;
 import org.apache.cloudstack.api.command.admin.user.RegisterCmd;
+import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd;
 
 import com.cloud.domain.Domain;
 import com.cloud.exception.PermissionDeniedException;
 import com.cloud.offering.DiskOffering;
 import com.cloud.offering.ServiceOffering;
 
-
 public interface AccountService {
 
     /**
      * Creates a new user and account, stores the password as is so encrypted passwords are recommended.
-     *
-     * @param userName
-     *            TODO
-     * @param password
-     *            TODO
-     * @param firstName
-     *            TODO
-     * @param lastName
-     *            TODO
-     * @param email
-     *            TODO
-     * @param timezone
-     *            TODO
-     * @param accountName
-     *            TODO
-     * @param accountType
-     *            TODO
-     * @param domainId
-     *            TODO
-     * @param networkDomain
-     *            TODO
-     *
      * @return the user if created successfully, null otherwise
      */
-    UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName,
-        short accountType, Long roleId, Long domainId, String networkDomain, Map<String, String> details, String accountUUID, String userUUID);
+    UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long roleId, Long domainId,
+            String networkDomain, Map<String, String> details, String accountUUID, String userUUID);
 
-    UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long roleId, Long domainId, String networkDomain,
-                                  Map<String, String> details, String accountUUID, String userUUID, User.Source source);
+    UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long roleId, Long domainId,
+            String networkDomain, Map<String, String> details, String accountUUID, String userUUID, User.Source source);
 
     /**
      * Locks a user by userId. A locked user cannot access the API, but will still have running VMs/IP addresses
      * allocated/etc.
-     *
-     * @param userId
-     * @return UserAccount object
      */
     UserAccount lockUser(long userId);
 
@@ -79,8 +54,7 @@ UserAccount createUserAccount(String userName, String password, String firstName
 
     User createUser(String userName, String password, String firstName, String lastName, String email, String timeZone, String accountName, Long domainId, String userUUID);
 
-    User createUser(String userName, String password, String firstName, String lastName, String email, String timeZone, String accountName, Long domainId, String userUUID,
-                    User.Source source);
+    User createUser(String userName, String password, String firstName, String lastName, String email, String timeZone, String accountName, Long domainId, String userUUID, User.Source source);
 
     boolean isAdmin(Long accountId);
 
@@ -90,7 +64,7 @@ User createUser(String userName, String password, String firstName, String lastN
 
     UserAccount getActiveUserAccount(String username, Long domainId);
 
-    UserAccount updateUser(Long userId, String firstName, String lastName, String email, String userName, String password, String apiKey, String secretKey, String timeZone);
+    UserAccount updateUser(UpdateUserCmd updateUserCmd);
 
     Account getActiveAccountById(long accountId);
 
@@ -128,15 +102,14 @@ User createUser(String userName, String password, String firstName, String lastN
 
     void checkAccess(User user, ControlledEntity entity);
 
-    void checkAccess(Account account, AccessType accessType, boolean sameOwner, String apiName,
-            ControlledEntity... entities) throws PermissionDeniedException;
+    void checkAccess(Account account, AccessType accessType, boolean sameOwner, String apiName, ControlledEntity... entities) throws PermissionDeniedException;
 
     Long finalyzeAccountId(String accountName, Long domainId, Long projectId, boolean enabledOnly);
 
     /**
      * returns the user account object for a given user id
      * @param userId user id
-     * @return useraccount object if it exists else null
+     * @return {@link UserAccount} object if it exists else null
      */
     UserAccount getUserAccountById(Long userId);
 
diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
index 56d5957f022..1a8014c03d0 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -214,8 +214,8 @@
     public static final String PARENT_DOMAIN_ID = "parentdomainid";
     public static final String PARENT_TEMPLATE_ID = "parenttemplateid";
     public static final String PASSWORD = "password";
+    public static final String CURRENT_PASSWORD = "currentpassword";
     public static final String SHOULD_UPDATE_PASSWORD = "update_passwd_on_host";
-    public static final String NEW_PASSWORD = "new_password";
     public static final String PASSWORD_ENABLED = "passwordenabled";
     public static final String SSHKEY_ENABLED = "sshkeyenabled";
     public static final String PATH = "path";
@@ -727,4 +727,4 @@
     public enum DomainDetails {
         all, resource, min;
     }
-}
+}
\ No newline at end of file
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/user/UpdateUserCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/user/UpdateUserCmd.java
index e6ac36719e3..ffef774c405 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/user/UpdateUserCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/user/UpdateUserCmd.java
@@ -34,7 +34,7 @@
 import com.cloud.user.UserAccount;
 
 @APICommand(name = "updateUser", description = "Updates a user account", responseObject = UserResponse.class,
-        requestHasSensitiveInfo = true, responseHasSensitiveInfo = true)
+requestHasSensitiveInfo = true, responseHasSensitiveInfo = true)
 public class UpdateUserCmd extends BaseCmd {
     public static final Logger s_logger = Logger.getLogger(UpdateUserCmd.class.getName());
 
@@ -65,20 +65,22 @@
             acceptedOnAdminPort = false)
     private String password;
 
+    @Parameter(name = ApiConstants.CURRENT_PASSWORD, type = CommandType.STRING, description = "Current password that was being used by the user. You must inform the current password when updating the password.", acceptedOnAdminPort = false)
+    private String currentPassword;
 
     @Parameter(name = ApiConstants.SECRET_KEY, type = CommandType.STRING, description = "The secret key for the user. Must be specified with userSecretKey")
     private String secretKey;
 
     @Parameter(name = ApiConstants.TIMEZONE,
-               type = CommandType.STRING,
-               description = "Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.")
+            type = CommandType.STRING,
+            description = "Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.")
     private String timezone;
 
     @Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, description = "Unique username")
     private String username;
 
     @Inject
-    RegionService _regionService;
+    private RegionService _regionService;
 
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
@@ -108,6 +110,10 @@ public String getPassword() {
         return password;
     }
 
+    public String getCurrentPassword() {
+        return currentPassword;
+    }
+
     public String getSecretKey() {
         return secretKey;
     }
@@ -152,4 +158,20 @@ public void execute() {
             throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update user");
         }
     }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public void setFirstname(String firstname) {
+        this.firstname = firstname;
+    }
+
+    public void setLastname(String lastname) {
+        this.lastname = lastname;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
 }
diff --git a/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/MockAccountManager.java b/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/MockAccountManager.java
index 37ca2bccff4..100f38060be 100644
--- a/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/MockAccountManager.java
+++ b/plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/MockAccountManager.java
@@ -167,13 +167,6 @@ public UserAccount getActiveUserAccount(String username, Long domainId) {
         return null;
     }
 
-    @Override
-    public UserAccount updateUser(Long userId, String firstName, String lastName, String email, String userName, String password, String apiKey, String secretKey,
-                                  String timeZone) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
     @Override
     public User getActiveUser(long arg0) {
         return _systemUser;
diff --git a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapImportUsersCmd.java b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapImportUsersCmd.java
index 564c1d0a1ef..90114523cfd 100644
--- a/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapImportUsersCmd.java
+++ b/plugins/user-authenticators/ldap/src/main/java/org/apache/cloudstack/api/command/LdapImportUsersCmd.java
@@ -26,9 +26,6 @@
 
 import javax.inject.Inject;
 
-import com.cloud.user.Account;
-import com.cloud.user.User;
-import com.cloud.user.UserAccount;
 import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
@@ -36,6 +33,7 @@
 import org.apache.cloudstack.api.BaseListCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd;
 import org.apache.cloudstack.api.response.DomainResponse;
 import org.apache.cloudstack.api.response.LdapUserResponse;
 import org.apache.cloudstack.api.response.ListResponse;
@@ -54,25 +52,23 @@
 import com.cloud.exception.NetworkRuleConflictException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.user.Account;
 import com.cloud.user.AccountService;
 import com.cloud.user.DomainService;
+import com.cloud.user.User;
+import com.cloud.user.UserAccount;
 
-@APICommand(name = "importLdapUsers", description = "Import LDAP users", responseObject = LdapUserResponse.class, since = "4.3.0",
-        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+@APICommand(name = "importLdapUsers", description = "Import LDAP users", responseObject = LdapUserResponse.class, since = "4.3.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
 public class LdapImportUsersCmd extends BaseListCmd {
 
     public static final Logger s_logger = Logger.getLogger(LdapImportUsersCmd.class.getName());
 
     private static final String s_name = "ldapuserresponse";
 
-    @Parameter(name = ApiConstants.TIMEZONE,
-               type = CommandType.STRING,
-               description = "Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.")
+    @Parameter(name = ApiConstants.TIMEZONE, type = CommandType.STRING, description = "Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.")
     private String timezone;
 
-    @Parameter(name = ApiConstants.ACCOUNT_TYPE,
-               type = CommandType.SHORT,
-               description = "Type of the account.  Specify 0 for user, 1 for root admin, and 2 for domain admin")
+    @Parameter(name = ApiConstants.ACCOUNT_TYPE, type = CommandType.SHORT, description = "Type of the account.  Specify 0 for user, 1 for root admin, and 2 for domain admin")
     private Short accountType;
 
     @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "Creates the account under the specified role.")
@@ -81,16 +77,13 @@
     @Parameter(name = ApiConstants.ACCOUNT_DETAILS, type = CommandType.MAP, description = "details for account used to store specific parameters")
     private Map<String, String> details;
 
-    @Parameter(name = ApiConstants.DOMAIN_ID,
-               type = CommandType.UUID,
-               entityType = DomainResponse.class,
-               description = "Specifies the domain to which the ldap users are to be "
-                   + "imported. If no domain is specified, a domain will created using group parameter. If the group is also not specified, a domain name based on the OU information will be "
-                   + "created. If no OU hierarchy exists, will be defaulted to ROOT domain")
+    @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Specifies the domain to which the ldap users are to be "
+            + "imported. If no domain is specified, a domain will created using group parameter. If the group is also not specified, a domain name based on the OU information will be "
+            + "created. If no OU hierarchy exists, will be defaulted to ROOT domain")
     private Long domainId;
 
     @Parameter(name = ApiConstants.GROUP, type = CommandType.STRING, description = "Specifies the group name from which the ldap users are to be imported. "
-        + "If no group is specified, all the users will be imported.")
+            + "If no group is specified, all the users will be imported.")
     private String groupName;
 
     private Domain _domain;
@@ -121,20 +114,27 @@ private void createCloudstackUserAccount(LdapUser user, String accountName, Doma
         } else {
 //            check if the user exists. if yes, call update
             UserAccount csuser = _accountService.getActiveUserAccount(user.getUsername(), domain.getId());
-            if(csuser == null) {
+            if (csuser == null) {
                 s_logger.debug("No user exists with name: " + user.getUsername() + " creating a user in the account: " + accountName);
                 _accountService.createUser(user.getUsername(), generatePassword(), user.getFirstname(), user.getLastname(), user.getEmail(), timezone, accountName, domain.getId(),
-                                           UUID.randomUUID().toString(), User.Source.LDAP);
+                        UUID.randomUUID().toString(), User.Source.LDAP);
             } else {
-                s_logger.debug("account with name: " + accountName + " exist and user with name: " + user.getUsername() + " exists in the account. Updating the account.");
-                _accountService.updateUser(csuser.getId(), user.getFirstname(), user.getLastname(), user.getEmail(), null, null, null, null, null);
+                s_logger.debug("Account [name=%s] and user [name=%s] already exist in CloudStack. Executing the user update.");
+
+                UpdateUserCmd updateUserCmd = new UpdateUserCmd();
+                updateUserCmd.setId(csuser.getId());
+                updateUserCmd.setFirstname(user.getFirstname());
+                updateUserCmd.setLastname(user.getLastname());
+                updateUserCmd.setEmail(user.getEmail());
+
+                _accountService.updateUser(updateUserCmd);
             }
         }
     }
 
     @Override
-    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
-        ResourceAllocationException, NetworkRuleConflictException {
+    public void execute()
+            throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
         if (getAccountType() == null && getRoleId() == null) {
             throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Both account type and role ID are not provided");
         }
@@ -177,7 +177,7 @@ public Long getRoleId() {
 
     private String getAccountName(LdapUser user) {
         String finalAccountName = accountName;
-        if(finalAccountName == null ) {
+        if (finalAccountName == null) {
             finalAccountName = user.getUsername();
         }
         return finalAccountName;
@@ -244,7 +244,7 @@ private String generatePassword() throws ServerApiException {
             final byte bytes[] = new byte[20];
             randomGen.nextBytes(bytes);
             return new String(Base64.encode(bytes), "UTF-8");
-        } catch ( NoSuchAlgorithmException | UnsupportedEncodingException e) {
+        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
             throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate random password");
         }
     }
diff --git a/server/src/main/java/com/cloud/user/AccountManager.java b/server/src/main/java/com/cloud/user/AccountManager.java
index e708b040ed9..de6dcca0a67 100644
--- a/server/src/main/java/com/cloud/user/AccountManager.java
+++ b/server/src/main/java/com/cloud/user/AccountManager.java
@@ -16,15 +16,17 @@
 // under the License.
 package com.cloud.user;
 
+import java.net.InetAddress;
 import java.util.List;
 import java.util.Map;
-import java.net.InetAddress;
 
 import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd;
 import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd;
 import org.apache.cloudstack.api.command.admin.user.MoveUserCmd;
 import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.Configurable;
 
 import com.cloud.api.query.vo.ControlledViewEntity;
 import com.cloud.exception.ConcurrentOperationException;
@@ -34,17 +36,14 @@
 import com.cloud.utils.Ternary;
 import com.cloud.utils.db.SearchBuilder;
 import com.cloud.utils.db.SearchCriteria;
-import org.apache.cloudstack.framework.config.ConfigKey;
-import org.apache.cloudstack.framework.config.Configurable;
 
 /**
  * AccountManager includes logic that deals with accounts, domains, and users.
  *
  */
-public interface AccountManager extends AccountService, Configurable{
+public interface AccountManager extends AccountService, Configurable {
     /**
      * Disables an account by accountId
-     * @param accountId
      * @return true if disable was successful, false otherwise
      */
     boolean disableAccount(long accountId) throws ConcurrentOperationException, ResourceUnavailableException;
@@ -57,24 +56,23 @@
 
     /**
      * Logs out a user
-     * @param userId
      */
     void logoutUser(long userId);
 
     /**
-      * Authenticates a user when s/he logs in.
-      *
-      * @param username
-      *            required username for authentication
-      * @param password
-      *            password to use for authentication, can be null for single sign-on case
-      * @param domainId
-      *            id of domain where user with username resides
-      * @param requestParameters
-      *            the request parameters of the login request, which should contain timestamp of when the request signature is
-      *            made, and the signature itself in the single sign-on case
-      * @return a user object, null if the user failed to authenticate
-      */
+     * Authenticates a user when s/he logs in.
+     *
+     * @param username
+     *            required username for authentication
+     * @param password
+     *            password to use for authentication, can be null for single sign-on case
+     * @param domainId
+     *            id of domain where user with username resides
+     * @param requestParameters
+     *            the request parameters of the login request, which should contain timestamp of when the request signature is
+     *            made, and the signature itself in the single sign-on case
+     * @return a user object, null if the user failed to authenticate
+     */
     UserAccount authenticateUser(String username, String password, Long domainId, InetAddress loginIpAddress, Map<String, Object[]> requestParameters);
 
     /**
@@ -88,23 +86,20 @@
 
     boolean enableAccount(long accountId);
 
+    void buildACLSearchBuilder(SearchBuilder<? extends ControlledEntity> sb, Long domainId, boolean isRecursive, List<Long> permittedAccounts,
+            ListProjectResourcesCriteria listProjectResourcesCriteria);
 
-    void buildACLSearchBuilder(SearchBuilder<? extends ControlledEntity> sb, Long domainId,
-            boolean isRecursive, List<Long> permittedAccounts, ListProjectResourcesCriteria listProjectResourcesCriteria);
-
-    void buildACLViewSearchBuilder(SearchBuilder<? extends ControlledViewEntity> sb, Long domainId,
-            boolean isRecursive, List<Long> permittedAccounts, ListProjectResourcesCriteria listProjectResourcesCriteria);
-
-    void buildACLSearchCriteria(SearchCriteria<? extends ControlledEntity> sc,
-            Long domainId, boolean isRecursive, List<Long> permittedAccounts, ListProjectResourcesCriteria listProjectResourcesCriteria);
+    void buildACLViewSearchBuilder(SearchBuilder<? extends ControlledViewEntity> sb, Long domainId, boolean isRecursive, List<Long> permittedAccounts,
+            ListProjectResourcesCriteria listProjectResourcesCriteria);
 
-    void buildACLSearchParameters(Account caller, Long id,
-            String accountName, Long projectId, List<Long> permittedAccounts, Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject, boolean listAll,
-            boolean forProjectInvitation);
+    void buildACLSearchCriteria(SearchCriteria<? extends ControlledEntity> sc, Long domainId, boolean isRecursive, List<Long> permittedAccounts,
+            ListProjectResourcesCriteria listProjectResourcesCriteria);
 
-    void buildACLViewSearchCriteria(SearchCriteria<? extends ControlledViewEntity> sc,
-            Long domainId, boolean isRecursive, List<Long> permittedAccounts, ListProjectResourcesCriteria listProjectResourcesCriteria);
+    void buildACLSearchParameters(Account caller, Long id, String accountName, Long projectId, List<Long> permittedAccounts,
+            Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject, boolean listAll, boolean forProjectInvitation);
 
+    void buildACLViewSearchCriteria(SearchCriteria<? extends ControlledViewEntity> sc, Long domainId, boolean isRecursive, List<Long> permittedAccounts,
+            ListProjectResourcesCriteria listProjectResourcesCriteria);
 
     /**
      * Deletes a user by userId
@@ -127,10 +122,6 @@ void buildACLViewSearchCriteria(SearchCriteria<? extends ControlledViewEntity> s
 
     /**
      * Disables an account by accountName and domainId
-     *
-     * @param accountName
-     * @param domainId
-     * @param accountId
      * @param disabled
      *            account if success
      * @return true if disable was successful, false otherwise
@@ -142,33 +133,21 @@ void buildACLViewSearchCriteria(SearchCriteria<? extends ControlledViewEntity> s
      *
      * @param accountName
      *            - the enableAccount command defining the accountId to be deleted.
-     * @param domainId
-     *            TODO
-     * @param accountId
-     * @return account object
      */
     Account enableAccount(String accountName, Long domainId, Long accountId);
 
     /**
      * Deletes user by Id
-     * @param deleteUserCmd
-     * @return
      */
     boolean deleteUser(DeleteUserCmd deleteUserCmd);
 
     /**
      * moves a user to another account within the same domain
-     * @param moveUserCmd
      * @return true if the user was successfully moved
      */
     boolean moveUser(MoveUserCmd moveUserCmd);
 
-    /**
-     * Update a user by userId
-     *
-     * @param cmd
-     * @return UserAccount object
-     */
+    @Override
     UserAccount updateUser(UpdateUserCmd cmd);
 
     /**
@@ -196,10 +175,6 @@ void buildACLViewSearchCriteria(SearchCriteria<? extends ControlledViewEntity> s
      *
      * @param accountName
      *            - the LockAccount command defining the accountId to be locked.
-     * @param domainId
-     *            TODO
-     * @param accountId
-     * @return account object
      */
     Account lockAccount(String accountName, Long domainId, Long accountId);
 
@@ -208,13 +183,8 @@ void buildACLViewSearchCriteria(SearchCriteria<? extends ControlledViewEntity> s
     public static final String MESSAGE_ADD_ACCOUNT_EVENT = "Message.AddAccount.Event";
 
     public static final String MESSAGE_REMOVE_ACCOUNT_EVENT = "Message.RemoveAccount.Event";
-    public static final ConfigKey<Boolean> UseSecretKeyInResponse = new ConfigKey<Boolean>(
-            "Advanced",
-            Boolean.class,
-            "use.secret.key.in.response",
-            "false",
-            "This parameter allows the users to enable or disable of showing secret key as a part of response for various APIs. By default it is set to false.",
-            true);
+    public static final ConfigKey<Boolean> UseSecretKeyInResponse = new ConfigKey<Boolean>("Advanced", Boolean.class, "use.secret.key.in.response", "false",
+            "This parameter allows the users to enable or disable of showing secret key as a part of response for various APIs. By default it is set to false.", true);
 
     boolean moveUser(long id, Long domainId, long accountId);
 }
diff --git a/server/src/main/java/com/cloud/user/AccountManagerImpl.java b/server/src/main/java/com/cloud/user/AccountManagerImpl.java
index dc9fdc0a9e5..b44e2803df6 100644
--- a/server/src/main/java/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/main/java/com/cloud/user/AccountManagerImpl.java
@@ -23,7 +23,6 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
@@ -38,10 +37,6 @@
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.lang.StringUtils;
-import org.apache.log4j.Logger;
-
 import org.apache.cloudstack.acl.ControlledEntity;
 import org.apache.cloudstack.acl.QuerySelector;
 import org.apache.cloudstack.acl.RoleType;
@@ -55,6 +50,7 @@
 import org.apache.cloudstack.api.command.admin.user.MoveUserCmd;
 import org.apache.cloudstack.api.command.admin.user.RegisterCmd;
 import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd;
+import org.apache.cloudstack.config.ApiServiceConfiguration;
 import org.apache.cloudstack.context.CallContext;
 import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
 import org.apache.cloudstack.framework.config.ConfigKey;
@@ -64,6 +60,11 @@
 import org.apache.cloudstack.managed.context.ManagedContextRunnable;
 import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao;
 import org.apache.cloudstack.utils.baremetal.BaremetalUtils;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Logger;
 
 import com.cloud.api.ApiDBUtils;
 import com.cloud.api.query.vo.ControlledViewEntity;
@@ -172,8 +173,6 @@
 import com.cloud.vm.snapshot.VMSnapshotManager;
 import com.cloud.vm.snapshot.VMSnapshotVO;
 import com.cloud.vm.snapshot.dao.VMSnapshotDao;
-import org.apache.cloudstack.config.ApiServiceConfiguration;
-
 
 public class AccountManagerImpl extends ManagerBase implements AccountManager, Manager {
     public static final Logger s_logger = Logger.getLogger(AccountManagerImpl.class);
@@ -540,8 +539,8 @@ public void checkAccess(Account caller, AccessType accessType, boolean sameOwner
                 Account account = ApiDBUtils.findAccountById(entity.getAccountId());
                 domainId = account != null ? account.getDomainId() : -1;
             }
-            if (entity.getAccountId() != -1 && domainId != -1 && !(entity instanceof VirtualMachineTemplate)
-                    && !(entity instanceof Network && accessType != null && accessType == AccessType.UseEntry) && !(entity instanceof AffinityGroup)) {
+            if (entity.getAccountId() != -1 && domainId != -1 && !(entity instanceof VirtualMachineTemplate) && !(entity instanceof Network && accessType != null && accessType == AccessType.UseEntry)
+                    && !(entity instanceof AffinityGroup)) {
                 List<ControlledEntity> toBeChecked = domains.get(entity.getDomainId());
                 // for templates, we don't have to do cross domains check
                 if (toBeChecked == null) {
@@ -563,7 +562,7 @@ public void checkAccess(Account caller, AccessType accessType, boolean sameOwner
 
             if (!granted) {
                 assert false : "How can all of the security checkers pass on checking this check: " + entity;
-                throw new PermissionDeniedException("There's no way to confirm " + caller + " has access to " + entity);
+            throw new PermissionDeniedException("There's no way to confirm " + caller + " has access to " + entity);
             }
         }
 
@@ -590,26 +589,27 @@ public void checkAccess(Account caller, AccessType accessType, boolean sameOwner
     public Long checkAccessAndSpecifyAuthority(Account caller, Long zoneId) {
         // We just care for resource domain admin for now. He should be permitted to see only his zone.
         if (isResourceDomainAdmin(caller.getAccountId())) {
-            if (zoneId == null)
+            if (zoneId == null) {
                 return getZoneIdForAccount(caller);
-            else if (zoneId.compareTo(getZoneIdForAccount(caller)) != 0)
+            } else if (zoneId.compareTo(getZoneIdForAccount(caller)) != 0) {
                 throw new PermissionDeniedException("Caller " + caller + "is not allowed to access the zone " + zoneId);
-            else
+            } else {
                 return zoneId;
-        }
-
-        else
+            }
+        } else {
             return zoneId;
+        }
     }
 
     private Long getZoneIdForAccount(Account account) {
 
         // Currently just for resource domain admin
         List<DataCenterVO> dcList = _dcDao.findZonesByDomainId(account.getDomainId());
-        if (dcList != null && dcList.size() != 0)
+        if (dcList != null && dcList.size() != 0) {
             return dcList.get(0).getId();
-        else
+        } else {
             throw new CloudRuntimeException("Failed to find any private zone for Resource domain admin.");
+        }
 
     }
 
@@ -1011,13 +1011,12 @@ private boolean doDisableAccount(long accountId) throws ConcurrentOperationExcep
 
     @Override
     @ActionEvents({@ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_CREATE, eventDescription = "creating Account"),
-            @ActionEvent(eventType = EventTypes.EVENT_USER_CREATE, eventDescription = "creating User")})
-    public UserAccount createUserAccount(final String userName, final String password, final String firstName, final String lastName, final String email, final String timezone,
-            String accountName, final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map<String, String> details, String accountUUID,
-            final String userUUID) {
+        @ActionEvent(eventType = EventTypes.EVENT_USER_CREATE, eventDescription = "creating User")})
+    public UserAccount createUserAccount(final String userName, final String password, final String firstName, final String lastName, final String email, final String timezone, String accountName,
+            final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map<String, String> details, String accountUUID, final String userUUID) {
 
-        return createUserAccount(userName, password, firstName, lastName, email, timezone, accountName, accountType, roleId, domainId, networkDomain, details, accountUUID,
-                userUUID, User.Source.UNKNOWN);
+        return createUserAccount(userName, password, firstName, lastName, email, timezone, accountName, accountType, roleId, domainId, networkDomain, details, accountUUID, userUUID,
+                User.Source.UNKNOWN);
     }
 
     // ///////////////////////////////////////////////////
@@ -1027,10 +1026,10 @@ public UserAccount createUserAccount(final String userName, final String passwor
     @Override
     @DB
     @ActionEvents({@ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_CREATE, eventDescription = "creating Account"),
-            @ActionEvent(eventType = EventTypes.EVENT_USER_CREATE, eventDescription = "creating User")})
-    public UserAccount createUserAccount(final String userName, final String password, final String firstName, final String lastName, final String email, final String timezone,
-            String accountName, final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map<String, String> details, String accountUUID,
-            final String userUUID, final User.Source source) {
+        @ActionEvent(eventType = EventTypes.EVENT_USER_CREATE, eventDescription = "creating User")})
+    public UserAccount createUserAccount(final String userName, final String password, final String firstName, final String lastName, final String email, final String timezone, String accountName,
+            final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map<String, String> details, String accountUUID, final String userUUID,
+            final User.Source source) {
 
         if (accountName == null) {
             accountName = userName;
@@ -1058,7 +1057,7 @@ public UserAccount createUserAccount(final String userName, final String passwor
         }
 
         // Check permissions
-        checkAccess(CallContext.current().getCallingAccount(), domain);
+        checkAccess(getCurrentCallingAccount(), domain);
 
         if (!_userAccountDao.validateUsernameInDomain(userName, domainId)) {
             throw new InvalidParameterValueException("The user " + userName + " already exists in domain " + domainId);
@@ -1132,7 +1131,7 @@ public UserVO createUser(String userName, String password, String firstName, Str
             throw new CloudRuntimeException("The user cannot be created as domain " + domain.getName() + " is being deleted");
         }
 
-        checkAccess(CallContext.current().getCallingAccount(), domain);
+        checkAccess(getCurrentCallingAccount(), domain);
 
         Account account = _accountDao.findEnabledAccount(accountName, domainId);
         if (account == null || account.getType() == Account.ACCOUNT_TYPE_PROJECT) {
@@ -1153,157 +1152,246 @@ public UserVO createUser(String userName, String password, String firstName, Str
 
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_USER_CREATE, eventDescription = "creating User")
-    public UserVO createUser(String userName, String password, String firstName, String lastName, String email, String timeZone, String accountName, Long domainId,
-            String userUUID) {
+    public UserVO createUser(String userName, String password, String firstName, String lastName, String email, String timeZone, String accountName, Long domainId, String userUUID) {
 
         return createUser(userName, password, firstName, lastName, email, timeZone, accountName, domainId, userUUID, User.Source.UNKNOWN);
     }
 
     @Override
-    @ActionEvent(eventType = EventTypes.EVENT_USER_UPDATE, eventDescription = "updating User")
-    public UserAccount updateUser(Long userId, String firstName, String lastName, String email, String userName, String password, String apiKey, String secretKey,
-            String timeZone) {
-        // Input validation
-        UserVO user = _userDao.getUser(userId);
+    @ActionEvent(eventType = EventTypes.EVENT_USER_UPDATE, eventDescription = "Updating User")
+    public UserAccount updateUser(UpdateUserCmd updateUserCmd) {
+        UserVO user = retrieveAndValidateUser(updateUserCmd);
+        s_logger.debug("Updating user with Id: " + user.getUuid());
 
-        if (user == null) {
-            throw new InvalidParameterValueException("unable to find user by id");
-        }
+        validateAndUpdatApiAndSecretKeyIfNeeded(updateUserCmd, user);
+        Account account = retrieveAndValidateAccount(user);
 
-        if ((apiKey == null && secretKey != null) || (apiKey != null && secretKey == null)) {
-            throw new InvalidParameterValueException("Please provide an userApiKey/userSecretKey pair");
-        }
+        validateAndUpdateFirstNameIfNeeded(updateUserCmd, user);
+        validateAndUpdateLastNameIfNeeded(updateUserCmd, user);
+        validateAndUpdateUsernameIfNeeded(updateUserCmd, user, account);
 
-        // If the account is an admin type, return an error. We do not allow this
-        Account account = _accountDao.findById(user.getAccountId());
-        if (account == null) {
-            throw new InvalidParameterValueException("unable to find user account " + user.getAccountId());
+        validateUserPasswordAndUpdateIfNeeded(updateUserCmd.getPassword(), user, updateUserCmd.getCurrentPassword());
+        String email = updateUserCmd.getEmail();
+        if (StringUtils.isNotBlank(email)) {
+            user.setEmail(email);
         }
-
-        // don't allow updating project account
-        if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) {
-            throw new InvalidParameterValueException("unable to find user by id");
+        String timezone = updateUserCmd.getTimezone();
+        if (StringUtils.isNotBlank(timezone)) {
+            user.setTimezone(timezone);
+        }
+        _userDao.update(user.getId(), user);
+        return _userAccountDao.findById(user.getId());
+    }
+
+    /**
+     * Updates the password in the user POJO if needed. If no password is provided, then the password is not updated.
+     * The following validations are executed if 'password' is not null. Admins (root admins or domain admins) can execute password updates without entering the current password.
+     * <ul>
+     *  <li> If 'password' is blank, we throw an {@link InvalidParameterValueException};
+     *  <li> If 'current password' is not provided and user is not an Admin, we throw an {@link InvalidParameterValueException};
+     *  <li> If a normal user is calling this method, we use {@link #validateCurrentPassword(UserVO, String)} to check if the provided old password matches the database one;
+     * </ul>
+     *
+     * If all checks pass, we encode the given password with the most preferable password mechanism given in {@link #_userPasswordEncoders}.
+     */
+    protected void validateUserPasswordAndUpdateIfNeeded(String newPassword, UserVO user, String currentPassword) {
+        if (newPassword == null) {
+            s_logger.trace("No new password to update for user: " + user.getUuid());
+            return;
         }
-
-        // don't allow updating system account
-        if (account.getId() == Account.ACCOUNT_ID_SYSTEM) {
-            throw new PermissionDeniedException("user id : " + userId + " is system account, update is not allowed");
+        if (StringUtils.isBlank(newPassword)) {
+            throw new InvalidParameterValueException("Password cannot be empty or blank.");
+        }
+        Account callingAccount = getCurrentCallingAccount();
+        boolean isRootAdminExecutingPasswordUpdate = callingAccount.getId() == Account.ACCOUNT_ID_SYSTEM || isRootAdmin(callingAccount.getId());
+        boolean isDomainAdmin = isDomainAdmin(callingAccount.getId());
+        boolean isAdmin = isDomainAdmin || isRootAdminExecutingPasswordUpdate;
+        if (isAdmin) {
+            s_logger.trace(String.format("Admin account [uuid=%s] executing password update for user [%s] ", callingAccount.getUuid(), user.getUuid()));
+        }
+        if (!isAdmin && StringUtils.isBlank(currentPassword)) {
+            throw new InvalidParameterValueException("To set a new password the current password must be provided.");
+        }
+        if (CollectionUtils.isEmpty(_userPasswordEncoders)) {
+            throw new CloudRuntimeException("No user authenticators configured!");
+        }
+        if (!isAdmin) {
+            validateCurrentPassword(user, currentPassword);
+        }
+        UserAuthenticator userAuthenticator = _userPasswordEncoders.get(0);
+        String newPasswordEncoded = userAuthenticator.encode(newPassword);
+        user.setPassword(newPasswordEncoded);
+    }
+
+    /**
+     * Iterates over all configured user authenticators and tries to authenticate the user using the current password.
+     * If the user is authenticated with success, we have nothing else to do here; otherwise, an {@link InvalidParameterValueException} is thrown.
+     */
+    protected void validateCurrentPassword(UserVO user, String currentPassword) {
+        AccountVO userAccount = _accountDao.findById(user.getAccountId());
+        boolean currentPasswordMatchesDataBasePassword = false;
+        for (UserAuthenticator userAuthenticator : _userPasswordEncoders) {
+            Pair<Boolean, ActionOnFailedAuthentication> authenticationResult = userAuthenticator.authenticate(user.getUsername(), currentPassword, userAccount.getDomainId(), null);
+            if (authenticationResult == null) {
+                s_logger.trace(String.format("Authenticator [%s] is returning null for the authenticate mehtod.", userAuthenticator.getClass()));
+                continue;
+            }
+            if (BooleanUtils.toBoolean(authenticationResult.first())) {
+                s_logger.debug(String.format("User [id=%s] re-authenticated [authenticator=%s] during password update.", user.getUuid(), userAuthenticator.getName()));
+                currentPasswordMatchesDataBasePassword = true;
+                break;
+            }
         }
+        if (!currentPasswordMatchesDataBasePassword) {
+            throw new InvalidParameterValueException("Current password is incorrect.");
+        }
+    }
 
-        checkAccess(CallContext.current().getCallingAccount(), AccessType.OperateEntry, true, account);
-
-        if (firstName != null) {
-            if (firstName.isEmpty()) {
-                throw new InvalidParameterValueException("Firstname is empty");
+    /**
+     * Validates the user 'username' if provided. The 'username' cannot be blank (when provided).
+     * <ul>
+     *  <li> If the 'username' is not provided, we do not update it (setting to null) in the User POJO.
+     *  <li> If the 'username' is blank, we throw an {@link InvalidParameterValueException}.
+     *  <li> The username must be unique in each domain. Therefore, if there is already another user with the same username, an {@link InvalidParameterValueException} is thrown.
+     * </ul>
+     */
+    protected void validateAndUpdateUsernameIfNeeded(UpdateUserCmd updateUserCmd, UserVO user, Account account) {
+        String userName = updateUserCmd.getUsername();
+        if (userName == null) {
+            return;
+        }
+        if (StringUtils.isBlank(userName)) {
+            throw new InvalidParameterValueException("Username cannot be empty.");
+        }
+        List<UserVO> duplicatedUsers = _userDao.findUsersByName(userName);
+        for (UserVO duplicatedUser : duplicatedUsers) {
+            if (duplicatedUser.getId() == user.getId()) {
+                continue;
+            }
+            Account duplicatedUserAccountWithUserThatHasTheSameUserName = _accountDao.findById(duplicatedUser.getAccountId());
+            if (duplicatedUserAccountWithUserThatHasTheSameUserName.getDomainId() == account.getDomainId()) {
+                DomainVO domain = _domainDao.findById(duplicatedUserAccountWithUserThatHasTheSameUserName.getDomainId());
+                throw new InvalidParameterValueException(String.format("Username [%s] already exists in domain [id=%s,name=%s]", duplicatedUser.getUsername(), domain.getUuid(), domain.getName()));
             }
-
-            user.setFirstname(firstName);
         }
+        user.setUsername(userName);
+    }
+
+    /**
+     * Validates the user 'lastName' if provided. The 'lastName' cannot be blank (when provided).
+     * <ul>
+     *  <li> If the 'lastName' is not provided, we do not update it (setting to null) in the User POJO.
+     *  <li> If the 'lastName' is blank, we throw an {@link InvalidParameterValueException}.
+     * </ul>
+     */
+    protected void validateAndUpdateLastNameIfNeeded(UpdateUserCmd updateUserCmd, UserVO user) {
+        String lastName = updateUserCmd.getLastname();
         if (lastName != null) {
-            if (lastName.isEmpty()) {
-                throw new InvalidParameterValueException("Lastname is empty");
+            if (StringUtils.isBlank(lastName)) {
+                throw new InvalidParameterValueException("Lastname cannot be empty.");
             }
 
             user.setLastname(lastName);
         }
-        if (userName != null) {
-            if (userName.isEmpty()) {
-                throw new InvalidParameterValueException("Username is empty");
-            }
+    }
 
-            // don't allow to have same user names in the same domain
-            List<UserVO> duplicatedUsers = _userDao.findUsersByName(userName);
-            for (UserVO duplicatedUser : duplicatedUsers) {
-                if (duplicatedUser.getId() != user.getId()) {
-                    Account duplicatedUserAccount = _accountDao.findById(duplicatedUser.getAccountId());
-                    if (duplicatedUserAccount.getDomainId() == account.getDomainId()) {
-                        throw new InvalidParameterValueException("User with name " + userName + " already exists in domain " + duplicatedUserAccount.getDomainId());
-                    }
-                }
+    /**
+     * Validates the user 'firstName' if provided. The 'firstName' cannot be blank (when provided).
+     * <ul>
+     *  <li> If the 'firstName' is not provided, we do not update it (setting to null) in the User POJO.
+     *  <li> If the 'firstName' is blank, we throw an {@link InvalidParameterValueException}.
+     * </ul>
+     */
+    protected void validateAndUpdateFirstNameIfNeeded(UpdateUserCmd updateUserCmd, UserVO user) {
+        String firstName = updateUserCmd.getFirstname();
+        if (firstName != null) {
+            if (StringUtils.isBlank(firstName)) {
+                throw new InvalidParameterValueException("Firstname cannot be empty.");
             }
-
-            user.setUsername(userName);
+            user.setFirstname(firstName);
         }
+    }
 
-        if (password != null) {
-            if (password.isEmpty()) {
-                throw new InvalidParameterValueException("Password cannot be empty");
-            }
-            String encodedPassword = null;
-            for (Iterator<UserAuthenticator> en = _userPasswordEncoders.iterator(); en.hasNext();) {
-                UserAuthenticator authenticator = en.next();
-                encodedPassword = authenticator.encode(password);
-                if (encodedPassword != null) {
-                    break;
-                }
-            }
-            if (encodedPassword == null) {
-                throw new CloudRuntimeException("Failed to encode password");
-            }
-            user.setPassword(encodedPassword);
-        }
-        if (email != null) {
-            user.setEmail(email);
-        }
-        if (timeZone != null) {
-            user.setTimezone(timeZone);
+    /**
+     * Searches an account for the given users. Then, we validate it as follows:
+     * <ul>
+     *  <li>If no account is found for the given user, we throw a {@link CloudRuntimeException}. There must be something wrong in the database for this case.
+     *  <li>If the account is of {@link Account#ACCOUNT_TYPE_PROJECT}, we throw an {@link InvalidParameterValueException}.
+     *  <li>If the account is of {@link Account#ACCOUNT_ID_SYSTEM}, we throw an {@link InvalidParameterValueException}.
+     * </ul>
+     *
+     * Afterwards, we check if the logged user has access to the user being updated via {@link #checkAccess(Account, AccessType, boolean, ControlledEntity...)}
+     */
+    protected Account retrieveAndValidateAccount(UserVO user) {
+        Account account = _accountDao.findById(user.getAccountId());
+        if (account == null) {
+            throw new CloudRuntimeException("Unable to find user account with ID: " + user.getAccountId());
         }
-        if (apiKey != null) {
-            user.setApiKey(apiKey);
+        if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) {
+            throw new InvalidParameterValueException("Unable to find user with ID: " + user.getUuid());
         }
-        if (secretKey != null) {
-            user.setSecretKey(secretKey);
+        if (account.getId() == Account.ACCOUNT_ID_SYSTEM) {
+            throw new PermissionDeniedException("user UUID : " + user.getUuid() + " is a system account; update is not allowed.");
         }
+        checkAccess(getCurrentCallingAccount(), AccessType.OperateEntry, true, account);
+        return account;
+    }
 
-        if (s_logger.isDebugEnabled()) {
-            s_logger.debug("updating user with id: " + userId);
+    /**
+     * Returns the calling account using the method {@link CallContext#getCallingAccount()}.
+     * We are introducing this method to avoid using 'PowerMockRunner' in unit tests. Then, we can mock the calls to this method, which facilitates the development of test cases.
+     */
+    protected Account getCurrentCallingAccount() {
+        return CallContext.current().getCallingAccount();
+    }
+
+    /**
+     * Validates user API and Secret keys. If a new pair of keys is provided, we update them in the user POJO.
+     * <ul>
+     * <li>When updating the keys, it must be provided a pair (API and Secret keys); otherwise, an {@link InvalidParameterValueException} is thrown.
+     * <li>If a pair of keys is provided, we validate to see if there is an user already using the provided API key. If there is someone else using, we throw an {@link InvalidParameterValueException} because two users cannot have the same API key.
+     * </ul>
+     */
+    protected void validateAndUpdatApiAndSecretKeyIfNeeded(UpdateUserCmd updateUserCmd, UserVO user) {
+        String apiKey = updateUserCmd.getApiKey();
+        String secretKey = updateUserCmd.getSecretKey();
+
+        boolean isApiKeyBlank = StringUtils.isBlank(apiKey);
+        boolean isSecretKeyBlank = StringUtils.isBlank(secretKey);
+        if (isApiKeyBlank ^ isSecretKeyBlank) {
+            throw new InvalidParameterValueException("Please provide a userApiKey/userSecretKey pair");
         }
-        try {
-            // check if the apiKey and secretKey are globally unique
-            if (apiKey != null && secretKey != null) {
-                Pair<User, Account> apiKeyOwner = _accountDao.findUserAccountByApiKey(apiKey);
-
-                if (apiKeyOwner != null) {
-                    User usr = apiKeyOwner.first();
-                    if (usr.getId() != userId) {
-                        throw new InvalidParameterValueException("The api key:" + apiKey + " exists in the system for user id:" + userId + " ,please provide a unique key");
-                    } else {
-                        // allow the updation to take place
-                    }
-                }
+        if (isApiKeyBlank && isSecretKeyBlank) {
+            return;
+        }
+        Pair<User, Account> apiKeyOwner = _accountDao.findUserAccountByApiKey(apiKey);
+        if (apiKeyOwner != null) {
+            User userThatHasTheProvidedApiKey = apiKeyOwner.first();
+            if (userThatHasTheProvidedApiKey.getId() != user.getId()) {
+                throw new InvalidParameterValueException(String.format("The API key [%s] already exists in the system. Please provide a unique key.", apiKey));
             }
-
-            _userDao.update(userId, user);
-        } catch (Throwable th) {
-            s_logger.error("error updating user", th);
-            throw new CloudRuntimeException("Unable to update user " + userId);
         }
-
-        CallContext.current().putContextParameter(User.class, user.getUuid());
-
-        return _userAccountDao.findById(userId);
+        user.setApiKey(apiKey);
+        user.setSecretKey(secretKey);
     }
 
-    @Override
-    @ActionEvent(eventType = EventTypes.EVENT_USER_UPDATE, eventDescription = "updating User")
-    public UserAccount updateUser(UpdateUserCmd cmd) {
-        Long id = cmd.getId();
-        String apiKey = cmd.getApiKey();
-        String firstName = cmd.getFirstname();
-        String email = cmd.getEmail();
-        String lastName = cmd.getLastname();
-        String password = cmd.getPassword();
-        String secretKey = cmd.getSecretKey();
-        String timeZone = cmd.getTimezone();
-        String userName = cmd.getUsername();
+    /**
+     * Searches for a user with the given userId. If no user is found we throw an {@link InvalidParameterValueException}.
+     */
+    protected UserVO retrieveAndValidateUser(UpdateUserCmd updateUserCmd) {
+        Long userId = updateUserCmd.getId();
 
-        return updateUser(id, firstName, lastName, email, userName, password, apiKey, secretKey, timeZone);
+        UserVO user = _userDao.getUser(userId);
+        if (user == null) {
+            throw new InvalidParameterValueException("Unable to find user with id: " + userId);
+        }
+        return user;
     }
 
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_USER_DISABLE, eventDescription = "disabling User", async = true)
     public UserAccount disableUser(long userId) {
-        Account caller = CallContext.current().getCallingAccount();
+        Account caller = getCurrentCallingAccount();
 
         // Check if user exists in the system
         User user = _userDao.findById(userId);
@@ -1345,7 +1433,7 @@ public UserAccount disableUser(long userId) {
     @ActionEvent(eventType = EventTypes.EVENT_USER_ENABLE, eventDescription = "enabling User")
     public UserAccount enableUser(final long userId) {
 
-        Account caller = CallContext.current().getCallingAccount();
+        Account caller = getCurrentCallingAccount();
 
         // Check if user exists in the system
         final User user = _userDao.findById(userId);
@@ -1396,7 +1484,7 @@ public Boolean doInTransaction(TransactionStatus status) {
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_USER_LOCK, eventDescription = "locking User")
     public UserAccount lockUser(long userId) {
-        Account caller = CallContext.current().getCallingAccount();
+        Account caller = getCurrentCallingAccount();
 
         // Check if user with id exists in the system
         User user = _userDao.findById(userId);
@@ -1462,7 +1550,6 @@ public UserAccount lockUser(long userId) {
 
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_DELETE, eventDescription = "deleting account", async = true)
-    // This method deletes the account
     public boolean deleteUserAccount(long accountId) {
 
         CallContext ctx = CallContext.current();
@@ -1528,7 +1615,7 @@ public AccountVO enableAccount(String accountName, Long domainId, Long accountId
         }
 
         // Check if user performing the action is allowed to modify this account
-        Account caller = CallContext.current().getCallingAccount();
+        Account caller = getCurrentCallingAccount();
         checkAccess(caller, AccessType.OperateEntry, true, account);
 
         boolean success = enableAccount(account.getId());
@@ -1545,7 +1632,7 @@ public AccountVO enableAccount(String accountName, Long domainId, Long accountId
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_DISABLE, eventDescription = "locking account", async = true)
     public AccountVO lockAccount(String accountName, Long domainId, Long accountId) {
-        Account caller = CallContext.current().getCallingAccount();
+        Account caller = getCurrentCallingAccount();
 
         Account account = null;
         if (accountId != null) {
@@ -1575,7 +1662,7 @@ public AccountVO lockAccount(String accountName, Long domainId, Long accountId)
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_DISABLE, eventDescription = "disabling account", async = true)
     public AccountVO disableAccount(String accountName, Long domainId, Long accountId) throws ConcurrentOperationException, ResourceUnavailableException {
-        Account caller = CallContext.current().getCallingAccount();
+        Account caller = getCurrentCallingAccount();
 
         Account account = null;
         if (accountId != null) {
@@ -1633,16 +1720,11 @@ public AccountVO updateAccount(UpdateAccountCmd cmd) {
         }
 
         // Check if user performing the action is allowed to modify this account
-        checkAccess(CallContext.current().getCallingAccount(), _domainMgr.getDomain(account.getDomainId()));
+        checkAccess(getCurrentCallingAccount(), _domainMgr.getDomain(account.getDomainId()));
 
         // check if the given account name is unique in this domain for updating
         Account duplicateAcccount = _accountDao.findActiveAccount(newAccountName, domainId);
-        if (duplicateAcccount != null && duplicateAcccount.getId() != account.getId()) {// allow
-                                                                                        // same
-                                                                                        // account
-                                                                                        // to
-                                                                                        // update
-                                                                                        // itself
+        if (duplicateAcccount != null && duplicateAcccount.getId() != account.getId()) {
             throw new InvalidParameterValueException(
                     "There already exists an account with the name:" + newAccountName + " in the domain:" + domainId + " with existing account id:" + duplicateAcccount.getId());
         }
@@ -1700,6 +1782,7 @@ public boolean deleteUser(DeleteUserCmd deleteUserCmd) {
         return _userDao.remove(deleteUserCmd.getId());
     }
 
+    @Override
     @ActionEvent(eventType = EventTypes.EVENT_USER_MOVE, eventDescription = "moving User to a new account")
     public boolean moveUser(MoveUserCmd cmd) {
         final Long id = cmd.getId();
@@ -1713,17 +1796,18 @@ public boolean moveUser(MoveUserCmd cmd) {
         return moveUser(user, newAccountId);
     }
 
+    @Override
     public boolean moveUser(long id, Long domainId, long accountId) {
         UserVO user = getValidUserVO(id);
         Account oldAccount = _accountDao.findById(user.getAccountId());
         checkAccountAndAccess(user, oldAccount);
         Account newAccount = _accountDao.findById(accountId);
         checkIfNotMovingAcrossDomains(domainId, newAccount);
-        return moveUser(user , accountId);
+        return moveUser(user, accountId);
     }
 
     private boolean moveUser(UserVO user, long newAccountId) {
-        if(newAccountId == user.getAccountId()) {
+        if (newAccountId == user.getAccountId()) {
             // could do a not silent fail but the objective of the user is reached
             return true; // no need to create a new user object for this user
         }
@@ -1734,7 +1818,7 @@ public Boolean doInTransaction(TransactionStatus status) {
                 UserVO newUser = new UserVO(user);
                 user.setExternalEntity(user.getUuid());
                 user.setUuid(UUID.randomUUID().toString());
-                _userDao.update(user.getId(),user);
+                _userDao.update(user.getId(), user);
                 newUser.setAccountId(newAccountId);
                 boolean success = _userDao.remove(user.getId());
                 UserVO persisted = _userDao.persist(newUser);
@@ -1746,7 +1830,7 @@ public Boolean doInTransaction(TransactionStatus status) {
     private long getNewAccountId(long domainId, String accountName, Long accountId) {
         Account newAccount = null;
         if (StringUtils.isNotBlank(accountName)) {
-            if(s_logger.isDebugEnabled()) {
+            if (s_logger.isDebugEnabled()) {
                 s_logger.debug("Getting id for account by name '" + accountName + "' in domain " + domainId);
             }
             newAccount = _accountDao.findEnabledAccount(accountName, domainId);
@@ -1763,7 +1847,7 @@ private long getNewAccountId(long domainId, String accountName, Long accountId)
     }
 
     private void checkIfNotMovingAcrossDomains(long domainId, Account newAccount) {
-        if(newAccount.getDomainId() != domainId) {
+        if (newAccount.getDomainId() != domainId) {
             // not in scope
             throw new InvalidParameterValueException("moving a user from an account in one domain to an account in annother domain is not supported!");
         }
@@ -1775,7 +1859,7 @@ private void checkAccountAndAccess(UserVO user, Account account) {
             throw new InvalidParameterValueException("Project users cannot be deleted or moved.");
         }
 
-        checkAccess(CallContext.current().getCallingAccount(), AccessType.OperateEntry, true, account);
+        checkAccess(getCurrentCallingAccount(), AccessType.OperateEntry, true, account);
         CallContext.current().putContextParameter(User.class, user.getUuid());
     }
 
@@ -1995,8 +2079,8 @@ public void markUserRegistered(long userId) {
 
     @Override
     @DB
-    public AccountVO createAccount(final String accountName, final short accountType, final Long roleId, final Long domainId, final String networkDomain,
-            final Map<String, String> details, final String uuid) {
+    public AccountVO createAccount(final String accountName, final short accountType, final Long roleId, final Long domainId, final String networkDomain, final Map<String, String> details,
+            final String uuid) {
         // Validate domain
         Domain domain = _domainMgr.getDomain(domainId);
         if (domain == null) {
@@ -2064,8 +2148,7 @@ public AccountVO doInTransaction(TransactionStatus status) {
         });
     }
 
-    protected UserVO createUser(long accountId, String userName, String password, String firstName, String lastName, String email, String timezone, String userUUID,
-            User.Source source) {
+    protected UserVO createUser(long accountId, String userName, String password, String firstName, String lastName, String email, String timezone, String userUUID, User.Source source) {
         if (s_logger.isDebugEnabled()) {
             s_logger.debug("Creating user: " + userName + ", accountId: " + accountId + " timezone:" + timezone);
         }
@@ -2098,8 +2181,7 @@ public void logoutUser(long userId) {
     }
 
     @Override
-    public UserAccount authenticateUser(final String username, final String password, final Long domainId, final InetAddress loginIpAddress, final Map<String, Object[]>
-            requestParameters) {
+    public UserAccount authenticateUser(final String username, final String password, final Long domainId, final InetAddress loginIpAddress, final Map<String, Object[]> requestParameters) {
         UserAccount user = null;
         if (password != null && !password.isEmpty()) {
             user = getUserAccount(username, password, domainId, requestParameters);
@@ -2211,10 +2293,10 @@ public UserAccount authenticateUser(final String username, final String password
 
             // We authenticated successfully by now, let's check if we are allowed to login from the ip address the reqest comes from
             final Account account = _accountMgr.getAccount(user.getAccountId());
-            final DomainVO domain = (DomainVO) _domainMgr.getDomain(account.getDomainId());
+            final DomainVO domain = (DomainVO)_domainMgr.getDomain(account.getDomainId());
 
             // Get the CIDRs from where this account is allowed to make calls
-            final String accessAllowedCidrs = ApiServiceConfiguration.ApiAllowedSourceCidrList.valueIn(account.getId()).replaceAll("\\s","");
+            final String accessAllowedCidrs = ApiServiceConfiguration.ApiAllowedSourceCidrList.valueIn(account.getId()).replaceAll("\\s", "");
             final Boolean ApiSourceCidrChecksEnabled = ApiServiceConfiguration.ApiSourceCidrChecksEnabled.value();
 
             if (ApiSourceCidrChecksEnabled) {
@@ -2222,10 +2304,9 @@ public UserAccount authenticateUser(final String username, final String password
 
                 // Block when is not in the list of allowed IPs
                 if (!NetUtils.isIpInCidrList(loginIpAddress, accessAllowedCidrs.split(","))) {
-                    s_logger.warn("Request by account '" + account.toString() + "' was denied since " + loginIpAddress.toString().replaceAll("/","")
-                            + " does not match " + accessAllowedCidrs);
+                    s_logger.warn("Request by account '" + account.toString() + "' was denied since " + loginIpAddress.toString().replaceAll("/", "") + " does not match " + accessAllowedCidrs);
                     throw new CloudAuthenticationException("Failed to authenticate user '" + username + "' in domain '" + domain.getPath() + "' from ip "
-                            + loginIpAddress.toString().replaceAll("/","") + "; please provide valid credentials");
+                            + loginIpAddress.toString().replaceAll("/", "") + "; please provide valid credentials");
                 }
             }
 
@@ -2234,8 +2315,7 @@ public UserAccount authenticateUser(final String username, final String password
                 s_logger.debug("User: " + username + " in domain " + domainId + " has successfully logged in");
             }
 
-            ActionEventUtils.onActionEvent(user.getId(), user.getAccountId(), user.getDomainId(), EventTypes.EVENT_USER_LOGIN,
-                    "user has logged in from IP Address " + loginIpAddress);
+            ActionEventUtils.onActionEvent(user.getId(), user.getAccountId(), user.getDomainId(), EventTypes.EVENT_USER_LOGIN, "user has logged in from IP Address " + loginIpAddress);
 
             return user;
         } else {
@@ -2285,12 +2365,12 @@ private UserAccount getUserAccount(String username, String password, Long domain
                 if (s_logger.isInfoEnabled()) {
                     s_logger.info("User " + username + " in domain " + domainName + " is disabled/locked (or account is disabled/locked)");
                 }
-                throw new CloudAuthenticationException(
-                        "User " + username + " (or their account) in domain " + domainName + " is disabled/locked. Please contact the administrator.");
+                throw new CloudAuthenticationException("User " + username + " (or their account) in domain " + domainName + " is disabled/locked. Please contact the administrator.");
             }
             // Whenever the user is able to log in successfully, reset the login attempts to zero
-            if (!isInternalAccount(userAccount.getId()))
+            if (!isInternalAccount(userAccount.getId())) {
                 updateLoginAttempts(userAccount.getId(), 0, false);
+            }
 
             return userAccount;
         } else {
@@ -2351,7 +2431,7 @@ private UserAccount getUserAccount(String username, String password, Long domain
     @DB
     @ActionEvent(eventType = EventTypes.EVENT_REGISTER_FOR_SECRET_API_KEY, eventDescription = "register for the developer API keys")
     public String[] createApiKeyAndSecretKey(RegisterCmd cmd) {
-        Account caller = CallContext.current().getCallingAccount();
+        Account caller = getCurrentCallingAccount();
         final Long userId = cmd.getId();
 
         User user = getUserIncludingRemoved(userId);
@@ -2668,8 +2748,9 @@ public UserAccount getUserByApiKey(String apiKey) {
 
     @Override
     public List<String> listAclGroupsByAccount(Long accountId) {
-        if (_querySelectors == null || _querySelectors.size() == 0)
+        if (_querySelectors == null || _querySelectors.size() == 0) {
             return new ArrayList<String>();
+        }
 
         QuerySelector qs = _querySelectors.get(0);
         return qs.listAclGroupsByAccount(accountId);
@@ -2692,8 +2773,7 @@ public Long finalyzeAccountId(final String accountName, final Long domainId, fin
                 if (!enabledOnly || account.getState() == Account.State.enabled) {
                     return account.getId();
                 } else {
-                    throw new PermissionDeniedException(
-                            "Can't add resources to the account id=" + account.getId() + " in state=" + account.getState() + " as it's no longer active");
+                    throw new PermissionDeniedException("Can't add resources to the account id=" + account.getId() + " in state=" + account.getState() + " as it's no longer active");
                 }
             } else {
                 // idList is not used anywhere, so removed it now
diff --git a/server/src/test/java/com/cloud/user/AccountManagerImplTest.java b/server/src/test/java/com/cloud/user/AccountManagerImplTest.java
index 9190cf83e63..fcb0c57278b 100644
--- a/server/src/test/java/com/cloud/user/AccountManagerImplTest.java
+++ b/server/src/test/java/com/cloud/user/AccountManagerImplTest.java
@@ -22,67 +22,100 @@
 import java.util.Arrays;
 import java.util.List;
 
-import com.cloud.acl.DomainChecker;
-import com.cloud.exception.PermissionDeniedException;
-import com.cloud.server.auth.UserAuthenticator;
-import com.cloud.utils.Pair;
-
+import org.apache.cloudstack.acl.ControlledEntity;
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
 import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd;
+import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd;
 import org.apache.cloudstack.context.CallContext;
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.apache.cloudstack.acl.ControlledEntity;
-import org.apache.cloudstack.acl.SecurityChecker.AccessType;
-import com.cloud.vm.snapshot.VMSnapshotVO;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import com.cloud.acl.DomainChecker;
 import com.cloud.domain.Domain;
 import com.cloud.domain.DomainVO;
 import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.PermissionDeniedException;
 import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.server.auth.UserAuthenticator;
+import com.cloud.server.auth.UserAuthenticator.ActionOnFailedAuthentication;
 import com.cloud.user.Account.State;
+import com.cloud.utils.Pair;
+import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.UserVmManagerImpl;
 import com.cloud.vm.UserVmVO;
 import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.snapshot.VMSnapshotVO;
 
-
+@RunWith(MockitoJUnitRunner.class)
 public class AccountManagerImplTest extends AccountManagetImplTestBase {
 
+    @Mock
+    private UserVmManagerImpl _vmMgr;
+    @Mock
+    private AccountVO callingAccount;
+    @Mock
+    private DomainChecker domainChecker;
+    @Mock
+    private AccountService accountService;
+    @Mock
+    private GetUserKeysCmd _listkeyscmd;
+    @Mock
+    private User _user;
+    @Mock
+    private UserAccountVO userAccountVO;
+
+    @Mock
+    private UpdateUserCmd UpdateUserCmdMock;
+
+    private long userVoIdMock = 111l;
+    @Mock
+    private UserVO userVoMock;
 
+    private long accountMockId = 100l;
     @Mock
-    UserVmManagerImpl _vmMgr;
+    private Account accountMock;
+
+    @Before
+    public void beforeTest() {
+        Mockito.doReturn(accountMockId).when(accountMock).getId();
+        Mockito.doReturn(accountMock).when(accountManagerImpl).getCurrentCallingAccount();
+
+        Mockito.doReturn(accountMockId).when(userVoMock).getAccountId();
+
+        Mockito.doReturn(userVoIdMock).when(userVoMock).getId();
+    }
 
     @Test
-    public void disableAccountNotexisting()
-            throws ConcurrentOperationException, ResourceUnavailableException {
-        Mockito.when(_accountDao.findById(42l)).thenReturn(null);
-        Assert.assertTrue(accountManager.disableAccount(42));
+    public void disableAccountNotexisting() throws ConcurrentOperationException, ResourceUnavailableException {
+        Mockito.when(accountDaoMock.findById(42l)).thenReturn(null);
+        Assert.assertTrue(accountManagerImpl.disableAccount(42));
     }
 
     @Test
-    public void disableAccountDisabled() throws ConcurrentOperationException,
-    ResourceUnavailableException {
+    public void disableAccountDisabled() throws ConcurrentOperationException, ResourceUnavailableException {
         AccountVO disabledAccount = new AccountVO();
         disabledAccount.setState(State.disabled);
-        Mockito.when(_accountDao.findById(42l)).thenReturn(disabledAccount);
-        Assert.assertTrue(accountManager.disableAccount(42));
+        Mockito.when(accountDaoMock.findById(42l)).thenReturn(disabledAccount);
+        Assert.assertTrue(accountManagerImpl.disableAccount(42));
     }
 
     @Test
-    public void disableAccount() throws ConcurrentOperationException,
-    ResourceUnavailableException {
+    public void disableAccount() throws ConcurrentOperationException, ResourceUnavailableException {
         AccountVO account = new AccountVO();
         account.setState(State.enabled);
-        Mockito.when(_accountDao.findById(42l)).thenReturn(account);
-        Mockito.when(_accountDao.createForUpdate()).thenReturn(new AccountVO());
-        Mockito.when(
-                _accountDao.update(Mockito.eq(42l),
-                        Mockito.any(AccountVO.class))).thenReturn(true);
-        Mockito.when(_vmDao.listByAccountId(42l)).thenReturn(
-                Arrays.asList(Mockito.mock(VMInstanceVO.class)));
-        Assert.assertTrue(accountManager.disableAccount(42));
-        Mockito.verify(_accountDao, Mockito.atLeastOnce()).update(
-                Mockito.eq(42l), Mockito.any(AccountVO.class));
+        Mockito.when(accountDaoMock.findById(42l)).thenReturn(account);
+        Mockito.when(accountDaoMock.createForUpdate()).thenReturn(new AccountVO());
+        Mockito.when(accountDaoMock.update(Mockito.eq(42l), Mockito.any(AccountVO.class))).thenReturn(true);
+        Mockito.when(_vmDao.listByAccountId(42l)).thenReturn(Arrays.asList(Mockito.mock(VMInstanceVO.class)));
+        Assert.assertTrue(accountManagerImpl.disableAccount(42));
+        Mockito.verify(accountDaoMock, Mockito.atLeastOnce()).update(Mockito.eq(42l), Mockito.any(AccountVO.class));
     }
 
     @Test
@@ -90,20 +123,12 @@ public void deleteUserAccount() {
         AccountVO account = new AccountVO();
         account.setId(42l);
         DomainVO domain = new DomainVO();
-        Mockito.when(_accountDao.findById(42l)).thenReturn(account);
-        Mockito.when(
-                securityChecker.checkAccess(Mockito.any(Account.class),
-                        Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class),
-                        Mockito.anyString()))
-        .thenReturn(true);
-        Mockito.when(_accountDao.remove(42l)).thenReturn(true);
-        Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l))
-        .thenReturn(true);
+        Mockito.when(accountDaoMock.findById(42l)).thenReturn(account);
+        Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class), Mockito.anyString())).thenReturn(true);
+        Mockito.when(accountDaoMock.remove(42l)).thenReturn(true);
+        Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l)).thenReturn(true);
         Mockito.when(_domainMgr.getDomain(Mockito.anyLong())).thenReturn(domain);
-        Mockito.when(
-                securityChecker.checkAccess(Mockito.any(Account.class),
-                        Mockito.any(Domain.class)))
-        .thenReturn(true);
+        Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(Domain.class))).thenReturn(true);
         Mockito.when(_vmSnapshotDao.listByAccountId(Mockito.anyLong())).thenReturn(new ArrayList<VMSnapshotVO>());
 
         List<SSHKeyPairVO> sshkeyList = new ArrayList<SSHKeyPairVO>();
@@ -113,10 +138,9 @@ public void deleteUserAccount() {
         Mockito.when(_sshKeyPairDao.listKeyPairs(Mockito.anyLong(), Mockito.anyLong())).thenReturn(sshkeyList);
         Mockito.when(_sshKeyPairDao.remove(Mockito.anyLong())).thenReturn(true);
 
-        Assert.assertTrue(accountManager.deleteUserAccount(42));
+        Assert.assertTrue(accountManagerImpl.deleteUserAccount(42));
         // assert that this was a clean delete
-        Mockito.verify(_accountDao, Mockito.never()).markForCleanup(
-                Mockito.eq(42l));
+        Mockito.verify(accountDaoMock, Mockito.never()).markForCleanup(Mockito.eq(42l));
     }
 
     @Test
@@ -124,33 +148,20 @@ public void deleteUserAccountCleanup() {
         AccountVO account = new AccountVO();
         account.setId(42l);
         DomainVO domain = new DomainVO();
-        Mockito.when(_accountDao.findById(42l)).thenReturn(account);
-        Mockito.when(
-                securityChecker.checkAccess(Mockito.any(Account.class),
-                        Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class),
-                        Mockito.anyString()))
-        .thenReturn(true);
-        Mockito.when(_accountDao.remove(42l)).thenReturn(true);
-        Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l))
-        .thenReturn(true);
-        Mockito.when(_userVmDao.listByAccountId(42l)).thenReturn(
-                Arrays.asList(Mockito.mock(UserVmVO.class)));
-        Mockito.when(
-                _vmMgr.expunge(Mockito.any(UserVmVO.class), Mockito.anyLong(),
-                        Mockito.any(Account.class))).thenReturn(false);
+        Mockito.when(accountDaoMock.findById(42l)).thenReturn(account);
+        Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class), Mockito.anyString())).thenReturn(true);
+        Mockito.when(accountDaoMock.remove(42l)).thenReturn(true);
+        Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l)).thenReturn(true);
+        Mockito.when(_userVmDao.listByAccountId(42l)).thenReturn(Arrays.asList(Mockito.mock(UserVmVO.class)));
+        Mockito.when(_vmMgr.expunge(Mockito.any(UserVmVO.class), Mockito.anyLong(), Mockito.any(Account.class))).thenReturn(false);
         Mockito.when(_domainMgr.getDomain(Mockito.anyLong())).thenReturn(domain);
-        Mockito.when(
-                securityChecker.checkAccess(Mockito.any(Account.class),
-                        Mockito.any(Domain.class)))
-        .thenReturn(true);
+        Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(Domain.class))).thenReturn(true);
 
-        Assert.assertTrue(accountManager.deleteUserAccount(42));
+        Assert.assertTrue(accountManagerImpl.deleteUserAccount(42));
         // assert that this was NOT a clean delete
-        Mockito.verify(_accountDao, Mockito.atLeastOnce()).markForCleanup(
-                Mockito.eq(42l));
+        Mockito.verify(accountDaoMock, Mockito.atLeastOnce()).markForCleanup(Mockito.eq(42l));
     }
 
-
     @Test
     public void testAuthenticateUser() throws UnknownHostException {
         Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> successAuthenticationPair = new Pair<>(true, null);
@@ -160,21 +171,21 @@ public void testAuthenticateUser() throws UnknownHostException {
         UserAccountVO userAccountVO = new UserAccountVO();
         userAccountVO.setSource(User.Source.UNKNOWN);
         userAccountVO.setState(Account.State.disabled.toString());
-        Mockito.when(_userAccountDao.getUserAccount("test", 1L)).thenReturn(userAccountVO);
+        Mockito.when(userAccountDaoMock.getUserAccount("test", 1L)).thenReturn(userAccountVO);
         Mockito.when(userAuthenticator.authenticate("test", "fail", 1L, null)).thenReturn(failureAuthenticationPair);
         Mockito.when(userAuthenticator.authenticate("test", null, 1L, null)).thenReturn(successAuthenticationPair);
         Mockito.when(userAuthenticator.authenticate("test", "", 1L, null)).thenReturn(successAuthenticationPair);
 
         //Test for incorrect password. authentication should fail
-        UserAccount userAccount = accountManager.authenticateUser("test", "fail", 1L, InetAddress.getByName("127.0.0.1"), null);
+        UserAccount userAccount = accountManagerImpl.authenticateUser("test", "fail", 1L, InetAddress.getByName("127.0.0.1"), null);
         Assert.assertNull(userAccount);
 
         //Test for null password. authentication should fail
-        userAccount = accountManager.authenticateUser("test", null, 1L, InetAddress.getByName("127.0.0.1"), null);
+        userAccount = accountManagerImpl.authenticateUser("test", null, 1L, InetAddress.getByName("127.0.0.1"), null);
         Assert.assertNull(userAccount);
 
         //Test for empty password. authentication should fail
-        userAccount = accountManager.authenticateUser("test", "", 1L, InetAddress.getByName("127.0.0.1"), null);
+        userAccount = accountManagerImpl.authenticateUser("test", "", 1L, InetAddress.getByName("127.0.0.1"), null);
         Assert.assertNull(userAccount);
 
         //Verifying that the authentication method is only called when password is specified
@@ -183,38 +194,509 @@ public void testAuthenticateUser() throws UnknownHostException {
         Mockito.verify(userAuthenticator, Mockito.never()).authenticate("test", "", 1L, null);
     }
 
-    @Mock
-    AccountVO callingAccount;
-    @Mock
-    DomainChecker domainChecker;
-    @Mock
-    AccountService accountService;
-    @Mock
-    private GetUserKeysCmd _listkeyscmd;
-    @Mock
-    private Account _account;
-    @Mock
-    private User _user;
-    @Mock
-    private UserAccountVO userAccountVO;
-
-
-    @Test (expected = PermissionDeniedException.class)
-    public void testgetUserCmd(){
+    @Test(expected = PermissionDeniedException.class)
+    public void testgetUserCmd() {
         CallContext.register(callingUser, callingAccount); // Calling account is user account i.e normal account
         Mockito.when(_listkeyscmd.getID()).thenReturn(1L);
-        Mockito.when(accountManager.getActiveUser(1L)).thenReturn(_user);
-        Mockito.when(accountManager.getUserAccountById(1L)).thenReturn(userAccountVO);
+        Mockito.when(accountManagerImpl.getActiveUser(1L)).thenReturn(_user);
+        Mockito.when(accountManagerImpl.getUserAccountById(1L)).thenReturn(userAccountVO);
         Mockito.when(userAccountVO.getAccountId()).thenReturn(1L);
-        Mockito.when(accountManager.getAccount(Mockito.anyLong())).thenReturn(_account); // Queried account - admin account
+        Mockito.when(accountManagerImpl.getAccount(Mockito.anyLong())).thenReturn(accountMock); // Queried account - admin account
 
         Mockito.when(callingUser.getAccountId()).thenReturn(1L);
-        Mockito.when(_accountDao.findById(1L)).thenReturn(callingAccount);
+        Mockito.when(accountDaoMock.findById(1L)).thenReturn(callingAccount);
 
         Mockito.when(accountService.isNormalUser(Mockito.anyLong())).thenReturn(Boolean.TRUE);
-        Mockito.when(_account.getAccountId()).thenReturn(2L);
+        Mockito.when(accountMock.getAccountId()).thenReturn(2L);
+
+        accountManagerImpl.getKeys(_listkeyscmd);
+    }
+
+    @Test
+    public void updateUserTestTimeZoneAndEmailNull() {
+        prepareMockAndExecuteUpdateUserTest(0);
+    }
+
+    @Test
+    public void updateUserTestTimeZoneAndEmailNotNull() {
+        Mockito.when(UpdateUserCmdMock.getEmail()).thenReturn("email");
+        Mockito.when(UpdateUserCmdMock.getTimezone()).thenReturn("timezone");
+        prepareMockAndExecuteUpdateUserTest(1);
+    }
+
+    private void prepareMockAndExecuteUpdateUserTest(int numberOfExpectedCallsForSetEmailAndSetTimeZone) {
+        Mockito.doReturn(userVoMock).when(accountManagerImpl).retrieveAndValidateUser(UpdateUserCmdMock);
+        Mockito.doNothing().when(accountManagerImpl).validateAndUpdatApiAndSecretKeyIfNeeded(UpdateUserCmdMock, userVoMock);
+        Mockito.doReturn(accountMock).when(accountManagerImpl).retrieveAndValidateAccount(userVoMock);
+
+        Mockito.doNothing().when(accountManagerImpl).validateAndUpdateFirstNameIfNeeded(UpdateUserCmdMock, userVoMock);
+        Mockito.doNothing().when(accountManagerImpl).validateAndUpdateLastNameIfNeeded(UpdateUserCmdMock, userVoMock);
+        Mockito.doNothing().when(accountManagerImpl).validateAndUpdateUsernameIfNeeded(UpdateUserCmdMock, userVoMock, accountMock);
+        Mockito.doNothing().when(accountManagerImpl).validateUserPasswordAndUpdateIfNeeded(Mockito.anyString(), Mockito.eq(userVoMock), Mockito.anyString());
+
+        Mockito.doReturn(true).when(userDaoMock).update(Mockito.anyLong(), Mockito.eq(userVoMock));
+        Mockito.doReturn(Mockito.mock(UserAccountVO.class)).when(userAccountDaoMock).findById(Mockito.anyLong());
+
+        accountManagerImpl.updateUser(UpdateUserCmdMock);
+
+        InOrder inOrder = Mockito.inOrder(userVoMock, accountManagerImpl, userDaoMock, userAccountDaoMock);
+
+        inOrder.verify(accountManagerImpl).retrieveAndValidateUser(UpdateUserCmdMock);
+        inOrder.verify(accountManagerImpl).validateAndUpdatApiAndSecretKeyIfNeeded(UpdateUserCmdMock, userVoMock);
+        inOrder.verify(accountManagerImpl).retrieveAndValidateAccount(userVoMock);
+
+        inOrder.verify(accountManagerImpl).validateAndUpdateFirstNameIfNeeded(UpdateUserCmdMock, userVoMock);
+        inOrder.verify(accountManagerImpl).validateAndUpdateLastNameIfNeeded(UpdateUserCmdMock, userVoMock);
+        inOrder.verify(accountManagerImpl).validateAndUpdateUsernameIfNeeded(UpdateUserCmdMock, userVoMock, accountMock);
+        inOrder.verify(accountManagerImpl).validateUserPasswordAndUpdateIfNeeded(Mockito.anyString(), Mockito.eq(userVoMock), Mockito.anyString());
+
+        inOrder.verify(userVoMock, Mockito.times(numberOfExpectedCallsForSetEmailAndSetTimeZone)).setEmail(Mockito.anyString());
+        inOrder.verify(userVoMock, Mockito.times(numberOfExpectedCallsForSetEmailAndSetTimeZone)).setTimezone(Mockito.anyString());
+
+        inOrder.verify(userDaoMock).update(Mockito.anyLong(), Mockito.eq(userVoMock));
+        inOrder.verify(userAccountDaoMock).findById(Mockito.anyLong());
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void retrieveAndValidateUserTestNoUserFound() {
+        Mockito.doReturn(null).when(userDaoMock).getUser(Mockito.anyLong());
+
+        accountManagerImpl.retrieveAndValidateUser(UpdateUserCmdMock);
+    }
+
+    @Test
+    public void retrieveAndValidateUserTestUserIsFound() {
+        Mockito.doReturn(userVoMock).when(userDaoMock).getUser(Mockito.anyLong());
+
+        UserVO receivedUser = accountManagerImpl.retrieveAndValidateUser(UpdateUserCmdMock);
+
+        Assert.assertEquals(userVoMock, receivedUser);
+    }
+
+    @Test
+    public void validateAndUpdatApiAndSecretKeyIfNeededTestNoKeys() {
+        accountManagerImpl.validateAndUpdatApiAndSecretKeyIfNeeded(UpdateUserCmdMock, userVoMock);
+
+        Mockito.verify(accountDaoMock, Mockito.times(0)).findUserAccountByApiKey(Mockito.anyString());
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void validateAndUpdatApiAndSecretKeyIfNeededTestOnlyApiKeyInformed() {
+        Mockito.doReturn("apiKey").when(UpdateUserCmdMock).getApiKey();
+
+        accountManagerImpl.validateAndUpdatApiAndSecretKeyIfNeeded(UpdateUserCmdMock, userVoMock);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void validateAndUpdatApiAndSecretKeyIfNeededTestOnlySecretKeyInformed() {
+        Mockito.doReturn("secretKey").when(UpdateUserCmdMock).getSecretKey();
+
+        accountManagerImpl.validateAndUpdatApiAndSecretKeyIfNeeded(UpdateUserCmdMock, userVoMock);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void validateAndUpdatApiAndSecretKeyIfNeededTestApiKeyAlreadyUsedBySomeoneElse() {
+        String apiKey = "apiKey";
+        Mockito.doReturn(apiKey).when(UpdateUserCmdMock).getApiKey();
+        Mockito.doReturn("secretKey").when(UpdateUserCmdMock).getSecretKey();
+
+        Mockito.doReturn(1L).when(userVoMock).getId();
+
+        User otherUserMock = Mockito.mock(User.class);
+        Mockito.doReturn(2L).when(otherUserMock).getId();
+
+        Pair<User, Account> pairUserAccountMock = new Pair<User, Account>(otherUserMock, Mockito.mock(Account.class));
+        Mockito.doReturn(pairUserAccountMock).when(accountDaoMock).findUserAccountByApiKey(apiKey);
+
+        accountManagerImpl.validateAndUpdatApiAndSecretKeyIfNeeded(UpdateUserCmdMock, userVoMock);
+    }
+
+    @Test
+    public void validateAndUpdatApiAndSecretKeyIfNeededTest() {
+        String apiKey = "apiKey";
+        Mockito.doReturn(apiKey).when(UpdateUserCmdMock).getApiKey();
+
+        String secretKey = "secretKey";
+        Mockito.doReturn(secretKey).when(UpdateUserCmdMock).getSecretKey();
+
+        Mockito.doReturn(1L).when(userVoMock).getId();
+
+        User otherUserMock = Mockito.mock(User.class);
+        Mockito.doReturn(1L).when(otherUserMock).getId();
+
+        Pair<User, Account> pairUserAccountMock = new Pair<User, Account>(otherUserMock, Mockito.mock(Account.class));
+        Mockito.doReturn(pairUserAccountMock).when(accountDaoMock).findUserAccountByApiKey(apiKey);
+
+        accountManagerImpl.validateAndUpdatApiAndSecretKeyIfNeeded(UpdateUserCmdMock, userVoMock);
+
+        Mockito.verify(accountDaoMock).findUserAccountByApiKey(apiKey);
+        Mockito.verify(userVoMock).setApiKey(apiKey);
+        Mockito.verify(userVoMock).setSecretKey(secretKey);
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void retrieveAndValidateAccountTestAccountNotFound() {
+        Mockito.doReturn(accountMockId).when(userVoMock).getAccountId();
+
+        Mockito.doReturn(null).when(accountDaoMock).findById(accountMockId);
+
+        accountManagerImpl.retrieveAndValidateAccount(userVoMock);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void retrieveAndValidateAccountTestAccountTypeEqualsProjectType() {
+        Mockito.doReturn(accountMockId).when(userVoMock).getAccountId();
+        Mockito.doReturn(Account.ACCOUNT_TYPE_PROJECT).when(accountMock).getType();
+        Mockito.doReturn(accountMock).when(accountDaoMock).findById(accountMockId);
+
+        accountManagerImpl.retrieveAndValidateAccount(userVoMock);
+    }
+
+    @Test(expected = PermissionDeniedException.class)
+    public void retrieveAndValidateAccountTestAccountTypeEqualsSystemType() {
+        Mockito.doReturn(Account.ACCOUNT_ID_SYSTEM).when(userVoMock).getAccountId();
+        Mockito.doReturn(Account.ACCOUNT_ID_SYSTEM).when(accountMock).getId();
+        Mockito.doReturn(accountMock).when(accountDaoMock).findById(Account.ACCOUNT_ID_SYSTEM);
+
+        accountManagerImpl.retrieveAndValidateAccount(userVoMock);
+    }
+
+    @Test
+    public void retrieveAndValidateAccountTest() {
+        Mockito.doReturn(accountMockId).when(userVoMock).getAccountId();
+        Mockito.doReturn(accountMock).when(accountDaoMock).findById(accountMockId);
+
+        Mockito.doNothing().when(accountManagerImpl).checkAccess(Mockito.eq(accountMock), Mockito.eq(AccessType.OperateEntry), Mockito.anyBoolean(), Mockito.any(Account.class));
+        accountManagerImpl.retrieveAndValidateAccount(userVoMock);
+
+        Mockito.verify(accountManagerImpl).getCurrentCallingAccount();
+        Mockito.verify(accountManagerImpl).checkAccess(Mockito.eq(accountMock), Mockito.eq(AccessType.OperateEntry), Mockito.anyBoolean(), Mockito.any(Account.class));
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void validateAndUpdateFirstNameIfNeededTestFirstNameBlank() {
+        Mockito.doReturn("   ").when(UpdateUserCmdMock).getFirstname();
+
+        accountManagerImpl.validateAndUpdateFirstNameIfNeeded(UpdateUserCmdMock, userVoMock);
+    }
+
+    @Test
+    public void validateAndUpdateFirstNameIfNeededTestFirstNameNull() {
+        Mockito.doReturn(null).when(UpdateUserCmdMock).getFirstname();
+
+        accountManagerImpl.validateAndUpdateFirstNameIfNeeded(UpdateUserCmdMock, userVoMock);
+
+        Mockito.verify(userVoMock, Mockito.times(0)).setFirstname(Mockito.anyString());
+    }
 
-        accountManager.getKeys(_listkeyscmd);
+    @Test
+    public void validateAndUpdateFirstNameIfNeededTest() {
+        String firstname = "firstName";
+        Mockito.doReturn(firstname).when(UpdateUserCmdMock).getFirstname();
+
+        accountManagerImpl.validateAndUpdateFirstNameIfNeeded(UpdateUserCmdMock, userVoMock);
+
+        Mockito.verify(userVoMock).setFirstname(firstname);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void validateAndUpdateLastNameIfNeededTestLastNameBlank() {
+        Mockito.doReturn("   ").when(UpdateUserCmdMock).getLastname();
+
+        accountManagerImpl.validateAndUpdateLastNameIfNeeded(UpdateUserCmdMock, userVoMock);
+    }
+
+    @Test
+    public void validateAndUpdateLastNameIfNeededTestLastNameNull() {
+        Mockito.doReturn(null).when(UpdateUserCmdMock).getLastname();
+
+        accountManagerImpl.validateAndUpdateLastNameIfNeeded(UpdateUserCmdMock, userVoMock);
+
+        Mockito.verify(userVoMock, Mockito.times(0)).setLastname(Mockito.anyString());
+    }
+
+    @Test
+    public void validateAndUpdateLastNameIfNeededTest() {
+        String lastName = "lastName";
+        Mockito.doReturn(lastName).when(UpdateUserCmdMock).getLastname();
+
+        accountManagerImpl.validateAndUpdateLastNameIfNeeded(UpdateUserCmdMock, userVoMock);
+
+        Mockito.verify(userVoMock).setLastname(lastName);
+    }
+
+    @Test
+    public void validateAndUpdateUsernameIfNeededTestNullUsername() {
+        Mockito.doReturn(null).when(UpdateUserCmdMock).getUsername();
+
+        accountManagerImpl.validateAndUpdateUsernameIfNeeded(UpdateUserCmdMock, userVoMock, accountMock);
+
+        Mockito.verify(userVoMock, Mockito.times(0)).setUsername(Mockito.anyString());
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void validateAndUpdateUsernameIfNeededTestBlankUsername() {
+        Mockito.doReturn("   ").when(UpdateUserCmdMock).getUsername();
+
+        accountManagerImpl.validateAndUpdateUsernameIfNeeded(UpdateUserCmdMock, userVoMock, accountMock);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void validateAndUpdateUsernameIfNeededTestDuplicatedUserSameDomainThisUser() {
+        long domanIdCurrentUser = 22l;
+
+        String userName = "username";
+        Mockito.doReturn(userName).when(UpdateUserCmdMock).getUsername();
+        Mockito.doReturn(userName).when(userVoMock).getUsername();
+        Mockito.doReturn(domanIdCurrentUser).when(accountMock).getDomainId();
+
+        long userVoDuplicatedMockId = 67l;
+        UserVO userVoDuplicatedMock = Mockito.mock(UserVO.class);
+        Mockito.doReturn(userName).when(userVoDuplicatedMock).getUsername();
+        Mockito.doReturn(userVoDuplicatedMockId).when(userVoDuplicatedMock).getId();
+
+        long accountIdUserDuplicated = 98l;
+        Mockito.doReturn(accountIdUserDuplicated).when(userVoDuplicatedMock).getAccountId();
+
+        Account accountUserDuplicatedMock = Mockito.mock(Account.class);
+        Mockito.doReturn(accountIdUserDuplicated).when(accountUserDuplicatedMock).getId();
+        Mockito.doReturn(domanIdCurrentUser).when(accountUserDuplicatedMock).getDomainId();
+
+        List<UserVO> usersWithSameUserName = new ArrayList<>();
+        usersWithSameUserName.add(userVoMock);
+        usersWithSameUserName.add(userVoDuplicatedMock);
+
+        Mockito.doReturn(usersWithSameUserName).when(userDaoMock).findUsersByName(userName);
+
+        Mockito.doReturn(accountMock).when(accountDaoMock).findById(accountMockId);
+        Mockito.doReturn(accountUserDuplicatedMock).when(accountDaoMock).findById(accountIdUserDuplicated);
+
+        Mockito.doReturn(Mockito.mock(DomainVO.class)).when(_domainDao).findById(Mockito.anyLong());
+
+        accountManagerImpl.validateAndUpdateUsernameIfNeeded(UpdateUserCmdMock, userVoMock, accountMock);
+    }
+
+    @Test
+    public void validateAndUpdateUsernameIfNeededTestDuplicatedUserButInDifferentDomains() {
+        long domanIdCurrentUser = 22l;
+
+        String userName = "username";
+        Mockito.doReturn(userName).when(UpdateUserCmdMock).getUsername();
+        Mockito.doReturn(userName).when(userVoMock).getUsername();
+        Mockito.doReturn(domanIdCurrentUser).when(accountMock).getDomainId();
+
+        long userVoDuplicatedMockId = 67l;
+        UserVO userVoDuplicatedMock = Mockito.mock(UserVO.class);
+        Mockito.doReturn(userName).when(userVoDuplicatedMock).getUsername();
+        Mockito.doReturn(userVoDuplicatedMockId).when(userVoDuplicatedMock).getId();
+
+        long accountIdUserDuplicated = 98l;
+        Mockito.doReturn(accountIdUserDuplicated).when(userVoDuplicatedMock).getAccountId();
+
+        Account accountUserDuplicatedMock = Mockito.mock(Account.class);
+        Mockito.doReturn(accountIdUserDuplicated).when(accountUserDuplicatedMock).getId();
+        Mockito.doReturn(45l).when(accountUserDuplicatedMock).getDomainId();
+
+        List<UserVO> usersWithSameUserName = new ArrayList<>();
+        usersWithSameUserName.add(userVoMock);
+        usersWithSameUserName.add(userVoDuplicatedMock);
+
+        Mockito.doReturn(usersWithSameUserName).when(userDaoMock).findUsersByName(userName);
+
+        Mockito.doReturn(accountMock).when(accountDaoMock).findById(accountMockId);
+        Mockito.doReturn(accountUserDuplicatedMock).when(accountDaoMock).findById(accountIdUserDuplicated);
+
+        accountManagerImpl.validateAndUpdateUsernameIfNeeded(UpdateUserCmdMock, userVoMock, accountMock);
+
+        Mockito.verify(userVoMock).setUsername(userName);
+    }
+
+    @Test
+    public void validateAndUpdateUsernameIfNeededTestNoDuplicatedUserNames() {
+        long domanIdCurrentUser = 22l;
+
+        String userName = "username";
+        Mockito.doReturn(userName).when(UpdateUserCmdMock).getUsername();
+        Mockito.doReturn(userName).when(userVoMock).getUsername();
+        Mockito.doReturn(domanIdCurrentUser).when(accountMock).getDomainId();
+
+        List<UserVO> usersWithSameUserName = new ArrayList<>();
+
+        Mockito.doReturn(usersWithSameUserName).when(userDaoMock).findUsersByName(userName);
+
+        Mockito.doReturn(accountMock).when(accountDaoMock).findById(accountMockId);
+
+        accountManagerImpl.validateAndUpdateUsernameIfNeeded(UpdateUserCmdMock, userVoMock, accountMock);
+
+        Mockito.verify(userVoMock).setUsername(userName);
+    }
+
+    @Test
+    public void valiateUserPasswordAndUpdateIfNeededTestPasswordNull() {
+        accountManagerImpl.validateUserPasswordAndUpdateIfNeeded(null, userVoMock, null);
+
+        Mockito.verify(userVoMock, Mockito.times(0)).setPassword(Mockito.anyString());
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void valiateUserPasswordAndUpdateIfNeededTestBlankPassword() {
+        accountManagerImpl.validateUserPasswordAndUpdateIfNeeded("       ", userVoMock, null);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void valiateUserPasswordAndUpdateIfNeededTestNoAdminAndNoCurrentPasswordProvided() {
+        Mockito.doReturn(accountMock).when(accountManagerImpl).getCurrentCallingAccount();
+        Mockito.doReturn(false).when(accountManagerImpl).isRootAdmin(accountMockId);
+        Mockito.doReturn(false).when(accountManagerImpl).isDomainAdmin(accountMockId);
+        Mockito.doReturn(true).when(accountManagerImpl).isResourceDomainAdmin(accountMockId);
+
+        accountManagerImpl.validateUserPasswordAndUpdateIfNeeded("newPassword", userVoMock, "  ");
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void valiateUserPasswordAndUpdateIfNeededTestNoUserAuthenticatorsConfigured() {
+        Mockito.doReturn(accountMock).when(accountManagerImpl).getCurrentCallingAccount();
+        Mockito.doReturn(true).when(accountManagerImpl).isRootAdmin(accountMockId);
+        Mockito.doReturn(false).when(accountManagerImpl).isDomainAdmin(accountMockId);
+
+        Mockito.doNothing().when(accountManagerImpl).validateCurrentPassword(Mockito.eq(userVoMock), Mockito.anyString());
+
+        accountManagerImpl.validateUserPasswordAndUpdateIfNeeded("newPassword", userVoMock, null);
+    }
+
+    @Test
+    public void validateUserPasswordAndUpdateIfNeededTestRootAdminUpdatingUserPassword() {
+        Mockito.doReturn(accountMock).when(accountManagerImpl).getCurrentCallingAccount();
+        Mockito.doReturn(true).when(accountManagerImpl).isRootAdmin(accountMockId);
+        Mockito.doReturn(false).when(accountManagerImpl).isDomainAdmin(accountMockId);
+
+        String newPassword = "newPassword";
+
+        String expectedUserPasswordAfterEncoded = configureUserMockAuthenticators(newPassword);
+
+        Mockito.doNothing().when(accountManagerImpl).validateCurrentPassword(Mockito.eq(userVoMock), Mockito.anyString());
+
+        accountManagerImpl.validateUserPasswordAndUpdateIfNeeded(newPassword, userVoMock, null);
+
+        Mockito.verify(accountManagerImpl, Mockito.times(0)).validateCurrentPassword(Mockito.eq(userVoMock), Mockito.anyString());
+        Mockito.verify(userVoMock, Mockito.times(1)).setPassword(expectedUserPasswordAfterEncoded);
+    }
+
+    @Test
+    public void validateUserPasswordAndUpdateIfNeededTestDomainAdminUpdatingUserPassword() {
+        Mockito.doReturn(accountMock).when(accountManagerImpl).getCurrentCallingAccount();
+        Mockito.doReturn(false).when(accountManagerImpl).isRootAdmin(accountMockId);
+        Mockito.doReturn(true).when(accountManagerImpl).isDomainAdmin(accountMockId);
+
+        String newPassword = "newPassword";
+
+        String expectedUserPasswordAfterEncoded = configureUserMockAuthenticators(newPassword);
+
+        Mockito.doNothing().when(accountManagerImpl).validateCurrentPassword(Mockito.eq(userVoMock), Mockito.anyString());
+
+        accountManagerImpl.validateUserPasswordAndUpdateIfNeeded(newPassword, userVoMock, null);
+
+        Mockito.verify(accountManagerImpl, Mockito.times(0)).validateCurrentPassword(Mockito.eq(userVoMock), Mockito.anyString());
+        Mockito.verify(userVoMock, Mockito.times(1)).setPassword(expectedUserPasswordAfterEncoded);
+    }
+
+    @Test
+    public void validateUserPasswordAndUpdateIfNeededTestUserUpdatingHisPassword() {
+        Mockito.doReturn(accountMock).when(accountManagerImpl).getCurrentCallingAccount();
+        Mockito.doReturn(false).when(accountManagerImpl).isRootAdmin(accountMockId);
+        Mockito.doReturn(false).when(accountManagerImpl).isDomainAdmin(accountMockId);
+
+        String newPassword = "newPassword";
+        String expectedUserPasswordAfterEncoded = configureUserMockAuthenticators(newPassword);
+
+        Mockito.doNothing().when(accountManagerImpl).validateCurrentPassword(Mockito.eq(userVoMock), Mockito.anyString());
+
+        String currentPassword = "theCurrentPassword";
+        accountManagerImpl.validateUserPasswordAndUpdateIfNeeded(newPassword, userVoMock, currentPassword);
+
+        Mockito.verify(accountManagerImpl, Mockito.times(1)).validateCurrentPassword(userVoMock, currentPassword);
+        Mockito.verify(userVoMock, Mockito.times(1)).setPassword(expectedUserPasswordAfterEncoded);
+    }
+
+    private String configureUserMockAuthenticators(String newPassword) {
+        accountManagerImpl._userPasswordEncoders = new ArrayList<>();
+        UserAuthenticator authenticatorMock1 = Mockito.mock(UserAuthenticator.class);
+        String expectedUserPasswordAfterEncoded = "passwordEncodedByAuthenticator1";
+        Mockito.doReturn(expectedUserPasswordAfterEncoded).when(authenticatorMock1).encode(newPassword);
+
+        UserAuthenticator authenticatorMock2 = Mockito.mock(UserAuthenticator.class);
+        Mockito.doReturn("passwordEncodedByAuthenticator2").when(authenticatorMock2).encode(newPassword);
+
+        accountManagerImpl._userPasswordEncoders.add(authenticatorMock1);
+        accountManagerImpl._userPasswordEncoders.add(authenticatorMock2);
+        return expectedUserPasswordAfterEncoded;
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void validateCurrentPasswordTestUserNotAuthenticatedWithProvidedCurrentPassword() {
+        Mockito.doReturn(Mockito.mock(AccountVO.class)).when(accountDaoMock).findById(accountMockId);
+        String newPassword = "newPassword";
+        configureUserMockAuthenticators(newPassword);
+
+        accountManagerImpl.validateCurrentPassword(userVoMock, "currentPassword");
+    }
+
+    @Test
+    public void validateCurrentPasswordTestUserAuthenticatedWithProvidedCurrentPasswordViaFirstAuthenticator() {
+        AccountVO accountVoMock = Mockito.mock(AccountVO.class);
+        long domainId = 14l;
+        Mockito.doReturn(domainId).when(accountVoMock).getDomainId();
+
+        Mockito.doReturn(accountVoMock).when(accountDaoMock).findById(accountMockId);
+        String username = "username";
+        Mockito.doReturn(username).when(userVoMock).getUsername();
+
+        accountManagerImpl._userPasswordEncoders = new ArrayList<>();
+        UserAuthenticator authenticatorMock1 = Mockito.mock(UserAuthenticator.class);
+        UserAuthenticator authenticatorMock2 = Mockito.mock(UserAuthenticator.class);
+
+        accountManagerImpl._userPasswordEncoders.add(authenticatorMock1);
+        accountManagerImpl._userPasswordEncoders.add(authenticatorMock2);
+
+        Pair<Boolean, ActionOnFailedAuthentication> authenticationResult = new Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication>(true,
+                UserAuthenticator.ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
+
+        String currentPassword = "currentPassword";
+        Mockito.doReturn(authenticationResult).when(authenticatorMock1).authenticate(username, currentPassword, domainId, null);
+
+        accountManagerImpl.validateCurrentPassword(userVoMock, currentPassword);
+
+        Mockito.verify(authenticatorMock1, Mockito.times(1)).authenticate(username, currentPassword, domainId, null);
+        Mockito.verify(authenticatorMock2, Mockito.times(0)).authenticate(username, currentPassword, domainId, null);
+    }
+
+    @Test
+    public void validateCurrentPasswordTestUserAuthenticatedWithProvidedCurrentPasswordViaSecondAuthenticator() {
+        AccountVO accountVoMock = Mockito.mock(AccountVO.class);
+        long domainId = 14l;
+        Mockito.doReturn(domainId).when(accountVoMock).getDomainId();
+
+        Mockito.doReturn(accountVoMock).when(accountDaoMock).findById(accountMockId);
+        String username = "username";
+        Mockito.doReturn(username).when(userVoMock).getUsername();
+
+        accountManagerImpl._userPasswordEncoders = new ArrayList<>();
+        UserAuthenticator authenticatorMock1 = Mockito.mock(UserAuthenticator.class);
+        UserAuthenticator authenticatorMock2 = Mockito.mock(UserAuthenticator.class);
+
+        accountManagerImpl._userPasswordEncoders.add(authenticatorMock1);
+        accountManagerImpl._userPasswordEncoders.add(authenticatorMock2);
+
+        Pair<Boolean, ActionOnFailedAuthentication> authenticationResult = new Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication>(true,
+                UserAuthenticator.ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
+
+        String currentPassword = "currentPassword";
+        Mockito.doReturn(authenticationResult).when(authenticatorMock2).authenticate(username, currentPassword, domainId, null);
+
+        accountManagerImpl.validateCurrentPassword(userVoMock, currentPassword);
+
+        Mockito.verify(authenticatorMock1, Mockito.times(1)).authenticate(username, currentPassword, domainId, null);
+        Mockito.verify(authenticatorMock2, Mockito.times(1)).authenticate(username, currentPassword, domainId, null);
+    }
 
-        }
 }
diff --git a/server/src/test/java/com/cloud/user/AccountManagerImplVolumeDeleteEventTest.java b/server/src/test/java/com/cloud/user/AccountManagerImplVolumeDeleteEventTest.java
index 239771361f7..48eb4738fef 100644
--- a/server/src/test/java/com/cloud/user/AccountManagerImplVolumeDeleteEventTest.java
+++ b/server/src/test/java/com/cloud/user/AccountManagerImplVolumeDeleteEventTest.java
@@ -16,12 +16,12 @@
 // under the License.
 package com.cloud.user;
 
-import static org.mockito.Mockito.when;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyLong;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.when;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
@@ -52,13 +52,12 @@
 import com.cloud.exception.CloudException;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.service.ServiceOfferingVO;
-import com.cloud.storage.VolumeVO;
 import com.cloud.storage.Volume.Type;
+import com.cloud.storage.VolumeVO;
 import com.cloud.vm.UserVmManagerImpl;
 import com.cloud.vm.UserVmVO;
 import com.cloud.vm.VirtualMachine;
 
-
 public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplTestBase {
 
     private static final Long ACCOUNT_ID = 1l;
@@ -70,12 +69,10 @@
     Map<String, Object> oldFields = new HashMap<>();
     UserVmVO vm = mock(UserVmVO.class);
 
-
     // Configures the static fields of the UsageEventUtils class, Storing the
     // previous values to be restored during the cleanup phase, to avoid
     // interference with other unit tests.
-    protected UsageEventUtils setupUsageUtils() throws NoSuchMethodException, SecurityException, IllegalAccessException,
-    IllegalArgumentException, InvocationTargetException {
+    protected UsageEventUtils setupUsageUtils() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
 
         _usageEventDao = new MockUsageEventDao();
         UsageEventUtils utils = new UsageEventUtils();
@@ -93,8 +90,7 @@ protected UsageEventUtils setupUsageUtils() throws NoSuchMethodException, Securi
                 Field staticField = UsageEventUtils.class.getDeclaredField("s_" + fieldName);
                 staticField.setAccessible(true);
                 oldFields.put(f.getName(), staticField.get(null));
-                f.set(utils,
-                        this.getClass().getSuperclass().getDeclaredField("_" + fieldName).get(this));
+                f.set(utils, this.getClass().getSuperclass().getDeclaredField("_" + fieldName).get(this));
             } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
                 e.printStackTrace();
             }
@@ -106,14 +102,12 @@ protected UsageEventUtils setupUsageUtils() throws NoSuchMethodException, Securi
         return utils;
     }
 
-
-    protected void defineMocksBehavior()
-            throws AgentUnavailableException, ConcurrentOperationException, CloudException {
+    protected void defineMocksBehavior() throws AgentUnavailableException, ConcurrentOperationException, CloudException {
 
         AccountVO account = new AccountVO();
         account.setId(ACCOUNT_ID);
-        when(_accountDao.remove(ACCOUNT_ID)).thenReturn(true);
-        when(_accountDao.findById(ACCOUNT_ID)).thenReturn(account);
+        when(accountDaoMock.remove(ACCOUNT_ID)).thenReturn(true);
+        when(accountDaoMock.findById(ACCOUNT_ID)).thenReturn(account);
 
         DomainVO domain = new DomainVO();
         VirtualMachineEntity vmEntity = mock(VirtualMachineEntity.class);
@@ -128,8 +122,7 @@ protected void defineMocksBehavior()
         List<VolumeVO> volumes = new ArrayList<>();
         volumes.add(vol);
 
-        when(securityChecker.checkAccess(any(Account.class), any(ControlledEntity.class), any(AccessType.class),
-                anyString())).thenReturn(true);
+        when(securityChecker.checkAccess(any(Account.class), any(ControlledEntity.class), any(AccessType.class), anyString())).thenReturn(true);
 
         when(_userVmDao.findById(anyLong())).thenReturn(vm);
         when(_userVmDao.listByAccountId(ACCOUNT_ID)).thenReturn(Arrays.asList(vm));
@@ -142,8 +135,7 @@ protected void defineMocksBehavior()
         when(offering.getId()).thenReturn(1l);
         when(offering.getCpu()).thenReturn(500);
         when(offering.getRamSize()).thenReturn(500);
-        when(_serviceOfferingDao.findByIdIncludingRemoved(anyLong(), anyLong()))
-        .thenReturn(offering);
+        when(_serviceOfferingDao.findByIdIncludingRemoved(anyLong(), anyLong())).thenReturn(offering);
 
         when(_domainMgr.getDomain(anyLong())).thenReturn(domain);
 
@@ -152,9 +144,8 @@ protected void defineMocksBehavior()
     }
 
     @Before
-    public void init()
-            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
-            InvocationTargetException, AgentUnavailableException, ConcurrentOperationException, CloudException {
+    public void init() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, AgentUnavailableException,
+    ConcurrentOperationException, CloudException {
 
         setupUsageUtils();
         defineMocksBehavior();
@@ -175,22 +166,19 @@ public void cleanupUsageUtils() throws ReflectiveOperationException, SecurityExc
         method.invoke(utils);
     }
 
-    @SuppressWarnings("unchecked")
-    protected List<UsageEventVO> deleteUserAccountRootVolumeUsageEvents(boolean vmDestroyedPrior)
-            throws AgentUnavailableException, ConcurrentOperationException, CloudException {
+    protected List<UsageEventVO> deleteUserAccountRootVolumeUsageEvents(boolean vmDestroyedPrior) throws AgentUnavailableException, ConcurrentOperationException, CloudException {
 
-        when(vm.getState())
-        .thenReturn(vmDestroyedPrior ? VirtualMachine.State.Destroyed : VirtualMachine.State.Running);
+        when(vm.getState()).thenReturn(vmDestroyedPrior ? VirtualMachine.State.Destroyed : VirtualMachine.State.Running);
         when(vm.getRemoved()).thenReturn(vmDestroyedPrior ? new Date() : null);
-        accountManager.deleteUserAccount(ACCOUNT_ID);
+        accountManagerImpl.deleteUserAccount(ACCOUNT_ID);
 
         return _usageEventDao.listAll();
     }
 
     @Test
     // If the VM is alerady destroyed, no events should get emitted
-    public void destroyedVMRootVolumeUsageEvent() throws SecurityException, IllegalArgumentException,
-    ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
+    public void destroyedVMRootVolumeUsageEvent()
+            throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
         List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(true);
         Assert.assertEquals(0, emittedEvents.size());
     }
@@ -198,8 +186,8 @@ public void destroyedVMRootVolumeUsageEvent() throws SecurityException, IllegalA
     @Test
     // If the VM is running, we should see one emitted event for the root
     // volume.
-    public void runningVMRootVolumeUsageEvent() throws SecurityException, IllegalArgumentException,
-    ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
+    public void runningVMRootVolumeUsageEvent()
+            throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
         List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(false);
         Assert.assertEquals(1, emittedEvents.size());
         UsageEventVO event = emittedEvents.get(0);
diff --git a/server/src/test/java/com/cloud/user/AccountManagetImplTestBase.java b/server/src/test/java/com/cloud/user/AccountManagetImplTestBase.java
index 53b781a5868..885a23d5a99 100644
--- a/server/src/test/java/com/cloud/user/AccountManagetImplTestBase.java
+++ b/server/src/test/java/com/cloud/user/AccountManagetImplTestBase.java
@@ -21,8 +21,6 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import javax.inject.Inject;
-
 import org.apache.cloudstack.acl.SecurityChecker;
 import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
 import org.apache.cloudstack.context.CallContext;
@@ -34,9 +32,10 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.mockito.Spy;
 import org.mockito.runners.MockitoJUnitRunner;
-import org.springframework.test.util.ReflectionTestUtils;
 
 import com.cloud.configuration.ConfigurationManager;
 import com.cloud.configuration.dao.ResourceCountDao;
@@ -84,17 +83,17 @@
 public class AccountManagetImplTestBase {
 
     @Mock
-    AccountDao _accountDao;
+    AccountDao accountDaoMock;
     @Mock
     ConfigurationDao _configDao;
     @Mock
     ResourceCountDao _resourceCountDao;
     @Mock
-    UserDao _userDao;
+    UserDao userDaoMock;
     @Mock
     InstanceGroupDao _vmGroupDao;
     @Mock
-    UserAccountDao _userAccountDao;
+    UserAccountDao userAccountDaoMock;
     @Mock
     VolumeDao _volumeDao;
     @Mock
@@ -193,27 +192,16 @@
     @Mock
     SSHKeyPairDao _sshKeyPairDao;
 
-    AccountManagerImpl accountManager;
-
-    UsageEventDao _usageEventDao = new MockUsageEventDao();
+    @Spy
+    @InjectMocks
+    AccountManagerImpl accountManagerImpl;
+    @Mock
+    UsageEventDao _usageEventDao;
 
     @Before
-    public void setup()
-            throws NoSuchFieldException, SecurityException,
-            IllegalArgumentException, IllegalAccessException {
-        accountManager = new AccountManagerImpl();
-        Map<String, Field> declaredFields = getInheritedFields(this.getClass());
-        for (Field field : AccountManagerImpl.class.getDeclaredFields()) {
-            if (field.getAnnotation(Inject.class) != null) {
-                field.setAccessible(true);
-                if (declaredFields.containsKey(field.getName())) {
-                    Field mockField = declaredFields.get(field.getName());
-                    field.set(accountManager, mockField.get(this));
-                }
-            }
-        }
-        ReflectionTestUtils.setField(accountManager, "_userAuthenticators", Arrays.asList(userAuthenticator));
-        accountManager.setSecurityCheckers(Arrays.asList(securityChecker));
+    public void setup() {
+        accountManagerImpl.setUserAuthenticators(Arrays.asList(userAuthenticator));
+        accountManagerImpl.setSecurityCheckers(Arrays.asList(securityChecker));
         CallContext.register(callingUser, callingAccount);
     }
 
@@ -231,14 +219,4 @@ public void cleanup() {
         }
         return fields;
     }
-
-    public static Map<Class<?>, Field> getInheritedFieldsByClass(Class<?> type) {
-        Map<Class<?>, Field> fields = new HashMap<>();
-        for (Class<?> c = type; c != null; c = c.getSuperclass()) {
-            for (Field f : c.getDeclaredFields()) {
-                fields.put(f.getType(), f);
-            }
-        }
-        return fields;
-    }
 }
diff --git a/server/src/test/java/com/cloud/user/MockAccountManagerImpl.java b/server/src/test/java/com/cloud/user/MockAccountManagerImpl.java
index 0a92c1446db..4fbf7526f31 100644
--- a/server/src/test/java/com/cloud/user/MockAccountManagerImpl.java
+++ b/server/src/test/java/com/cloud/user/MockAccountManagerImpl.java
@@ -157,13 +157,6 @@ public UserAccount getActiveUserAccount(String username, Long domainId) {
         return null;
     }
 
-    @Override
-    public UserAccount updateUser(Long userId, String firstName, String lastName, String email, String userName, String password, String apiKey, String secretKey,
-                                  String timeZone) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
     @Override
     public Account getActiveAccountById(long accountId) {
         // TODO Auto-generated method stub
diff --git a/server/src/test/java/com/cloud/user/MockDomainManagerImpl.java b/server/src/test/java/com/cloud/user/MockDomainManagerImpl.java
deleted file mode 100644
index 394c3e22719..00000000000
--- a/server/src/test/java/com/cloud/user/MockDomainManagerImpl.java
+++ /dev/null
@@ -1,164 +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 com.cloud.user;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.naming.ConfigurationException;
-
-import org.springframework.stereotype.Component;
-
-import org.apache.cloudstack.api.command.admin.domain.ListDomainChildrenCmd;
-import org.apache.cloudstack.api.command.admin.domain.ListDomainsCmd;
-import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd;
-
-import com.cloud.domain.Domain;
-import com.cloud.domain.DomainVO;
-import com.cloud.exception.PermissionDeniedException;
-import com.cloud.utils.Pair;
-import com.cloud.utils.component.ManagerBase;
-
-@Component
-public class MockDomainManagerImpl extends ManagerBase implements DomainManager, DomainService {
-
-    @Override
-    public Domain getDomain(long id) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public Domain getDomain(String uuid) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public Domain getDomainByName(String name, long parentId) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public boolean isChildDomain(Long parentId, Long childId) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public boolean deleteDomain(long domainId, Boolean cleanup) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public Pair<List<? extends Domain>, Integer> searchForDomains(ListDomainsCmd cmd) throws PermissionDeniedException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public Pair<List<? extends Domain>, Integer> searchForDomainChildren(ListDomainChildrenCmd cmd) throws PermissionDeniedException {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public Set<Long> getDomainChildrenIds(String parentDomainPath) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public DomainVO findDomainByPath(String domainPath) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public DomainVO findDomainByIdOrPath(Long id, String domainPath) {
-        return null;
-    }
-
-    @Override
-    public Set<Long> getDomainParentIds(long domainId) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public boolean removeDomain(long domainId) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public List<? extends Domain> findInactiveDomains() {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public boolean deleteDomain(DomainVO domain, Boolean cleanup) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
-    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
-        return true;
-    }
-
-    @Override
-    public boolean start() {
-        // TODO Auto-generated method stub
-        return true;
-    }
-
-    @Override
-    public boolean stop() {
-        // TODO Auto-generated method stub
-        return true;
-    }
-
-    @Override
-    public String getName() {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public Domain createDomain(String name, Long parentId, String networkDomain, String domainUUID) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public Domain updateDomain(UpdateDomainCmd cmd) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    @Override
-    public Domain createDomain(String name, Long parentId, Long ownerId, String networkDomain, String domainUUID) {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-}
diff --git a/ui/l10n/ar.js b/ui/l10n/ar.js
index c8129b1ff41..636ad906655 100644
--- a/ui/l10n/ar.js
+++ b/ui/l10n/ar.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "الشبكات",
     "label.new": "جديد",
     "label.new.password": "New Password",
+    "label.current.password": "Current Password",
     "label.new.project": "مشروع جديد",
     "label.new.ssh.key.pair": "New SSH Key Pair",
     "label.new.vm": "New VM",
diff --git a/ui/l10n/ca.js b/ui/l10n/ca.js
index 5f4f55b0b28..192e5c67c81 100644
--- a/ui/l10n/ca.js
+++ b/ui/l10n/ca.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "Xarxes",
     "label.new": "Nou",
     "label.new.password": "New Password",
+    "label.current.password": "Current Password",
     "label.new.project": "Nou projecte",
     "label.new.ssh.key.pair": "New SSH Key Pair",
     "label.new.vm": "Nova MV",
diff --git a/ui/l10n/de_DE.js b/ui/l10n/de_DE.js
index 382f7c43b4e..c9478cd7ba9 100644
--- a/ui/l10n/de_DE.js
+++ b/ui/l10n/de_DE.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "Netzwerke",
     "label.new": "Neu",
     "label.new.password": "Neues Passwort",
+    "label.current.password": "Current Password",
     "label.new.project": "Neues Projekt",
     "label.new.ssh.key.pair": "Neues SSH-Schlüsselpaar",
     "label.new.vm": "Neue VM",
diff --git a/ui/l10n/en.js b/ui/l10n/en.js
index 342e8838284..e8944643f13 100644
--- a/ui/l10n/en.js
+++ b/ui/l10n/en.js
@@ -1181,6 +1181,7 @@ var dictionary = {
 "label.networks":"Networks",
 "label.new":"New",
 "label.new.password":"New Password",
+"label.current.password": "Current Password",
 "label.new.project":"New Project",
 "label.new.ssh.key.pair":"New SSH Key Pair",
 "label.new.vm":"New VM",
diff --git a/ui/l10n/es.js b/ui/l10n/es.js
index 2f4727fad7a..6e9802c60c3 100644
--- a/ui/l10n/es.js
+++ b/ui/l10n/es.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "Redes",
     "label.new": "Nuevo",
     "label.new.password": "Nueva contraseña",
+    "label.current.password": "Current Password",
     "label.new.project": "Nuevo Proyecto",
     "label.new.ssh.key.pair": "Nuevo Par de Claves SSH",
     "label.new.vm": "Nueva MV",
diff --git a/ui/l10n/fr_FR.js b/ui/l10n/fr_FR.js
index be31c1c7e60..b8f143fd33f 100644
--- a/ui/l10n/fr_FR.js
+++ b/ui/l10n/fr_FR.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "Réseaux",
     "label.new": "Nouveau",
     "label.new.password": "Nouveau mot de passe",
+    "label.current.password": "Current Password",
     "label.new.project": "Nouveau projet",
     "label.new.ssh.key.pair": "Nouvelle bi-clé SSH",
     "label.new.vm": "Nouvelle VM",
diff --git a/ui/l10n/hu.js b/ui/l10n/hu.js
index 8337b5a8612..244a570e86d 100644
--- a/ui/l10n/hu.js
+++ b/ui/l10n/hu.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "Hálózatok",
     "label.new": "Új",
     "label.new.password": "Új jelszó",
+    "label.current.password": "Current Password",
     "label.new.project": "Új projekt",
     "label.new.ssh.key.pair": "Új SSH kulcspár",
     "label.new.vm": "Új VM",
diff --git a/ui/l10n/it_IT.js b/ui/l10n/it_IT.js
index a54f1774e07..1a4f46ee730 100644
--- a/ui/l10n/it_IT.js
+++ b/ui/l10n/it_IT.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "Reti",
     "label.new": "Nuovo",
     "label.new.password": "New Password",
+    "label.current.password": "Current Password",
     "label.new.project": "Nuovo Progetto",
     "label.new.ssh.key.pair": "New SSH Key Pair",
     "label.new.vm": "Nuova VM",
diff --git a/ui/l10n/ja_JP.js b/ui/l10n/ja_JP.js
index d02b62c2cbc..8328d14103d 100644
--- a/ui/l10n/ja_JP.js
+++ b/ui/l10n/ja_JP.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "ネットワーク",
     "label.new": "新規",
     "label.new.password": "新しいパスワード",
+    "label.current.password": "Current Password",
     "label.new.project": "新しいプロジェクト",
     "label.new.ssh.key.pair": "新しい SSH キーペア",
     "label.new.vm": "新しい VM",
diff --git a/ui/l10n/ko_KR.js b/ui/l10n/ko_KR.js
index 731ccac9987..c96d25cefd9 100644
--- a/ui/l10n/ko_KR.js
+++ b/ui/l10n/ko_KR.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "네트워크",
     "label.new": "신규",
     "label.new.password": "새로운 암호",
+    "label.current.password": "Current Password",
     "label.new.project": "새 프로젝트",
     "label.new.ssh.key.pair": "New SSH Key Pair",
     "label.new.vm": "새 VM",
diff --git a/ui/l10n/nb_NO.js b/ui/l10n/nb_NO.js
index 7785ea8ad8a..8373f24a13b 100644
--- a/ui/l10n/nb_NO.js
+++ b/ui/l10n/nb_NO.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "Nettverk",
     "label.new": "Ny",
     "label.new.password": "Nytt passord",
+    "label.current.password": "Current Password",
     "label.new.project": "Nytt prosjekt",
     "label.new.ssh.key.pair": "Nytt SSH-nøkkelpar",
     "label.new.vm": "Ny VM",
diff --git a/ui/l10n/nl_NL.js b/ui/l10n/nl_NL.js
index 1b3fd0e5e6f..d92478053b2 100644
--- a/ui/l10n/nl_NL.js
+++ b/ui/l10n/nl_NL.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "Netwerken",
     "label.new": "Nieuw",
     "label.new.password": "Nieuw wachtwoord",
+    "label.current.password": "Current Password",
     "label.new.project": "Nieuw Project",
     "label.new.ssh.key.pair": "nieuw SSH sleutelpaar",
     "label.new.vm": "Nieuwe VM",
diff --git a/ui/l10n/pl.js b/ui/l10n/pl.js
index 6cb486b6fb9..10829f14f11 100644
--- a/ui/l10n/pl.js
+++ b/ui/l10n/pl.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "Sieci",
     "label.new": "Nowy",
     "label.new.password": "New Password",
+    "label.current.password": "Current Password",
     "label.new.project": "Nowy projekt",
     "label.new.ssh.key.pair": "New SSH Key Pair",
     "label.new.vm": "New VM",
diff --git a/ui/l10n/pt_BR.js b/ui/l10n/pt_BR.js
index 04d129c7c6d..0d095242254 100644
--- a/ui/l10n/pt_BR.js
+++ b/ui/l10n/pt_BR.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "Redes",
     "label.new": "Novo",
     "label.new.password": "Nova Senha",
+    "label.current.password": "Senha Antiga",
     "label.new.project": "Novo Projeto",
     "label.new.ssh.key.pair": "Novo par de chaves SSH",
     "label.new.vm": "Nova VM",
diff --git a/ui/l10n/ru_RU.js b/ui/l10n/ru_RU.js
index 5d3d3de6603..5393a29dfde 100644
--- a/ui/l10n/ru_RU.js
+++ b/ui/l10n/ru_RU.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "Сети",
     "label.new": "Создать",
     "label.new.password": "Новый пароль",
+    "label.current.password": "Current Password",
     "label.new.project": "Новый проект",
     "label.new.ssh.key.pair": "New SSH Key Pair",
     "label.new.vm": "Новая ВМ",
diff --git a/ui/l10n/zh_CN.js b/ui/l10n/zh_CN.js
index e733b446847..3e5fdf7ec61 100644
--- a/ui/l10n/zh_CN.js
+++ b/ui/l10n/zh_CN.js
@@ -1147,6 +1147,7 @@ var dictionary = {
     "label.networks": "网络",
     "label.new": "新建",
     "label.new.password": "新密码",
+    "label.current.password": "Current Password",
     "label.new.project": "新建项目",
     "label.new.ssh.key.pair": "新SSH密钥对",
     "label.new.vm": "新建 VM",
diff --git a/ui/scripts/accounts.js b/ui/scripts/accounts.js
index 529e5e391d0..86efb3ef29c 100644
--- a/ui/scripts/accounts.js
+++ b/ui/scripts/accounts.js
@@ -1476,6 +1476,14 @@
                                                 form: {
                                                     title: 'label.action.change.password',
                                                     fields: {
+                                                        currentPassword: {
+                                                            label: 'label.current.password',
+                                                            isPassword: true,
+                                                            validation: {
+                                                                required: !(isAdmin() || isDomainAdmin())
+                                                            },
+                                                            id: 'currentPassword'
+                                                        },
                                                         newPassword: {
                                                             label: 'label.new.password',
                                                             isPassword: true,
@@ -1496,13 +1504,13 @@
                                                 },
                                                 after: function(args) {
                                                     start();
-
+                                                    var currentPassword = args.data.currentPassword;
                                                     var password = args.data.newPassword;
-
                                                     $.ajax({
                                                         url: createURL('updateUser'),
                                                         data: {
                                                             id: context.users[0].id,
+                                                            currentPassword: currentPassword,
                                                             password: password
                                                         },
                                                         type: "POST",
@@ -1515,6 +1523,9 @@
                                                     });
                                                 }
                                             });
+                                            if(isAdmin() || isDomainAdmin()){
+                                                $('div[rel=currentPassword]').hide();
+                                            }
                                         } else {
                                             cloudStack.dialog.notice({ message: _l('error.could.not.change.your.password.because.non.native.user') });
                                         }


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services