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
 *
 *      https://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.core.log.LogMessage;
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 { 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(); /** * @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; } /** * Creates a new instance with a default filterProcessesUrl and an * {@link AuthenticationManager} * @param defaultFilterProcessesUrl the default value for filterProcessesUrl. * @param authenticationManager the {@link AuthenticationManager} used to authenticate * an {@link Authentication} object. Cannot be null. */ protected AbstractAuthenticationProcessingFilter(String defaultFilterProcessesUrl, AuthenticationManager authenticationManager) { setFilterProcessesUrl(defaultFilterProcessesUrl); setAuthenticationManager(authenticationManager); } /** * Creates a new instance with a {@link RequestMatcher} and an * {@link AuthenticationManager} * @param requiresAuthenticationRequestMatcher the {@link RequestMatcher} used to * determine if authentication is required. Cannot be null. * @param authenticationManager the {@link AuthenticationManager} used to authenticate * an {@link Authentication} object. Cannot be null. */ protected AbstractAuthenticationProcessingFilter(RequestMatcher requiresAuthenticationRequestMatcher, AuthenticationManager authenticationManager) { setRequiresAuthenticationRequestMatcher(requiresAuthenticationRequestMatcher); setAuthenticationManager(authenticationManager); } @Override public void afterPropertiesSet() { Assert.notNull(this.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. *
*/ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain); } private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { if (!requiresAuthentication(request, response)) { chain.doFilter(request, response); return; } try { Authentication authenticationResult = attemptAuthentication(request, response); if (authenticationResult == null) { // return immediately as subclass has indicated that it hasn't completed return; } this.sessionStrategy.onAuthentication(authenticationResult, request, response); // Authentication success if (this.continueChainBeforeSuccessfulAuthentication) { chain.doFilter(request, response); } successfulAuthentication(request, response, chain, authenticationResult); } catch (InternalAuthenticationServiceException failed) { this.logger.error("An internal error occurred while trying to authenticate the user.", failed); unsuccessfulAuthentication(request, response, failed); } catch (AuthenticationException ex) { // Authentication failed unsuccessfulAuthentication(request, response, ex); } } /** * 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 https://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) { if (this.requiresAuthenticationRequestMatcher.matches(request)) { return true; } if (this.logger.isTraceEnabled()) { this.logger .trace(LogMessage.format("Did not match request to %s", this.requiresAuthenticationRequestMatcher)); } return false; } /** * 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 { SecurityContextHolder.getContext().setAuthentication(authResult); if (this.logger.isDebugEnabled()) { this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authResult)); } this.rememberMeServices.loginSuccess(request, response, authResult); if (this.eventPublisher != null) { this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass())); } this.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(); this.logger.trace("Failed to process authentication request", failed); this.logger.trace("Cleared SecurityContextHolder"); this.logger.trace("Handling authentication failure"); this.rememberMeServices.loginFail(request, response); this.failureHandler.onAuthenticationFailure(request, response, failed); } protected AuthenticationManager getAuthenticationManager() { return this.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 this.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; } @Override public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) { this.eventPublisher = eventPublisher; } public void setAuthenticationDetailsSource( AuthenticationDetailsSource authenticationDetailsSource) { Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource required"); this.authenticationDetailsSource = authenticationDetailsSource; } @Override public void setMessageSource(MessageSource messageSource) { this.messages = new MessageSourceAccessor(messageSource); } protected boolean getAllowSessionCreation() { return this.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 this.successHandler; } protected AuthenticationFailureHandler getFailureHandler() { return this.failureHandler; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy