org.structr.rest.auth.SessionHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.structr.rest.auth.SessionHelper.java

Source

/**
 * Copyright (C) 2010-2018 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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jetty.server.session.SessionCache;
import org.eclipse.jetty.websocket.servlet.UpgradeHttpServletRequest;
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.core.property.PropertyKey;
import org.structr.rest.service.HttpService;

/**
 * Utility class for session handling
 *
 *
 */
public class SessionHelper {

    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.debug("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 {

        try {

            return Services.getInstance().getService(HttpService.class).getSessionCache().get(sessionId);

        } catch (final Exception ex) {
            logger.debug("Unable to retrieve session " + sessionId + " from session cache:", ex);
        }

        return null;
    }

    public static void newSession(final HttpServletRequest request) {

        if (request.getSession(true) == null) {

            if (request instanceof UpgradeHttpServletRequest) {
                logger.debug("Requested to create a new session on a Websocket request, aborting");
                return;
            }

            request.changeSessionId();
        }

        if (request.getSession(false) != null) {

            logger.debug("Created new session " + request.getSession(false).getId());
        } else {

            logger.warn("Request still has no valid session");
        }
    }

    /**
     * Make sure the given sessionId is not set for any user.
     *
     * @param sessionId
     */
    public static void clearSession(final String sessionId) {

        if (StringUtils.isBlank(sessionId)) {
            return;
        }

        final App app = StructrApp.getInstance();
        final PropertyKey<String[]> sessionIdKey = StructrApp.key(Principal.class, "sessionIds");
        final Query<Principal> query = app.nodeQuery(Principal.class).and(sessionIdKey, new String[] { sessionId })
                .disableSorting();

        try {
            for (final Principal p : query.getAsList()) {

                p.removeSessionId(sessionId);
            }

        } catch (Exception 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 PropertyKey<String[]> sessionIdKey = StructrApp.key(Principal.class, "sessionIds");
        final String[] sessionIds = user.getProperty(sessionIdKey);

        if (sessionIds != null && sessionIds.length > 0) {

            final SessionCache sessionCache = Services.getInstance().getService(HttpService.class)
                    .getSessionCache();

            for (final String sessionId : sessionIds) {

                HttpSession session = null;
                try {
                    session = sessionCache.get(sessionId);

                } catch (Exception ex) {
                    logger.warn("Unable to retrieve session " + sessionId + " from session cache:", ex);
                }

                if (session == null || SessionHelper.isSessionTimedOut(session)) {
                    SessionHelper.clearSession(sessionId);
                }
            }
        }
    }

    public static void invalidateSession(final String sessionId) {

        if (sessionId != null) {

            try {
                Services.getInstance().getService(HttpService.class).getSessionCache().delete(sessionId);

            } catch (final Exception ex) {

                logger.warn("Invalidating session failed: {}", sessionId);
            }
        }
    }

    public static Principal checkSessionAuthentication(final HttpServletRequest request) throws FrameworkException {

        String requestedSessionId = request.getRequestedSessionId();
        String sessionId = null;

        logger.debug("0. Requested session id: " + requestedSessionId + ", request says is valid? "
                + request.isRequestedSessionIdValid());

        //HttpSession session       = request.getSession(false);
        boolean isNotTimedOut = false;

        if (requestedSessionId == null) {

            logger.debug("1b. Empty requested session id, creating a new one.");

            // 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 {

            requestedSessionId = getShortSessionId(requestedSessionId);

            // Existing session id, check if we have an existing session
            if (request.getSession(false) != null) {

                logger.debug("1a. Requested session id without worker id suffix: " + requestedSessionId);

                sessionId = request.getSession(false).getId();
                logger.debug("2a. Current session id: " + sessionId);

                if (sessionId.equals(requestedSessionId)) {

                    logger.debug("3a. Current session id equals requested session id");
                } else {

                    logger.debug("3b. Current session id does not equal requested session id.");
                }

            } else {

                logger.debug("2b. Current session is null.");

                // Try to find session in session cache
                if (getSessionBySessionId(requestedSessionId) == null) {

                    // Not found, create new
                    SessionHelper.newSession(request);
                    logger.debug("3a. Created new session");

                    // remove session ID without session
                    SessionHelper.clearSession(requestedSessionId);
                    logger.debug("4. Cleared unknown session " + requestedSessionId);

                    // we just created a totally new session, there can't
                    // be a user with this session ID, so don't search.
                    return null;

                } else {
                    logger.debug("3b. Session with requested id " + requestedSessionId + " found, continuing.");

                    sessionId = requestedSessionId;

                }

            }

            if (SessionHelper.isSessionTimedOut(request.getSession(false))) {

                isNotTimedOut = false;

                // invalidate session
                SessionHelper.invalidateSession(sessionId);

                // remove invalid session ID
                SessionHelper.clearSession(sessionId);

                logger.debug("4a. Cleared timed-out session " + sessionId);

                SessionHelper.newSession(request);
                // we just created a totally new session, there can't
                // be a user with this session ID, so don't search.
                return null;

            } else {

                logger.debug("4b. Session " + sessionId + " is not timed-out.");

                isNotTimedOut = true;
            }
        }

        if (isNotTimedOut) {

            final Principal user = AuthHelper.getPrincipalForSessionId(sessionId);
            //logger.debug("Valid session found: {}, last accessed {}, authenticated with user {}", new Object[]{session, session.getLastAccessedTime(), user});

            return user;

        } else {

            final Principal user = AuthHelper.getPrincipalForSessionId(sessionId);
            if (user != null) {

                //logger.info("Timed-out session: {}, last accessed {}, authenticated with user {}", new Object[]{session, (session != null ? session.getLastAccessedTime() : ""), user});
                logger.debug("Logging out user {}", new Object[] { user });
                AuthHelper.doLogout(request, user);
                try {
                    request.logout();
                } catch (Throwable t) {
                }
            }

            SessionHelper.newSession(request);

            return null;
        }
    }

    public static String getShortSessionId(final String sessionId) {
        return StringUtils.substringBeforeLast(sessionId, ".");
    }
}