/** * Copyright (C) 2011 JTalks.org Team * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jtalks.jcommune.web.listeners; import org.jtalks.jcommune.model.entity.JCommuneProperty; import org.jtalks.jcommune.service.nontransactional.LocationService; import org.jtalks.jcommune.web.controller.AdministrationController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import javax.servlet.ServletContext; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import java.util.concurrent.TimeUnit; import static org.jtalks.jcommune.web.util.AppContextUtils.getBeanFormApplicationContext; /** * Performs initial session setup. * Any general session settings are to be set here. * * @author Evgeniy Naumenko * @author Oleg Tkachenko */ public class SessionSetupListener implements HttpSessionListener { private static volatile JCommuneProperty sessionTimeoutProperty = null; private static LocationService locationService = null; private static int TIME_OUT_SECONDS; private Logger logger = LoggerFactory.getLogger(SessionSetupListener.class); /** * Sets session timeout for any crated session based on a database-located property. * * @param se session event to get new session from */ @Override public void sessionCreated(HttpSessionEvent se) { try { if (sessionTimeoutProperty == null) { synchronized (this) { if (sessionTimeoutProperty == null){ ServletContext context = se.getSession().getServletContext(); sessionTimeoutProperty = getBeanFormApplicationContext(context, JCommuneProperty.class, "sessionTimeoutProperty"); locationService = getBeanFormApplicationContext(context, LocationService.class); int seconds = extractValueFromProperty(sessionTimeoutProperty); /* Zero property value should mean infinitive session. To disable session expiration we should pass negative value here. Setting zero as is results in weird Tomcat behavior.*/ TIME_OUT_SECONDS = seconds > 0 ? seconds : -1; } } } se.getSession().setMaxInactiveInterval(TIME_OUT_SECONDS); } catch (Exception ex) { logger.warn("Bean instantiation error: " + ex); throw ex; } } /** * If session contain user when destroyed, then we need to clean location info of this user. * * @param se session event to get session and check for user in security context. */ @Override public void sessionDestroyed(HttpSessionEvent se) { Object principal = getPrincipalFromSession(se.getSession()); if (principal != null) { try { locationService.clearUserLocation(principal); } catch (Exception ex) { logger.warn("Error clearing user location when session being destroyed: " + ex.getMessage()); } } } /** * Returns principal from SecurityContext * * @param currentSession current session * @return {@link Object} authenticated principal. */ private Object getPrincipalFromSession(HttpSession currentSession) { Object securityContext = currentSession.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); if (securityContext == null) return null; Authentication authentication = ((SecurityContext) securityContext).getAuthentication(); return authentication != null ? authentication.getPrincipal() : null; } /** * @param sessionTimeoutProperty property to read * @return time in seconds */ private int extractValueFromProperty(JCommuneProperty sessionTimeoutProperty) { int value = sessionTimeoutProperty != null ? sessionTimeoutProperty.intValue() : 0; return (int) TimeUnit.SECONDS.convert(value, TimeUnit.MINUTES); } /** * Needed in tests and {@link AdministrationController} when sessionTimeoutProperty is updated. */ public static void resetSessionTimeoutProperty(){ sessionTimeoutProperty = null; } }