blob: 4a1540fcc10adfea202e4e0f6958908ad90e87a0 [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.authc.Account;
import org.jsecurity.authc.AuthenticationException;
import org.jsecurity.authc.AuthenticationToken;
import org.jsecurity.authc.Authenticator;
import org.jsecurity.authc.event.AuthenticationEventListener;
import org.jsecurity.authc.event.mgt.AuthenticationEventListenerRegistrar;
import org.jsecurity.authc.event.mgt.AuthenticationEventManager;
import org.jsecurity.authc.pam.ModularAuthenticationStrategy;
import org.jsecurity.authc.pam.ModularRealmAuthenticator;
import org.jsecurity.realm.Realm;
import org.jsecurity.util.LifecycleUtils;
import java.util.Collection;
/**
* JSecurity support of a {@link SecurityManager} class hierarchy that delegates all
* authentication operations to a wrapped {@link Authenticator Authenticator} instance. That is, this class
* implements all the <tt>Authenticator</tt> methods in the {@link SecurityManager SecurityManager}
* interface, but in reality, those methods are merely passthrough calls to the underlying 'real'
* <tt>Authenticator</tt> instance.
*
* <p>All other <tt>SecurityManager</tt> (authorization, session, etc) methods 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 AuthenticatingSecurityManager extends RealmSecurityManager implements AuthenticationEventListenerRegistrar {
private Authenticator authenticator;
private AuthenticationEventManager authenticationEventManager;
private Collection<AuthenticationEventListener> authenticationEventListeners;
private ModularAuthenticationStrategy modularAuthenticationStrategy;
/**
* 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 AuthenticatingSecurityManager() {
}
/**
* Supporting constructor for a single-realm application (automatically calls {@link #init()} before returning).
*
* @param singleRealm the single realm used by this SecurityManager.
*/
public AuthenticatingSecurityManager(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 AuthenticatingSecurityManager(Collection<Realm> realms) {
super(realms);
}
public Authenticator getAuthenticator() {
return authenticator;
}
public void setAuthenticator(Authenticator authenticator) {
this.authenticator = authenticator;
}
public AuthenticationEventManager getAuthenticationEventManager() {
return authenticationEventManager;
}
public void setAuthenticationEventManager(AuthenticationEventManager authenticationEventManager) {
this.authenticationEventManager = authenticationEventManager;
}
public ModularAuthenticationStrategy getModularAuthenticationStrategy() {
return modularAuthenticationStrategy;
}
public void setModularAuthenticationStrategy(ModularAuthenticationStrategy modularAuthenticationStrategy) {
this.modularAuthenticationStrategy = modularAuthenticationStrategy;
}
public Collection<AuthenticationEventListener> getAuthenticationEventListeners() {
return authenticationEventListeners;
}
/**
* This is a convenience method that allows registration of AuthenticationEventListeners with the underlying
* delegate Authenticator instance at startup.
*
* <p>This is more convenient than having to configure your own Authenticator instance, inject the listeners on
* it, and then set that Authenticator instance as an attribute of this class. Instead, you can just rely
* on the <tt>SecurityManager</tt>'s default initialization logic to create the Authenticator instance for you
* and then apply these <tt>AuthenticationEventListener</tt>s on your behalf.
*
* <p>One notice however: The underlying Authenticator delegate must implement the
* {@link org.jsecurity.authc.event.mgt.AuthenticationEventListenerRegistrar AuthenticationEventListenerRegistrar}
* 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}.
*
* <p>All of JSecurity's <tt>Authenticator</tt> implementations implement the
* <tt>AuthenticationEventListenerRegistrar</tt> interface, so you would only need
* to worry about an exception being thrown if you provided your own Authenticator instance and did not
* implement it.
*
* @param listeners the <tt>AuthenticationEventListener</tt>s to register with the underlying delegate
* <tt>Authenticator</tt> at startup.
*/
public void setAuthenticationEventListeners(Collection<AuthenticationEventListener> listeners) {
this.authenticationEventListeners = listeners;
}
protected void afterRealmsSet() {
ensureAuthenticator();
afterAuthenticatorSet();
}
protected void ensureAuthenticator() {
if (getAuthenticator() == null) {
Authenticator authc = createAuthenticator();
setAuthenticator(authc);
}
}
protected Authenticator createAuthenticator() {
ModularRealmAuthenticator mra = new ModularRealmAuthenticator();
mra.setRealms(getRealms());
if ( getAuthenticationEventManager() != null ) {
mra.setAuthenticationEventManager( getAuthenticationEventManager());
}
if ( getAuthenticationEventListeners() != null ) {
mra.setAuthenticationEventListeners(getAuthenticationEventListeners());
}
if ( getModularAuthenticationStrategy() != null ) {
mra.setModularAuthenticationStrategy( getModularAuthenticationStrategy() );
}
return mra;
}
protected void afterAuthenticatorSet() {
}
protected void beforeRealmsDestroyed() {
beforeAuthenticatorDestroyed();
destroyAuthenticator();
}
protected void beforeAuthenticatorDestroyed() {
}
protected void destroyAuthenticator() {
LifecycleUtils.destroy(getAuthenticator());
this.authenticator = null;
this.authenticationEventListeners = null;
}
private void assertAuthenticatorEventListenerSupport(Authenticator authc) {
if (!(authc instanceof AuthenticationEventListenerRegistrar)) {
String msg = "AuthenticationEventListener registration failed: The underlying Authenticator instance of " +
"type [" + authc.getClass().getName() + "] does not implement the " +
AuthenticationEventListenerRegistrar.class.getName() + " interface and therefore cannot support " +
"runtime registration of AuthenticationEventListeners.";
throw new IllegalStateException(msg);
}
}
public void add(AuthenticationEventListener listener) {
Authenticator authc = getRequiredAuthenticator();
assertAuthenticatorEventListenerSupport(authc);
((AuthenticationEventListenerRegistrar) authc).add(listener);
}
public boolean remove(AuthenticationEventListener listener) {
Authenticator authc = getAuthenticator();
return (authc instanceof AuthenticationEventListenerRegistrar) &&
((AuthenticationEventListenerRegistrar) authc).remove(listener);
}
/** Delegates to the authenticator for authentication. */
public Account authenticate(AuthenticationToken token) throws AuthenticationException {
return getRequiredAuthenticator().authenticate(token);
}
protected Authenticator getRequiredAuthenticator() {
Authenticator authc = getAuthenticator();
if (authc == null) {
String msg = "No authenticator attribute configured for this SecurityManager instance. Please ensure " +
"the init() method is called prior to using this instance and a default one will be created.";
throw new IllegalStateException(msg);
}
return authc;
}
}