| /* |
| * Copyright 2005-2008 Jeremy Haile, 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.authc; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.jsecurity.authc.event.AuthenticationEventListener; |
| import org.jsecurity.authc.event.mgt.AuthenticationEventListenerRegistrar; |
| import org.jsecurity.authc.event.mgt.AuthenticationEventManager; |
| import org.jsecurity.authc.event.mgt.DefaultAuthenticationEventManager; |
| import org.jsecurity.subject.PrincipalCollection; |
| |
| import java.util.Collection; |
| |
| /** |
| * Superclass for almost all {@link Authenticator} implementations that performs the common work around authentication |
| * attempts. |
| * |
| * <p>This class delegates the actual authentication attempt to subclasses but supports event propagation for |
| * successful and failed logins and logouts. |
| * |
| * <p>In most cases, the only thing a subclass needs to do (via its {@link #doAuthenticate} implementation) |
| * is perform the actual principal/credential verification process for the submitted <tt>AuthenticationToken</tt>. |
| * |
| * <p>This implementation employs an event-based architecture so other components may react to both failed and |
| * successful authentication attempts. Failure or success events are triggered based on the |
| * subclass's {@link #doAuthenticate} implementation throwing an exception or not, respectively. That is, a failure |
| * event will be created if <tt>doAuthenticate</tt> throws an exception a success event will be created and |
| * sent if it does not. The actual events |
| * themselves are constructed and sent via an {@link AuthenticationEventManager} to interested |
| * {@link AuthenticationEventListener}s. If no <tt>AuthenticationEventListener</tt>s are configured, no events will |
| * be created or sent. |
| * |
| * <p>Both the event manager and the event listeners may be set as properties of this class, but a default event |
| * manager will be provided. |
| * |
| * @author Jeremy Haile |
| * @author Les Hazlewood |
| * @since 0.1 |
| */ |
| public abstract class AbstractAuthenticator |
| implements Authenticator, LogoutAware, AuthenticationEventListenerRegistrar { |
| |
| /*-------------------------------------------- |
| | C O N S T A N T S | |
| ============================================*/ |
| /** |
| * Commons-logging logger |
| */ |
| protected final transient Log log = LogFactory.getLog(getClass()); |
| |
| /*-------------------------------------------- |
| | I N S T A N C E V A R I A B L E S | |
| ============================================*/ |
| private AuthenticationEventManager authcEventManager = new DefaultAuthenticationEventManager(); |
| |
| /*-------------------------------------------- |
| | C O N S T R U C T O R S | |
| ============================================*/ |
| public AbstractAuthenticator() { |
| } |
| |
| /*-------------------------------------------- |
| | A C C E S S O R S / M O D I F I E R S | |
| ============================================*/ |
| |
| public AuthenticationEventManager getAuthenticationEventManager() { |
| return authcEventManager; |
| } |
| |
| public void setAuthenticationEventManager(AuthenticationEventManager authcEventManager) { |
| this.authcEventManager = authcEventManager; |
| } |
| |
| public void setAuthenticationEventListeners(Collection<AuthenticationEventListener> listeners) { |
| this.authcEventManager.setAuthenticationEventListeners(listeners); |
| } |
| |
| public void add(AuthenticationEventListener listener) { |
| this.authcEventManager.add(listener); |
| } |
| |
| public boolean remove(AuthenticationEventListener listener) { |
| return this.authcEventManager.remove(listener); |
| } |
| |
| /*------------------------------------------- |
| | M E T H O D S | |
| ============================================*/ |
| protected void sendFailureEvent(AuthenticationToken token, AuthenticationException ae) { |
| this.authcEventManager.sendFailureEvent(token, ae); |
| } |
| |
| protected void sendSuccessEvent(AuthenticationToken token, Account account) { |
| this.authcEventManager.sendSuccessEvent(token, account); |
| } |
| |
| protected void sendLogoutEvent(PrincipalCollection subjectPrincipal) { |
| this.authcEventManager.sendLogoutEvent(subjectPrincipal); |
| } |
| |
| public void onLogout(PrincipalCollection principals) { |
| sendLogoutEvent(principals); |
| } |
| |
| |
| /** |
| * Implementation of the {@link Authenticator} interface that functions in the following manner: |
| * |
| * <ol> |
| * <li>Calls template {@link #doAuthenticate doAuthenticate} method for subclass execution of the actual |
| * authentication behavior.</li> |
| * <li>If an <tt>AuthenticationException</tt> is thrown during <tt>doAuthenticate</tt>, create and send a |
| * failure <tt>AuthenticationEvent</tt> that represents this failure, and then propogate this exception |
| * for the caller to handle.</li> |
| * <li>If no exception is thrown (indicating a successful login), send a success <tt>AuthenticationEvent</tt> |
| * noting the successful authentication.</li> |
| * <li>Return the <tt>Account</tt></li> |
| * </ol> |
| * |
| * @param token the submitted token representing the subject's (user's) login principals and credentials. |
| * @return the Account referencing the authenticated user's account data. |
| * @throws AuthenticationException if there is any problem during the authentication process - see the |
| * interface's JavaDoc for a more detailed explanation. |
| */ |
| public final Account authenticate(AuthenticationToken token) |
| throws AuthenticationException { |
| |
| if (token == null) { |
| throw new IllegalArgumentException("Method argumet (authentication token) cannot be null."); |
| } |
| |
| if (log.isTraceEnabled()) { |
| log.trace("Authentication attempt received for token [" + token + "]"); |
| } |
| |
| Account account; |
| try { |
| account = doAuthenticate(token); |
| if (account == null) { |
| String msg = "No account information found for authentication token [" + token + "] by this " + |
| "Authenticator instance. Please check that it is configured correctly."; |
| throw new AuthenticationException(msg); |
| } |
| } catch (Throwable t) { |
| AuthenticationException ae = null; |
| if (t instanceof AuthenticationException) { |
| ae = (AuthenticationException) t; |
| } |
| if (ae == null) { |
| //Exception thrown was not an expected AuthenticationException. Therefore it is probably a little more |
| //severe or unexpected. So, wrap in an AuthenticationException, log to warn, and propagate: |
| String msg = "Authentication failed for token submission [" + token + "]. Possible unexpected " + |
| "error? (Typical or expected login exceptions should extend from AuthenticationException)."; |
| ae = new AuthenticationException(msg, t); |
| if (log.isWarnEnabled()) { |
| log.warn(msg, t); |
| } |
| } |
| try { |
| sendFailureEvent(token, ae); |
| } catch (Throwable t2) { |
| String msg = "Unable to send event for failed authentication attempt - listener error?. Please check " + |
| "your AuthenticationEventListener implementation(s). Logging sending exception and " + |
| "propagating original AuthenticationException instead..."; |
| if (log.isWarnEnabled()) { |
| log.warn(msg, t2); |
| } |
| } |
| |
| |
| throw ae; |
| } |
| |
| if (log.isInfoEnabled()) { |
| log.info("Authentication successful for token [" + token + "]. " + |
| "Returned account: [" + account + "]"); |
| } |
| |
| sendSuccessEvent(token, account); |
| |
| return account; |
| } |
| |
| /** |
| * Template design pattern hook for subclasses to implement specific authentication behavior. |
| * |
| * <p>Common behavior for most authentication attempts is encapsulated in the |
| * {@link #authenticate} method and that method invokes this one for custom behavior. |
| * |
| * <p><b>N.B.</b> Subclasses <em>should</em> throw some kind of |
| * <tt>AuthenticationException</tt> if there is a problem during |
| * authentication instead of returning <tt>null</tt>. A <tt>null</tt> return value indicates |
| * a configuration or programming error, since <tt>AuthenticationException</tt>s should |
| * indicate any expected problem (such as an unknown account or username, or invalid password, etc). |
| * |
| * @param token the authentication token encapsulating the user's login information. |
| * @return an <tt>Account</tt> object encapsulating the user's account information |
| * important to JSecurity. |
| * @throws AuthenticationException if there is a problem logging in the user. |
| */ |
| protected abstract Account doAuthenticate(AuthenticationToken token) |
| throws AuthenticationException; |
| |
| |
| |
| } |