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

View File

@ -215,8 +215,8 @@ public class ApiConstants {
public static final String PARENT_DOMAIN_ID = "parentdomainid";
public static final String PARENT_TEMPLATE_ID = "parenttemplateid";
public static final String PASSWORD = "password";
public static final String CURRENT_PASSWORD = "currentpassword";
public static final String SHOULD_UPDATE_PASSWORD = "update_passwd_on_host";
public static final String NEW_PASSWORD = "new_password";
public static final String PASSWORD_ENABLED = "passwordenabled";
public static final String SSHKEY_ENABLED = "sshkeyenabled";
public static final String PATH = "path";
@ -729,4 +729,4 @@ public class ApiConstants {
public enum DomainDetails {
all, resource, min;
}
}
}

View File

@ -34,7 +34,7 @@ import com.cloud.user.User;
import com.cloud.user.UserAccount;
@APICommand(name = "updateUser", description = "Updates a user account", responseObject = UserResponse.class,
requestHasSensitiveInfo = true, responseHasSensitiveInfo = true)
requestHasSensitiveInfo = true, responseHasSensitiveInfo = true)
public class UpdateUserCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(UpdateUserCmd.class.getName());
@ -65,20 +65,22 @@ public class UpdateUserCmd extends BaseCmd {
acceptedOnAdminPort = false)
private String password;
@Parameter(name = ApiConstants.CURRENT_PASSWORD, type = CommandType.STRING, description = "Current password that was being used by the user. You must inform the current password when updating the password.", acceptedOnAdminPort = false)
private String currentPassword;
@Parameter(name = ApiConstants.SECRET_KEY, type = CommandType.STRING, description = "The secret key for the user. Must be specified with userApiKey")
private String secretKey;
@Parameter(name = ApiConstants.TIMEZONE,
type = CommandType.STRING,
description = "Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.")
type = CommandType.STRING,
description = "Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.")
private String timezone;
@Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, description = "Unique username")
private String username;
@Inject
RegionService _regionService;
private RegionService _regionService;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
@ -108,6 +110,10 @@ public class UpdateUserCmd extends BaseCmd {
return password;
}
public String getCurrentPassword() {
return currentPassword;
}
public String getSecretKey() {
return secretKey;
}
@ -152,4 +158,20 @@ public class UpdateUserCmd extends BaseCmd {
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;
}
@Override
public UserAccount updateUser(Long userId, String firstName, String lastName, String email, String userName, String password, String apiKey, String secretKey,
String timeZone) {
// TODO Auto-generated method stub
return null;
}
@Override
public User getActiveUser(long arg0) {
return _systemUser;

View File

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

View File

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

View File

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

View File

@ -22,67 +22,100 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.cloud.acl.DomainChecker;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.server.auth.UserAuthenticator;
import com.cloud.utils.Pair;
import org.apache.cloudstack.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.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.DomainVO;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.server.auth.UserAuthenticator;
import com.cloud.server.auth.UserAuthenticator.ActionOnFailedAuthentication;
import com.cloud.user.Account.State;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.UserVmManagerImpl;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.snapshot.VMSnapshotVO;
@RunWith(MockitoJUnitRunner.class)
public class AccountManagerImplTest extends AccountManagetImplTestBase {
@Mock
private UserVmManagerImpl _vmMgr;
@Mock
private AccountVO callingAccount;
@Mock
private DomainChecker domainChecker;
@Mock
private AccountService accountService;
@Mock
private GetUserKeysCmd _listkeyscmd;
@Mock
private User _user;
@Mock
private UserAccountVO userAccountVO;
@Mock
UserVmManagerImpl _vmMgr;
private UpdateUserCmd UpdateUserCmdMock;
@Test
public void disableAccountNotexisting()
throws ConcurrentOperationException, ResourceUnavailableException {
Mockito.when(_accountDao.findById(42l)).thenReturn(null);
Assert.assertTrue(accountManager.disableAccount(42));
private long userVoIdMock = 111l;
@Mock
private UserVO userVoMock;
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
public void disableAccountDisabled() throws ConcurrentOperationException,
ResourceUnavailableException {
public void disableAccountNotexisting() throws ConcurrentOperationException, ResourceUnavailableException {
Mockito.when(accountDaoMock.findById(42l)).thenReturn(null);
Assert.assertTrue(accountManagerImpl.disableAccount(42));
}
@Test
public void disableAccountDisabled() throws ConcurrentOperationException, ResourceUnavailableException {
AccountVO disabledAccount = new AccountVO();
disabledAccount.setState(State.disabled);
Mockito.when(_accountDao.findById(42l)).thenReturn(disabledAccount);
Assert.assertTrue(accountManager.disableAccount(42));
Mockito.when(accountDaoMock.findById(42l)).thenReturn(disabledAccount);
Assert.assertTrue(accountManagerImpl.disableAccount(42));
}
@Test
public void disableAccount() throws ConcurrentOperationException,
ResourceUnavailableException {
public void disableAccount() throws ConcurrentOperationException, ResourceUnavailableException {
AccountVO account = new AccountVO();
account.setState(State.enabled);
Mockito.when(_accountDao.findById(42l)).thenReturn(account);
Mockito.when(_accountDao.createForUpdate()).thenReturn(new AccountVO());
Mockito.when(
_accountDao.update(Mockito.eq(42l),
Mockito.any(AccountVO.class))).thenReturn(true);
Mockito.when(_vmDao.listByAccountId(42l)).thenReturn(
Arrays.asList(Mockito.mock(VMInstanceVO.class)));
Assert.assertTrue(accountManager.disableAccount(42));
Mockito.verify(_accountDao, Mockito.atLeastOnce()).update(
Mockito.eq(42l), Mockito.any(AccountVO.class));
Mockito.when(accountDaoMock.findById(42l)).thenReturn(account);
Mockito.when(accountDaoMock.createForUpdate()).thenReturn(new AccountVO());
Mockito.when(accountDaoMock.update(Mockito.eq(42l), Mockito.any(AccountVO.class))).thenReturn(true);
Mockito.when(_vmDao.listByAccountId(42l)).thenReturn(Arrays.asList(Mockito.mock(VMInstanceVO.class)));
Assert.assertTrue(accountManagerImpl.disableAccount(42));
Mockito.verify(accountDaoMock, Mockito.atLeastOnce()).update(Mockito.eq(42l), Mockito.any(AccountVO.class));
}
@Test
@ -90,20 +123,12 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase {
AccountVO account = new AccountVO();
account.setId(42l);
DomainVO domain = new DomainVO();
Mockito.when(_accountDao.findById(42l)).thenReturn(account);
Mockito.when(
securityChecker.checkAccess(Mockito.any(Account.class),
Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class),
Mockito.anyString()))
.thenReturn(true);
Mockito.when(_accountDao.remove(42l)).thenReturn(true);
Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l))
.thenReturn(true);
Mockito.when(accountDaoMock.findById(42l)).thenReturn(account);
Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class), Mockito.anyString())).thenReturn(true);
Mockito.when(accountDaoMock.remove(42l)).thenReturn(true);
Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l)).thenReturn(true);
Mockito.when(_domainMgr.getDomain(Mockito.anyLong())).thenReturn(domain);
Mockito.when(
securityChecker.checkAccess(Mockito.any(Account.class),
Mockito.any(Domain.class)))
.thenReturn(true);
Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(Domain.class))).thenReturn(true);
Mockito.when(_vmSnapshotDao.listByAccountId(Mockito.anyLong())).thenReturn(new ArrayList<VMSnapshotVO>());
List<SSHKeyPairVO> sshkeyList = new ArrayList<SSHKeyPairVO>();
@ -113,10 +138,9 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase {
Mockito.when(_sshKeyPairDao.listKeyPairs(Mockito.anyLong(), Mockito.anyLong())).thenReturn(sshkeyList);
Mockito.when(_sshKeyPairDao.remove(Mockito.anyLong())).thenReturn(true);
Assert.assertTrue(accountManager.deleteUserAccount(42));
Assert.assertTrue(accountManagerImpl.deleteUserAccount(42));
// assert that this was a clean delete
Mockito.verify(_accountDao, Mockito.never()).markForCleanup(
Mockito.eq(42l));
Mockito.verify(accountDaoMock, Mockito.never()).markForCleanup(Mockito.eq(42l));
}
@Test
@ -124,33 +148,20 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase {
AccountVO account = new AccountVO();
account.setId(42l);
DomainVO domain = new DomainVO();
Mockito.when(_accountDao.findById(42l)).thenReturn(account);
Mockito.when(
securityChecker.checkAccess(Mockito.any(Account.class),
Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class),
Mockito.anyString()))
.thenReturn(true);
Mockito.when(_accountDao.remove(42l)).thenReturn(true);
Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l))
.thenReturn(true);
Mockito.when(_userVmDao.listByAccountId(42l)).thenReturn(
Arrays.asList(Mockito.mock(UserVmVO.class)));
Mockito.when(
_vmMgr.expunge(Mockito.any(UserVmVO.class), Mockito.anyLong(),
Mockito.any(Account.class))).thenReturn(false);
Mockito.when(accountDaoMock.findById(42l)).thenReturn(account);
Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class), Mockito.anyString())).thenReturn(true);
Mockito.when(accountDaoMock.remove(42l)).thenReturn(true);
Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l)).thenReturn(true);
Mockito.when(_userVmDao.listByAccountId(42l)).thenReturn(Arrays.asList(Mockito.mock(UserVmVO.class)));
Mockito.when(_vmMgr.expunge(Mockito.any(UserVmVO.class), Mockito.anyLong(), Mockito.any(Account.class))).thenReturn(false);
Mockito.when(_domainMgr.getDomain(Mockito.anyLong())).thenReturn(domain);
Mockito.when(
securityChecker.checkAccess(Mockito.any(Account.class),
Mockito.any(Domain.class)))
.thenReturn(true);
Mockito.when(securityChecker.checkAccess(Mockito.any(Account.class), Mockito.any(Domain.class))).thenReturn(true);
Assert.assertTrue(accountManager.deleteUserAccount(42));
Assert.assertTrue(accountManagerImpl.deleteUserAccount(42));
// assert that this was NOT a clean delete
Mockito.verify(_accountDao, Mockito.atLeastOnce()).markForCleanup(
Mockito.eq(42l));
Mockito.verify(accountDaoMock, Mockito.atLeastOnce()).markForCleanup(Mockito.eq(42l));
}
@Test
public void testAuthenticateUser() throws UnknownHostException {
Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> successAuthenticationPair = new Pair<>(true, null);
@ -160,21 +171,21 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase {
UserAccountVO userAccountVO = new UserAccountVO();
userAccountVO.setSource(User.Source.UNKNOWN);
userAccountVO.setState(Account.State.disabled.toString());
Mockito.when(_userAccountDao.getUserAccount("test", 1L)).thenReturn(userAccountVO);
Mockito.when(userAccountDaoMock.getUserAccount("test", 1L)).thenReturn(userAccountVO);
Mockito.when(userAuthenticator.authenticate("test", "fail", 1L, null)).thenReturn(failureAuthenticationPair);
Mockito.when(userAuthenticator.authenticate("test", null, 1L, null)).thenReturn(successAuthenticationPair);
Mockito.when(userAuthenticator.authenticate("test", "", 1L, null)).thenReturn(successAuthenticationPair);
//Test for incorrect password. authentication should fail
UserAccount userAccount = accountManager.authenticateUser("test", "fail", 1L, InetAddress.getByName("127.0.0.1"), null);
UserAccount userAccount = accountManagerImpl.authenticateUser("test", "fail", 1L, InetAddress.getByName("127.0.0.1"), null);
Assert.assertNull(userAccount);
//Test for null password. authentication should fail
userAccount = accountManager.authenticateUser("test", null, 1L, InetAddress.getByName("127.0.0.1"), null);
userAccount = accountManagerImpl.authenticateUser("test", null, 1L, InetAddress.getByName("127.0.0.1"), null);
Assert.assertNull(userAccount);
//Test for empty password. authentication should fail
userAccount = accountManager.authenticateUser("test", "", 1L, InetAddress.getByName("127.0.0.1"), null);
userAccount = accountManagerImpl.authenticateUser("test", "", 1L, InetAddress.getByName("127.0.0.1"), null);
Assert.assertNull(userAccount);
//Verifying that the authentication method is only called when password is specified
@ -183,38 +194,509 @@ public class AccountManagerImplTest extends AccountManagetImplTestBase {
Mockito.verify(userAuthenticator, Mockito.never()).authenticate("test", "", 1L, null);
}
@Mock
AccountVO callingAccount;
@Mock
DomainChecker domainChecker;
@Mock
AccountService accountService;
@Mock
private GetUserKeysCmd _listkeyscmd;
@Mock
private Account _account;
@Mock
private User _user;
@Mock
private UserAccountVO userAccountVO;
@Test (expected = PermissionDeniedException.class)
public void testgetUserCmd(){
@Test(expected = PermissionDeniedException.class)
public void testgetUserCmd() {
CallContext.register(callingUser, callingAccount); // Calling account is user account i.e normal account
Mockito.when(_listkeyscmd.getID()).thenReturn(1L);
Mockito.when(accountManager.getActiveUser(1L)).thenReturn(_user);
Mockito.when(accountManager.getUserAccountById(1L)).thenReturn(userAccountVO);
Mockito.when(accountManagerImpl.getActiveUser(1L)).thenReturn(_user);
Mockito.when(accountManagerImpl.getUserAccountById(1L)).thenReturn(userAccountVO);
Mockito.when(userAccountVO.getAccountId()).thenReturn(1L);
Mockito.when(accountManager.getAccount(Mockito.anyLong())).thenReturn(_account); // Queried account - admin account
Mockito.when(accountManagerImpl.getAccount(Mockito.anyLong())).thenReturn(accountMock); // Queried account - admin account
Mockito.when(callingUser.getAccountId()).thenReturn(1L);
Mockito.when(_accountDao.findById(1L)).thenReturn(callingAccount);
Mockito.when(accountDaoMock.findById(1L)).thenReturn(callingAccount);
Mockito.when(accountService.isNormalUser(Mockito.anyLong())).thenReturn(Boolean.TRUE);
Mockito.when(_account.getAccountId()).thenReturn(2L);
Mockito.when(accountMock.getAccountId()).thenReturn(2L);
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.
package com.cloud.user;
import static org.mockito.Mockito.when;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.when;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@ -52,13 +52,12 @@ import com.cloud.exception.AgentUnavailableException;
import com.cloud.exception.CloudException;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.Volume.Type;
import com.cloud.storage.VolumeVO;
import com.cloud.vm.UserVmManagerImpl;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VirtualMachine;
public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplTestBase {
private static final Long ACCOUNT_ID = 1l;
@ -70,12 +69,10 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
Map<String, Object> oldFields = new HashMap<>();
UserVmVO vm = mock(UserVmVO.class);
// Configures the static fields of the UsageEventUtils class, Storing the
// previous values to be restored during the cleanup phase, to avoid
// interference with other unit tests.
protected UsageEventUtils setupUsageUtils() throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
protected UsageEventUtils setupUsageUtils() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
_usageEventDao = new MockUsageEventDao();
UsageEventUtils utils = new UsageEventUtils();
@ -93,8 +90,7 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
Field staticField = UsageEventUtils.class.getDeclaredField("s_" + fieldName);
staticField.setAccessible(true);
oldFields.put(f.getName(), staticField.get(null));
f.set(utils,
this.getClass().getSuperclass().getDeclaredField("_" + fieldName).get(this));
f.set(utils, this.getClass().getSuperclass().getDeclaredField("_" + fieldName).get(this));
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
e.printStackTrace();
}
@ -106,14 +102,12 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
return utils;
}
protected void defineMocksBehavior()
throws AgentUnavailableException, ConcurrentOperationException, CloudException {
protected void defineMocksBehavior() throws AgentUnavailableException, ConcurrentOperationException, CloudException {
AccountVO account = new AccountVO();
account.setId(ACCOUNT_ID);
when(_accountDao.remove(ACCOUNT_ID)).thenReturn(true);
when(_accountDao.findById(ACCOUNT_ID)).thenReturn(account);
when(accountDaoMock.remove(ACCOUNT_ID)).thenReturn(true);
when(accountDaoMock.findById(ACCOUNT_ID)).thenReturn(account);
DomainVO domain = new DomainVO();
VirtualMachineEntity vmEntity = mock(VirtualMachineEntity.class);
@ -128,8 +122,7 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
List<VolumeVO> volumes = new ArrayList<>();
volumes.add(vol);
when(securityChecker.checkAccess(any(Account.class), any(ControlledEntity.class), any(AccessType.class),
anyString())).thenReturn(true);
when(securityChecker.checkAccess(any(Account.class), any(ControlledEntity.class), any(AccessType.class), anyString())).thenReturn(true);
when(_userVmDao.findById(anyLong())).thenReturn(vm);
when(_userVmDao.listByAccountId(ACCOUNT_ID)).thenReturn(Arrays.asList(vm));
@ -142,8 +135,7 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
when(offering.getId()).thenReturn(1l);
when(offering.getCpu()).thenReturn(500);
when(offering.getRamSize()).thenReturn(500);
when(_serviceOfferingDao.findByIdIncludingRemoved(anyLong(), anyLong()))
.thenReturn(offering);
when(_serviceOfferingDao.findByIdIncludingRemoved(anyLong(), anyLong())).thenReturn(offering);
when(_domainMgr.getDomain(anyLong())).thenReturn(domain);
@ -152,9 +144,8 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
}
@Before
public void init()
throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
InvocationTargetException, AgentUnavailableException, ConcurrentOperationException, CloudException {
public void init() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, AgentUnavailableException,
ConcurrentOperationException, CloudException {
setupUsageUtils();
defineMocksBehavior();
@ -175,22 +166,19 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
method.invoke(utils);
}
@SuppressWarnings("unchecked")
protected List<UsageEventVO> deleteUserAccountRootVolumeUsageEvents(boolean vmDestroyedPrior)
throws AgentUnavailableException, ConcurrentOperationException, CloudException {
protected List<UsageEventVO> deleteUserAccountRootVolumeUsageEvents(boolean vmDestroyedPrior) throws AgentUnavailableException, ConcurrentOperationException, CloudException {
when(vm.getState())
.thenReturn(vmDestroyedPrior ? VirtualMachine.State.Destroyed : VirtualMachine.State.Running);
when(vm.getState()).thenReturn(vmDestroyedPrior ? VirtualMachine.State.Destroyed : VirtualMachine.State.Running);
when(vm.getRemoved()).thenReturn(vmDestroyedPrior ? new Date() : null);
accountManager.deleteUserAccount(ACCOUNT_ID);
accountManagerImpl.deleteUserAccount(ACCOUNT_ID);
return _usageEventDao.listAll();
}
@Test
// If the VM is alerady destroyed, no events should get emitted
public void destroyedVMRootVolumeUsageEvent() throws SecurityException, IllegalArgumentException,
ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
public void destroyedVMRootVolumeUsageEvent()
throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(true);
Assert.assertEquals(0, emittedEvents.size());
}
@ -198,8 +186,8 @@ public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplT
@Test
// If the VM is running, we should see one emitted event for the root
// volume.
public void runningVMRootVolumeUsageEvent() throws SecurityException, IllegalArgumentException,
ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
public void runningVMRootVolumeUsageEvent()
throws SecurityException, IllegalArgumentException, ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(false);
Assert.assertEquals(1, emittedEvents.size());
UsageEventVO event = emittedEvents.get(0);

View File

@ -21,8 +21,6 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.context.CallContext;
@ -34,9 +32,10 @@ import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao;
import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.configuration.dao.ResourceCountDao;
@ -84,17 +83,17 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDao;
public class AccountManagetImplTestBase {
@Mock
AccountDao _accountDao;
AccountDao accountDaoMock;
@Mock
ConfigurationDao _configDao;
@Mock
ResourceCountDao _resourceCountDao;
@Mock
UserDao _userDao;
UserDao userDaoMock;
@Mock
InstanceGroupDao _vmGroupDao;
@Mock
UserAccountDao _userAccountDao;
UserAccountDao userAccountDaoMock;
@Mock
VolumeDao _volumeDao;
@Mock
@ -193,27 +192,16 @@ public class AccountManagetImplTestBase {
@Mock
SSHKeyPairDao _sshKeyPairDao;
AccountManagerImpl accountManager;
UsageEventDao _usageEventDao = new MockUsageEventDao();
@Spy
@InjectMocks
AccountManagerImpl accountManagerImpl;
@Mock
UsageEventDao _usageEventDao;
@Before
public void setup()
throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
accountManager = new AccountManagerImpl();
Map<String, Field> declaredFields = getInheritedFields(this.getClass());
for (Field field : AccountManagerImpl.class.getDeclaredFields()) {
if (field.getAnnotation(Inject.class) != null) {
field.setAccessible(true);
if (declaredFields.containsKey(field.getName())) {
Field mockField = declaredFields.get(field.getName());
field.set(accountManager, mockField.get(this));
}
}
}
ReflectionTestUtils.setField(accountManager, "_userAuthenticators", Arrays.asList(userAuthenticator));
accountManager.setSecurityCheckers(Arrays.asList(securityChecker));
public void setup() {
accountManagerImpl.setUserAuthenticators(Arrays.asList(userAuthenticator));
accountManagerImpl.setSecurityCheckers(Arrays.asList(securityChecker));
CallContext.register(callingUser, callingAccount);
}
@ -231,14 +219,4 @@ public class AccountManagetImplTestBase {
}
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;
}
@Override
public UserAccount updateUser(Long userId, String firstName, String lastName, String email, String userName, String password, String apiKey, String secretKey,
String timeZone) {
// TODO Auto-generated method stub
return null;
}
@Override
public Account getActiveAccountById(long accountId) {
// TODO Auto-generated method stub

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.new": "جديد",
"label.new.password": "New Password",
"label.current.password": "Current Password",
"label.new.project": "مشروع جديد",
"label.new.ssh.key.pair": "New SSH Key Pair",
"label.new.vm": "New VM",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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