org.jsecurity.web.session.DefaultWebSessionManager.java Source code

Java tutorial

Introduction

Here is the source code for org.jsecurity.web.session.DefaultWebSessionManager.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.jsecurity.web.session;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jsecurity.authz.AuthorizationException;
import org.jsecurity.authz.HostUnauthorizedException;
import org.jsecurity.session.InvalidSessionException;
import org.jsecurity.session.Session;
import org.jsecurity.session.mgt.DefaultSessionManager;
import org.jsecurity.web.WebUtils;
import org.jsecurity.web.attr.CookieAttribute;
import org.jsecurity.web.attr.RequestParamAttribute;
import org.jsecurity.web.attr.WebAttribute;
import org.jsecurity.web.servlet.JSecurityHttpServletRequest;
import org.jsecurity.web.servlet.JSecurityHttpSession;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;
import java.net.InetAddress;

/**
 * Web-application capable <tt>SessionManager</tt> implementation.
 *
 * @author Les Hazlewood
 * @since 0.9
 */
public class DefaultWebSessionManager extends DefaultSessionManager implements WebSessionManager {

    //TODO - complete JavaDoc

    private static final Log log = LogFactory.getLog(DefaultWebSessionManager.class);

    /**
     * Property specifying if, after a session object is acquired from the request, if that session should be
     * validated to ensure the starting origin of the session is the same as the incoming request.
     */
    private boolean validateRequestOrigin = false; //default

    protected CookieAttribute<Serializable> sessionIdCookieAttribute = null;
    protected RequestParamAttribute<Serializable> sessionIdRequestParamAttribute = null;

    public DefaultWebSessionManager() {
        ensureCookieSessionIdStore();
        ensureRequestParamSessionIdStore();
    }

    public CookieAttribute<Serializable> getSessionIdCookieAttribute() {
        return sessionIdCookieAttribute;
    }

    public void setSessionIdCookieAttribute(CookieAttribute<Serializable> sessionIdCookieAttribute) {
        this.sessionIdCookieAttribute = sessionIdCookieAttribute;
    }

    public RequestParamAttribute<Serializable> getSessionIdRequestParamAttribute() {
        return sessionIdRequestParamAttribute;
    }

    public void setSessionIdRequestParamAttribute(
            RequestParamAttribute<Serializable> sessionIdRequestParamAttribute) {
        this.sessionIdRequestParamAttribute = sessionIdRequestParamAttribute;
    }

    /**
     * If set to <tt>true</tt>, this implementation will ensure that any
     * <tt>HttpRequest</tt> attempting
     * to join a session (i.e. via {@link #getSession getSession} must have the same
     * IP Address of the <tt>HttpRequest</tt> that started the session.
     *
     * <p> If set to <tt>false</tt>, any <tt>HttpRequest</tt> with a reference to a valid
     * session id may acquire that <tt>Session</tt>.
     *
     * <p>Although convenient, this should only be enabled in environments where the
     * system can <em>guarantee</em> that each IP address represents one and only one
     * machine accessing the system.
     *
     * <p>Public websites are not good candidates for enabling this
     * feature since many browser clients often sit behind NAT routers (in
     * which case many machines are viewed to come from the same IP, thereby making this
     * validation check useless).  Also, some internet service providers (e.g. AOL) may change a
     * client's IP in mid-session, making subsequent requests appear to come from a different
     * location.  Again, this feature should only be enabled where IP Addresses can be guaranteed a
     * 1-to-1 relationship with a user's session.
     *
     * <p>For the reasons specified above, this property is <tt>false</tt> by default.
     *
     * @return true if this factory will verify each HttpRequest joining a session
     */
    public boolean isValidateRequestOrigin() {
        return validateRequestOrigin;
    }

