[CLOUDSTACK-5235] ask users current password when they are executing a password update (#2574)

* [CLOUDSTACK-5235] Force users to enter old password when updating password

* Formatting for checkstyle

* Remove an unused import in AccountManagerImpl

* Apply Nitin's suggestions

* Change 'oldPassword' to 'currentPassword'

* Second review of Resmo

* Fix typos found by Nitin
This commit is contained in:
Rafael Weingärtner 2018-05-02 09:19:06 -03:00 committed by GitHub
parent 5df580ef64
commit 3adc2b8485
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1013 additions and 671 deletions

View File

@ -23,53 +23,28 @@ import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd; 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.RegisterCmd;
import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd;
import com.cloud.domain.Domain; import com.cloud.domain.Domain;
import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.PermissionDeniedException;
import com.cloud.offering.DiskOffering; import com.cloud.offering.DiskOffering;
import com.cloud.offering.ServiceOffering; import com.cloud.offering.ServiceOffering;
public interface AccountService { public interface AccountService {
/** /**
* Creates a new user and account, stores the password as is so encrypted passwords are recommended. * 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 * @return the user if created successfully, null otherwise
*/ */
UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long roleId, Long domainId,
short accountType, Long roleId, Long domainId, String networkDomain, Map<String, String> details, String accountUUID, String userUUID); 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, UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long roleId, Long domainId,
Map<String, String> details, String accountUUID, String userUUID, User.Source source); 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 * Locks a user by userId. A locked user cannot access the API, but will still have running VMs/IP addresses
* allocated/etc. * allocated/etc.
*
* @param userId
* @return UserAccount object
*/ */
UserAccount lockUser(long userId); UserAccount lockUser(long userId);
@ -79,8 +54,7 @@ public interface AccountService {
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 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.Source source);
boolean isAdmin(Long accountId); boolean isAdmin(Long accountId);
@ -90,7 +64,7 @@ public interface AccountService {
UserAccount getActiveUserAccount(String username, Long domainId); 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); Account getActiveAccountById(long accountId);
@ -128,15 +102,14 @@ public interface AccountService {
void checkAccess(User user, ControlledEntity entity); void checkAccess(User user, ControlledEntity entity);
void checkAccess(Account account, AccessType accessType, boolean sameOwner, String apiName, void checkAccess(Account account, AccessType accessType, boolean sameOwner, String apiName, ControlledEntity... entities) throws PermissionDeniedException;
ControlledEntity... entities) throws PermissionDeniedException;
Long finalyzeAccountId(String accountName, Long domainId, Long projectId, boolean enabledOnly); Long finalyzeAccountId(String accountName, Long domainId, Long projectId, boolean enabledOnly);
/** /**
* returns the user account object for a given user id * returns the user account object for a given user id
* @param userId 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); UserAccount getUserAccountById(Long userId);

View File

@ -215,8 +215,8 @@ public class ApiConstants {
public static final String PARENT_DOMAIN_ID = "parentdomainid"; public static final String PARENT_DOMAIN_ID = "parentdomainid";
public static final String PARENT_TEMPLATE_ID = "parenttemplateid"; public static final String PARENT_TEMPLATE_ID = "parenttemplateid";
public static final String PASSWORD = "password"; 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 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 PASSWORD_ENABLED = "passwordenabled";
public static final String SSHKEY_ENABLED = "sshkeyenabled"; public static final String SSHKEY_ENABLED = "sshkeyenabled";
public static final String PATH = "path"; public static final String PATH = "path";
@ -729,4 +729,4 @@ public class ApiConstants {
public enum DomainDetails { public enum DomainDetails {
all, resource, min; all, resource, min;
} }
} }

View File

@ -34,7 +34,7 @@ import com.cloud.user.User;
import com.cloud.user.UserAccount; import com.cloud.user.UserAccount;
@APICommand(name = "updateUser", description = "Updates a user account", responseObject = UserResponse.class, @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 class UpdateUserCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(UpdateUserCmd.class.getName()); public static final Logger s_logger = Logger.getLogger(UpdateUserCmd.class.getName());
@ -65,20 +65,22 @@ public class UpdateUserCmd extends BaseCmd {
acceptedOnAdminPort = false) acceptedOnAdminPort = false)
private String password; 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 userApiKey") @Parameter(name = ApiConstants.SECRET_KEY, type = CommandType.STRING, description = "The secret key for the user. Must be specified with userApiKey")
private String secretKey; private String secretKey;
@Parameter(name = ApiConstants.TIMEZONE, @Parameter(name = ApiConstants.TIMEZONE,
type = CommandType.STRING, type = CommandType.STRING,
description = "Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.") description = "Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.")
private String timezone; private String timezone;
@Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, description = "Unique username") @Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, description = "Unique username")
private String username; private String username;
@Inject @Inject
RegionService _regionService; private RegionService _regionService;
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
/////////////////// Accessors /////////////////////// /////////////////// Accessors ///////////////////////
@ -108,6 +110,10 @@ public class UpdateUserCmd extends BaseCmd {
return password; return password;
} }
public String getCurrentPassword() {
return currentPassword;
}
public String getSecretKey() { public String getSecretKey() {
return secretKey; return secretKey;
} }
@ -152,4 +158,20 @@ public class UpdateUserCmd extends BaseCmd {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update user"); 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;
}
} }

View File

@ -167,13 +167,6 @@ public class MockAccountManager extends ManagerBase implements AccountManager {
return null; 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 @Override
public User getActiveUser(long arg0) { public User getActiveUser(long arg0) {
return _systemUser; return _systemUser;

View File

@ -26,9 +26,6 @@ import java.util.UUID;
import javax.inject.Inject; 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.acl.RoleType;
import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants;
@ -36,6 +33,7 @@ import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException; 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.DomainResponse;
import org.apache.cloudstack.api.response.LdapUserResponse; import org.apache.cloudstack.api.response.LdapUserResponse;
import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ListResponse;
@ -54,25 +52,23 @@ import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account;
import com.cloud.user.AccountService; import com.cloud.user.AccountService;
import com.cloud.user.DomainService; 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", @APICommand(name = "importLdapUsers", description = "Import LDAP users", responseObject = LdapUserResponse.class, since = "4.3.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class LdapImportUsersCmd extends BaseListCmd { public class LdapImportUsersCmd extends BaseListCmd {
public static final Logger s_logger = Logger.getLogger(LdapImportUsersCmd.class.getName()); public static final Logger s_logger = Logger.getLogger(LdapImportUsersCmd.class.getName());
private static final String s_name = "ldapuserresponse"; private static final String s_name = "ldapuserresponse";
@Parameter(name = ApiConstants.TIMEZONE, @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; private String timezone;
@Parameter(name = ApiConstants.ACCOUNT_TYPE, @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")
type = CommandType.SHORT,
description = "Type of the account. Specify 0 for user, 1 for root admin, and 2 for domain admin")
private Short accountType; private Short accountType;
@Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "Creates the account under the specified role.") @Parameter(name = ApiConstants.ROLE_ID, type = CommandType.UUID, entityType = RoleResponse.class, description = "Creates the account under the specified role.")
@ -81,16 +77,13 @@ public class LdapImportUsersCmd extends BaseListCmd {
@Parameter(name = ApiConstants.ACCOUNT_DETAILS, type = CommandType.MAP, description = "details for account used to store specific parameters") @Parameter(name = ApiConstants.ACCOUNT_DETAILS, type = CommandType.MAP, description = "details for account used to store specific parameters")
private Map<String, String> details; private Map<String, String> details;
@Parameter(name = ApiConstants.DOMAIN_ID, @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "Specifies the domain to which the ldap users are to be "
type = CommandType.UUID, + "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 "
entityType = DomainResponse.class, + "created. If no OU hierarchy exists, will be defaulted to ROOT domain")
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; private Long domainId;
@Parameter(name = ApiConstants.GROUP, type = CommandType.STRING, description = "Specifies the group name from which the ldap users are to be imported. " @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 String groupName;
private Domain _domain; private Domain _domain;
@ -121,20 +114,27 @@ public class LdapImportUsersCmd extends BaseListCmd {
} else { } else {
// check if the user exists. if yes, call update // check if the user exists. if yes, call update
UserAccount csuser = _accountService.getActiveUserAccount(user.getUsername(), domain.getId()); 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); 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(), _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 { } else {
s_logger.debug("account with name: " + accountName + " exist and user with name: " + user.getUsername() + " exists in the account. Updating the account."); s_logger.debug("Account [name=%s] and user [name=%s] already exist in CloudStack. Executing the user update.");
_accountService.updateUser(csuser.getId(), user.getFirstname(), user.getLastname(), user.getEmail(), null, null, null, null, null);
UpdateUserCmd updateUserCmd = new UpdateUserCmd();
updateUserCmd.setId(csuser.getId());
updateUserCmd.setFirstname(user.getFirstname());
updateUserCmd.setLastname(user.getLastname());
updateUserCmd.setEmail(user.getEmail());
_accountService.updateUser(updateUserCmd);
} }
} }
} }
@Override @Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, public void execute()
ResourceAllocationException, NetworkRuleConflictException { throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
if (getAccountType() == null && getRoleId() == null) { if (getAccountType() == null && getRoleId() == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Both account type and role ID are not provided"); throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Both account type and role ID are not provided");
} }
@ -177,7 +177,7 @@ public class LdapImportUsersCmd extends BaseListCmd {
private String getAccountName(LdapUser user) { private String getAccountName(LdapUser user) {
String finalAccountName = accountName; String finalAccountName = accountName;
if(finalAccountName == null ) { if (finalAccountName == null) {
finalAccountName = user.getUsername(); finalAccountName = user.getUsername();
} }
return finalAccountName; return finalAccountName;
@ -244,7 +244,7 @@ public class LdapImportUsersCmd extends BaseListCmd {
final byte bytes[] = new byte[20]; final byte bytes[] = new byte[20];
randomGen.nextBytes(bytes); randomGen.nextBytes(bytes);
return new String(Base64.encode(bytes), "UTF-8"); 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"); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to generate random password");
} }
} }

View File

@ -16,15 +16,17 @@
// under the License. // under the License.
package com.cloud.user; package com.cloud.user;
import java.net.InetAddress;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.net.InetAddress;
import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; 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.DeleteUserCmd;
import org.apache.cloudstack.api.command.admin.user.MoveUserCmd; import org.apache.cloudstack.api.command.admin.user.MoveUserCmd;
import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; 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.api.query.vo.ControlledViewEntity;
import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConcurrentOperationException;
@ -34,17 +36,14 @@ import com.cloud.utils.Pair;
import com.cloud.utils.Ternary; import com.cloud.utils.Ternary;
import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria; 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. * 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 * Disables an account by accountId
* @param accountId
* @return true if disable was successful, false otherwise * @return true if disable was successful, false otherwise
*/ */
boolean disableAccount(long accountId) throws ConcurrentOperationException, ResourceUnavailableException; boolean disableAccount(long accountId) throws ConcurrentOperationException, ResourceUnavailableException;
@ -57,24 +56,23 @@ public interface AccountManager extends AccountService, Configurable{
/** /**
* Logs out a user * Logs out a user
* @param userId
*/ */
void logoutUser(long userId); void logoutUser(long userId);
/** /**
* Authenticates a user when s/he logs in. * Authenticates a user when s/he logs in.
* *
* @param username * @param username
* required username for authentication * required username for authentication
* @param password * @param password
* password to use for authentication, can be null for single sign-on case * password to use for authentication, can be null for single sign-on case
* @param domainId * @param domainId
* id of domain where user with username resides * id of domain where user with username resides
* @param requestParameters * @param requestParameters
* the request parameters of the login request, which should contain timestamp of when the request signature is * 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 * made, and the signature itself in the single sign-on case
* @return a user object, null if the user failed to authenticate * @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); UserAccount authenticateUser(String username, String password, Long domainId, InetAddress loginIpAddress, Map<String, Object[]> requestParameters);
/** /**
@ -88,23 +86,20 @@ public interface AccountManager extends AccountService, Configurable{
boolean enableAccount(long accountId); 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, void buildACLViewSearchBuilder(SearchBuilder<? extends ControlledViewEntity> sb, Long domainId, boolean isRecursive, List<Long> permittedAccounts,
boolean isRecursive, List<Long> permittedAccounts, ListProjectResourcesCriteria listProjectResourcesCriteria); ListProjectResourcesCriteria listProjectResourcesCriteria);
void buildACLViewSearchBuilder(SearchBuilder<? extends ControlledViewEntity> sb, Long domainId, void buildACLSearchCriteria(SearchCriteria<? extends ControlledEntity> sc, Long domainId, boolean isRecursive, List<Long> permittedAccounts,
boolean isRecursive, List<Long> permittedAccounts, ListProjectResourcesCriteria listProjectResourcesCriteria); ListProjectResourcesCriteria listProjectResourcesCriteria);
void buildACLSearchCriteria(SearchCriteria<? extends ControlledEntity> sc, void buildACLSearchParameters(Account caller, Long id, String accountName, Long projectId, List<Long> permittedAccounts,
Long domainId, boolean isRecursive, List<Long> permittedAccounts, ListProjectResourcesCriteria listProjectResourcesCriteria); Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject, boolean listAll, boolean forProjectInvitation);
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);
void buildACLViewSearchCriteria(SearchCriteria<? extends ControlledViewEntity> sc, Long domainId, boolean isRecursive, List<Long> permittedAccounts,
ListProjectResourcesCriteria listProjectResourcesCriteria);
/** /**
* Deletes a user by userId * Deletes a user by userId
@ -127,10 +122,6 @@ public interface AccountManager extends AccountService, Configurable{
/** /**
* Disables an account by accountName and domainId * Disables an account by accountName and domainId
*
* @param accountName
* @param domainId
* @param accountId
* @param disabled * @param disabled
* account if success * account if success
* @return true if disable was successful, false otherwise * @return true if disable was successful, false otherwise
@ -142,33 +133,21 @@ public interface AccountManager extends AccountService, Configurable{
* *
* @param accountName * @param accountName
* - the enableAccount command defining the accountId to be deleted. * - 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); Account enableAccount(String accountName, Long domainId, Long accountId);
/** /**
* Deletes user by Id * Deletes user by Id
* @param deleteUserCmd
* @return
*/ */
boolean deleteUser(DeleteUserCmd deleteUserCmd); boolean deleteUser(DeleteUserCmd deleteUserCmd);
/** /**
* moves a user to another account within the same domain * moves a user to another account within the same domain
* @param moveUserCmd
* @return true if the user was successfully moved * @return true if the user was successfully moved
*/ */
boolean moveUser(MoveUserCmd moveUserCmd); boolean moveUser(MoveUserCmd moveUserCmd);
/** @Override
* Update a user by userId
*
* @param cmd
* @return UserAccount object
*/
UserAccount updateUser(UpdateUserCmd cmd); UserAccount updateUser(UpdateUserCmd cmd);
/** /**
@ -196,10 +175,6 @@ public interface AccountManager extends AccountService, Configurable{
* *
* @param accountName * @param accountName
* - the LockAccount command defining the accountId to be locked. * - 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); Account lockAccount(String accountName, Long domainId, Long accountId);
@ -208,13 +183,8 @@ public interface AccountManager extends AccountService, Configurable{
public static final String MESSAGE_ADD_ACCOUNT_EVENT = "Message.AddAccount.Event"; 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 String MESSAGE_REMOVE_ACCOUNT_EVENT = "Message.RemoveAccount.Event";
public static final ConfigKey<Boolean> UseSecretKeyInResponse = new ConfigKey<Boolean>( public static final ConfigKey<Boolean> UseSecretKeyInResponse = new ConfigKey<Boolean>("Advanced", Boolean.class, "use.secret.key.in.response", "false",
"Advanced", "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.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); boolean moveUser(long id, Long domainId, long accountId);
} }

View File

@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
@ -38,10 +37,6 @@ import javax.crypto.spec.SecretKeySpec;
import javax.inject.Inject; import javax.inject.Inject;
import javax.naming.ConfigurationException; 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.ControlledEntity;
import org.apache.cloudstack.acl.QuerySelector; import org.apache.cloudstack.acl.QuerySelector;
import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.acl.RoleType;
@ -55,6 +50,7 @@ import org.apache.cloudstack.api.command.admin.user.GetUserKeysCmd;
import org.apache.cloudstack.api.command.admin.user.MoveUserCmd; 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.RegisterCmd;
import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; 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.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.ConfigKey;
@ -64,6 +60,11 @@ import org.apache.cloudstack.framework.messagebus.PublishScope;
import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao; import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao;
import org.apache.cloudstack.utils.baremetal.BaremetalUtils; 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.ApiDBUtils;
import com.cloud.api.query.vo.ControlledViewEntity; import com.cloud.api.query.vo.ControlledViewEntity;
@ -172,8 +173,6 @@ import com.cloud.vm.snapshot.VMSnapshot;
import com.cloud.vm.snapshot.VMSnapshotManager; import com.cloud.vm.snapshot.VMSnapshotManager;
import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.VMSnapshotVO;
import com.cloud.vm.snapshot.dao.VMSnapshotDao; import com.cloud.vm.snapshot.dao.VMSnapshotDao;
import org.apache.cloudstack.config.ApiServiceConfiguration;
public class AccountManagerImpl extends ManagerBase implements AccountManager, Manager { public class AccountManagerImpl extends ManagerBase implements AccountManager, Manager {
public static final Logger s_logger = Logger.getLogger(AccountManagerImpl.class); public static final Logger s_logger = Logger.getLogger(AccountManagerImpl.class);
@ -540,8 +539,8 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
Account account = ApiDBUtils.findAccountById(entity.getAccountId()); Account account = ApiDBUtils.findAccountById(entity.getAccountId());
domainId = account != null ? account.getDomainId() : -1; domainId = account != null ? account.getDomainId() : -1;
} }
if (entity.getAccountId() != -1 && domainId != -1 && !(entity instanceof VirtualMachineTemplate) if (entity.getAccountId() != -1 && domainId != -1 && !(entity instanceof VirtualMachineTemplate) && !(entity instanceof Network && accessType != null && accessType == AccessType.UseEntry)
&& !(entity instanceof Network && accessType != null && accessType == AccessType.UseEntry) && !(entity instanceof AffinityGroup)) { && !(entity instanceof AffinityGroup)) {
List<ControlledEntity> toBeChecked = domains.get(entity.getDomainId()); List<ControlledEntity> toBeChecked = domains.get(entity.getDomainId());
// for templates, we don't have to do cross domains check // for templates, we don't have to do cross domains check
if (toBeChecked == null) { if (toBeChecked == null) {
@ -563,7 +562,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
if (!granted) { if (!granted) {
assert false : "How can all of the security checkers pass on checking this check: " + entity; 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 class AccountManagerImpl extends ManagerBase implements AccountManager, M
public Long checkAccessAndSpecifyAuthority(Account caller, Long zoneId) { 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. // We just care for resource domain admin for now. He should be permitted to see only his zone.
if (isResourceDomainAdmin(caller.getAccountId())) { if (isResourceDomainAdmin(caller.getAccountId())) {
if (zoneId == null) if (zoneId == null) {
return getZoneIdForAccount(caller); 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); throw new PermissionDeniedException("Caller " + caller + "is not allowed to access the zone " + zoneId);
else } else {
return zoneId; return zoneId;
} }
} else {
else
return zoneId; return zoneId;
}
} }
private Long getZoneIdForAccount(Account account) { private Long getZoneIdForAccount(Account account) {
// Currently just for resource domain admin // Currently just for resource domain admin
List<DataCenterVO> dcList = _dcDao.findZonesByDomainId(account.getDomainId()); List<DataCenterVO> dcList = _dcDao.findZonesByDomainId(account.getDomainId());
if (dcList != null && dcList.size() != 0) if (dcList != null && dcList.size() != 0) {
return dcList.get(0).getId(); return dcList.get(0).getId();
else } else {
throw new CloudRuntimeException("Failed to find any private zone for Resource domain admin."); throw new CloudRuntimeException("Failed to find any private zone for Resource domain admin.");
}
} }
@ -1011,13 +1011,12 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@Override @Override
@ActionEvents({@ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_CREATE, eventDescription = "creating Account"), @ActionEvents({@ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_CREATE, eventDescription = "creating Account"),
@ActionEvent(eventType = EventTypes.EVENT_USER_CREATE, eventDescription = "creating User")}) @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, public UserAccount createUserAccount(final String userName, final String password, final String firstName, final String lastName, final String email, final String timezone, String accountName,
String accountName, final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map<String, String> details, String accountUUID, final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map<String, String> details, String accountUUID, final String userUUID) {
final String userUUID) {
return createUserAccount(userName, password, firstName, lastName, email, timezone, accountName, accountType, roleId, domainId, networkDomain, details, accountUUID, return createUserAccount(userName, password, firstName, lastName, email, timezone, accountName, accountType, roleId, domainId, networkDomain, details, accountUUID, userUUID,
userUUID, User.Source.UNKNOWN); User.Source.UNKNOWN);
} }
// /////////////////////////////////////////////////// // ///////////////////////////////////////////////////
@ -1027,10 +1026,10 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@Override @Override
@DB @DB
@ActionEvents({@ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_CREATE, eventDescription = "creating Account"), @ActionEvents({@ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_CREATE, eventDescription = "creating Account"),
@ActionEvent(eventType = EventTypes.EVENT_USER_CREATE, eventDescription = "creating User")}) @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, public UserAccount createUserAccount(final String userName, final String password, final String firstName, final String lastName, final String email, final String timezone, String accountName,
String accountName, final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map<String, String> details, String accountUUID, final short accountType, final Long roleId, Long domainId, final String networkDomain, final Map<String, String> details, String accountUUID, final String userUUID,
final String userUUID, final User.Source source) { final User.Source source) {
if (accountName == null) { if (accountName == null) {
accountName = userName; accountName = userName;
@ -1058,7 +1057,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
} }
// Check permissions // Check permissions
checkAccess(CallContext.current().getCallingAccount(), domain); checkAccess(getCurrentCallingAccount(), domain);
if (!_userAccountDao.validateUsernameInDomain(userName, domainId)) { if (!_userAccountDao.validateUsernameInDomain(userName, domainId)) {
throw new InvalidParameterValueException("The user " + userName + " already exists in domain " + domainId); throw new InvalidParameterValueException("The user " + userName + " already exists in domain " + domainId);
@ -1132,7 +1131,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
throw new CloudRuntimeException("The user cannot be created as domain " + domain.getName() + " is being deleted"); 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); Account account = _accountDao.findEnabledAccount(accountName, domainId);
if (account == null || account.getType() == Account.ACCOUNT_TYPE_PROJECT) { if (account == null || account.getType() == Account.ACCOUNT_TYPE_PROJECT) {
@ -1153,157 +1152,246 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_USER_CREATE, eventDescription = "creating User") @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, public UserVO createUser(String userName, String password, String firstName, String lastName, String email, String timeZone, String accountName, Long domainId, String userUUID) {
String userUUID) {
return createUser(userName, password, firstName, lastName, email, timeZone, accountName, domainId, userUUID, User.Source.UNKNOWN); return createUser(userName, password, firstName, lastName, email, timeZone, accountName, domainId, userUUID, User.Source.UNKNOWN);
} }
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_USER_UPDATE, eventDescription = "updating User") @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, public UserAccount updateUser(UpdateUserCmd updateUserCmd) {
String timeZone) { UserVO user = retrieveAndValidateUser(updateUserCmd);
// Input validation s_logger.debug("Updating user with Id: " + user.getUuid());
UserVO user = _userDao.getUser(userId);
if (user == null) { validateAndUpdatApiAndSecretKeyIfNeeded(updateUserCmd, user);
throw new InvalidParameterValueException("unable to find user by id"); Account account = retrieveAndValidateAccount(user);
validateAndUpdateFirstNameIfNeeded(updateUserCmd, user);
validateAndUpdateLastNameIfNeeded(updateUserCmd, user);
validateAndUpdateUsernameIfNeeded(updateUserCmd, user, account);
validateUserPasswordAndUpdateIfNeeded(updateUserCmd.getPassword(), user, updateUserCmd.getCurrentPassword());
String email = updateUserCmd.getEmail();
if (StringUtils.isNotBlank(email)) {
user.setEmail(email);
} }
String timezone = updateUserCmd.getTimezone();
if ((apiKey == null && secretKey != null) || (apiKey != null && secretKey == null)) { if (StringUtils.isNotBlank(timezone)) {
throw new InvalidParameterValueException("Please provide an userApiKey/userSecretKey pair"); user.setTimezone(timezone);
} }
_userDao.update(user.getId(), user);
return _userAccountDao.findById(user.getId());
}
// If the account is an admin type, return an error. We do not allow this /**
Account account = _accountDao.findById(user.getAccountId()); * Updates the password in the user POJO if needed. If no password is provided, then the password is not updated.
if (account == null) { * 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.
throw new InvalidParameterValueException("unable to find user account " + user.getAccountId()); * <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;
} }
if (StringUtils.isBlank(newPassword)) {
// don't allow updating project account throw new InvalidParameterValueException("Password cannot be empty or blank.");
if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) {
throw new InvalidParameterValueException("unable to find user by id");
} }
Account callingAccount = getCurrentCallingAccount();
// don't allow updating system account boolean isRootAdminExecutingPasswordUpdate = callingAccount.getId() == Account.ACCOUNT_ID_SYSTEM || isRootAdmin(callingAccount.getId());
if (account.getId() == Account.ACCOUNT_ID_SYSTEM) { boolean isDomainAdmin = isDomainAdmin(callingAccount.getId());
throw new PermissionDeniedException("user id : " + userId + " is system account, update is not allowed"); 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);
}
checkAccess(CallContext.current().getCallingAccount(), AccessType.OperateEntry, true, account); /**
* Iterates over all configured user authenticators and tries to authenticate the user using the current password.
if (firstName != null) { * If the user is authenticated with success, we have nothing else to do here; otherwise, an {@link InvalidParameterValueException} is thrown.
if (firstName.isEmpty()) { */
throw new InvalidParameterValueException("Firstname is empty"); 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;
} }
user.setFirstname(firstName);
} }
if (!currentPasswordMatchesDataBasePassword) {
throw new InvalidParameterValueException("Current password is incorrect.");
}
}
/**
* 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.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 != null) {
if (lastName.isEmpty()) { if (StringUtils.isBlank(lastName)) {
throw new InvalidParameterValueException("Lastname is empty"); throw new InvalidParameterValueException("Lastname cannot be empty.");
} }
user.setLastname(lastName); 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());
}
}
}
user.setUsername(userName);
}
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);
}
if (apiKey != null) {
user.setApiKey(apiKey);
}
if (secretKey != null) {
user.setSecretKey(secretKey);
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("updating user with id: " + userId);
}
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
}
}
}
_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);
} }
@Override /**
@ActionEvent(eventType = EventTypes.EVENT_USER_UPDATE, eventDescription = "updating User") * Validates the user 'firstName' if provided. The 'firstName' cannot be blank (when provided).
public UserAccount updateUser(UpdateUserCmd cmd) { * <ul>
Long id = cmd.getId(); * <li> If the 'firstName' is not provided, we do not update it (setting to null) in the User POJO.
String apiKey = cmd.getApiKey(); * <li> If the 'firstName' is blank, we throw an {@link InvalidParameterValueException}.
String firstName = cmd.getFirstname(); * </ul>
String email = cmd.getEmail(); */
String lastName = cmd.getLastname(); protected void validateAndUpdateFirstNameIfNeeded(UpdateUserCmd updateUserCmd, UserVO user) {
String password = cmd.getPassword(); String firstName = updateUserCmd.getFirstname();
String secretKey = cmd.getSecretKey(); if (firstName != null) {
String timeZone = cmd.getTimezone(); if (StringUtils.isBlank(firstName)) {
String userName = cmd.getUsername(); throw new InvalidParameterValueException("Firstname cannot be empty.");
}
user.setFirstname(firstName);
}
}
return updateUser(id, firstName, lastName, email, userName, password, apiKey, secretKey, 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 (account.getType() == Account.ACCOUNT_TYPE_PROJECT) {
throw new InvalidParameterValueException("Unable to find user with ID: " + user.getUuid());
}
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;
}
/**
* 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");
}
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));
}
}
user.setApiKey(apiKey);
user.setSecretKey(secretKey);
}
/**
* 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();
UserVO user = _userDao.getUser(userId);
if (user == null) {
throw new InvalidParameterValueException("Unable to find user with id: " + userId);
}
return user;
} }
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_USER_DISABLE, eventDescription = "disabling User", async = true) @ActionEvent(eventType = EventTypes.EVENT_USER_DISABLE, eventDescription = "disabling User", async = true)
public UserAccount disableUser(long userId) { public UserAccount disableUser(long userId) {
Account caller = CallContext.current().getCallingAccount(); Account caller = getCurrentCallingAccount();
// Check if user exists in the system // Check if user exists in the system
User user = _userDao.findById(userId); User user = _userDao.findById(userId);
@ -1345,7 +1433,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@ActionEvent(eventType = EventTypes.EVENT_USER_ENABLE, eventDescription = "enabling User") @ActionEvent(eventType = EventTypes.EVENT_USER_ENABLE, eventDescription = "enabling User")
public UserAccount enableUser(final long userId) { public UserAccount enableUser(final long userId) {
Account caller = CallContext.current().getCallingAccount(); Account caller = getCurrentCallingAccount();
// Check if user exists in the system // Check if user exists in the system
final User user = _userDao.findById(userId); final User user = _userDao.findById(userId);
@ -1396,7 +1484,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_USER_LOCK, eventDescription = "locking User") @ActionEvent(eventType = EventTypes.EVENT_USER_LOCK, eventDescription = "locking User")
public UserAccount lockUser(long userId) { public UserAccount lockUser(long userId) {
Account caller = CallContext.current().getCallingAccount(); Account caller = getCurrentCallingAccount();
// Check if user with id exists in the system // Check if user with id exists in the system
User user = _userDao.findById(userId); User user = _userDao.findById(userId);
@ -1462,7 +1550,6 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_DELETE, eventDescription = "deleting account", async = true) @ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_DELETE, eventDescription = "deleting account", async = true)
// This method deletes the account
public boolean deleteUserAccount(long accountId) { public boolean deleteUserAccount(long accountId) {
CallContext ctx = CallContext.current(); CallContext ctx = CallContext.current();
@ -1528,7 +1615,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
} }
// Check if user performing the action is allowed to modify this account // 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); checkAccess(caller, AccessType.OperateEntry, true, account);
boolean success = enableAccount(account.getId()); boolean success = enableAccount(account.getId());
@ -1545,7 +1632,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_DISABLE, eventDescription = "locking account", async = true) @ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_DISABLE, eventDescription = "locking account", async = true)
public AccountVO lockAccount(String accountName, Long domainId, Long accountId) { public AccountVO lockAccount(String accountName, Long domainId, Long accountId) {
Account caller = CallContext.current().getCallingAccount(); Account caller = getCurrentCallingAccount();
Account account = null; Account account = null;
if (accountId != null) { if (accountId != null) {
@ -1575,7 +1662,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@Override @Override
@ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_DISABLE, eventDescription = "disabling account", async = true) @ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_DISABLE, eventDescription = "disabling account", async = true)
public AccountVO disableAccount(String accountName, Long domainId, Long accountId) throws ConcurrentOperationException, ResourceUnavailableException { public AccountVO disableAccount(String accountName, Long domainId, Long accountId) throws ConcurrentOperationException, ResourceUnavailableException {
Account caller = CallContext.current().getCallingAccount(); Account caller = getCurrentCallingAccount();
Account account = null; Account account = null;
if (accountId != null) { if (accountId != null) {
@ -1633,16 +1720,11 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
} }
// Check if user performing the action is allowed to modify this account // 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 // check if the given account name is unique in this domain for updating
Account duplicateAcccount = _accountDao.findActiveAccount(newAccountName, domainId); Account duplicateAcccount = _accountDao.findActiveAccount(newAccountName, domainId);
if (duplicateAcccount != null && duplicateAcccount.getId() != account.getId()) {// allow if (duplicateAcccount != null && duplicateAcccount.getId() != account.getId()) {
// same
// account
// to
// update
// itself
throw new InvalidParameterValueException( throw new InvalidParameterValueException(
"There already exists an account with the name:" + newAccountName + " in the domain:" + domainId + " with existing account id:" + duplicateAcccount.getId()); "There already exists an account with the name:" + newAccountName + " in the domain:" + domainId + " with existing account id:" + duplicateAcccount.getId());
} }
@ -1700,6 +1782,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
return _userDao.remove(deleteUserCmd.getId()); return _userDao.remove(deleteUserCmd.getId());
} }
@Override
@ActionEvent(eventType = EventTypes.EVENT_USER_MOVE, eventDescription = "moving User to a new account") @ActionEvent(eventType = EventTypes.EVENT_USER_MOVE, eventDescription = "moving User to a new account")
public boolean moveUser(MoveUserCmd cmd) { public boolean moveUser(MoveUserCmd cmd) {
final Long id = cmd.getId(); final Long id = cmd.getId();
@ -1713,17 +1796,18 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
return moveUser(user, newAccountId); return moveUser(user, newAccountId);
} }
@Override
public boolean moveUser(long id, Long domainId, long accountId) { public boolean moveUser(long id, Long domainId, long accountId) {
UserVO user = getValidUserVO(id); UserVO user = getValidUserVO(id);
Account oldAccount = _accountDao.findById(user.getAccountId()); Account oldAccount = _accountDao.findById(user.getAccountId());
checkAccountAndAccess(user, oldAccount); checkAccountAndAccess(user, oldAccount);
Account newAccount = _accountDao.findById(accountId); Account newAccount = _accountDao.findById(accountId);
checkIfNotMovingAcrossDomains(domainId, newAccount); checkIfNotMovingAcrossDomains(domainId, newAccount);
return moveUser(user , accountId); return moveUser(user, accountId);
} }
private boolean moveUser(UserVO user, long newAccountId) { 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 // 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 return true; // no need to create a new user object for this user
} }
@ -1734,7 +1818,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
UserVO newUser = new UserVO(user); UserVO newUser = new UserVO(user);
user.setExternalEntity(user.getUuid()); user.setExternalEntity(user.getUuid());
user.setUuid(UUID.randomUUID().toString()); user.setUuid(UUID.randomUUID().toString());
_userDao.update(user.getId(),user); _userDao.update(user.getId(), user);
newUser.setAccountId(newAccountId); newUser.setAccountId(newAccountId);
boolean success = _userDao.remove(user.getId()); boolean success = _userDao.remove(user.getId());
UserVO persisted = _userDao.persist(newUser); UserVO persisted = _userDao.persist(newUser);
@ -1746,7 +1830,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
private long getNewAccountId(long domainId, String accountName, Long accountId) { private long getNewAccountId(long domainId, String accountName, Long accountId) {
Account newAccount = null; Account newAccount = null;
if (StringUtils.isNotBlank(accountName)) { 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); s_logger.debug("Getting id for account by name '" + accountName + "' in domain " + domainId);
} }
newAccount = _accountDao.findEnabledAccount(accountName, domainId); newAccount = _accountDao.findEnabledAccount(accountName, domainId);
@ -1763,7 +1847,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
} }
private void checkIfNotMovingAcrossDomains(long domainId, Account newAccount) { private void checkIfNotMovingAcrossDomains(long domainId, Account newAccount) {
if(newAccount.getDomainId() != domainId) { if (newAccount.getDomainId() != domainId) {
// not in scope // not in scope
throw new InvalidParameterValueException("moving a user from an account in one domain to an account in annother domain is not supported!"); 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 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
throw new InvalidParameterValueException("Project users cannot be deleted or moved."); 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()); CallContext.current().putContextParameter(User.class, user.getUuid());
} }
@ -1995,8 +2079,8 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@Override @Override
@DB @DB
public AccountVO createAccount(final String accountName, final short accountType, final Long roleId, final Long domainId, final String networkDomain, public AccountVO createAccount(final String accountName, final short accountType, final Long roleId, final Long domainId, final String networkDomain, final Map<String, String> details,
final Map<String, String> details, final String uuid) { final String uuid) {
// Validate domain // Validate domain
Domain domain = _domainMgr.getDomain(domainId); Domain domain = _domainMgr.getDomain(domainId);
if (domain == null) { if (domain == null) {
@ -2064,8 +2148,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
}); });
} }
protected UserVO createUser(long accountId, String userName, String password, String firstName, String lastName, String email, String timezone, String userUUID, protected UserVO createUser(long accountId, String userName, String password, String firstName, String lastName, String email, String timezone, String userUUID, User.Source source) {
User.Source source) {
if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) {
s_logger.debug("Creating user: " + userName + ", accountId: " + accountId + " timezone:" + timezone); s_logger.debug("Creating user: " + userName + ", accountId: " + accountId + " timezone:" + timezone);
} }
@ -2098,8 +2181,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
} }
@Override @Override
public UserAccount authenticateUser(final String username, final String password, final Long domainId, final InetAddress loginIpAddress, final Map<String, Object[]> public UserAccount authenticateUser(final String username, final String password, final Long domainId, final InetAddress loginIpAddress, final Map<String, Object[]> requestParameters) {
requestParameters) {
UserAccount user = null; UserAccount user = null;
if (password != null && !password.isEmpty()) { if (password != null && !password.isEmpty()) {
user = getUserAccount(username, password, domainId, requestParameters); user = getUserAccount(username, password, domainId, requestParameters);
@ -2211,10 +2293,10 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
// We authenticated successfully by now, let's check if we are allowed to login from the ip address the reqest comes from // 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 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 // 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(); final Boolean ApiSourceCidrChecksEnabled = ApiServiceConfiguration.ApiSourceCidrChecksEnabled.value();
if (ApiSourceCidrChecksEnabled) { if (ApiSourceCidrChecksEnabled) {
@ -2222,10 +2304,9 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
// Block when is not in the list of allowed IPs // Block when is not in the list of allowed IPs
if (!NetUtils.isIpInCidrList(loginIpAddress, accessAllowedCidrs.split(","))) { if (!NetUtils.isIpInCidrList(loginIpAddress, accessAllowedCidrs.split(","))) {
s_logger.warn("Request by account '" + account.toString() + "' was denied since " + loginIpAddress.toString().replaceAll("/","") s_logger.warn("Request by account '" + account.toString() + "' was denied since " + loginIpAddress.toString().replaceAll("/", "") + " does not match " + accessAllowedCidrs);
+ " does not match " + accessAllowedCidrs);
throw new CloudAuthenticationException("Failed to authenticate user '" + username + "' in domain '" + domain.getPath() + "' from ip " 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 class AccountManagerImpl extends ManagerBase implements AccountManager, M
s_logger.debug("User: " + username + " in domain " + domainId + " has successfully logged in"); s_logger.debug("User: " + username + " in domain " + domainId + " has successfully logged in");
} }
ActionEventUtils.onActionEvent(user.getId(), user.getAccountId(), user.getDomainId(), EventTypes.EVENT_USER_LOGIN, ActionEventUtils.onActionEvent(user.getId(), user.getAccountId(), user.getDomainId(), EventTypes.EVENT_USER_LOGIN, "user has logged in from IP Address " + loginIpAddress);
"user has logged in from IP Address " + loginIpAddress);
return user; return user;
} else { } else {
@ -2285,12 +2365,12 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
if (s_logger.isInfoEnabled()) { if (s_logger.isInfoEnabled()) {
s_logger.info("User " + username + " in domain " + domainName + " is disabled/locked (or account is disabled/locked)"); s_logger.info("User " + username + " in domain " + domainName + " is disabled/locked (or account is disabled/locked)");
} }
throw new CloudAuthenticationException( throw new CloudAuthenticationException("User " + username + " (or their account) in domain " + domainName + " is disabled/locked. Please contact the administrator.");
"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 // 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); updateLoginAttempts(userAccount.getId(), 0, false);
}
return userAccount; return userAccount;
} else { } else {
@ -2351,7 +2431,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@DB @DB
@ActionEvent(eventType = EventTypes.EVENT_REGISTER_FOR_SECRET_API_KEY, eventDescription = "register for the developer API keys") @ActionEvent(eventType = EventTypes.EVENT_REGISTER_FOR_SECRET_API_KEY, eventDescription = "register for the developer API keys")
public String[] createApiKeyAndSecretKey(RegisterCmd cmd) { public String[] createApiKeyAndSecretKey(RegisterCmd cmd) {
Account caller = CallContext.current().getCallingAccount(); Account caller = getCurrentCallingAccount();
final Long userId = cmd.getId(); final Long userId = cmd.getId();
User user = getUserIncludingRemoved(userId); User user = getUserIncludingRemoved(userId);
@ -2668,8 +2748,9 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
@Override @Override
public List<String> listAclGroupsByAccount(Long accountId) { public List<String> listAclGroupsByAccount(Long accountId) {
if (_querySelectors == null || _querySelectors.size() == 0) if (_querySelectors == null || _querySelectors.size() == 0) {
return new ArrayList<String>(); return new ArrayList<String>();
}
QuerySelector qs = _querySelectors.get(0); QuerySelector qs = _querySelectors.get(0);
return qs.listAclGroupsByAccount(accountId); return qs.listAclGroupsByAccount(accountId);
@ -2692,8 +2773,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
if (!enabledOnly || account.getState() == Account.State.enabled) { if (!enabledOnly || account.getState() == Account.State.enabled) {
return account.getId(); return account.getId();
} else { } else {
throw new PermissionDeniedException( throw new PermissionDeniedException("Can't add resources to the account id=" + account.getId() + " in state=" + account.getState() + " as it's no longer active");
"Can't add resources to the account id=" + account.getId() + " in state=" + account.getState() + " as it's no longer active");
} }
} else { } else {
// idList is not used anywhere, so removed it now // idList is not used anywhere, so removed it now

View File

@ -22,67 +22,100 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; 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.api.command.admin.user.GetUserKeysCmd;
import org.apache.cloudstack.context.CallContext;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import com.cloud.vm.snapshot.VMSnapshotVO; 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.mockito.runners.MockitoJUnitRunner;
import com.cloud.acl.DomainChecker;
import com.cloud.domain.Domain; import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO; import com.cloud.domain.DomainVO;
import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceUnavailableException; 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.user.Account.State;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.UserVmManagerImpl; import com.cloud.vm.UserVmManagerImpl;
import com.cloud.vm.UserVmVO; import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.snapshot.VMSnapshotVO;
@RunWith(MockitoJUnitRunner.class)
public class AccountManagerImplTest extends AccountManagetImplTestBase { 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 @Mock
UserVmManagerImpl _vmMgr; private UpdateUserCmd UpdateUserCmdMock;
@Test private long userVoIdMock = 111l;
public void disableAccountNotexisting() @Mock
throws ConcurrentOperationException, ResourceUnavailableException { private UserVO userVoMock;
Mockito.when(_accountDao.findById(42l)).thenReturn(null);
Assert.assertTrue(accountManager.disableAccount(42)); private long accountMockId = 100l;
@Mock
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 @Test
public void disableAccountDisabled() throws ConcurrentOperationException, public void disableAccountNotexisting() throws ConcurrentOperationException, ResourceUnavailableException {
ResourceUnavailableException { Mockito.when(accountDaoMock.findById(42l)).thenReturn(null);
Assert.assertTrue(accountManagerImpl.disableAccount(42));
}
@Test
public void disableAccountDisabled() throws ConcurrentOperationException, ResourceUnavailableException {
AccountVO disabledAccount = new AccountVO(); AccountVO disabledAccount = new AccountVO();
disabledAccount.setState(State.disabled); disabledAccount.setState(State.disabled);
Mockito.when(_accountDao.findById(42l)).thenReturn(disabledAccount); Mockito.when(accountDaoMock.findById(42l)).thenReturn(disabledAccount);
Assert.assertTrue(accountManager.disableAccount(42)); Assert.assertTrue(accountManagerImpl.disableAccount(42));
} }
@Test @Test
public void disableAccount() throws ConcurrentOperationException, public void disableAccount() throws ConcurrentOperationException, ResourceUnavailableException {
ResourceUnavailableException {
AccountVO account = new AccountVO(); AccountVO account = new AccountVO();
account.setState(State.enabled); account.setState(State.enabled);
Mockito.when(_accountDao.findById(42l)).thenReturn(account); Mockito.when(accountDaoMock.findById(42l)).thenReturn(account);
Mockito.when(_accountDao.createForUpdate()).thenReturn(new AccountVO()); Mockito.when(accountDaoMock.createForUpdate()).thenReturn(new AccountVO());
Mockito.when( Mockito.when(accountDaoMock.update(Mockito.eq(42l), Mockito.any(AccountVO.class))).thenReturn(true);
_accountDao.update(Mockito.eq(42l), Mockito.when(_vmDao.listByAccountId(42l)).thenReturn(Arrays.asList(Mockito.mock(VMInstanceVO.class)));
Mockito.any(AccountVO.class))).thenReturn(true); Assert.assertTrue(accountManagerImpl.disableAccount(42));
Mockito.when(_vmDao.listByAccountId(42l)).thenReturn( Mockito.verify(accountDaoMock, Mockito.atLeastOnce()).update(Mockito.eq(42l), Mockito.any(AccountVO.class));
Arrays.asList(Mockito.mock(VMInstanceVO.class)));
Assert.assertTrue(accountManager.disableAccount(42));
Mockito.verify(_accountDao, Mockito.atLeastOnce()).update(
Mockito.eq(42l), Mockito.any(AccountVO.class));
} }
@Test @Test
@ -90,20 +123,12 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase {
AccountVO account = new AccountVO(); AccountVO account = new AccountVO();
account.setId(42l); account.setId(42l);
DomainVO domain = new DomainVO(); DomainVO domain = new DomainVO();
Mockito.when(_accountDao.findById(42l)).thenReturn(account); Mockito.when(accountDaoMock.findById(42l)).thenReturn(account);
Mockito.when( Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class), Mockito.anyString())).thenReturn(true);
securityChecker.checkAccess(Mockito.any(Account.class), Mockito.when(accountDaoMock.remove(42l)).thenReturn(true);
Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class), Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l)).thenReturn(true);
Mockito.anyString()))
.thenReturn(true);
Mockito.when(_accountDao.remove(42l)).thenReturn(true);
Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l))
.thenReturn(true);
Mockito.when(_domainMgr.getDomain(Mockito.anyLong())).thenReturn(domain); Mockito.when(_domainMgr.getDomain(Mockito.anyLong())).thenReturn(domain);
Mockito.when( Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(Domain.class))).thenReturn(true);
securityChecker.checkAccess(Mockito.any(Account.class),
Mockito.any(Domain.class)))
.thenReturn(true);
Mockito.when(_vmSnapshotDao.listByAccountId(Mockito.anyLong())).thenReturn(new ArrayList<VMSnapshotVO>()); Mockito.when(_vmSnapshotDao.listByAccountId(Mockito.anyLong())).thenReturn(new ArrayList<VMSnapshotVO>());
List<SSHKeyPairVO> sshkeyList = new ArrayList<SSHKeyPairVO>(); List<SSHKeyPairVO> sshkeyList = new ArrayList<SSHKeyPairVO>();
@ -113,10 +138,9 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase {
Mockito.when(_sshKeyPairDao.listKeyPairs(Mockito.anyLong(), Mockito.anyLong())).thenReturn(sshkeyList); Mockito.when(_sshKeyPairDao.listKeyPairs(Mockito.anyLong(), Mockito.anyLong())).thenReturn(sshkeyList);
Mockito.when(_sshKeyPairDao.remove(Mockito.anyLong())).thenReturn(true); 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 // assert that this was a clean delete
Mockito.verify(_accountDao, Mockito.never()).markForCleanup( Mockito.verify(accountDaoMock, Mockito.never()).markForCleanup(Mockito.eq(42l));
Mockito.eq(42l));
} }
@Test @Test
@ -124,33 +148,20 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase {
AccountVO account = new AccountVO(); AccountVO account = new AccountVO();
account.setId(42l); account.setId(42l);
DomainVO domain = new DomainVO(); DomainVO domain = new DomainVO();
Mockito.when(_accountDao.findById(42l)).thenReturn(account); Mockito.when(accountDaoMock.findById(42l)).thenReturn(account);
Mockito.when( Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class), Mockito.anyString())).thenReturn(true);
securityChecker.checkAccess(Mockito.any(Account.class), Mockito.when(accountDaoMock.remove(42l)).thenReturn(true);
Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class), Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l)).thenReturn(true);
Mockito.anyString())) Mockito.when(_userVmDao.listByAccountId(42l)).thenReturn(Arrays.asList(Mockito.mock(UserVmVO.class)));
.thenReturn(true); Mockito.when(_vmMgr.expunge(Mockito.any(UserVmVO.class), Mockito.anyLong(), Mockito.any(Account.class))).thenReturn(false);
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(_domainMgr.getDomain(Mockito.anyLong())).thenReturn(domain); Mockito.when(_domainMgr.getDomain(Mockito.anyLong())).thenReturn(domain);
Mockito.when( Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(Domain.class))).thenReturn(true);
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 // assert that this was NOT a clean delete
Mockito.verify(_accountDao, Mockito.atLeastOnce()).markForCleanup( Mockito.verify(accountDaoMock, Mockito.atLeastOnce()).markForCleanup(Mockito.eq(42l));
Mockito.eq(42l));
} }
@Test @Test
public void testAuthenticateUser() throws UnknownHostException { public void testAuthenticateUser() throws UnknownHostException {
Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> successAuthenticationPair = new Pair<>(true, null); Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> successAuthenticationPair = new Pair<>(true, null);
@ -160,21 +171,21 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase {
UserAccountVO userAccountVO = new UserAccountVO(); UserAccountVO userAccountVO = new UserAccountVO();
userAccountVO.setSource(User.Source.UNKNOWN); userAccountVO.setSource(User.Source.UNKNOWN);
userAccountVO.setState(Account.State.disabled.toString()); 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", "fail", 1L, null)).thenReturn(failureAuthenticationPair);
Mockito.when(userAuthenticator.authenticate("test", null, 1L, null)).thenReturn(successAuthenticationPair); Mockito.when(userAuthenticator.authenticate("test", null, 1L, null)).thenReturn(successAuthenticationPair);
Mockito.when(userAuthenticator.authenticate("test", "", 1L, null)).thenReturn(successAuthenticationPair); Mockito.when(userAuthenticator.authenticate("test", "", 1L, null)).thenReturn(successAuthenticationPair);
//Test for incorrect password. authentication should fail //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); Assert.assertNull(userAccount);
//Test for null password. authentication should fail //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); Assert.assertNull(userAccount);
//Test for empty password. authentication should fail //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); Assert.assertNull(userAccount);
//Verifying that the authentication method is only called when password is specified //Verifying that the authentication method is only called when password is specified
@ -183,38 +194,509 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase {
Mockito.verify(userAuthenticator, Mockito.never()).authenticate("test", "", 1L, null); Mockito.verify(userAuthenticator, Mockito.never()).authenticate("test", "", 1L, null);
} }
@Mock @Test(expected = PermissionDeniedException.class)
AccountVO callingAccount; public void testgetUserCmd() {
@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(){
CallContext.register(callingUser, callingAccount); // Calling account is user account i.e normal account CallContext.register(callingUser, callingAccount); // Calling account is user account i.e normal account
Mockito.when(_listkeyscmd.getID()).thenReturn(1L); Mockito.when(_listkeyscmd.getID()).thenReturn(1L);
Mockito.when(accountManager.getActiveUser(1L)).thenReturn(_user); Mockito.when(accountManagerImpl.getActiveUser(1L)).thenReturn(_user);
Mockito.when(accountManager.getUserAccountById(1L)).thenReturn(userAccountVO); Mockito.when(accountManagerImpl.getUserAccountById(1L)).thenReturn(userAccountVO);
Mockito.when(userAccountVO.getAccountId()).thenReturn(1L); 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(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(accountService.isNormalUser(Mockito.anyLong())).thenReturn(Boolean.TRUE);
Mockito.when(_account.getAccountId()).thenReturn(2L); Mockito.when(accountMock.getAccountId()).thenReturn(2L);
accountManager.getKeys(_listkeyscmd); 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());
}
@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);
}
}
} }

View File

@ -16,12 +16,12 @@
// under the License. // under the License.
package com.cloud.user; 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.mock;
import static org.mockito.Mockito.any; import static org.mockito.Mockito.when;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.anyBoolean;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -52,13 +52,12 @@ import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.CloudException; import com.cloud.exception.CloudException;
import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConcurrentOperationException;
import com.cloud.service.ServiceOfferingVO; import com.cloud.service.ServiceOfferingVO;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.Volume.Type; import com.cloud.storage.Volume.Type;
import com.cloud.storage.VolumeVO;
import com.cloud.vm.UserVmManagerImpl; import com.cloud.vm.UserVmManagerImpl;
import com.cloud.vm.UserVmVO; import com.cloud.vm.UserVmVO;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplTestBase { public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplTestBase {
private static final Long ACCOUNT_ID = 1l; private static final Long ACCOUNT_ID = 1l;
@ -70,12 +69,10 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
Map<String, Object> oldFields = new HashMap<>(); Map<String, Object> oldFields = new HashMap<>();
UserVmVO vm = mock(UserVmVO.class); UserVmVO vm = mock(UserVmVO.class);
// Configures the static fields of the UsageEventUtils class, Storing the // Configures the static fields of the UsageEventUtils class, Storing the
// previous values to be restored during the cleanup phase, to avoid // previous values to be restored during the cleanup phase, to avoid
// interference with other unit tests. // interference with other unit tests.
protected UsageEventUtils setupUsageUtils() throws NoSuchMethodException, SecurityException, IllegalAccessException, protected UsageEventUtils setupUsageUtils() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
IllegalArgumentException, InvocationTargetException {
_usageEventDao = new MockUsageEventDao(); _usageEventDao = new MockUsageEventDao();
UsageEventUtils utils = new UsageEventUtils(); UsageEventUtils utils = new UsageEventUtils();
@ -93,8 +90,7 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
Field staticField = UsageEventUtils.class.getDeclaredField("s_" + fieldName); Field staticField = UsageEventUtils.class.getDeclaredField("s_" + fieldName);
staticField.setAccessible(true); staticField.setAccessible(true);
oldFields.put(f.getName(), staticField.get(null)); oldFields.put(f.getName(), staticField.get(null));
f.set(utils, f.set(utils, this.getClass().getSuperclass().getDeclaredField("_" + fieldName).get(this));
this.getClass().getSuperclass().getDeclaredField("_" + fieldName).get(this));
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -106,14 +102,12 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
return utils; return utils;
} }
protected void defineMocksBehavior() throws AgentUnavailableException, ConcurrentOperationException, CloudException {
protected void defineMocksBehavior()
throws AgentUnavailableException, ConcurrentOperationException, CloudException {
AccountVO account = new AccountVO(); AccountVO account = new AccountVO();
account.setId(ACCOUNT_ID); account.setId(ACCOUNT_ID);
when(_accountDao.remove(ACCOUNT_ID)).thenReturn(true); when(accountDaoMock.remove(ACCOUNT_ID)).thenReturn(true);
when(_accountDao.findById(ACCOUNT_ID)).thenReturn(account); when(accountDaoMock.findById(ACCOUNT_ID)).thenReturn(account);
DomainVO domain = new DomainVO(); DomainVO domain = new DomainVO();
VirtualMachineEntity vmEntity = mock(VirtualMachineEntity.class); VirtualMachineEntity vmEntity = mock(VirtualMachineEntity.class);
@ -128,8 +122,7 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
List<VolumeVO> volumes = new ArrayList<>(); List<VolumeVO> volumes = new ArrayList<>();
volumes.add(vol); volumes.add(vol);
when(securityChecker.checkAccess(any(Account.class), any(ControlledEntity.class), any(AccessType.class), when(securityChecker.checkAccess(any(Account.class), any(ControlledEntity.class), any(AccessType.class), anyString())).thenReturn(true);
anyString())).thenReturn(true);
when(_userVmDao.findById(anyLong())).thenReturn(vm); when(_userVmDao.findById(anyLong())).thenReturn(vm);
when(_userVmDao.listByAccountId(ACCOUNT_ID)).thenReturn(Arrays.asList(vm)); when(_userVmDao.listByAccountId(ACCOUNT_ID)).thenReturn(Arrays.asList(vm));
@ -142,8 +135,7 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
when(offering.getId()).thenReturn(1l); when(offering.getId()).thenReturn(1l);
when(offering.getCpu()).thenReturn(500); when(offering.getCpu()).thenReturn(500);
when(offering.getRamSize()).thenReturn(500); when(offering.getRamSize()).thenReturn(500);
when(_serviceOfferingDao.findByIdIncludingRemoved(anyLong(), anyLong())) when(_serviceOfferingDao.findByIdIncludingRemoved(anyLong(), anyLong())).thenReturn(offering);
.thenReturn(offering);
when(_domainMgr.getDomain(anyLong())).thenReturn(domain); when(_domainMgr.getDomain(anyLong())).thenReturn(domain);
@ -152,9 +144,8 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
} }
@Before @Before
public void init() public void init() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, AgentUnavailableException,
throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, ConcurrentOperationException, CloudException {
InvocationTargetException, AgentUnavailableException, ConcurrentOperationException, CloudException {
setupUsageUtils(); setupUsageUtils();
defineMocksBehavior(); defineMocksBehavior();
@ -175,22 +166,19 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
method.invoke(utils); 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()) when(vm.getState()).thenReturn(vmDestroyedPrior ? VirtualMachine.State.Destroyed : VirtualMachine.State.Running);
.thenReturn(vmDestroyedPrior ? VirtualMachine.State.Destroyed : VirtualMachine.State.Running);
when(vm.getRemoved()).thenReturn(vmDestroyedPrior ? new Date() : null); when(vm.getRemoved()).thenReturn(vmDestroyedPrior ? new Date() : null);
accountManager.deleteUserAccount(ACCOUNT_ID); accountManagerImpl.deleteUserAccount(ACCOUNT_ID);
return _usageEventDao.listAll(); return _usageEventDao.listAll();
} }
@Test @Test
// If the VM is alerady destroyed, no events should get emitted // If the VM is alerady destroyed, no events should get emitted
public void destroyedVMRootVolumeUsageEvent() throws SecurityException, IllegalArgumentException, public void destroyedVMRootVolumeUsageEvent()
ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException { throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(true); List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(true);
Assert.assertEquals(0, emittedEvents.size()); Assert.assertEquals(0, emittedEvents.size());
} }
@ -198,8 +186,8 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
@Test @Test
// If the VM is running, we should see one emitted event for the root // If the VM is running, we should see one emitted event for the root
// volume. // volume.
public void runningVMRootVolumeUsageEvent() throws SecurityException, IllegalArgumentException, public void runningVMRootVolumeUsageEvent()
ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException { throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(false); List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(false);
Assert.assertEquals(1, emittedEvents.size()); Assert.assertEquals(1, emittedEvents.size());
UsageEventVO event = emittedEvents.get(0); UsageEventVO event = emittedEvents.get(0);

View File

@ -21,8 +21,6 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.inject.Inject;
import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao; import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.context.CallContext;
@ -34,9 +32,10 @@ import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.ConfigurationManager;
import com.cloud.configuration.dao.ResourceCountDao; import com.cloud.configuration.dao.ResourceCountDao;
@ -84,17 +83,17 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDao;
public class AccountManagetImplTestBase { public class AccountManagetImplTestBase {
@Mock @Mock
AccountDao _accountDao; AccountDao accountDaoMock;
@Mock @Mock
ConfigurationDao _configDao; ConfigurationDao _configDao;
@Mock @Mock
ResourceCountDao _resourceCountDao; ResourceCountDao _resourceCountDao;
@Mock @Mock
UserDao _userDao; UserDao userDaoMock;
@Mock @Mock
InstanceGroupDao _vmGroupDao; InstanceGroupDao _vmGroupDao;
@Mock @Mock
UserAccountDao _userAccountDao; UserAccountDao userAccountDaoMock;
@Mock @Mock
VolumeDao _volumeDao; VolumeDao _volumeDao;
@Mock @Mock
@ -193,27 +192,16 @@ public class AccountManagetImplTestBase {
@Mock @Mock
SSHKeyPairDao _sshKeyPairDao; SSHKeyPairDao _sshKeyPairDao;
AccountManagerImpl accountManager; @Spy
@InjectMocks
UsageEventDao _usageEventDao = new MockUsageEventDao(); AccountManagerImpl accountManagerImpl;
@Mock
UsageEventDao _usageEventDao;
@Before @Before
public void setup() public void setup() {
throws NoSuchFieldException, SecurityException, accountManagerImpl.setUserAuthenticators(Arrays.asList(userAuthenticator));
IllegalArgumentException, IllegalAccessException { accountManagerImpl.setSecurityCheckers(Arrays.asList(securityChecker));
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));
CallContext.register(callingUser, callingAccount); CallContext.register(callingUser, callingAccount);
} }
@ -231,14 +219,4 @@ public class AccountManagetImplTestBase {
} }
return fields; 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;
}
} }

View File

@ -157,13 +157,6 @@ public class MockAccountManagerImpl extends ManagerBase implements Manager, Acco
return null; 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 @Override
public Account getActiveAccountById(long accountId) { public Account getActiveAccountById(long accountId) {
// TODO Auto-generated method stub // TODO Auto-generated method stub

View File

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

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "الشبكات", "label.networks": "الشبكات",
"label.new": "جديد", "label.new": "جديد",
"label.new.password": "New Password", "label.new.password": "New Password",
"label.current.password": "Current Password",
"label.new.project": "مشروع جديد", "label.new.project": "مشروع جديد",
"label.new.ssh.key.pair": "New SSH Key Pair", "label.new.ssh.key.pair": "New SSH Key Pair",
"label.new.vm": "New VM", "label.new.vm": "New VM",

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "Xarxes", "label.networks": "Xarxes",
"label.new": "Nou", "label.new": "Nou",
"label.new.password": "New Password", "label.new.password": "New Password",
"label.current.password": "Current Password",
"label.new.project": "Nou projecte", "label.new.project": "Nou projecte",
"label.new.ssh.key.pair": "New SSH Key Pair", "label.new.ssh.key.pair": "New SSH Key Pair",
"label.new.vm": "Nova MV", "label.new.vm": "Nova MV",

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "Netzwerke", "label.networks": "Netzwerke",
"label.new": "Neu", "label.new": "Neu",
"label.new.password": "Neues Passwort", "label.new.password": "Neues Passwort",
"label.current.password": "Current Password",
"label.new.project": "Neues Projekt", "label.new.project": "Neues Projekt",
"label.new.ssh.key.pair": "Neues SSH-Schlüsselpaar", "label.new.ssh.key.pair": "Neues SSH-Schlüsselpaar",
"label.new.vm": "Neue VM", "label.new.vm": "Neue VM",

View File

@ -1186,6 +1186,7 @@ var dictionary = {
"label.networks":"Networks", "label.networks":"Networks",
"label.new":"New", "label.new":"New",
"label.new.password":"New Password", "label.new.password":"New Password",
"label.current.password": "Current Password",
"label.new.project":"New Project", "label.new.project":"New Project",
"label.new.ssh.key.pair":"New SSH Key Pair", "label.new.ssh.key.pair":"New SSH Key Pair",
"label.new.vm":"New VM", "label.new.vm":"New VM",

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "Redes", "label.networks": "Redes",
"label.new": "Nuevo", "label.new": "Nuevo",
"label.new.password": "Nueva contraseña", "label.new.password": "Nueva contraseña",
"label.current.password": "Current Password",
"label.new.project": "Nuevo Proyecto", "label.new.project": "Nuevo Proyecto",
"label.new.ssh.key.pair": "Nuevo Par de Claves SSH", "label.new.ssh.key.pair": "Nuevo Par de Claves SSH",
"label.new.vm": "Nueva MV", "label.new.vm": "Nueva MV",

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "Réseaux", "label.networks": "Réseaux",
"label.new": "Nouveau", "label.new": "Nouveau",
"label.new.password": "Nouveau mot de passe", "label.new.password": "Nouveau mot de passe",
"label.current.password": "Current Password",
"label.new.project": "Nouveau projet", "label.new.project": "Nouveau projet",
"label.new.ssh.key.pair": "Nouvelle bi-clé SSH", "label.new.ssh.key.pair": "Nouvelle bi-clé SSH",
"label.new.vm": "Nouvelle VM", "label.new.vm": "Nouvelle VM",

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "Hálózatok", "label.networks": "Hálózatok",
"label.new": "Új", "label.new": "Új",
"label.new.password": "Új jelszó", "label.new.password": "Új jelszó",
"label.current.password": "Current Password",
"label.new.project": "Új projekt", "label.new.project": "Új projekt",
"label.new.ssh.key.pair": "Új SSH kulcspár", "label.new.ssh.key.pair": "Új SSH kulcspár",
"label.new.vm": "Új VM", "label.new.vm": "Új VM",

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "Reti", "label.networks": "Reti",
"label.new": "Nuovo", "label.new": "Nuovo",
"label.new.password": "New Password", "label.new.password": "New Password",
"label.current.password": "Current Password",
"label.new.project": "Nuovo Progetto", "label.new.project": "Nuovo Progetto",
"label.new.ssh.key.pair": "New SSH Key Pair", "label.new.ssh.key.pair": "New SSH Key Pair",
"label.new.vm": "Nuova VM", "label.new.vm": "Nuova VM",

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "ネットワーク", "label.networks": "ネットワーク",
"label.new": "新規", "label.new": "新規",
"label.new.password": "新しいパスワード", "label.new.password": "新しいパスワード",
"label.current.password": "Current Password",
"label.new.project": "新しいプロジェクト", "label.new.project": "新しいプロジェクト",
"label.new.ssh.key.pair": "新しい SSH キーペア", "label.new.ssh.key.pair": "新しい SSH キーペア",
"label.new.vm": "新しい VM", "label.new.vm": "新しい VM",

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "네트워크", "label.networks": "네트워크",
"label.new": "신규", "label.new": "신규",
"label.new.password": "새로운 암호", "label.new.password": "새로운 암호",
"label.current.password": "Current Password",
"label.new.project": "새 프로젝트", "label.new.project": "새 프로젝트",
"label.new.ssh.key.pair": "New SSH Key Pair", "label.new.ssh.key.pair": "New SSH Key Pair",
"label.new.vm": "새 VM", "label.new.vm": "새 VM",

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "Nettverk", "label.networks": "Nettverk",
"label.new": "Ny", "label.new": "Ny",
"label.new.password": "Nytt passord", "label.new.password": "Nytt passord",
"label.current.password": "Current Password",
"label.new.project": "Nytt prosjekt", "label.new.project": "Nytt prosjekt",
"label.new.ssh.key.pair": "Nytt SSH-nøkkelpar", "label.new.ssh.key.pair": "Nytt SSH-nøkkelpar",
"label.new.vm": "Ny VM", "label.new.vm": "Ny VM",

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "Netwerken", "label.networks": "Netwerken",
"label.new": "Nieuw", "label.new": "Nieuw",
"label.new.password": "Nieuw wachtwoord", "label.new.password": "Nieuw wachtwoord",
"label.current.password": "Current Password",
"label.new.project": "Nieuw Project", "label.new.project": "Nieuw Project",
"label.new.ssh.key.pair": "nieuw SSH sleutelpaar", "label.new.ssh.key.pair": "nieuw SSH sleutelpaar",
"label.new.vm": "Nieuwe VM", "label.new.vm": "Nieuwe VM",

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "Sieci", "label.networks": "Sieci",
"label.new": "Nowy", "label.new": "Nowy",
"label.new.password": "New Password", "label.new.password": "New Password",
"label.current.password": "Current Password",
"label.new.project": "Nowy projekt", "label.new.project": "Nowy projekt",
"label.new.ssh.key.pair": "New SSH Key Pair", "label.new.ssh.key.pair": "New SSH Key Pair",
"label.new.vm": "New VM", "label.new.vm": "New VM",

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "Redes", "label.networks": "Redes",
"label.new": "Novo", "label.new": "Novo",
"label.new.password": "Nova Senha", "label.new.password": "Nova Senha",
"label.current.password": "Senha Antiga",
"label.new.project": "Novo Projeto", "label.new.project": "Novo Projeto",
"label.new.ssh.key.pair": "Novo par de chaves SSH", "label.new.ssh.key.pair": "Novo par de chaves SSH",
"label.new.vm": "Nova VM", "label.new.vm": "Nova VM",

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "Сети", "label.networks": "Сети",
"label.new": "Создать", "label.new": "Создать",
"label.new.password": "Новый пароль", "label.new.password": "Новый пароль",
"label.current.password": "Current Password",
"label.new.project": "Новый проект", "label.new.project": "Новый проект",
"label.new.ssh.key.pair": "New SSH Key Pair", "label.new.ssh.key.pair": "New SSH Key Pair",
"label.new.vm": "Новая ВМ", "label.new.vm": "Новая ВМ",

View File

@ -1151,6 +1151,7 @@ var dictionary = {
"label.networks": "网络", "label.networks": "网络",
"label.new": "新建", "label.new": "新建",
"label.new.password": "新密码", "label.new.password": "新密码",
"label.current.password": "Current Password",
"label.new.project": "新建项目", "label.new.project": "新建项目",
"label.new.ssh.key.pair": "新SSH密钥对", "label.new.ssh.key.pair": "新SSH密钥对",
"label.new.vm": "新建 VM", "label.new.vm": "新建 VM",

View File

@ -1476,6 +1476,14 @@
form: { form: {
title: 'label.action.change.password', title: 'label.action.change.password',
fields: { fields: {
currentPassword: {
label: 'label.current.password',
isPassword: true,
validation: {
required: !(isAdmin() || isDomainAdmin())
},
id: 'currentPassword'
},
newPassword: { newPassword: {
label: 'label.new.password', label: 'label.new.password',
isPassword: true, isPassword: true,
@ -1496,13 +1504,13 @@
}, },
after: function(args) { after: function(args) {
start(); start();
var currentPassword = args.data.currentPassword;
var password = args.data.newPassword; var password = args.data.newPassword;
$.ajax({ $.ajax({
url: createURL('updateUser'), url: createURL('updateUser'),
data: { data: {
id: context.users[0].id, id: context.users[0].id,
currentPassword: currentPassword,
password: password password: password
}, },
type: "POST", type: "POST",
@ -1515,6 +1523,9 @@
}); });
} }
}); });
if(isAdmin() || isDomainAdmin()){
$('div[rel=currentPassword]').hide();
}
} else { } else {
cloudStack.dialog.notice({ message: _l('error.could.not.change.your.password.because.non.native.user') }); cloudStack.dialog.notice({ message: _l('error.could.not.change.your.password.because.non.native.user') });
} }