blob: e4c7d56679f52d0d743623ff9e0578c1676585ad [file] [log] [blame]
/*
* Copyright 2005-2008 Les Hazlewood
*
* 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.jsecurity.mgt;
import org.jsecurity.authz.AuthorizationException;
import org.jsecurity.authz.HostUnauthorizedException;
import org.jsecurity.realm.Realm;
import org.jsecurity.session.ExpiredSessionException;
import org.jsecurity.session.InvalidSessionException;
import org.jsecurity.session.Session;
import org.jsecurity.session.StoppedSessionException;
import org.jsecurity.session.event.SessionEventListener;
import org.jsecurity.session.event.mgt.SessionEventListenerRegistrar;
import org.jsecurity.session.mgt.DefaultSessionManager;
import org.jsecurity.session.mgt.DelegatingSession;
import org.jsecurity.session.mgt.SessionManager;
import org.jsecurity.util.LifecycleUtils;
import java.io.Serializable;
import java.net.InetAddress;
import java.util.Collection;
/**
* JSecurity support of a {@link SecurityManager} class hierarchy that delegates all
* {@link org.jsecurity.session.Session session} operations to a wrapped {@link SessionManager SessionManager}
* instance. That is, this class implements the methods in the
* {@link SecurityManager SecurityManager} interface, but in reality, those methods are merely passthrough calls to
* the underlying 'real' <tt>SessionManager</tt> instance.
*
* <p>The remaining <tt>SecurityManager</tt> methods not implemented by this class or its parents are left to be
* implemented by subclasses.
*
* <p>In keeping with the other classes in this hierarchy and JSecurity's desire to minimize configuration whenever
* possible, suitable default instances for all dependencies will be created upon {@link #init() initialization} if
* they have not been provided.
*
* @author Les Hazlewood
* @since 0.9
*/
public abstract class SessionsSecurityManager extends AuthorizingSecurityManager implements SessionEventListenerRegistrar {
protected SessionManager sessionManager;
protected Collection<SessionEventListener> sessionEventListeners = null;
/**
* Default no-arg constructor - used in IoC environments or when the programmer wishes to explicitly call
* {@link #init()} after the necessary properties have been set.
*/
public SessionsSecurityManager() {
}
/**
* Supporting constructor for a single-realm application (automatically calls {@link #init()} before returning).
*
* @param singleRealm the single realm used by this SecurityManager.
*/
public SessionsSecurityManager(Realm singleRealm) {
super(singleRealm);
}
/**
* Supporting constructor that sets the {@link #setRealms realms} property and then automatically calls {@link #init()}.
*
* @param realms the realm instances backing this SecurityManager.
*/
public SessionsSecurityManager(Collection<Realm> realms) {
super(realms);
}
/**
* Sets the underlying delegate {@link SessionManager} instance that will be used to support this implementation's
* <tt>SessionManager</tt> method calls.
*
* <p>This <tt>SecurityManager</tt> implementation does not provide logic to support the inherited
* <tt>SessionManager</tt> interface, but instead delegates these calls to an internal
* <tt>SessionManager</tt> instance.
*
* <p>If a <tt>SessionManager</tt> instance is not set, a default one will be automatically created and
* initialized appropriately for the the existing runtime environment.
*
* @param sessionManager delegate instance to use to support this manager's <tt>SessionManager</tt> method calls.
*/
public void setSessionManager(SessionManager sessionManager) {
this.sessionManager = sessionManager;
}
public SessionManager getSessionManager() {
return this.sessionManager;
}
protected SessionManager createSessionManager() {
DefaultSessionManager sessionManager = new DefaultSessionManager();
if ( getCacheManager() != null ) {
sessionManager.setCacheManager(getCacheManager());
}
if ( getSessionEventListeners() != null ) {
sessionManager.setSessionEventListeners( getSessionEventListeners() );
}
sessionManager.init();
return sessionManager;
}
protected void ensureSessionManager() {
if (getSessionManager() == null) {
if (log.isInfoEnabled()) {
log.info("No delegate SessionManager instance has been set as a property of this class. Creating a " +
"default SessionManager instance...");
}
SessionManager sessionManager = createSessionManager();
setSessionManager(sessionManager);
}
}
protected SessionManager getRequiredSessionManager() {
if (getSessionManager() == null) {
ensureSessionManager();
}
return getSessionManager();
}
public Collection<SessionEventListener> getSessionEventListeners() {
return sessionEventListeners;
}
/**
* This is a convenience method that allows registration of SessionEventListeners with the underlying delegate
* SessionManager at startup.
*
* <p>This is more convenient than having to configure your own SessionManager instance, inject the listeners on
* it, and then set that SessionManager instance as an attribute of this class. Instead, you can just rely
* on the <tt>SecurityManager</tt>'s default initialization logic to create the SessionManager instance for you
* and then apply these <tt>SessionEventListener</tt>s on your behalf.
*
* <p>One notice however: The underlying SessionManager delegate must implement the
* {@link SessionEventListenerRegistrar SessionEventListenerRegistrar} interface in order for these listeners to
* be applied. If it does not implement this interface, it is considered a configuration error and an exception
* will be thrown during {@link #init() initialization}.
*
* @param sessionEventListeners the <tt>SessionEventListener</tt>s to register with the underlying delegate
* <tt>SessionManager</tt> at startup.
*/
public void setSessionEventListeners(Collection<SessionEventListener> sessionEventListeners) {
this.sessionEventListeners = sessionEventListeners;
}
private void assertSessionEventListenerSupport(SessionManager sessionManager) {
if (!(sessionManager instanceof SessionEventListenerRegistrar)) {
String msg = "SessionEventListener registration failed: The underlying SessionManager instance of " +
"type [" + sessionManager.getClass().getName() + "] does not implement the " +
SessionEventListenerRegistrar.class.getName() + " interface and therefore cannot support " +
"runtime SessionEvent propagation.";
throw new IllegalStateException(msg);
}
}
public void add(SessionEventListener listener) {
ensureSessionManager();
SessionManager sm = getSessionManager();
assertSessionEventListenerSupport(sm);
((SessionEventListenerRegistrar)sm).add(listener);
}
public boolean remove(SessionEventListener listener) {
SessionManager sm = getSessionManager();
return (sm instanceof SessionEventListenerRegistrar) &&
((SessionEventListenerRegistrar)sm).remove(listener);
}
protected void afterAuthorizerSet() {
ensureSessionManager();
afterSessionManagerSet();
}
protected void afterSessionManagerSet(){}
protected void beforeSessionManagerDestroyed(){}
protected void destroySessionManager() {
LifecycleUtils.destroy(getSessionManager());
this.sessionManager = null;
this.sessionEventListeners = null;
}
protected void beforeAuthorizerDestroyed() {
beforeSessionManagerDestroyed();
destroySessionManager();
}
public Session start(InetAddress hostAddress) throws HostUnauthorizedException, IllegalArgumentException {
Serializable sessionId = getRequiredSessionManager().start(hostAddress);
return new DelegatingSession(sessionManager, sessionId);
}
public Session getSession(Serializable sessionId) throws InvalidSessionException, AuthorizationException {
SessionManager sm = getRequiredSessionManager();
if (sm.isExpired(sessionId)) {
String msg = "Session with id [" + sessionId + "] has expired and may not be used.";
throw new ExpiredSessionException(msg);
} else if (sm.isStopped(sessionId)) {
String msg = "Session with id [" + sessionId + "] has been stopped and may not be used.";
throw new StoppedSessionException(msg);
}
return new DelegatingSession(sm, sessionId);
}
}