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 bca2e2ea6f..4ae81cb611 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
@@ -21,6 +21,7 @@
import java.util.ArrayList;
import java.util.Calendar;
+import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -326,6 +327,18 @@ public XXAuthSession processFailureLogin(int authStatus, int authType,
return gjAuthSession;
}
+ public Date getLastSuccessLoginAuthTimeByUserId(String loginId) {
+ XXAuthSession xXAuthSession = daoManager.getXXAuthSession().getLastSuccessLoginAuthSessionByUserId(loginId);
+
+ if (xXAuthSession != null) {
+ return authSessionService.populateViewBean(xXAuthSession).getAuthTime();
+ } else {
+ logger.info("Session cleaned up or User logged in for first time");
+ }
+
+ return null;
+ }
+
protected boolean validateUserSession(UserSessionBase userSession,
String currentLoginId) {
if (currentLoginId
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/UserMgr.java b/security-admin/src/main/java/org/apache/ranger/biz/UserMgr.java
index f7433f6f21..14cbfa9072 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/UserMgr.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/UserMgr.java
@@ -585,7 +585,9 @@ public VXPortalUser mapXXPortalUserToVXPortalUser(XXPortalUser user,
userProfile.setUserRoleList(userRoleList);
}
+ userProfile.setLastLoginTime(sessionMgr.getLastSuccessLoginAuthTimeByUserId(sess.getLoginId()));
userProfile.setUserSource(user.getUserSource());
+
return userProfile;
}
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 b49d192b53..297546ed12 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
@@ -71,6 +71,23 @@ public List getAuthSessionByUserId(Long userId){
}
}
+ public XXAuthSession getLastSuccessLoginAuthSessionByUserId(String loginId) {
+ if (loginId == null) {
+ return null;
+ }
+ try {
+ List sessions = getEntityManager()
+ .createNamedQuery("XXAuthSession.getSuccessAuthSessionsByUserId", tClass)
+ .setParameter("loginId", loginId)
+ .setParameter("authStatus", XXAuthSession.AUTH_STATUS_SUCCESS)
+ .setMaxResults(2)
+ .getResultList();
+ return sessions.size() >= 2 ? sessions.get(1) : null;
+ } catch (NoResultException ignoreNoResultFound) {
+ return null;
+ }
+ }
+
public long getRecentAuthFailureCountByLoginId(String loginId, int timeRangezSecond){
Date authWindowStartTime = new Date(DateUtil.getUTCDate().getTime() - timeRangezSecond * 1000);
diff --git a/security-admin/src/main/java/org/apache/ranger/view/VXPortalUser.java b/security-admin/src/main/java/org/apache/ranger/view/VXPortalUser.java
index 27bae7e8a8..6db4d9d9ab 100644
--- a/security-admin/src/main/java/org/apache/ranger/view/VXPortalUser.java
+++ b/security-admin/src/main/java/org/apache/ranger/view/VXPortalUser.java
@@ -20,14 +20,17 @@
package org.apache.ranger.view;
import java.util.Collection;
+import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.ranger.common.AppConstants;
+import org.apache.ranger.json.JsonDateSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
@JsonAutoDetect(getterVisibility=Visibility.NONE, setterVisibility=Visibility.NONE, fieldVisibility=Visibility.ANY)
@JsonInclude(JsonInclude.Include.NON_NULL)
@@ -95,6 +98,9 @@ public class VXPortalUser extends VXDataObject implements java.io.Serializable {
*/
protected String syncSource;
+ @JsonSerialize(using = JsonDateSerializer.class)
+ protected Date lastLoginTime;
+
/**
* Configuration properties.
*
@@ -348,6 +354,14 @@ public void setSyncSource(final String syncSource) {
this.syncSource = syncSource;
}
+ public Date getLastLoginTime() {
+ return lastLoginTime;
+ }
+
+ public void setLastLoginTime(Date lastLoginTime) {
+ this.lastLoginTime = lastLoginTime;
+ }
+
/**
* This return the bean content in string format
* @return formatedStr
@@ -366,6 +380,7 @@ public String toString( ) {
str += "userRoleList={" + userRoleList + "} ";
str += "otherAttributes={" + otherAttributes + "} ";
str += "syncSource={" + syncSource + "} ";
+ str += "lastLoginTime={" + lastLoginTime + "} ";
str += "}";
return str;
}
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 6f7108eac3..9db7bf1ca9 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
@@ -48,6 +48,11 @@
DELETE FROM XXAuthSession obj WHERE obj.id in :ids
+
+ SELECT obj FROM XXAuthSession obj WHERE obj.loginId = :loginId and obj.authStatus = :authStatus order by obj.id DESC
+
+
+
diff --git a/security-admin/src/main/webapp/react-webapp/src/styles/style.css b/security-admin/src/main/webapp/react-webapp/src/styles/style.css
index 646ebebd5f..57adcf354b 100644
--- a/security-admin/src/main/webapp/react-webapp/src/styles/style.css
+++ b/security-admin/src/main/webapp/react-webapp/src/styles/style.css
@@ -1309,7 +1309,7 @@ header {
}
.top-scroll {
- bottom: 3px;
+ bottom: 10px;
right: 5px;
}
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/Layout.jsx b/security-admin/src/main/webapp/react-webapp/src/views/Layout.jsx
index 1edb384232..d6199b41f5 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/Layout.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/Layout.jsx
@@ -40,6 +40,7 @@ import { Loader } from "../components/CommonComponents";
import { Suspense } from "react";
import { PathAssociateWithModule } from "../utils/XAEnums";
import { flatMap, values } from "lodash";
+import dateFormat from "dateformat";
const Layout = () => {
let location = useLocation();
@@ -94,6 +95,13 @@ const Layout = () => {
activate();
};
+ const lastLoginInformation = userProfile?.lastLoginTime
+ ? `You last logged in on, ${dateFormat(
+ new Date(userProfile.lastLoginTime),
+ "dddd, mmm dd, yyyy, hh:MM:ss TT"
+ )}`
+ : "";
+
useEffect(() => {
const interval = setInterval(() => {
if (isPrompted()) {
@@ -170,6 +178,9 @@ const Layout = () => {
>
Licensed under the Apache License, Version 2.0
+
+ {lastLoginInformation}
+
diff --git a/security-admin/src/main/webapp/react-webapp/src/views/SideBar/SideBar.jsx b/security-admin/src/main/webapp/react-webapp/src/views/SideBar/SideBar.jsx
index 19078216b9..6a5db4502c 100644
--- a/security-admin/src/main/webapp/react-webapp/src/views/SideBar/SideBar.jsx
+++ b/security-admin/src/main/webapp/react-webapp/src/views/SideBar/SideBar.jsx
@@ -125,7 +125,7 @@ export const SideBar = () => {
const userProps = getUserProfile();
const loginId = (
- {userProps?.loginId}
+ {userProps?.loginId}
);
let location = useLocation();