You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ma...@apache.org on 2022/03/21 07:36:30 UTC
[ranger] branch master updated: RANGER-2362: lockout login after too many failure attempts
This is an automated email from the ASF dual-hosted git repository.
madhan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/master by this push:
new 943a3a0 RANGER-2362: lockout login after too many failure attempts
943a3a0 is described below
commit 943a3a0bb02e7897c7b621994c244733c9dc0d2b
Author: ZhouTianling <zh...@sensorsdata.cn>
AuthorDate: Thu Mar 17 20:01:04 2022 +0800
RANGER-2362: lockout login after too many failure attempts
Signed-off-by: Madhan Neethiraj <ma...@apache.org>
---
.../java/org/apache/ranger/biz/SessionMgr.java | 29 +++++++++++++++++++++-
.../org/apache/ranger/db/XXAuthSessionDao.java | 13 ++++++++++
.../handler/RangerAuthenticationProvider.java | 15 +++++++++++
.../security/listener/SpringEventListener.java | 16 +++++++++++-
.../main/resources/META-INF/jpa_named_queries.xml | 12 +++++++++
.../conf.dist/ranger-admin-default-site.xml | 13 ++++++++++
6 files changed, 96 insertions(+), 2 deletions(-)
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/SessionMgr.java b/security-admin/src/main/java/org/apache/ranger/biz/SessionMgr.java
index 6b002cf..3f56448 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/SessionMgr.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/SessionMgr.java
@@ -44,6 +44,7 @@ import org.apache.ranger.common.SearchCriteria;
import org.apache.ranger.common.StringUtil;
import org.apache.ranger.common.UserSessionBase;
import org.apache.ranger.db.RangerDaoManager;
+import org.apache.ranger.db.XXAuthSessionDao;
import org.apache.ranger.entity.XXAuthSession;
import org.apache.ranger.entity.XXPortalUser;
import org.apache.ranger.entity.XXPortalUserRole;
@@ -453,7 +454,33 @@ public class SessionMgr {
VXAuthSession vXAuthSession = authSessionService.populateViewBean(xXAuthSession);
return vXAuthSession;
}
-
+
+ /**
+ * Check whether the user failed to log in so many times that we need to lock it for
+ * a while. The current limit of is to fail at most n times in a sliding time window,
+ * otherwise the login verification will not be performed in the future.
+ * @param loginId
+ * @return
+ */
+ public boolean isLoginIdLocked(String loginId) {
+ boolean ret = false;
+ boolean autoLockEnabled = PropertiesUtil.getBooleanProperty("ranger.admin.login.autolock.enabled", true);
+
+ if (autoLockEnabled) {
+ int windowSeconds = PropertiesUtil.getIntProperty("ranger.admin.login.autolock.window.seconds", 300);
+ int maxFailuresCount = PropertiesUtil.getIntProperty("ranger.admin.login.autolock.maxfailure", 5);
+ long failuresCount = daoManager.getXXAuthSession().getRecentAuthFailureCountByLoginId(loginId, windowSeconds);
+
+ ret = failuresCount >= maxFailuresCount;
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("isLoginIdLocked(loginId={}): windowSeconds={}, maxFailuresCount={}, failuresCount={}, ret={}", loginId, windowSeconds, maxFailuresCount, failuresCount, ret);
+ }
+ }
+
+ return ret;
+ }
+
public boolean isValidXAUser(String loginId) {
XXPortalUser pUser = daoManager.getXXPortalUser().findByLoginId(loginId);
if (pUser == null) {
diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXAuthSessionDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXAuthSessionDao.java
index b0270e9..934d258 100644
--- a/security-admin/src/main/java/org/apache/ranger/db/XXAuthSessionDao.java
+++ b/security-admin/src/main/java/org/apache/ranger/db/XXAuthSessionDao.java
@@ -19,10 +19,12 @@
package org.apache.ranger.db;
+import java.util.Date;
import java.util.List;
import javax.persistence.NoResultException;
+import org.apache.ranger.common.DateUtil;
import org.apache.ranger.common.db.BaseDao;
import org.apache.ranger.entity.XXAuthSession;
import org.springframework.stereotype.Service;
@@ -63,5 +65,16 @@ public class XXAuthSessionDao extends BaseDao<XXAuthSession> {
return null;
}
}
+
+ public long getRecentAuthFailureCountByLoginId(String loginId, int timeRangezSecond){
+ Date authWindowStartTime = new Date(DateUtil.getUTCDate().getTime() - timeRangezSecond * 1000);
+
+ return getEntityManager()
+ .createNamedQuery("XXAuthSession.getRecentAuthFailureCountByLoginId", Long.class)
+ .setParameter("loginId", loginId)
+ .setParameter("authWindowStartTime", authWindowStartTime)
+ .getSingleResult();
+ }
+
}
diff --git a/security-admin/src/main/java/org/apache/ranger/security/handler/RangerAuthenticationProvider.java b/security-admin/src/main/java/org/apache/ranger/security/handler/RangerAuthenticationProvider.java
index 8f7abbe..efd5417 100644
--- a/security-admin/src/main/java/org/apache/ranger/security/handler/RangerAuthenticationProvider.java
+++ b/security-admin/src/main/java/org/apache/ranger/security/handler/RangerAuthenticationProvider.java
@@ -41,6 +41,7 @@ import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.jaas.DefaultJaasAuthenticationProvider;
import org.springframework.security.authentication.jaas.memory.InMemoryConfiguration;
@@ -62,6 +63,7 @@ import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.apache.ranger.biz.UserMgr;
+import org.apache.ranger.biz.SessionMgr;
@@ -73,7 +75,12 @@ public class RangerAuthenticationProvider implements AuthenticationProvider {
@Autowired
UserMgr userMgr;
+
+ @Autowired
+ SessionMgr sessionMgr;
+
private static final Logger logger = LoggerFactory.getLogger(RangerAuthenticationProvider.class);
+
private String rangerAuthenticationMethod;
private LdapAuthenticator authenticator;
@@ -137,6 +144,14 @@ public class RangerAuthenticationProvider implements AuthenticationProvider {
return authentication;
}
}
+
+ // Following are JDBC
+ if (sessionMgr.isLoginIdLocked(authentication.getName())) {
+ logger.debug("Failed to authenticate since user account is locked");
+
+ throw new LockedException(String.format("User account {} is locked", authentication.getName()));
+ }
+
if (this.isFipsEnabled) {
try {
authentication = getJDBCAuthentication(authentication,"");
diff --git a/security-admin/src/main/java/org/apache/ranger/security/listener/SpringEventListener.java b/security-admin/src/main/java/org/apache/ranger/security/listener/SpringEventListener.java
index af5622a..9b048a0 100644
--- a/security-admin/src/main/java/org/apache/ranger/security/listener/SpringEventListener.java
+++ b/security-admin/src/main/java/org/apache/ranger/security/listener/SpringEventListener.java
@@ -30,6 +30,7 @@ import org.springframework.security.authentication.event.AbstractAuthenticationE
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.security.authentication.event.AuthenticationFailureDisabledEvent;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
+import org.springframework.security.authentication.event.AuthenticationFailureLockedEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
@@ -49,6 +50,8 @@ public class SpringEventListener implements
process((AuthenticationSuccessEvent) event);
} else if (event instanceof AuthenticationFailureBadCredentialsEvent) {
process((AuthenticationFailureBadCredentialsEvent) event);
+ } else if (event instanceof AuthenticationFailureLockedEvent) {
+ process((AuthenticationFailureLockedEvent) event);
} else if (event instanceof AuthenticationFailureDisabledEvent) {
process((AuthenticationFailureDisabledEvent) event);
}
@@ -93,6 +96,17 @@ public class SpringEventListener implements
remoteAddress, sessionId);
}
+ protected void process(AuthenticationFailureLockedEvent authFailEvent) {
+ Authentication auth = authFailEvent.getAuthentication();
+ WebAuthenticationDetails details = (WebAuthenticationDetails) auth.getDetails();
+ String remoteAddress = details != null ? details.getRemoteAddress() : "";
+ String sessionId = details != null ? details.getSessionId() : "";
+
+ logger.info("Login Unsuccessful:" + auth.getName() + " | Ip Address:" + remoteAddress + " | User Locked");
+
+ sessionMgr.processFailureLogin(XXAuthSession.AUTH_STATUS_LOCKED, XXAuthSession.AUTH_TYPE_PASSWORD, auth.getName(), remoteAddress, sessionId);
+ }
+
protected void process(AuthenticationFailureDisabledEvent authFailEvent) {
Authentication auth = authFailEvent.getAuthentication();
WebAuthenticationDetails details = (WebAuthenticationDetails) auth
@@ -102,7 +116,7 @@ public class SpringEventListener implements
String sessionId = details != null ? details.getSessionId() : "";
logger.info("Login Unsuccessful:" + auth.getName() + " | Ip Address:"
- + remoteAddress);
+ + remoteAddress + " | User Disabled");
sessionMgr.processFailureLogin(XXAuthSession.AUTH_STATUS_DISABLED,
XXAuthSession.AUTH_TYPE_PASSWORD, auth.getName(),
diff --git a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
index b56cd26..2f50d71 100755
--- a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
+++ b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
@@ -24,6 +24,18 @@
WHERE obj.extSessionId = :sessionId
</query>
</named-query>
+ <named-query name="XXAuthSession.getRecentAuthFailureCountByLoginId">
+ <query>SELECT COUNT(1) FROM XXAuthSession obj
+ WHERE obj.loginId = :loginId
+ AND obj.authStatus != 1
+ AND obj.createTime > COALESCE(
+ (SELECT MAX(obj2.createTime) FROM XXAuthSession obj2
+ WHERE obj2.loginId = :loginId
+ AND obj2.authStatus = 1
+ AND obj2.createTime > :authWindowStartTime),
+ :authWindowStartTime)
+ </query>
+ </named-query>
<!-- XXPortalUser -->
<named-query name="XXPortalUser.findByEmailAddress">
diff --git a/security-admin/src/main/resources/conf.dist/ranger-admin-default-site.xml b/security-admin/src/main/resources/conf.dist/ranger-admin-default-site.xml
index 2471f6a..e2bfc8f 100644
--- a/security-admin/src/main/resources/conf.dist/ranger-admin-default-site.xml
+++ b/security-admin/src/main/resources/conf.dist/ranger-admin-default-site.xml
@@ -157,6 +157,19 @@
<value>1</value>
</property>
+<!-- #auto lock when too many failed logon attempts -->
+ <property>
+ <name>ranger.admin.login.autolock.enabled</name>
+ <value>true</value>
+ </property>
+ <property>
+ <name>ranger.admin.login.autolock.window.seconds</name>
+ <value>300</value>
+ </property>
+ <property>
+ <name>ranger.admin.login.autolock.maxfailure</name>
+ <value>5</value>
+ </property>
<!-- #hacks -->
<property>