All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter Maven / Gradle / Ivy

There is a newer version: 6.2.4
Show newest version
/*
 * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
 *
 * 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.web.authentication;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean;

/**
 * Abstract processor of browser-based HTTP-based authentication requests.
 *
 * 

Authentication Process

* * The filter requires that you set the authenticationManager property. An * AuthenticationManager is required to process the authentication request tokens * created by implementing classes. *

* This filter will intercept a request and attempt to perform authentication from that * request if the request matches the * {@link #setRequiresAuthenticationRequestMatcher(RequestMatcher)}. *

* Authentication is performed by the * {@link #attemptAuthentication(HttpServletRequest, HttpServletResponse) * attemptAuthentication} method, which must be implemented by subclasses. * *

Authentication Success

* * If authentication is successful, the resulting {@link Authentication} object will be * placed into the SecurityContext for the current thread, which is * guaranteed to have already been created by an earlier filter. *

* The configured {@link #setAuthenticationSuccessHandler(AuthenticationSuccessHandler) * AuthenticationSuccessHandler} will then be called to take the redirect to the * appropriate destination after a successful login. The default behaviour is implemented * in a {@link SavedRequestAwareAuthenticationSuccessHandler} which will make use of any * DefaultSavedRequest set by the ExceptionTranslationFilter and * redirect the user to the URL contained therein. Otherwise it will redirect to the * webapp root "/". You can customize this behaviour by injecting a differently configured * instance of this class, or by using a different implementation. *

* See the * {@link #successfulAuthentication(HttpServletRequest, HttpServletResponse, FilterChain, Authentication)} * method for more information. * *

Authentication Failure

* * If authentication fails, it will delegate to the configured * {@link AuthenticationFailureHandler} to allow the failure information to be conveyed to * the client. The default implementation is {@link SimpleUrlAuthenticationFailureHandler} * , which sends a 401 error code to the client. It may also be configured with a failure * URL as an alternative. Again you can inject whatever behaviour you require here. * *

Event Publication

* * If authentication is successful, an {@link InteractiveAuthenticationSuccessEvent} will * be published via the application context. No events will be published if authentication * was unsuccessful, because this would generally be recorded via an * {@code AuthenticationManager}-specific application event. * *

Session Authentication

* * The class has an optional {@link SessionAuthenticationStrategy} which will be invoked * immediately after a successful call to {@code attemptAuthentication()}. Different * implementations * {@link #setSessionAuthenticationStrategy(SessionAuthenticationStrategy) can be * injected} to enable things like session-fixation attack prevention or to control the * number of simultaneous sessions a principal may have. * * @author Ben Alex * @author Luke Taylor */ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean implements ApplicationEventPublisherAware, MessageSourceAware { // ~ Static fields/initializers // ===================================================================================== // ~ Instance fields // ================================================================================================ protected ApplicationEventPublisher eventPublisher; protected AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource(); private AuthenticationManager authenticationManager; protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); private RememberMeServices rememberMeServices = new NullRememberMeServices(); private RequestMatcher requiresAuthenticationRequestMatcher; private boolean continueChainBeforeSuccessfulAuthentication = false; private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy(); private boolean allowSessionCreation = true; private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler(); // ~ Constructors // =================================================================================================== /** * @param defaultFilterProcessesUrl the default value for filterProcessesUrl. */ protected AbstractAuthenticationProcessingFilter(String defaultFilterProcessesUrl) { setFilterProcessesUrl(defaultFilterProcessesUrl); } /** * Creates a new instance * * @param requiresAuthenticationRequestMatcher the {@link RequestMatcher} used to * determine if authentication is required. Cannot be null. */ protected AbstractAuthenticationProcessingFilter( RequestMatcher requiresAuthenticationRequestMatcher) { Assert.notNull(requiresAuthenticationRequestMatcher, "requiresAuthenticationRequestMatcher cannot be null"); this.requiresAuthenticationRequestMatcher = requiresAuthenticationRequestMatcher; } // ~ Methods // ======================================================================================================== @Override public void afterPropertiesSet() { Assert.notNull(authenticationManager, "authenticationManager must be specified"); } /** * Invokes the * {@link #requiresAuthentication(HttpServletRequest, HttpServletResponse) * requiresAuthentication} method to determine whether the request is for * authentication and should be handled by this filter. If it is an authentication * request, the * {@link #attemptAuthentication(HttpServletRequest, HttpServletResponse) * attemptAuthentication} will be invoked to perform the authentication. There are * then three possible outcomes: *
    *
  1. An Authentication object is returned. The configured * {@link SessionAuthenticationStrategy} will be invoked (to handle any * session-related behaviour such as creating a new session to protect against * session-fixation attacks) followed by the invocation of * {@link #successfulAuthentication(HttpServletRequest, HttpServletResponse, FilterChain, Authentication)} * method
  2. *
  3. An AuthenticationException occurs during authentication. The * {@link #unsuccessfulAuthentication(HttpServletRequest, HttpServletResponse, AuthenticationException) * unsuccessfulAuthentication} method will be invoked
  4. *
  5. Null is returned, indicating that the authentication process is incomplete. The * method will then return immediately, assuming that the subclass has done any * necessary work (such as redirects) to continue the authentication process. The * assumption is that a later request will be received by this method where the * returned Authentication object is not null. *
*/ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; if (!requiresAuthentication(request, response)) { chain.doFilter(request, response); return; } if (logger.isDebugEnabled()) { logger.debug("Request is to process authentication"); } Authentication authResult; try { authResult = attemptAuthentication(request, response); if (authResult == null) { // return immediately as subclass has indicated that it hasn't completed // authentication return; } sessionStrategy.onAuthentication(authResult, request, response); } catch (InternalAuthenticationServiceException failed) { logger.error( "An internal error occurred while trying to authenticate the user.", failed); unsuccessfulAuthentication(request, response, failed); return; } catch (AuthenticationException failed) { // Authentication failed unsuccessfulAuthentication(request, response, failed); return; } // Authentication success if (continueChainBeforeSuccessfulAuthentication) { chain.doFilter(request, response); } successfulAuthentication(request, response, chain, authResult); } /** * Indicates whether this filter should attempt to process a login request for the * current invocation. *

* It strips any parameters from the "path" section of the request URL (such as the * jsessionid parameter in http://host/myapp/index.html;jsessionid=blah) * before matching against the filterProcessesUrl property. *

* Subclasses may override for special requirements, such as Tapestry integration. * * @return true if the filter should attempt authentication, * false otherwise. */ protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) { return requiresAuthenticationRequestMatcher.matches(request); } /** * Performs actual authentication. *

* The implementation should do one of the following: *

    *
  1. Return a populated authentication token for the authenticated user, indicating * successful authentication
  2. *
  3. Return null, indicating that the authentication process is still in progress. * Before returning, the implementation should perform any additional work required to * complete the process.
  4. *
  5. Throw an AuthenticationException if the authentication process fails
  6. *
* * @param request from which to extract parameters and perform the authentication * @param response the response, which may be needed if the implementation has to do a * redirect as part of a multi-stage authentication process (such as OpenID). * * @return the authenticated user token, or null if authentication is incomplete. * * @throws AuthenticationException if authentication fails. */ public abstract Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException; /** * Default behaviour for successful authentication. *
    *
  1. Sets the successful Authentication object on the * {@link SecurityContextHolder}
  2. *
  3. Informs the configured RememberMeServices of the successful login
  4. *
  5. Fires an {@link InteractiveAuthenticationSuccessEvent} via the configured * ApplicationEventPublisher
  6. *
  7. Delegates additional behaviour to the {@link AuthenticationSuccessHandler}.
  8. *
* * Subclasses can override this method to continue the {@link FilterChain} after * successful authentication. * @param request * @param response * @param chain * @param authResult the object returned from the attemptAuthentication * method. * @throws IOException * @throws ServletException */ protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { if (logger.isDebugEnabled()) { logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult); } SecurityContextHolder.getContext().setAuthentication(authResult); rememberMeServices.loginSuccess(request, response, authResult); // Fire event if (this.eventPublisher != null) { eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent( authResult, this.getClass())); } successHandler.onAuthenticationSuccess(request, response, authResult); } /** * Default behaviour for unsuccessful authentication. *
    *
  1. Clears the {@link SecurityContextHolder}
  2. *
  3. Stores the exception in the session (if it exists or * allowSesssionCreation is set to true)
  4. *
  5. Informs the configured RememberMeServices of the failed login
  6. *
  7. Delegates additional behaviour to the {@link AuthenticationFailureHandler}.
  8. *
*/ protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { SecurityContextHolder.clearContext(); if (logger.isDebugEnabled()) { logger.debug("Authentication request failed: " + failed.toString(), failed); logger.debug("Updated SecurityContextHolder to contain null Authentication"); logger.debug("Delegating to authentication failure handler " + failureHandler); } rememberMeServices.loginFail(request, response); failureHandler.onAuthenticationFailure(request, response, failed); } protected AuthenticationManager getAuthenticationManager() { return authenticationManager; } public void setAuthenticationManager(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; } /** * Sets the URL that determines if authentication is required * * @param filterProcessesUrl */ public void setFilterProcessesUrl(String filterProcessesUrl) { setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher( filterProcessesUrl)); } public final void setRequiresAuthenticationRequestMatcher( RequestMatcher requestMatcher) { Assert.notNull(requestMatcher, "requestMatcher cannot be null"); this.requiresAuthenticationRequestMatcher = requestMatcher; } public RememberMeServices getRememberMeServices() { return rememberMeServices; } public void setRememberMeServices(RememberMeServices rememberMeServices) { Assert.notNull(rememberMeServices, "rememberMeServices cannot be null"); this.rememberMeServices = rememberMeServices; } /** * Indicates if the filter chain should be continued prior to delegation to * {@link #successfulAuthentication(HttpServletRequest, HttpServletResponse, FilterChain, Authentication)} * , which may be useful in certain environment (such as Tapestry applications). * Defaults to false. */ public void setContinueChainBeforeSuccessfulAuthentication( boolean continueChainBeforeSuccessfulAuthentication) { this.continueChainBeforeSuccessfulAuthentication = continueChainBeforeSuccessfulAuthentication; } public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) { this.eventPublisher = eventPublisher; } public void setAuthenticationDetailsSource( AuthenticationDetailsSource authenticationDetailsSource) { Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource required"); this.authenticationDetailsSource = authenticationDetailsSource; } public void setMessageSource(MessageSource messageSource) { this.messages = new MessageSourceAccessor(messageSource); } protected boolean getAllowSessionCreation() { return allowSessionCreation; } public void setAllowSessionCreation(boolean allowSessionCreation) { this.allowSessionCreation = allowSessionCreation; } /** * The session handling strategy which will be invoked immediately after an * authentication request is successfully processed by the * AuthenticationManager. Used, for example, to handle changing of the * session identifier to prevent session fixation attacks. * * @param sessionStrategy the implementation to use. If not set a null implementation * is used. */ public void setSessionAuthenticationStrategy( SessionAuthenticationStrategy sessionStrategy) { this.sessionStrategy = sessionStrategy; } /** * Sets the strategy used to handle a successful authentication. By default a * {@link SavedRequestAwareAuthenticationSuccessHandler} is used. */ public void setAuthenticationSuccessHandler( AuthenticationSuccessHandler successHandler) { Assert.notNull(successHandler, "successHandler cannot be null"); this.successHandler = successHandler; } public void setAuthenticationFailureHandler( AuthenticationFailureHandler failureHandler) { Assert.notNull(failureHandler, "failureHandler cannot be null"); this.failureHandler = failureHandler; } protected AuthenticationSuccessHandler getSuccessHandler() { return successHandler; } protected AuthenticationFailureHandler getFailureHandler() { return failureHandler; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy