Package org.springframework.security.saml.storage

Source Code of org.springframework.security.saml.storage.HttpSessionStorage

/* Copyright 2009 Vladimir Schäfer
*
* Licensed 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.springframework.security.saml.storage;

import org.opensaml.xml.XMLObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.saml.parser.SAMLObject;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Set;

/**
* Class implements storage of SAML messages and uses HttpSession as underlying dataStore. As the XMLObjects
* can't be serialized (which could lead to problems during failover), the messages are transformed into SAMLObject
* which internally marshalls the content into XML during serialization.
*
* Messages are populated to a Hashtable and stored inside HttpSession. The Hashtable is lazily initialized
* during first attempt to create or retrieve a message.
*
* @author Vladimir Schäfer
*/
public class HttpSessionStorage implements SAMLMessageStorage {

    /**
     * Class logger.
     */
    protected final Logger log = LoggerFactory.getLogger(getClass());

    /**
     * Session the storage operates on.
     */
    private final HttpSession session;

    /**
     * Internal storage for messages, corresponding to the object in session.
     */
    private Hashtable<String, SAMLObject<XMLObject>> internalMessages;

    /**
     * Session key for storage of the hashtable.
     */
    private static final String SAML_STORAGE_KEY = "_springSamlStorageKey";

    /**
     * Creates the storage object. The session is manipulated only once caller tries to store
     * or retrieve a message.
     *
     * In case request doesn't already have a started session, it will be created.
     *
     * @param request request to load/store internalMessages from
     */
    public HttpSessionStorage(HttpServletRequest request) {
        Assert.notNull(request, "Request must be set");
        this.session = request.getSession(true);
    }

    /**
     * Creates the storage object. The session is manipulated only once caller tries to store
     * or retrieve a message.
     *
     * @param session session to load/store internalMessages from
     */
    public HttpSessionStorage(HttpSession session) {
        Assert.notNull(session, "Session must be set");
        this.session = session;
    }

    /**
     * Stores a request message into the repository. RequestAbstractType must have an ID
     * set. Any previous message with the same ID will be overwritten.
     *
     * @param messageID ID of message
     * @param message   message to be stored
     */
    public void storeMessage(String messageID, XMLObject message) {
        log.debug("Storing message {} to session {}", messageID, session.getId());
        Hashtable<String, SAMLObject<XMLObject>> messages = getMessages();
        messages.put(messageID, new SAMLObject<XMLObject>(message));
        updateSession(messages);
    }

    /**
     * Returns previously stored message with the given ID or null, if there is no message
     * stored.
     * <p>
     * Message is stored in String format and must be unmarshalled into XMLObject. Call to this
     * method may thus be expensive.
     * <p>
     * Messages are automatically cleared upon successful reception, as we presume that there
     * are never multiple ongoing SAML exchanges for the same session. This saves memory used by
     * the session.
     *
     * @param messageID ID of message to retrieve
     * @return message found or null
     */
    public XMLObject retrieveMessage(String messageID) {
        Hashtable<String, SAMLObject<XMLObject>> messages = getMessages();
        SAMLObject o = messages.get(messageID);
        if (o == null) {
            log.debug("Message {} not found in session {}", messageID, session.getId());
            return null;
        } else {
            log.debug("Message {} found in session {}, clearing", messageID, session.getId());
            messages.clear();
            updateSession(messages);
            return o.getObject();
        }
    }

    /**
     * @return all internalMessages currently stored in the storage
     */
    public Set<String> getAllMessages() {
        Hashtable<String, SAMLObject<XMLObject>> messages = getMessages();
        return Collections.unmodifiableSet(messages.keySet());
    }

    /**
     * Provides message storage hashtable. Table is lazily initialized when user tries to store or retrieve
     * the first message.
     *
     * @return message storage
     */
    private Hashtable<String, SAMLObject<XMLObject>> getMessages() {
        if (internalMessages == null) {
            internalMessages = initializeSession();
        }
        return internalMessages;
    }

    /**
     * Call to the method tries to load internalMessages hashtable object from the session, if the object doesn't exist
     * it will be created and stored.
     * <p>
     * Method synchronizes on session object to prevent two threads from overwriting each others hashtable.
     */
    @SuppressWarnings("unchecked")
    private Hashtable<String, SAMLObject<XMLObject>> initializeSession() {
        Hashtable<String, SAMLObject<XMLObject>> messages = (Hashtable<String, SAMLObject<XMLObject>>) session.getAttribute(SAML_STORAGE_KEY);
        if (messages == null) {
            synchronized (session) {
                messages = (Hashtable<String, SAMLObject<XMLObject>>) session.getAttribute(SAML_STORAGE_KEY);
                if (messages == null) {
                    messages = new Hashtable<String, SAMLObject<XMLObject>>();
                    updateSession(messages);
                }
            }
        }
        return messages;
    }

    /**
     * Updates session with the internalMessages key. Some application servers require session value to be updated
     * in order to replicate the session across nodes or persist it correctly.
     */
    private void updateSession(Hashtable<String, SAMLObject<XMLObject>> messages) {
        session.setAttribute(SAML_STORAGE_KEY, messages);
    }

}
TOP

Related Classes of org.springframework.security.saml.storage.HttpSessionStorage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.