/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program 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 Lesser General Public License for more details.
*
* Copyright (c) 2002-2016 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.platform.web.http;
import org.apache.commons.codec.digest.DigestUtils;
import org.pentaho.platform.api.engine.IPentahoSession;
import org.pentaho.platform.engine.core.system.PentahoSessionHolder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
* This class serves to capture a users IPentahoSession and Spring Authentication by assigning them a key. The returned
* key can be used by another party to regain the users session/authentication, in essence logging them in from another
* client.
*
* User: nbaker Date: 6/28/12
*/
public class PreAuthenticatedSessionHolder {
private final Map<String, SessionAuthenticationTuple> sessionMap = Collections
.synchronizedMap( new HashMap<String, SessionAuthenticationTuple>() );
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor( new ThreadFactory() {
public Thread newThread( Runnable r ) {
Thread t = new Thread( r, "PreAuthenticationSessionHolder-Eviction" );
t.setDaemon( true );
return t;
}
} );
private ScheduledFuture<?> scheduleHandle;
private int TTL = 10 * 60 * 1000; // default to 10 minutes
private int evictionInterval = 60;
/**
* Constructs a new session holder with the given TTL and eviction schedule.
*
* @param ttl
* The time a captured session will be retained
* @param evictionInterval
* The interval in which sessions will be scanned and evicted if over the TTL
*/
public PreAuthenticatedSessionHolder( int ttl, int evictionInterval ) {
this.TTL = ttl * 1000;
this.evictionInterval = evictionInterval;
initializeEvictionSchedule();
}
/**
* Constructs a new session holder with the default TTL and eviction schedule.
*/
public PreAuthenticatedSessionHolder() {
initializeEvictionSchedule();
}
private void initializeEvictionSchedule() {
// Start a recurring thread to clean out old entries.
final Runnable sessionCleaner = new Runnable() {
public void run() {
Iterator<Map.Entry<String, SessionAuthenticationTuple>> iterator = sessionMap.entrySet().iterator();
while ( iterator.hasNext() ) {
Map.Entry<String, SessionAuthenticationTuple> entry = iterator.next();
if ( entry.getValue().entryTime.getTime() + TTL < new Date().getTime() ) {
// more than the allowed time has passed for this entry. Evict
sessionMap.remove( entry.getKey() );
}
}
}
};
scheduleHandle =
scheduler.scheduleWithFixedDelay( sessionCleaner, evictionInterval, evictionInterval, TimeUnit.SECONDS );
}
/**
* Stores the active IPentahoSession and Spring Security Authentication objects (both ThreadLocal based).
*
* @return key associated with the captured session.
*/
public String captureSession() {
SessionAuthenticationTuple tuple = new SessionAuthenticationTuple();
tuple.session = PentahoSessionHolder.getSession();
tuple.auth = SecurityContextHolder.getContext().getAuthentication();
tuple.entryTime = new Date();
String hash = DigestUtils.md5Hex( tuple.session.getId().getBytes() );
sessionMap.put( hash, tuple );
return hash;
}
/**
* Assigns the IPentahoSession and Authentication stored with the given key to the current request.
*
* @param hash
* Stored key
*
* @return success if the given key matches a session stored in the holder.
*/
public boolean restoreSession( String hash ) {
SessionAuthenticationTuple tuple = sessionMap.get( hash );
if ( tuple == null ) {
return false;
}
SecurityContextHolder.getContext().setAuthentication( tuple.auth );
PentahoSessionHolder.setSession( tuple.session );
return true;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
close();
}
/**
* This should be called with this class is no longer in use. Cleans-up the eviction scheduled task.
*/
public void close() {
if ( !scheduler.isShutdown() ) {
try {
scheduleHandle.cancel( true );
scheduler.shutdown();
} catch ( Exception ignored ) {
//ignored
}
}
}
private static class SessionAuthenticationTuple {
IPentahoSession session;
Authentication auth;
Date entryTime;
}
}