    /**
     * Sets whether or not a request's origin will be validated when accessing a session.  See
     * the {@link #isValidateRequestOrigin} JavaDoc for an in-depth explanation of this property.
     *
     * @param validateRequestOrigin whether or not to validate the request's origin when accessing
     *                              a session.
     * @see #isValidateRequestOrigin
     */
    public void setValidateRequestOrigin(boolean validateRequestOrigin) {
        this.validateRequestOrigin = validateRequestOrigin;
    }

    public void setSessionIdCookieName(String name) {
        getSessionIdCookieAttribute().setName(name);
    }

    public void setSessionIdCookiePath(String path) {
        getSessionIdCookieAttribute().setPath(path);
    }

    public void setSessionIdCookieMaxAge(int maxAge) {
        getSessionIdCookieAttribute().setMaxAge(maxAge);
    }

    public void setSessionIdCookieSecure(boolean secure) {
        getSessionIdCookieAttribute().setSecure(secure);
    }

    protected void ensureCookieSessionIdStore() {
        CookieAttribute<Serializable> cookieStore = getSessionIdCookieAttribute();
        if (cookieStore == null) {
            cookieStore = new CookieAttribute<Serializable>(JSecurityHttpSession.DEFAULT_SESSION_ID_NAME);
            cookieStore.setCheckRequestParams(false);
            setSessionIdCookieAttribute(cookieStore);
        }
    }

    protected void ensureRequestParamSessionIdStore() {
        RequestParamAttribute<Serializable> reqParamStore = getSessionIdRequestParamAttribute();
        if (reqParamStore == null) {
            reqParamStore = new RequestParamAttribute<Serializable>(JSecurityHttpSession.DEFAULT_SESSION_ID_NAME);
            setSessionIdRequestParamAttribute(reqParamStore);
        }
    }

    protected void validateSessionOrigin(ServletRequest request, Session session) throws HostUnauthorizedException {
        InetAddress requestIp = WebUtils.getInetAddress(request);
        InetAddress originIp = session.getHostAddress();
        Serializable sessionId = session.getId();

        if (originIp == null) {
            if (requestIp != null) {
                String msg = "No IP Address was specified when creating session with id [" + sessionId
                        + "].  Attempting to access session from " + "IP [" + requestIp
                        + "].  Origin IP and request IP must match.";
                throw new HostUnauthorizedException(msg);
            }
        } else {
            if (requestIp != null) {
                if (!requestIp.equals(originIp)) {
                    String msg = "Session with id [" + sessionId + "] originated from [" + originIp
                            + "], but the current HttpServletRequest originated " + "from [" + requestIp
                            + "].  Disallowing session access: "
                            + "session origin and request origin must match to allow access.";
                    throw new HostUnauthorizedException(msg);
                }

            } else {
                String msg = "No IP Address associated with the current HttpServletRequest.  " + "Session with id ["
                        + sessionId + "] originated from " + "[" + originIp
                        + "].  Request IP must match the session's origin "
                        + "IP in order to gain access to that session.";
                throw new HostUnauthorizedException(msg);
            }
        }
    }

    protected void storeSessionId(Serializable currentId, ServletRequest request, ServletResponse response) {
        if (currentId == null) {
            String msg = "sessionId cannot be null when persisting for subsequent requests.";
            throw new IllegalArgumentException(msg);
        }
        //ensure that the id has been set in the idStore, or if it already has, that it is not different than the
        //'real' session value:
        Serializable existingId = retrieveSessionId(request, response);
        if (existingId == null || !currentId.equals(existingId)) {
            getSessionIdCookieAttribute().storeValue(currentId, request, response);
        }
    }

