dk.itst.oiosaml.sp.service.session.SingleVMSessionHandler.java Source code

Java tutorial

Introduction

Here is the source code for dk.itst.oiosaml.sp.service.session.SingleVMSessionHandler.java

Source

/*
 * The contents of this file are subject to the Mozilla Public 
 * License Version 1.1 (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.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an 
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express 
 * or implied. See the License for the specific language governing
 * rights and limitations under the License.
 *
 *
 * The Original Code is OIOSAML Java Service Provider.
 * 
 * The Initial Developer of the Original Code is Trifork A/S. Portions 
 * created by Trifork A/S are Copyright (C) 2009 Danish National IT 
 * and Telecom Agency (http://www.itst.dk). All Rights Reserved.
 * 
 * Contributor(s):
 *   Joakim Recht <jre@trifork.com>
 *   Rolf Njor Jensen <rolf@trifork.com>
 *
 */
package dk.itst.oiosaml.sp.service.session;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpSession;

import org.apache.commons.collections.map.LRUMap;
import org.apache.log4j.Logger;
import org.opensaml.saml2.core.Issuer;

import dk.itst.oiosaml.logging.Audit;
import dk.itst.oiosaml.logging.Operation;
import dk.itst.oiosaml.sp.model.OIOAssertion;
import dk.itst.oiosaml.sp.service.util.Constants;
import dk.itst.oiosaml.sp.service.util.Utils;

/**
 * Singleton implementation of a SessionHandler. Do not use this in a clustered environment, as it depends on static maps flor state sharing.
 * 
 * @author Joakim Recht
 *
 */
@SuppressWarnings("unchecked")
public class SingleVMSessionHandler implements SessionHandler {
    private static final Logger log = Logger.getLogger(SingleVMSessionHandler.class);

    private final Map<String, TimeOutWrapper<OIOAssertion>> sessionMap = new ConcurrentHashMap<String, TimeOutWrapper<OIOAssertion>>();
    private final Map<String, TimeOutWrapper<String>> sessionIndexMap = new ConcurrentHashMap<String, TimeOutWrapper<String>>();
    private final Map<String, TimeOutWrapper<String>> requestIds = new ConcurrentHashMap<String, TimeOutWrapper<String>>();
    private final Map<String, TimeOutWrapper<Request>> requests = new ConcurrentHashMap<String, TimeOutWrapper<Request>>();
    private Map<String, String> usedAssertionIds = new LRUMap(10000);

    public synchronized void setAssertion(String sessionId, OIOAssertion assertion)
            throws IllegalArgumentException {
        Issuer issuer = assertion.getAssertion().getIssuer();
        String key = (issuer != null ? issuer.getValue() : "unknown") + ":" + assertion.getAssertion().getID();
        if (usedAssertionIds.containsKey(key)) {
            throw new IllegalArgumentException("Assertion ID begin replayed: " + key);
        }
        usedAssertionIds.put(key, assertion.getAssertion().getID());
        sessionMap.put(sessionId, new TimeOutWrapper<OIOAssertion>(assertion));

        String sessionIndex = assertion.getSessionIndex();
        if (sessionIndex != null) {
            // Remove the old sessionIndex
            sessionIndexMap.remove(sessionIndex);

            // Store the new sessionIndex
            sessionIndexMap.put(sessionIndex, new TimeOutWrapper<String>(sessionId));
        }
    }

    public boolean isLoggedIn(String sessionId) {
        OIOAssertion ass = getAssertion(sessionId);
        return ass != null && !ass.hasSessionExpired();
    }

    public void logOut(HttpSession session) {
        // We cannot remove the SESSION_ID_LIST since we use it in LogoutHttpResponseServlet
        // session.removeAttribute(Constants.SESSION_ID_LIST);
        removeAssertion(session.getId());
        session.removeAttribute(Constants.SESSION_USER_ASSERTION);
    }

    private void removeAssertion(String sessionId) {
        TimeOutWrapper<OIOAssertion> tow = sessionMap.remove(sessionId);
        if (tow != null) {
            OIOAssertion ass = tow.getObject();

            if (ass != null) {
                String sessionIndex = ass.getSessionIndex();
                if (sessionIndex != null) {
                    sessionIndexMap.remove(sessionIndex);
                }
            }
        }
    }

    public void logOut(String sessionId) {
        removeAssertion(sessionId);
    }

    public synchronized OIOAssertion getAssertion(String sessionId) {
        if (sessionId == null) {
            return null;
        }
        if (!sessionMap.containsKey(sessionId))
            return null;

        TimeOutWrapper<OIOAssertion> tow = sessionMap.get(sessionId);
        tow.setAccesstime();
        return tow.getObject();
    }

    public String getRelatedSessionId(String sessionIndex) {
        return sessionIndexMap.get(sessionIndex).getObject();
    }

    public Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }

    public void registerRequest(String id, String receiverEntityID) {
        if (log.isDebugEnabled())
            log.debug("Registered id " + id + " for " + receiverEntityID + "(size: " + requestIds.size() + ")");

        requestIds.put(id, new TimeOutWrapper<String>(receiverEntityID));
    }

    /**
     * Remove a request id from the list of registered request ids and return the registered IdP entity id.
     * @param id
     * @throws IllegalArgumentException If the request id is unknown.
     */
    public String removeEntityIdForRequest(String id) {
        if (log.isDebugEnabled())
            log.debug("Removing id " + id);

        TimeOutWrapper<String> tow = requestIds.remove(id);
        if (tow == null) {
            throw new IllegalArgumentException("Request id " + id + " is unknown");
        }
        if (log.isDebugEnabled())
            log.debug("Entity for request " + id + ": " + tow.getObject());
        return tow.getObject();
    }

    public void cleanup(long requestIdsCleanupDelay, long sessionCleanupDelay) {
        cleanup(sessionMap, sessionCleanupDelay, "Session ");
        cleanup(requestIds, requestIdsCleanupDelay, "Request ");
        cleanup(sessionIndexMap, sessionCleanupDelay, "SessionIndex ");
        cleanup(requests, sessionCleanupDelay, "Request ");
    }

    private <E, T> void cleanup(Map<E, TimeOutWrapper<T>> map, long cleanupDelay, String msg) {
        if (log.isDebugEnabled())
            log.debug(hashCode() + " Running cleanup timer on " + map);
        for (E key : map.keySet()) {
            TimeOutWrapper<T> tow = map.get(key);
            if (tow.isExpired(cleanupDelay)) {
                log.debug("Expiring " + tow);
                if (tow.getObject() instanceof OIOAssertion) {
                    OIOAssertion a = (OIOAssertion) tow.getObject();
                    Audit.logSystem(null, a.getID(), Operation.TIMEOUT, a.getSubjectNameIDValue());
                }
                map.remove(key);
            }
        }
    }

    public void resetReplayProtection(int maxNum) {
        usedAssertionIds = new LRUMap(maxNum);
    }

    public String saveRequest(Request request) {
        String state = Utils.generateUUID();
        requests.put(state, new TimeOutWrapper<Request>(request));
        return state;
    }

    public Request getRequest(String state) throws IllegalArgumentException {
        TimeOutWrapper<Request> request = requests.remove(state);
        if (request == null) {
            throw new IllegalArgumentException("No request for state " + state);
        }
        return request.getObject();
    }

}