You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by an...@apache.org on 2014/01/22 22:17:49 UTC
[4/4] git commit: updated refs/heads/4.3 to aa6f4dc
CLOUDSTACK-5930: Changed "authenticate" method to return both - result of authentication, and action to perform when authentication failed - to the accountManagerImpl. Only if authenicators request INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT, the incorrect_login_attempts parameter will be increased
Signed-off-by: Alena Prokharchyk <al...@citrix.com>
Conflicts:
plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java
plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java
plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java
plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java
server/src/com/cloud/server/auth/UserAuthenticator.java
server/src/com/cloud/user/AccountManagerImpl.java
(cherry picked from commit f160b31f51f9165a94c6912bba3b4f6447b73854)
Signed-off-by: Animesh Chaturvedi <an...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/aa6f4dc8
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/aa6f4dc8
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/aa6f4dc8
Branch: refs/heads/4.3
Commit: aa6f4dc8a7c4f1222b6fa2e3b0ca3542215b246b
Parents: 7125ac7
Author: Alena Prokharchyk <al...@citrix.com>
Authored: Tue Jan 7 12:15:37 2014 -0800
Committer: Animesh Chaturvedi <an...@apache.org>
Committed: Wed Jan 22 13:07:43 2014 -0800
----------------------------------------------------------------------
.../cloudstack/ldap/LdapAuthenticator.java | 31 ++++++----
.../cloud/server/auth/MD5UserAuthenticator.java | 64 ++++++++++----------
.../server/auth/PlainTextUserAuthenticator.java | 42 +++++++------
.../auth/SHA256SaltedUserAuthenticator.java | 13 ++--
.../server/auth/test/AuthenticatorTest.java | 10 +--
.../cloud/server/auth/UserAuthenticator.java | 35 ++++++-----
.../src/com/cloud/user/AccountManagerImpl.java | 25 +++++---
7 files changed, 123 insertions(+), 97 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/aa6f4dc8/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java
index 559a979..dac917b 100644
--- a/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java
+++ b/plugins/user-authenticators/ldap/src/org/apache/cloudstack/ldap/LdapAuthenticator.java
@@ -25,6 +25,7 @@ import org.apache.log4j.Logger;
import com.cloud.server.auth.DefaultUserAuthenticator;
import com.cloud.user.UserAccount;
import com.cloud.user.dao.UserAccountDao;
+import com.cloud.utils.Pair;
public class LdapAuthenticator extends DefaultUserAuthenticator {
private static final Logger s_logger = Logger
@@ -46,23 +47,27 @@ public class LdapAuthenticator extends DefaultUserAuthenticator {
_userAccountDao = userAccountDao;
}
- @Override
- public boolean authenticate(final String username, final String password,
- final Long domainId, final Map<String, Object[]> requestParameters) {
+ @Override
+ public Pair<Boolean, ActionOnFailedAuthentication> authenticate(final String username, final String password, final Long domainId, final Map<String, Object[]> requestParameters) {
final UserAccount user = _userAccountDao.getUserAccount(username,
domainId);
- if (user == null) {
- s_logger.debug("Unable to find user with " + username
- + " in domain " + domainId);
- return false;
- } else if (_ldapManager.isLdapEnabled()) {
- return _ldapManager.canAuthenticate(username, password);
- } else {
- return false;
- }
- }
+ if (user == null) {
+ s_logger.debug("Unable to find user with " + username + " in domain " + domainId);
+ return new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
+ } else if (_ldapManager.isLdapEnabled()) {
+ boolean result = _ldapManager.canAuthenticate(username, password);
+ ActionOnFailedAuthentication action = null;
+ if (result == false) {
+ action = ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT;
+ }
+ return new Pair<Boolean, ActionOnFailedAuthentication>(result, action);
+
+ } else {
+ return new Pair<Boolean, ActionOnFailedAuthentication>(false, ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
+ }
+ }
@Override
public String encode(final String password) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/aa6f4dc8/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java b/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java
index 63583af..f8f75ed 100644
--- a/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java
+++ b/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java
@@ -27,6 +27,7 @@ import org.apache.log4j.Logger;
import com.cloud.user.UserAccount;
import com.cloud.user.dao.UserAccountDao;
+import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
/**
@@ -34,47 +35,48 @@ import com.cloud.utils.exception.CloudRuntimeException;
* comparing it against the local database.
*
*/
-@Local(value={UserAuthenticator.class})
+@Local(value = {UserAuthenticator.class})
public class MD5UserAuthenticator extends DefaultUserAuthenticator {
- public static final Logger s_logger = Logger.getLogger(MD5UserAuthenticator.class);
-
- @Inject private UserAccountDao _userAccountDao;
-
- @Override
- public boolean authenticate(String username, String password, Long domainId, Map<String, Object[]> requestParameters ) {
- if (s_logger.isDebugEnabled()) {
+ public static final Logger s_logger = Logger.getLogger(MD5UserAuthenticator.class);
+
+ @Inject
+ private UserAccountDao _userAccountDao;
+
+ @Override
+ public Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String password, Long domainId, Map<String, Object[]> requestParameters) {
+ if (s_logger.isDebugEnabled()) {
s_logger.debug("Retrieving user: " + username);
}
UserAccount user = _userAccountDao.getUserAccount(username, domainId);
if (user == null) {
s_logger.debug("Unable to find user with " + username + " in domain " + domainId);
- return false;
+ return new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
}
-
+
if (!user.getPassword().equals(encode(password))) {
s_logger.debug("Password does not match");
- return false;
+ return new Pair<Boolean, ActionOnFailedAuthentication>(false, ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
}
- return true;
- }
+ return new Pair<Boolean, ActionOnFailedAuthentication>(true, null);
+ }
- public String encode(String password) {
- MessageDigest md5 = null;
- try {
- md5 = MessageDigest.getInstance("MD5");
- } catch (NoSuchAlgorithmException e) {
- throw new CloudRuntimeException("Unable to hash password", e);
- }
+ public String encode(String password) {
+ MessageDigest md5 = null;
+ try {
+ md5 = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ throw new CloudRuntimeException("Unable to hash password", e);
+ }
- md5.reset();
- BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes()));
- String pwStr = pwInt.toString(16);
- int padding = 32 - pwStr.length();
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < padding; i++) {
- sb.append('0'); // make sure the MD5 password is 32 digits long
- }
- sb.append(pwStr);
- return sb.toString();
- }
+ md5.reset();
+ BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes()));
+ String pwStr = pwInt.toString(16);
+ int padding = 32 - pwStr.length();
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < padding; i++) {
+ sb.append('0'); // make sure the MD5 password is 32 digits long
+ }
+ sb.append(pwStr);
+ return sb.toString();
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/aa6f4dc8/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java b/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java
index 849e82e..6a5f415 100644
--- a/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java
+++ b/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java
@@ -24,36 +24,38 @@ import org.apache.log4j.Logger;
import com.cloud.user.UserAccount;
import com.cloud.user.dao.UserAccountDao;
+import com.cloud.utils.Pair;
-
-@Local(value={UserAuthenticator.class})
+@Local(value = {UserAuthenticator.class})
public class PlainTextUserAuthenticator extends DefaultUserAuthenticator {
- public static final Logger s_logger = Logger.getLogger(PlainTextUserAuthenticator.class);
-
- @Inject private UserAccountDao _userAccountDao;
-
- @Override
- public boolean authenticate(String username, String password, Long domainId, Map<String, Object[]> requestParameters ) {
- if (s_logger.isDebugEnabled()) {
+ public static final Logger s_logger = Logger.getLogger(PlainTextUserAuthenticator.class);
+
+ @Inject
+ private UserAccountDao _userAccountDao;
+
+ @Override
+ public Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String password, Long domainId, Map<String, Object[]> requestParameters) {
+ if (s_logger.isDebugEnabled()) {
s_logger.debug("Retrieving user: " + username);
}
UserAccount user = _userAccountDao.getUserAccount(username, domainId);
if (user == null) {
s_logger.debug("Unable to find user with " + username + " in domain " + domainId);
- return false;
+ return new Pair<Boolean, ActionOnFailedAuthentication>(false, null);
}
-
+
if (!user.getPassword().equals(password)) {
s_logger.debug("Password does not match");
- return false;
+ return new Pair<Boolean, ActionOnFailedAuthentication>(false, ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
}
- return true;
- }
-
- @Override
- public String encode(String password) {
- // Plaintext so no encoding at all
- return password;
- }
+
+ return new Pair<Boolean, ActionOnFailedAuthentication>(true, null);
+ }
+
+ @Override
+ public String encode(String password) {
+ // Plaintext so no encoding at all
+ return password;
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/aa6f4dc8/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java b/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java
index 3592ddc..36305f1 100644
--- a/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java
+++ b/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java
@@ -30,9 +30,10 @@ import org.bouncycastle.util.encoders.Base64;
import com.cloud.user.UserAccount;
import com.cloud.user.dao.UserAccountDao;
+import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
-@Local(value={UserAuthenticator.class})
+@Local(value = {UserAuthenticator.class})
public class SHA256SaltedUserAuthenticator extends DefaultUserAuthenticator {
public static final Logger s_logger = Logger.getLogger(SHA256SaltedUserAuthenticator.class);
private static final String s_defaultPassword = "000000000000000000000000000=";
@@ -45,8 +46,7 @@ public class SHA256SaltedUserAuthenticator extends DefaultUserAuthenticator {
* @see com.cloud.server.auth.UserAuthenticator#authenticate(java.lang.String, java.lang.String, java.lang.Long, java.util.Map)
*/
@Override
- public boolean authenticate(String username, String password,
- Long domainId, Map<String, Object[]> requestParameters) {
+ public Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String password, Long domainId, Map<String, Object[]> requestParameters) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Retrieving user: " + username);
}
@@ -72,7 +72,12 @@ public class SHA256SaltedUserAuthenticator extends DefaultUserAuthenticator {
try {
String hashedPassword = encode(password, salt);
/* constantTimeEquals comes first in boolean since we need to thwart timing attacks */
- return constantTimeEquals(realPassword, hashedPassword) && realUser;
+ boolean result = constantTimeEquals(realPassword, hashedPassword) && realUser;
+ ActionOnFailedAuthentication action = null;
+ if (!result && realUser) {
+ action = ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT;
+ }
+ return new Pair<Boolean, ActionOnFailedAuthentication>(result, action);
} catch (NoSuchAlgorithmException e) {
throw new CloudRuntimeException("Unable to hash password", e);
} catch (UnsupportedEncodingException e) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/aa6f4dc8/plugins/user-authenticators/sha256salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java
----------------------------------------------------------------------
diff --git a/plugins/user-authenticators/sha256salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java b/plugins/user-authenticators/sha256salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java
index 4c4c152..39751c7 100644
--- a/plugins/user-authenticators/sha256salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java
+++ b/plugins/user-authenticators/sha256salted/test/src/com/cloud/server/auth/test/AuthenticatorTest.java
@@ -92,11 +92,11 @@ public class AuthenticatorTest {
@Test
public void testAuthentication() throws UnsupportedEncodingException, NoSuchAlgorithmException {
Map<String, Object[]> dummyMap = new HashMap<String, Object[]>();
- assertEquals("32 byte salt authenticated", true, authenticator.authenticate("admin", "password", 0L, dummyMap));
- assertEquals("20 byte salt authenticated", true, authenticator.authenticate("admin20Byte", "password", 0L, dummyMap));
- assertEquals("fake user not authenticated", false, authenticator.authenticate("fake", "fake", 0L, dummyMap));
- assertEquals("bad password not authenticated", false, authenticator.authenticate("admin", "fake", 0L, dummyMap));
- assertEquals("20 byte user bad password not authenticated", false, authenticator.authenticate("admin20Byte", "fake", 0L, dummyMap));
+ assertEquals("32 byte salt authenticated", true, authenticator.authenticate("admin", "password", 0L, dummyMap).first());
+ assertEquals("20 byte salt authenticated", true, authenticator.authenticate("admin20Byte", "password", 0L, dummyMap).first());
+ assertEquals("fake user not authenticated", false, authenticator.authenticate("fake", "fake", 0L, dummyMap).first());
+ assertEquals("bad password not authenticated", false, authenticator.authenticate("admin", "fake", 0L, dummyMap).first());
+ assertEquals("20 byte user bad password not authenticated", false, authenticator.authenticate("admin20Byte", "fake", 0L, dummyMap).first());
}
// @Test
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/aa6f4dc8/server/src/com/cloud/server/auth/UserAuthenticator.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/auth/UserAuthenticator.java b/server/src/com/cloud/server/auth/UserAuthenticator.java
index 95c4f0e..cc527b8 100644
--- a/server/src/com/cloud/server/auth/UserAuthenticator.java
+++ b/server/src/com/cloud/server/auth/UserAuthenticator.java
@@ -18,26 +18,29 @@ package com.cloud.server.auth;
import java.util.Map;
+import com.cloud.utils.Pair;
import com.cloud.utils.component.Adapter;
/**
* which UserAuthenticator to user in components.xml.
- *
*/
public interface UserAuthenticator extends Adapter {
-
- /**
- *
- * @param username
- * @param password
- * @param domainId
- * @return true if the user has been successfully authenticated, false otherwise
- */
- public boolean authenticate(String username, String password, Long domainId, Map<String, Object[]> requestParameters);
-
- /**
- * @param password
- * @return the encoded password
- */
- public String encode(String password);
+ public enum ActionOnFailedAuthentication {
+ INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT;
+ }
+
+ /**
+ *
+ * @param username
+ * @param password
+ * @param domainId
+ * @return the pair of 2 booleans - first identifies the success of authenciation, the second - whether to increase incorrect login attempts count in case of failed authentication
+ */
+ public Pair<Boolean, ActionOnFailedAuthentication> authenticate(String username, String password, Long domainId, Map<String, Object[]> requestParameters);
+
+ /**
+ * @param password
+ * @return the encoded password
+ */
+ public String encode(String password);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/aa6f4dc8/server/src/com/cloud/user/AccountManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java
index 0655f8c..d367653 100755
--- a/server/src/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/com/cloud/user/AccountManagerImpl.java
@@ -21,6 +21,7 @@ import java.security.NoSuchAlgorithmException;
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;
@@ -110,6 +111,7 @@ import com.cloud.projects.ProjectVO;
import com.cloud.projects.dao.ProjectAccountDao;
import com.cloud.projects.dao.ProjectDao;
import com.cloud.server.auth.UserAuthenticator;
+import com.cloud.server.auth.UserAuthenticator.ActionOnFailedAuthentication;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeApiService;
@@ -1960,13 +1962,19 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
}
boolean authenticated = false;
+ HashSet<ActionOnFailedAuthentication> actionsOnFailedAuthenticaion = new HashSet<ActionOnFailedAuthentication>();
for (UserAuthenticator authenticator : _userAuthenticators) {
- if (authenticator.authenticate(username, password, domainId, requestParameters)) {
+ Pair<Boolean, ActionOnFailedAuthentication> result = authenticator.authenticate(username, password, domainId, requestParameters);
+ if (result.first()) {
authenticated = true;
break;
+ } else if (result.second() != null) {
+ actionsOnFailedAuthenticaion.add(result.second());
}
}
+ boolean updateIncorrectLoginCount = actionsOnFailedAuthenticaion.contains(ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
+
if (authenticated) {
UserAccount userAccount = _userAccountDao.getUserAccount(username, domainId);
if (userAccount == null) {
@@ -2003,13 +2011,14 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
if (!isInternalAccount(userAccount.getType())) {
// Internal accounts are not disabled
int attemptsMade = userAccount.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 " + userAccount.getUsername() + " has been disabled due to multiple failed login attempts." +
- " Please contact admin.");
+ if (updateIncorrectLoginCount) {
+ 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 " + userAccount.getUsername() + " has been disabled due to multiple failed login attempts." + " Please contact admin.");
+ }
}
}
} else {