    protected Serializable retrieveSessionId(ServletRequest request, ServletResponse response) {
        WebAttribute<Serializable> cookieSessionIdAttribute = getSessionIdCookieAttribute();
        Serializable id = cookieSessionIdAttribute.retrieveValue(request, response);
        if (id != null) {
            request.setAttribute(JSecurityHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
                    JSecurityHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
        } else {
            id = getSessionIdRequestParamAttribute().retrieveValue(request, response);
            if (id != null) {
                request.setAttribute(JSecurityHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
                        JSecurityHttpServletRequest.URL_SESSION_ID_SOURCE);
            }
        }
        return id;
    }

    public Serializable start(InetAddress hostAddress) throws HostUnauthorizedException, IllegalArgumentException {
        ServletRequest request = WebUtils.getRequiredServletRequest();
        ServletResponse response = WebUtils.getRequiredServletResponse();
        return start(request, response, hostAddress);
    }

    protected Serializable start(ServletRequest request, ServletResponse response, InetAddress inetAddress) {
        Serializable sessionId = super.start(inetAddress);
        storeSessionId(sessionId, request, response);
        request.removeAttribute(JSecurityHttpServletRequest.REFERENCED_SESSION_ID_SOURCE);
        request.setAttribute(JSecurityHttpServletRequest.REFERENCED_SESSION_IS_NEW, Boolean.TRUE);
        return sessionId;
    }

    public Session retrieveSession(Serializable sessionId) throws InvalidSessionException, AuthorizationException {
        if (sessionId != null) {
            return super.retrieveSession(sessionId);
        } else {
            ServletRequest request = WebUtils.getRequiredServletRequest();
            ServletResponse response = WebUtils.getRequiredServletResponse();
            return getSession(request, response);
        }
    }

    /**
     * Returns the Session associated with the specified request if it is valid or <tt>null</tt> if a Session doesn't
     * exist or it was invalid.
     *
     * @param request  incoming servlet request
     * @param response outgoing servlet response
     * @return the Session associated with the incoming request or <tt>null</tt> if one does not exist.
     * @throws org.jsecurity.session.InvalidSessionException
     *          if the associated Session has expired prior to invoking this method.
     * @throws org.jsecurity.authz.AuthorizationException
     *          if the caller is not authorized to access the session associated with the request.
     */
    public final Session getSession(ServletRequest request, ServletResponse response)
            throws InvalidSessionException, AuthorizationException {

        Session session;
        try {
            session = doGetSession(request, response);
        } catch (InvalidSessionException ise) {
            if (log.isTraceEnabled()) {
                log.trace("Request Session is invalid, message: [" + ise.getMessage() + "].  Removing any "
                        + "associated session cookie...");
            }
            getSessionIdCookieAttribute().removeValue(request, response);

            //give subclass a chance to do something additional if necessary.  Otherwise returning null is just fine:
            session = handleInvalidSession(request, response, ise);
        }

        return session;
    }

    protected Session doGetSession(ServletRequest request, ServletResponse response) {

        Session session = null;
        Serializable sessionId = retrieveSessionId(request, response);

        if (sessionId != null) {
            request.setAttribute(JSecurityHttpServletRequest.REFERENCED_SESSION_ID, sessionId);
            session = super.retrieveSession(sessionId);
            if (isValidateRequestOrigin()) {
                if (log.isDebugEnabled()) {
                    log.debug("Validating request origin against session origin");
                }
                validateSessionOrigin(request, session);
            }
            if (session != null) {
                request.setAttribute(JSecurityHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            }
        } else {
            if (log.isTraceEnabled()) {
                log.trace("No JSecurity session id associated with the given "
                        + "HttpServletRequest.  A Session will not be returned.");
            }
        }

        return session;
    }

    protected Session handleInvalidSession(ServletRequest request, ServletResponse response,
            InvalidSessionException ise) {
        if (log.isTraceEnabled()) {
            log.trace("Sesssion associated with the current request is nonexistent or invalid.  Returning null.");
        }
        return null;
    }

    protected void onStop(Session session) {
        super.onStop(session);
        ServletRequest request = WebUtils.getRequiredServletRequest();
        ServletResponse response = WebUtils.getRequiredServletResponse();
        getSessionIdCookieAttribute().removeValue(request, response);
    }
}