From eda9eeb6e87cafe164db86c1062edb9efc44b4ae Mon Sep 17 00:00:00 2001 From: MaxKey Date: Wed, 18 Aug 2021 16:33:46 +0800 Subject: [PATCH] v2.9.0 & SessionListenerAdapter v2.9.0 & SessionListenerAdapter --- .../authn/AbstractAuthenticationProvider.java | 2 - .../authn/RealmAuthenticationProvider.java | 12 ++- .../realm/AbstractAuthenticationRealm.java | 17 ++++ .../AuthenticationAutoConfiguration.java | 10 +- .../java/org/maxkey/util/DateUtilsTest.java | 2 + .../persistence/db/LoginHistoryService.java | 2 +- .../maxkey/persistence/db/LoginService.java | 4 +- .../main/java/org/maxkey/MaxKeyMvcConfig.java | 16 ++++ .../web/interceptor/PermissionAdapter.java | 4 +- .../interceptor/SessionListenerAdapter.java | 96 +++++++++++++++++++ 10 files changed, 153 insertions(+), 12 deletions(-) create mode 100644 maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/interceptor/SessionListenerAdapter.java diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/AbstractAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/AbstractAuthenticationProvider.java index 5387e83d0..10d56ab6c 100644 --- a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/AbstractAuthenticationProvider.java +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/AbstractAuthenticationProvider.java @@ -143,8 +143,6 @@ public abstract class AbstractAuthenticationProvider { WebContext.setAttribute(attributeName, sessionAttributeMap.get(attributeName)); } - WebContext.setAttribute( - WebConstants.CURRENT_USER_SESSION_ID, WebContext.getSession().getId()); _logger.debug("Login Success Session {}.", WebContext.getSession().getId()); } diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/RealmAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/RealmAuthenticationProvider.java index 9eeb3b902..5016361b5 100644 --- a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/RealmAuthenticationProvider.java +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/RealmAuthenticationProvider.java @@ -135,10 +135,12 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider authenticationRealm.passwordMatches(loadeduserInfo, loginCredential.getPassword()); authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(loadeduserInfo); - + + Authentication authentication = setOnline(loginCredential,loadeduserInfo); + authenticationRealm.insertLoginHistory(loadeduserInfo, loginCredential.getAuthType(), "", "", "SUCCESS"); - return setOnline(loginCredential,loadeduserInfo); + return authentication; }else { String message = WebContext.getI18nValue("login.error.username"); _logger.debug("login user " + loginCredential.getUsername() + " not in this System ." + message); @@ -166,9 +168,11 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider LoginCredential loginCredential = new LoginCredential(); loginCredential.setUsername(loadeduserInfo.getUsername()); + Authentication authentication = setOnline(loginCredential,loadeduserInfo); + authenticationRealm.insertLoginHistory(loadeduserInfo, type, provider, code, message); - return setOnline(loginCredential,loadeduserInfo); + return authentication; }else { String i18nMessage = WebContext.getI18nValue("login.error.username"); _logger.debug("login user " + username + " not in this System ." + i18nMessage); @@ -178,7 +182,7 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider public UsernamePasswordAuthenticationToken setOnline(LoginCredential credential,UserInfo userInfo) { //Online Tickit Id - String onlineTickitId = WebConstants.ONLINE_TICKET_PREFIX + "-" + java.util.UUID.randomUUID().toString().toLowerCase(); + String onlineTickitId = WebConstants.ONLINE_TICKET_PREFIX + "-" +WebContext.genId(); _logger.debug("set online Tickit Cookie " + onlineTickitId + " on domain "+ this.applicationConfig.getBaseDomainName()); OnlineTicket onlineTicket = new OnlineTicket(onlineTickitId); diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/realm/AbstractAuthenticationRealm.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/realm/AbstractAuthenticationRealm.java index f9e152cbe..e29ff7ee7 100644 --- a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/realm/AbstractAuthenticationRealm.java +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/authn/realm/AbstractAuthenticationRealm.java @@ -21,6 +21,9 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.servlet.http.HttpServletResponse; + +import org.maxkey.authn.SigninPrincipal; +import org.maxkey.authn.online.OnlineTicket; import org.maxkey.authn.support.rememberme.AbstractRemeberMeService; import org.maxkey.entity.Groups; import org.maxkey.entity.UserInfo; @@ -34,6 +37,7 @@ import org.maxkey.web.WebContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; /** @@ -134,7 +138,18 @@ public abstract class AbstractAuthenticationRealm { */ public boolean insertLoginHistory(UserInfo userInfo, String type, String provider, String code, String message) { String sessionId = WebContext.genId(); + OnlineTicket onlineTicket = null ; + Authentication authentication = WebContext.getAuthentication(); + if(authentication.getPrincipal() instanceof SigninPrincipal) { + SigninPrincipal signinPrincipal = (SigninPrincipal)authentication.getPrincipal(); + onlineTicket = signinPrincipal.getOnlineTicket(); + sessionId = onlineTicket.getTicketId().substring(3); + } + WebContext.setAttribute(WebConstants.CURRENT_USER_SESSION_ID, sessionId); + + _logger.debug("user session id is {} , online ticket {} ",sessionId,(onlineTicket == null ? "" : onlineTicket.getTicketId())); + userInfo.setLastLoginTime(DateUtils.formatDateTime(new Date())); userInfo.setLastLoginIp(WebContext.getRequestIpAddress()); String platform = ""; @@ -202,6 +217,8 @@ public abstract class AbstractAuthenticationRealm { _logger.debug("Session " + WebContext.getAttribute(WebConstants.CURRENT_USER_SESSION_ID) + ", user " + userInfo.getUsername() + " Logout, datetime " + userInfo.getLastLogoffTime() + " ."); + //remove login user session id + WebContext.removeAttribute(WebConstants.CURRENT_USER_SESSION_ID); } return true; diff --git a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/autoconfigure/AuthenticationAutoConfiguration.java b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/autoconfigure/AuthenticationAutoConfiguration.java index 276fcbf4f..8825145ba 100644 --- a/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/autoconfigure/AuthenticationAutoConfiguration.java +++ b/maxkey-authentications/maxkey-authentication-core/src/main/java/org/maxkey/autoconfigure/AuthenticationAutoConfiguration.java @@ -163,8 +163,14 @@ public class AuthenticationAutoConfiguration implements InitializingBean { public OnlineTicketServices onlineTicketServices( @Value("${maxkey.server.persistence}") int persistence, JdbcTemplate jdbcTemplate, - RedisConnectionFactory redisConnFactory) { - return new OnlineTicketServicesFactory().getService(persistence, jdbcTemplate, redisConnFactory); + RedisConnectionFactory redisConnFactory, + @Value("${server.servlet.session.timeout:1800}") int timeout + ) { + OnlineTicketServices onlineTicketServices = + new OnlineTicketServicesFactory().getService(persistence, jdbcTemplate, redisConnFactory); + onlineTicketServices.setValiditySeconds(timeout); + _logger.trace("onlineTicket timeout " + timeout); + return onlineTicketServices; } @Override diff --git a/maxkey-common/src/test/java/org/maxkey/util/DateUtilsTest.java b/maxkey-common/src/test/java/org/maxkey/util/DateUtilsTest.java index ad4ee22f3..6c1881eaa 100644 --- a/maxkey-common/src/test/java/org/maxkey/util/DateUtilsTest.java +++ b/maxkey-common/src/test/java/org/maxkey/util/DateUtilsTest.java @@ -74,6 +74,8 @@ public class DateUtilsTest { System.out.println(DateUtils.toUtcLocal("2015-11-04T16:00:22.875Z")); System.out.println(DateUtils.toUtcLocal("2015-11-04T23:58:14.286+08:00")); + + System.out.println(DateUtils.formatDateTime(new Date())); } } diff --git a/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginHistoryService.java b/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginHistoryService.java index 88e7ed356..d917e14bf 100644 --- a/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginHistoryService.java +++ b/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginHistoryService.java @@ -55,6 +55,6 @@ public class LoginHistoryService { _logger.debug(" sessionId " +sessionId +" , lastlogofftime " + lastLogoffTime); jdbcTemplate.update(HISTORY_LOGOUT_UPDATE_STATEMENT, new Object[] { lastLogoffTime, sessionId }, - new int[] { Types.TIMESTAMP, Types.VARCHAR }); + new int[] { Types.VARCHAR, Types.VARCHAR }); } } diff --git a/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginService.java b/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginService.java index 4300777e3..39c4ab139 100644 --- a/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginService.java +++ b/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginService.java @@ -240,13 +240,13 @@ public class LoginService { public void setLastLoginInfo(UserInfo userInfo) { jdbcTemplate.update(LOGIN_USERINFO_UPDATE_STATEMENT, new Object[] { userInfo.getLastLoginTime(), userInfo.getLastLoginIp(), userInfo.getLoginCount() + 1, userInfo.getId() }, - new int[] { Types.TIMESTAMP, Types.VARCHAR, Types.INTEGER, Types.VARCHAR }); + new int[] { Types.VARCHAR, Types.VARCHAR, Types.INTEGER, Types.VARCHAR }); } public void setLastLogoffInfo(UserInfo userInfo) { jdbcTemplate.update(LOGOUT_USERINFO_UPDATE_STATEMENT, new Object[] { userInfo.getLastLogoffTime(), userInfo.getId() }, - new int[] { Types.TIMESTAMP, Types.VARCHAR }); + new int[] { Types.VARCHAR, Types.VARCHAR }); } diff --git a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/MaxKeyMvcConfig.java b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/MaxKeyMvcConfig.java index 75c66298b..0f0737740 100644 --- a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/MaxKeyMvcConfig.java +++ b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/MaxKeyMvcConfig.java @@ -26,15 +26,19 @@ import org.maxkey.authn.support.rememberme.AbstractRemeberMeService; import org.maxkey.authn.support.rememberme.HttpRemeberMeEntryPoint; import org.maxkey.configuration.ApplicationConfig; import org.maxkey.constants.ConstantsProperties; +import org.maxkey.persistence.db.LoginHistoryService; +import org.maxkey.persistence.db.LoginService; import org.maxkey.web.interceptor.HistoryLoginAppAdapter; import org.maxkey.web.interceptor.HistoryLogsAdapter; import org.maxkey.web.interceptor.PermissionAdapter; import org.maxkey.web.interceptor.PreLoginAppAdapter; +import org.maxkey.web.interceptor.SessionListenerAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -227,5 +231,17 @@ public class MaxKeyMvcConfig implements WebMvcConfigurer { } + + @Bean(name = "sessionListenerAdapter") + public SessionListenerAdapter sessionListenerAdapter( + LoginService loginService, + LoginHistoryService loginHistoryService + ) { + SessionListenerAdapter sessionListenerAdapter =new SessionListenerAdapter(); + sessionListenerAdapter.setLoginService(loginService); + sessionListenerAdapter.setLoginHistoryService(loginHistoryService); + return sessionListenerAdapter; + } + } diff --git a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/interceptor/PermissionAdapter.java b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/interceptor/PermissionAdapter.java index 6f17c1a7b..5e273ed71 100644 --- a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/interceptor/PermissionAdapter.java +++ b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/interceptor/PermissionAdapter.java @@ -79,7 +79,7 @@ public class PermissionAdapter implements AsyncHandlerInterceptor { HttpServletResponse response, Object handler) throws Exception { _logger.trace("PermissionAdapter preHandle"); - + _logger.trace("PermissionAdapter " + request.getSession().getId()); Object passwordSetTypeAttribute=WebContext.getSession().getAttribute(WebConstants.CURRENT_LOGIN_USER_PASSWORD_SET_TYPE); if(passwordSetTypeAttribute != null) { @@ -140,10 +140,12 @@ public class PermissionAdapter implements AsyncHandlerInterceptor { try { if(authentication.getPrincipal() instanceof SigninPrincipal) { SigninPrincipal signinPrincipal = (SigninPrincipal)authentication.getPrincipal(); + //if onlineTicket refresh is removed or timeout then Exception OnlineTicket onlineTicket = signinPrincipal.getOnlineTicket(); onlineTicketServices.refresh(onlineTicket.getTicketId()); } }catch(Exception e) { + _logger.debug("Online Ticket timeout ... forward to /login"); RequestDispatcher dispatcher = request.getRequestDispatcher("/logout"); dispatcher.forward(request, response); } diff --git a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/interceptor/SessionListenerAdapter.java b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/interceptor/SessionListenerAdapter.java new file mode 100644 index 000000000..cee9cf138 --- /dev/null +++ b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/maxkey/web/interceptor/SessionListenerAdapter.java @@ -0,0 +1,96 @@ +/* + * Copyright [2021] [MaxKey of copyright http://www.maxkey.top] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.maxkey.web.interceptor; + +import java.util.Date; + +import javax.servlet.annotation.WebListener; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionListener; + +import org.apache.mybatis.jpa.util.WebContext; +import org.maxkey.entity.UserInfo; +import org.maxkey.persistence.db.LoginHistoryService; +import org.maxkey.persistence.db.LoginService; +import org.maxkey.util.DateUtils; +import org.maxkey.web.WebConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@WebListener +public class SessionListenerAdapter implements HttpSessionListener { + + private static final Logger _logger = LoggerFactory.getLogger(SessionListenerAdapter.class); + + LoginService loginService; + + LoginHistoryService loginHistoryService; + + public SessionListenerAdapter() { + super(); + _logger.debug("SessionListenerAdapter inited . "); + } + + public void init() { + if(loginService == null ) { + loginService = (LoginService)WebContext.getBean("loginService"); + loginHistoryService = (LoginHistoryService)WebContext.getBean("loginHistoryService"); + _logger.debug("SessionListenerAdapter function inited . "); + } + } + /** + * session Created + */ + @Override + public void sessionCreated(HttpSessionEvent sessionEvent) { + _logger.trace("new session Created :" + sessionEvent.getSession().getId()); + } + + /** + * session Destroyed + */ + @Override + public void sessionDestroyed(HttpSessionEvent sessionEvent) { + HttpSession session = sessionEvent.getSession(); + Object sessionIdAttribute = session.getAttribute(WebConstants.CURRENT_USER_SESSION_ID); + _logger.trace("session Id : " + session.getId()); + if(sessionIdAttribute != null) { + init(); + UserInfo userInfo = (UserInfo)session.getAttribute(WebConstants.CURRENT_USER); + userInfo.setLastLogoffTime(DateUtils.formatDateTime(new Date())); + loginService.setLastLogoffInfo(userInfo); + loginHistoryService.logoff(userInfo.getLastLogoffTime(), sessionIdAttribute.toString()); + + _logger.debug( + "session {} Destroyed as {} userId : {} , username : {}" , + sessionIdAttribute, + userInfo.getLastLogoffTime(), + userInfo.getId(), + userInfo.getUsername()); + } + + } + + public void setLoginService(LoginService loginService) { + this.loginService = loginService; + } + + public void setLoginHistoryService(LoginHistoryService loginHistoryService) { + this.loginHistoryService = loginHistoryService; + } + +}