mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Mark LDAP user query timeout as incorrect login instead of disabling user immediately (#11220)
* Mark LDAP user query timeout as incorrect login instead of disabling user immediately * code improvements
This commit is contained in:
parent
890386e949
commit
ed6ee6b704
@ -140,10 +140,11 @@ public class LdapListUsersCmd extends BaseListCmd {
|
||||
try {
|
||||
final List<LdapUser> users = _ldapManager.getUsers(domainId);
|
||||
ldapResponses = createLdapUserResponse(users);
|
||||
// now filter and annotate
|
||||
// now filter and annotate
|
||||
ldapResponses = applyUserFilter(ldapResponses);
|
||||
} catch (final NoLdapUserMatchingQueryException ex) {
|
||||
// ok, we'll make do with the empty list ldapResponses = new ArrayList<LdapUserResponse>();
|
||||
logger.debug(ex.getMessage());
|
||||
// ok, we'll make do with the empty list
|
||||
} finally {
|
||||
response.setResponses(ldapResponses);
|
||||
response.setResponseName(getCommandName());
|
||||
|
||||
@ -45,6 +45,8 @@ public class LdapAuthenticator extends AdapterBase implements UserAuthenticator
|
||||
@Inject
|
||||
private AccountManager _accountManager;
|
||||
|
||||
private static final String LDAP_READ_TIMED_OUT_MESSAGE = "LDAP response read timed out";
|
||||
|
||||
public LdapAuthenticator() {
|
||||
super();
|
||||
}
|
||||
@ -74,8 +76,8 @@ public class LdapAuthenticator extends AdapterBase implements UserAuthenticator
|
||||
return rc;
|
||||
}
|
||||
List<LdapTrustMapVO> ldapTrustMapVOs = getLdapTrustMapVOS(domainId);
|
||||
if(ldapTrustMapVOs != null && ldapTrustMapVOs.size() > 0) {
|
||||
if(ldapTrustMapVOs.size() == 1 && ldapTrustMapVOs.get(0).getAccountId() == 0) {
|
||||
if (ldapTrustMapVOs != null && ldapTrustMapVOs.size() > 0) {
|
||||
if (ldapTrustMapVOs.size() == 1 && ldapTrustMapVOs.get(0).getAccountId() == 0) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("We have a single mapping of a domain to an ldap group or ou");
|
||||
}
|
||||
@ -125,11 +127,11 @@ public class LdapAuthenticator extends AdapterBase implements UserAuthenticator
|
||||
mappedGroups.retainAll(memberships);
|
||||
tracelist("actual groups for " + username, mappedGroups);
|
||||
// check membership, there must be only one match in this domain
|
||||
if(ldapUser.isDisabled()) {
|
||||
if (ldapUser.isDisabled()) {
|
||||
logAndDisable(userAccount, "attempt to log on using disabled ldap user " + userAccount.getUsername(), false);
|
||||
} else if(mappedGroups.size() > 1) {
|
||||
} else if (mappedGroups.size() > 1) {
|
||||
logAndDisable(userAccount, "user '" + username + "' is mapped to more then one account in domain and will be disabled.", false);
|
||||
} else if(mappedGroups.size() < 1) {
|
||||
} else if (mappedGroups.size() < 1) {
|
||||
logAndDisable(userAccount, "user '" + username + "' is not mapped to an account in domain and will be removed.", true);
|
||||
} else {
|
||||
// a valid ldap configured user exists
|
||||
@ -137,12 +139,12 @@ public class LdapAuthenticator extends AdapterBase implements UserAuthenticator
|
||||
// we could now assert that ldapTrustMapVOs.contains(mapping);
|
||||
// createUser in Account can only be done by account name not by account id;
|
||||
Account account = _accountManager.getAccount(mapping.getAccountId());
|
||||
if(null == account) {
|
||||
if (null == account) {
|
||||
throw new CloudRuntimeException(String.format("account for user (%s) not found by id %d", username, mapping.getAccountId()));
|
||||
}
|
||||
String accountName = account.getAccountName();
|
||||
rc.first(_ldapManager.canAuthenticate(ldapUser.getPrincipal(), password, domainId));
|
||||
if (! rc.first()) {
|
||||
if (!rc.first()) {
|
||||
rc.second(ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
|
||||
}
|
||||
// for security reasons we keep processing on faulty login attempt to not give a way information on userid existence
|
||||
@ -162,7 +164,7 @@ public class LdapAuthenticator extends AdapterBase implements UserAuthenticator
|
||||
userAccount = _accountManager.getUserAccountById(user.getId());
|
||||
} else {
|
||||
// not a new user, check if mapped group has changed
|
||||
if(userAccount.getAccountId() != mapping.getAccountId()) {
|
||||
if (userAccount.getAccountId() != mapping.getAccountId()) {
|
||||
final Account mappedAccount = _accountManager.getAccount(mapping.getAccountId());
|
||||
if (mappedAccount == null || mappedAccount.getRemoved() != null) {
|
||||
throw new CloudRuntimeException("Mapped account for users does not exist. Please contact your administrator.");
|
||||
@ -174,12 +176,21 @@ public class LdapAuthenticator extends AdapterBase implements UserAuthenticator
|
||||
}
|
||||
} catch (NoLdapUserMatchingQueryException e) {
|
||||
logger.debug(e.getMessage());
|
||||
disableUserInCloudStack(userAccount);
|
||||
processLdapUserErrorMessage(userAccount, e.getMessage(), rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
private void processLdapUserErrorMessage(UserAccount user, String errorMessage, Pair<Boolean, ActionOnFailedAuthentication> rc) {
|
||||
if (StringUtils.isNotEmpty(errorMessage) && errorMessage.contains(LDAP_READ_TIMED_OUT_MESSAGE) && !rc.first()) {
|
||||
rc.second(ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
|
||||
} else {
|
||||
// no user in ldap ==>> disable user in cloudstack
|
||||
disableUserInCloudStack(user);
|
||||
}
|
||||
}
|
||||
|
||||
private void tracelist(String msg, List<String> listToTrace) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
StringBuilder logMsg = new StringBuilder();
|
||||
@ -197,7 +208,7 @@ public class LdapAuthenticator extends AdapterBase implements UserAuthenticator
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(msg);
|
||||
}
|
||||
if(remove) {
|
||||
if (remove) {
|
||||
removeUserInCloudStack(userAccount);
|
||||
} else {
|
||||
disableUserInCloudStack(userAccount);
|
||||
@ -229,23 +240,22 @@ public class LdapAuthenticator extends AdapterBase implements UserAuthenticator
|
||||
processLdapUser(password, domainId, user, rc, ldapUser, accountType);
|
||||
} catch (NoLdapUserMatchingQueryException e) {
|
||||
logger.debug(e.getMessage());
|
||||
// no user in ldap ==>> disable user in cloudstack
|
||||
disableUserInCloudStack(user);
|
||||
processLdapUserErrorMessage(user, e.getMessage(), rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
private void processLdapUser(String password, Long domainId, UserAccount user, Pair<Boolean, ActionOnFailedAuthentication> rc, LdapUser ldapUser, Account.Type accountType) {
|
||||
if(!ldapUser.isDisabled()) {
|
||||
if (!ldapUser.isDisabled()) {
|
||||
rc.first(_ldapManager.canAuthenticate(ldapUser.getPrincipal(), password, domainId));
|
||||
if(rc.first()) {
|
||||
if(user == null) {
|
||||
if (rc.first()) {
|
||||
if (user == null) {
|
||||
// import user to cloudstack
|
||||
createCloudStackUserAccount(ldapUser, domainId, accountType);
|
||||
} else {
|
||||
enableUserInCloudStack(user);
|
||||
}
|
||||
} else if(user != null) {
|
||||
} else if (user != null) {
|
||||
rc.second(ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
|
||||
}
|
||||
} else {
|
||||
@ -264,30 +274,34 @@ public class LdapAuthenticator extends AdapterBase implements UserAuthenticator
|
||||
*/
|
||||
Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String password, Long domainId, UserAccount user) {
|
||||
boolean result = false;
|
||||
boolean timedOut = false;
|
||||
|
||||
if(user != null ) {
|
||||
if (user != null ) {
|
||||
try {
|
||||
LdapUser ldapUser = _ldapManager.getUser(username, domainId);
|
||||
if(!ldapUser.isDisabled()) {
|
||||
if (!ldapUser.isDisabled()) {
|
||||
result = _ldapManager.canAuthenticate(ldapUser.getPrincipal(), password, domainId);
|
||||
} else {
|
||||
logger.debug("user with principal "+ ldapUser.getPrincipal() + " is disabled in ldap");
|
||||
}
|
||||
} catch (NoLdapUserMatchingQueryException e) {
|
||||
logger.debug(e.getMessage());
|
||||
if (e.getMessage().contains(LDAP_READ_TIMED_OUT_MESSAGE)) {
|
||||
timedOut = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return processResultAndAction(user, result);
|
||||
return processResultAndAction(user, result, timedOut);
|
||||
}
|
||||
|
||||
private Pair<Boolean, ActionOnFailedAuthentication> processResultAndAction(UserAccount user, boolean result) {
|
||||
return (!result && user != null) ?
|
||||
private Pair<Boolean, ActionOnFailedAuthentication> processResultAndAction(UserAccount user, boolean result, boolean timedOut) {
|
||||
return (!result && (user != null || timedOut)) ?
|
||||
new Pair<Boolean, ActionOnFailedAuthentication>(result, ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT):
|
||||
new Pair<Boolean, ActionOnFailedAuthentication>(result, null);
|
||||
}
|
||||
|
||||
private void enableUserInCloudStack(UserAccount user) {
|
||||
if(user != null && (user.getState().equalsIgnoreCase(Account.State.DISABLED.toString()))) {
|
||||
if (user != null && (user.getState().equalsIgnoreCase(Account.State.DISABLED.toString()))) {
|
||||
_accountManager.enableUser(user.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,7 +166,7 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
|
||||
|
||||
private LdapConfigurationResponse addConfigurationInternal(final String hostname, int port, final Long domainId) throws InvalidParameterValueException {
|
||||
// TODO evaluate what the right default should be
|
||||
if(port <= 0) {
|
||||
if (port <= 0) {
|
||||
port = 389;
|
||||
}
|
||||
|
||||
@ -210,7 +210,7 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
|
||||
// TODO return the right account for this user
|
||||
final LdapContext context = _ldapContextFactory.createUserContext(principal, password, domainId);
|
||||
closeContext(context);
|
||||
if(logger.isTraceEnabled()) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(String.format("User(%s) authenticated for domain(%s)", principal, domainId));
|
||||
}
|
||||
return true;
|
||||
@ -234,7 +234,7 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
|
||||
@Override
|
||||
public LdapConfigurationResponse createLdapConfigurationResponse(final LdapConfigurationVO configuration) {
|
||||
String domainUuid = null;
|
||||
if(configuration.getDomainId() != null) {
|
||||
if (configuration.getDomainId() != null) {
|
||||
DomainVO domain = domainDao.findById(configuration.getDomainId());
|
||||
if (domain != null) {
|
||||
domainUuid = domain.getUuid();
|
||||
@ -303,8 +303,8 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
|
||||
return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider(null)).getUser(escapedUsername, context, domainId);
|
||||
|
||||
} catch (NamingException | IOException e) {
|
||||
logger.debug("ldap Exception: ",e);
|
||||
throw new NoLdapUserMatchingQueryException("No Ldap User found for username: "+username);
|
||||
logger.debug("LDAP Exception: ", e);
|
||||
throw new NoLdapUserMatchingQueryException("Unable to find LDAP User for username: " + username + ", due to " + e.getMessage());
|
||||
} finally {
|
||||
closeContext(context);
|
||||
}
|
||||
@ -324,8 +324,8 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
|
||||
LdapUserManager userManagerFactory = _ldapUserManagerFactory.getInstance(ldapProvider);
|
||||
return userManagerFactory.getUser(escapedUsername, type, name, context, domainId);
|
||||
} catch (NamingException | IOException e) {
|
||||
logger.debug("ldap Exception: ",e);
|
||||
throw new NoLdapUserMatchingQueryException("No Ldap User found for username: "+username + " in group: " + name + " of type: " + type);
|
||||
logger.debug("LDAP Exception: ", e);
|
||||
throw new NoLdapUserMatchingQueryException("Unable to find LDAP User for username: " + username + " in group: " + name + " of type: " + type + ", due to " + e.getMessage());
|
||||
} finally {
|
||||
closeContext(context);
|
||||
}
|
||||
@ -338,7 +338,7 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
|
||||
context = _ldapContextFactory.createBindContext(domainId);
|
||||
return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider(domainId)).getUsers(context, domainId);
|
||||
} catch (NamingException | IOException e) {
|
||||
logger.debug("ldap Exception: ",e);
|
||||
logger.debug("LDAP Exception: ", e);
|
||||
throw new NoLdapUserMatchingQueryException("*");
|
||||
} finally {
|
||||
closeContext(context);
|
||||
@ -352,7 +352,7 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
|
||||
context = _ldapContextFactory.createBindContext(domainId);
|
||||
return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider(domainId)).getUsersInGroup(groupName, context, domainId);
|
||||
} catch (NamingException | IOException e) {
|
||||
logger.debug("ldap NamingException: ",e);
|
||||
logger.debug("LDAP Exception: ", e);
|
||||
throw new NoLdapUserMatchingQueryException("groupName=" + groupName);
|
||||
} finally {
|
||||
closeContext(context);
|
||||
@ -390,7 +390,7 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
|
||||
final String escapedUsername = LdapUtils.escapeLDAPSearchFilter(username);
|
||||
return _ldapUserManagerFactory.getInstance(_ldapConfiguration.getLdapProvider(null)).getUsers("*" + escapedUsername + "*", context, null);
|
||||
} catch (NamingException | IOException e) {
|
||||
logger.debug("ldap Exception: ",e);
|
||||
logger.debug("LDAP Exception: ",e);
|
||||
throw new NoLdapUserMatchingQueryException(username);
|
||||
} finally {
|
||||
closeContext(context);
|
||||
@ -481,7 +481,7 @@ public class LdapManagerImpl extends ComponentLifecycleBase implements LdapManag
|
||||
private void clearOldAccountMapping(LinkAccountToLdapCmd cmd) {
|
||||
// first find if exists log warning and update
|
||||
LdapTrustMapVO oldVo = _ldapTrustMapDao.findGroupInDomain(cmd.getDomainId(), cmd.getLdapDomain());
|
||||
if(oldVo != null) {
|
||||
if (oldVo != null) {
|
||||
// deal with edge cases, i.e. check if the old account is indeed deleted etc.
|
||||
if (oldVo.getAccountId() != 0l) {
|
||||
AccountVO oldAcount = accountDao.findByIdIncludingRemoved(oldVo.getAccountId());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user