mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
bug CS-15278: Added global setting login.attempts.allowed which defines the maximum incorrect password attempts allowed.
Also after the maximum attempts are reached the user account is disabled
This commit is contained in:
parent
41f6127fe1
commit
a56631bc66
@ -83,6 +83,9 @@ public class UserAccountVO implements UserAccount {
|
||||
@Column(name="is_registered")
|
||||
boolean registered;
|
||||
|
||||
@Column (name="incorrect_login_attempts")
|
||||
int loginAttempts;
|
||||
|
||||
@Column(name="account_name", table="account", insertable=false, updatable=false)
|
||||
private String accountName = null;
|
||||
|
||||
@ -269,4 +272,12 @@ public class UserAccountVO implements UserAccount {
|
||||
public void setRegistered(boolean registered) {
|
||||
this.registered = registered;
|
||||
}
|
||||
}
|
||||
|
||||
public void setLoginAttempts(int loginAttempts) {
|
||||
this.loginAttempts = loginAttempts;
|
||||
}
|
||||
|
||||
public int getLoginAttempts() {
|
||||
return loginAttempts;
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +229,7 @@ public enum Config {
|
||||
EnableEC2API("Advanced", ManagementServer.class, Boolean.class, "enable.ec2.api", "false", "enable EC2 API on CloudStack", null),
|
||||
EnableS3API("Advanced", ManagementServer.class, Boolean.class, "enable.s3.api", "false", "enable Amazon S3 API on CloudStack", null),
|
||||
RecreateSystemVmEnabled("Advanced", ManagementServer.class, Boolean.class, "recreate.systemvm.enabled", "false", "If true, will recreate system vm root disk whenever starting system vm", "true,false"),
|
||||
|
||||
IncorrectLoginAttemptsAllowed("Advanced", ManagementServer.class, Integer.class, "incorrect.login.attempts.allowed", "5", "Incorrect login attempts allowed before the user is disabled", null),
|
||||
// Ovm
|
||||
OvmPublicNetwork("Hidden", ManagementServer.class, String.class, "ovm.public.network.device", null, "Specify the public bridge on host for public network", null),
|
||||
OvmPrivateNetwork("Hidden", ManagementServer.class, String.class, "ovm.private.network.device", null, "Specify the private bridge on host for private network", null),
|
||||
|
||||
@ -274,6 +274,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura
|
||||
configValuesForValidation.add("storage.cleanup.interval");
|
||||
configValuesForValidation.add("wait");
|
||||
configValuesForValidation.add("xen.heartbeat.interval");
|
||||
configValuesForValidation.add("incorrect.login.attempts.allowed");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -224,6 +224,8 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
|
||||
|
||||
private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AccountChecker"));
|
||||
|
||||
int _allowedLoginAttempts;
|
||||
|
||||
UserVO _systemUser;
|
||||
AccountVO _systemAccount;
|
||||
@Inject(adapter = SecurityChecker.class)
|
||||
@ -248,6 +250,9 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
|
||||
ConfigurationDao configDao = locator.getDao(ConfigurationDao.class);
|
||||
Map<String, String> configs = configDao.getConfiguration(params);
|
||||
|
||||
String loginAttempts = configs.get(Config.IncorrectLoginAttemptsAllowed.key());
|
||||
_allowedLoginAttempts = NumbersUtil.parseInt(loginAttempts, 5);
|
||||
|
||||
String value = configs.get(Config.AccountCleanupInterval.key());
|
||||
_cleanupInterval = NumbersUtil.parseInt(value, 60 * 60 * 24); // 1 day.
|
||||
|
||||
@ -302,6 +307,13 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
|
||||
return (accountType == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN);
|
||||
}
|
||||
|
||||
public boolean isInternalAccount(short accountType) {
|
||||
if (isRootAdmin(accountType) || (accountType == Account.ACCOUNT_ID_SYSTEM)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAccess(Account caller, Domain domain) throws PermissionDeniedException {
|
||||
for (SecurityChecker checker : _securityCheckers) {
|
||||
@ -420,6 +432,25 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
|
||||
|
||||
}
|
||||
|
||||
@DB
|
||||
public void updateLoginAttempts(Long id, int attempts, boolean toDisable) {
|
||||
Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
try {
|
||||
UserAccountVO user = null;
|
||||
user = _userAccountDao.lockRow(id, true);
|
||||
user.setLoginAttempts(attempts);
|
||||
if(toDisable) {
|
||||
user.setState(State.disabled.toString());
|
||||
}
|
||||
_userAccountDao.update(id, user);
|
||||
txn.commit();
|
||||
} catch (Exception e) {
|
||||
s_logger.error("Failed to update login attempts for user with id " + id );
|
||||
}
|
||||
txn.close();
|
||||
}
|
||||
|
||||
private boolean doSetUserStatus(long userId, State state) {
|
||||
UserVO userForUpdate = _userDao.createForUpdate();
|
||||
userForUpdate.setState(state);
|
||||
@ -732,7 +763,7 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
|
||||
if (domainId == null) {
|
||||
domainId = DomainVO.ROOT_DOMAIN;
|
||||
}
|
||||
|
||||
|
||||
if (userName.isEmpty()) {
|
||||
throw new InvalidParameterValueException("Username is empty");
|
||||
}
|
||||
@ -740,7 +771,7 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
|
||||
if (firstName.isEmpty()) {
|
||||
throw new InvalidParameterValueException("Firstname is empty");
|
||||
}
|
||||
|
||||
|
||||
if (lastName.isEmpty()) {
|
||||
throw new InvalidParameterValueException("Lastname is empty");
|
||||
}
|
||||
@ -1002,6 +1033,8 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
|
||||
txn.commit();
|
||||
|
||||
if (success) {
|
||||
// whenever the user is successfully enabled, reset the login attempts to zero
|
||||
updateLoginAttempts(userId, 0, false);
|
||||
return _userAccountDao.findById(userId);
|
||||
} else {
|
||||
throw new CloudRuntimeException("Unable to enable user " + userId);
|
||||
@ -1818,11 +1851,36 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
|
||||
throw new CloudAuthenticationException("User " + username + " in domain " + domainName + " is disabled/locked (or account is disabled/locked)");
|
||||
// return null;
|
||||
}
|
||||
// Whenever the user is able to log in successfully, reset the login attempts to zero
|
||||
if(!isInternalAccount(userAccount.getType()))
|
||||
updateLoginAttempts(userAccount.getId(), 0, false);
|
||||
|
||||
return userAccount;
|
||||
} else {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Unable to authenticate user with username " + username + " in domain " + domainId);
|
||||
}
|
||||
|
||||
UserAccount userAccount = _userAccountDao.getUserAccount(username, domainId);
|
||||
UserAccountVO user = _userAccountDao.findById(userAccount.getId());
|
||||
if (user != null) {
|
||||
if ((user.getState().toString()).equals("enabled")) {
|
||||
if (!isInternalAccount(user.getType())) {
|
||||
//Internal accounts are not disabled
|
||||
int attemptsMade = user.getLoginAttempts() + 1;
|
||||
if (attemptsMade < _allowedLoginAttempts) {
|
||||
updateLoginAttempts(userAccount.getId(), attemptsMade, false);
|
||||
s_logger.warn("Login attempt failed. You have " + ( _allowedLoginAttempts - attemptsMade ) + " attempt(s) remaining");
|
||||
} else {
|
||||
updateLoginAttempts(userAccount.getId(), _allowedLoginAttempts, true);
|
||||
s_logger.warn("User " + user.getUsername() + " has been disabled due to multiple failed login attempts." +
|
||||
" Please contact admin.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s_logger.info("User " + user.getUsername() + " is disabled/locked");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -890,6 +890,7 @@ CREATE TABLE `cloud`.`user` (
|
||||
`timezone` varchar(30) default NULL,
|
||||
`registration_token` varchar(255) default NULL,
|
||||
`is_registered` tinyint NOT NULL DEFAULT 0 COMMENT '1: yes, 0: no',
|
||||
`incorrect_login_attempts` integer unsigned NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `i_user__removed`(`removed`),
|
||||
INDEX `i_user__secret_key_removed`(`secret_key`, `removed`),
|
||||
|
||||
@ -472,3 +472,6 @@ INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Network', 'DEFAULT', 'manage
|
||||
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Network', 'DEFAULT', 'management-server', 'site2site.vpn.customergateway.subnets.limit', '10', 'The maximum number of subnets per customer gateway');
|
||||
|
||||
INSERT IGNORE INTO `cloud`.`guest_os_category` VALUES ('11','None',NULL);
|
||||
ALTER TABLE `cloud`.`user` ADD COLUMN `incorrect_login_attempts` integer unsigned NOT NULL DEFAULT '0';
|
||||
INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'incorrect.login.attempts.allowed', '5', 'Incorrect login attempts allowed before the user is disabled');
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user