/** * Copyright (C) 2010-2017 Structr GmbH * * This file is part of Structr <http://structr.org>. * * Structr is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * Structr 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Structr. If not, see <http://www.gnu.org/licenses/>. */ package org.structr.rest.auth; import java.time.Instant; import java.util.Date; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.eclipse.jetty.server.session.HashSessionManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.structr.common.error.FrameworkException; import org.structr.core.Services; import org.structr.core.app.App; import org.structr.core.app.Query; import org.structr.core.app.StructrApp; import org.structr.core.entity.Principal; import org.structr.rest.service.HttpService; /** * Utility class for session handling * * */ public class SessionHelper { public static final String STANDARD_ERROR_MSG = "Wrong username or password, or user is blocked. Check caps lock. Note: Username is case sensitive!"; public static final String SESSION_IS_NEW = "SESSION_IS_NEW"; private static final Logger logger = LoggerFactory.getLogger(SessionHelper.class.getName()); public static boolean isSessionTimedOut(final HttpSession session) { if (session == null) { return true; } final long now = (new Date()).getTime(); try { final long lastAccessed = session.getLastAccessedTime(); if (now > lastAccessed + Services.getGlobalSessionTimeout() * 1000) { logger.info("Session {} timed out, last accessed at {}", new Object[]{session.getId(), Instant.ofEpochMilli(lastAccessed).toString()}); return true; } return false; } catch (IllegalStateException ise) { return true; } } public static HttpSession getSessionBySessionId (final String sessionId) throws FrameworkException { return Services.getInstance().getService(HttpService.class).getHashSessionManager().getSession(sessionId); } public static HttpSession newSession(final HttpServletRequest request) { HttpSession session = request.getSession(true); if (session == null) { // try again session = request.getSession(true); } if (session != null) { session.setMaxInactiveInterval(Services.getGlobalSessionTimeout()); } else { logger.error("Unable to create new session after two attempts"); } return session; } /** * Make sure the given sessionId is not set for any user. * * @param sessionId */ public static void clearSession(final String sessionId) { final App app = StructrApp.getInstance(); final Query<Principal> query = app.nodeQuery(Principal.class).and(Principal.sessionIds, new String[]{sessionId}); try { List<Principal> principals = query.getAsList(); for (Principal p : principals) { p.removeSessionId(sessionId); } } catch (FrameworkException fex) { logger.warn("Error while removing sessionId " + sessionId + " from all principals", fex); } } /** * Remove old sessionIds of the given user * * @param user */ public static void clearInvalidSessions(final Principal user) { logger.info("Clearing invalid sessions for user {} ({})", user.getName(), user.getUuid()); final HashSessionManager sessionManager = Services.getInstance().getService(HttpService.class).getHashSessionManager(); final String[] sessionIds = user.getProperty(Principal.sessionIds); if (sessionIds != null && sessionIds.length > 0) { for (String sessionId : sessionIds) { final HttpSession session = sessionManager.getSession(sessionId); if (session == null || SessionHelper.isSessionTimedOut(session)) { SessionHelper.clearSession(sessionId); } } } } public static void invalidateSession(final HttpSession session) { if (session != null) { try { session.invalidate(); } catch (IllegalArgumentException iae) { logger.warn("Invalidating already invalidated session failed: {}", session.getId()); } } } public static Principal checkSessionAuthentication(final HttpServletRequest request) throws FrameworkException { String requestedSessionId = request.getRequestedSessionId(); HttpSession session = request.getSession(false); boolean sessionValid = false; if (requestedSessionId == null) { // No session id requested => create new session SessionHelper.newSession(request); // Store info in request that session is new => saves us a lookup later request.setAttribute(SESSION_IS_NEW, true); // we just created a totally new session, there can't // be a user with this session ID, so don't search. return null; } else { // Existing session id, check if we have an existing session if (session != null) { if (session.getId().equals(requestedSessionId)) { if (SessionHelper.isSessionTimedOut(session)) { sessionValid = false; // remove invalid session ID SessionHelper.clearSession(requestedSessionId); } else { sessionValid = true; } } } else { // No existing session, create new session = SessionHelper.newSession(request); // remove session ID without session SessionHelper.clearSession(requestedSessionId); } } if (sessionValid) { final Principal user = AuthHelper.getPrincipalForSessionId(session.getId()); logger.debug("Valid session found: {}, last accessed {}, authenticated with user {}", new Object[]{session, session.getLastAccessedTime(), user}); return user; } else { final Principal user = AuthHelper.getPrincipalForSessionId(requestedSessionId); logger.debug("Invalid session: {}, last accessed {}, authenticated with user {}", new Object[]{session, (session != null ? session.getLastAccessedTime() : ""), user}); if (user != null) { AuthHelper.doLogout(request, user); } try { request.logout(); request.changeSessionId(); } catch (Throwable t) {} } return null; } }