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

org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter Maven / Gradle / Ivy

There is a newer version: 6.2.3
Show newest version
/*
 * Copyright 2002-2018 the original author or authors.
 *
 * 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.preauth;

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 javax.servlet.http.HttpSession;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.*;
import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean;

/**
 * Base class for processing filters that handle pre-authenticated authentication
 * requests, where it is assumed that the principal has already been authenticated by an
 * external system.
 * 

* The purpose is then only to extract the necessary information on the principal from the * incoming request, rather than to authenticate them. External authentication systems may * provide this information via request data such as headers or cookies which the * pre-authentication system can extract. It is assumed that the external system is * responsible for the accuracy of the data and preventing the submission of forged * values. * * Subclasses must implement the {@code getPreAuthenticatedPrincipal()} and * {@code getPreAuthenticatedCredentials()} methods. Subclasses of this filter are * typically used in combination with a {@code PreAuthenticatedAuthenticationProvider}, * which is used to load additional data for the user. This provider will reject null * credentials, so the {@link #getPreAuthenticatedCredentials} method should not return * null for a valid principal. *

* If the security context already contains an {@code Authentication} object (either from * a invocation of the filter or because of some other authentication mechanism), the * filter will do nothing by default. You can force it to check for a change in the * principal by setting the {@link #setCheckForPrincipalChanges(boolean) * checkForPrincipalChanges} property. *

* By default, the filter chain will proceed when an authentication attempt fails in order * to allow other authentication mechanisms to process the request. To reject the * credentials immediately, set the * continueFilterChainOnUnsuccessfulAuthentication flag to false. The exception * raised by the AuthenticationManager will the be re-thrown. Note that this will * not affect cases where the principal returned by {@link #getPreAuthenticatedPrincipal} * is null, when the chain will still proceed as normal. * * @author Luke Taylor * @author Ruud Senden * @author Rob Winch * @since 2.0 */ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFilterBean implements ApplicationEventPublisherAware { private ApplicationEventPublisher eventPublisher = null; private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource(); private AuthenticationManager authenticationManager = null; private boolean continueFilterChainOnUnsuccessfulAuthentication = true; private boolean checkForPrincipalChanges; private boolean invalidateSessionOnPrincipalChange = true; private AuthenticationSuccessHandler authenticationSuccessHandler = null; private AuthenticationFailureHandler authenticationFailureHandler = null; /** * Check whether all required properties have been set. */ @Override public void afterPropertiesSet() { try { super.afterPropertiesSet(); } catch (ServletException e) { // convert to RuntimeException for passivity on afterPropertiesSet signature throw new RuntimeException(e); } Assert.notNull(authenticationManager, "An AuthenticationManager must be set"); } /** * Try to authenticate a pre-authenticated user with Spring Security if the user has * not yet been authenticated. */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (logger.isDebugEnabled()) { logger.debug("Checking secure context token: " + SecurityContextHolder.getContext().getAuthentication()); } if (requiresAuthentication((HttpServletRequest) request)) { doAuthenticate((HttpServletRequest) request, (HttpServletResponse) response); } chain.doFilter(request, response); } /** * Determines if the current principal has changed. The default implementation tries * *

    *
  • If the {@link #getPreAuthenticatedPrincipal(HttpServletRequest)} is a String, the {@link Authentication#getName()} is compared against the pre authenticated principal
  • *
  • Otherwise, the {@link #getPreAuthenticatedPrincipal(HttpServletRequest)} is compared against the {@link Authentication#getPrincipal()} *
* *

* Subclasses can override this method to determine when a principal has changed. *

* * @param request * @param currentAuthentication * @return true if the principal has changed, else false */ protected boolean principalChanged(HttpServletRequest request, Authentication currentAuthentication) { Object principal = getPreAuthenticatedPrincipal(request); if ((principal instanceof String) && currentAuthentication.getName().equals(principal)) { return false; } if (principal != null && principal.equals(currentAuthentication.getPrincipal())) { return false; } if (logger.isDebugEnabled()) { logger.debug("Pre-authenticated principal has changed to " + principal + " and will be reauthenticated"); } return true; } /** * Do the actual authentication for a pre-authenticated user. */ private void doAuthenticate(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { Authentication authResult; Object principal = getPreAuthenticatedPrincipal(request); Object credentials = getPreAuthenticatedCredentials(request); if (principal == null) { if (logger.isDebugEnabled()) { logger.debug("No pre-authenticated principal found in request"); } return; } if (logger.isDebugEnabled()) { logger.debug("preAuthenticatedPrincipal = " + principal + ", trying to authenticate"); } try { PreAuthenticatedAuthenticationToken authRequest = new PreAuthenticatedAuthenticationToken( principal, credentials); authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); authResult = authenticationManager.authenticate(authRequest); successfulAuthentication(request, response, authResult); } catch (AuthenticationException failed) { unsuccessfulAuthentication(request, response, failed); if (!continueFilterChainOnUnsuccessfulAuthentication) { throw failed; } } } private boolean requiresAuthentication(HttpServletRequest request) { Authentication currentUser = SecurityContextHolder.getContext() .getAuthentication(); if (currentUser == null) { return true; } if (!checkForPrincipalChanges) { return false; } if (!principalChanged(request, currentUser)) { return false; } logger.debug("Pre-authenticated principal has changed and will be reauthenticated"); if (invalidateSessionOnPrincipalChange) { SecurityContextHolder.clearContext(); HttpSession session = request.getSession(false); if (session != null) { logger.debug("Invalidating existing session"); session.invalidate(); request.getSession(); } } return true; } /** * Puts the Authentication instance returned by the authentication * manager into the secure context. */ protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException, ServletException { if (logger.isDebugEnabled()) { logger.debug("Authentication success: " + authResult); } SecurityContextHolder.getContext().setAuthentication(authResult); // Fire event if (this.eventPublisher != null) { eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent( authResult, this.getClass())); } if (authenticationSuccessHandler != null) { authenticationSuccessHandler.onAuthenticationSuccess(request, response, authResult); } } /** * Ensures the authentication object in the secure context is set to null when * authentication fails. *

* Caches the failure exception as a request attribute */ protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { SecurityContextHolder.clearContext(); if (logger.isDebugEnabled()) { logger.debug("Cleared security context due to exception", failed); } request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, failed); if (authenticationFailureHandler != null) { authenticationFailureHandler.onAuthenticationFailure(request, response, failed); } } /** * @param anApplicationEventPublisher The ApplicationEventPublisher to use */ public void setApplicationEventPublisher( ApplicationEventPublisher anApplicationEventPublisher) { this.eventPublisher = anApplicationEventPublisher; } /** * @param authenticationDetailsSource The AuthenticationDetailsSource to use */ public void setAuthenticationDetailsSource( AuthenticationDetailsSource authenticationDetailsSource) { Assert.notNull(authenticationDetailsSource, "AuthenticationDetailsSource required"); this.authenticationDetailsSource = authenticationDetailsSource; } protected AuthenticationDetailsSource getAuthenticationDetailsSource() { return authenticationDetailsSource; } /** * @param authenticationManager The AuthenticationManager to use */ public void setAuthenticationManager(AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; } /** * If set to {@code true}, any {@code AuthenticationException} raised by the * {@code AuthenticationManager} will be swallowed, and the request will be allowed to * proceed, potentially using alternative authentication mechanisms. If {@code false} * (the default), authentication failure will result in an immediate exception. * * @param shouldContinue set to {@code true} to allow the request to proceed after a * failed authentication. */ public void setContinueFilterChainOnUnsuccessfulAuthentication(boolean shouldContinue) { continueFilterChainOnUnsuccessfulAuthentication = shouldContinue; } /** * If set, the pre-authenticated principal will be checked on each request and * compared against the name of the current Authentication object. A check to * determine if {@link Authentication#getPrincipal()} is equal to the principal will * also be performed. If a change is detected, the user will be reauthenticated. * * @param checkForPrincipalChanges */ public void setCheckForPrincipalChanges(boolean checkForPrincipalChanges) { this.checkForPrincipalChanges = checkForPrincipalChanges; } /** * If checkForPrincipalChanges is set, and a change of principal is detected, * determines whether any existing session should be invalidated before proceeding to * authenticate the new principal. * * @param invalidateSessionOnPrincipalChange false to retain the existing * session. Defaults to true. */ public void setInvalidateSessionOnPrincipalChange( boolean invalidateSessionOnPrincipalChange) { this.invalidateSessionOnPrincipalChange = invalidateSessionOnPrincipalChange; } /** * Sets the strategy used to handle a successful authentication. */ public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler authenticationSuccessHandler) { this.authenticationSuccessHandler = authenticationSuccessHandler; } /** * Sets the strategy used to handle a failed authentication. */ public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) { this.authenticationFailureHandler = authenticationFailureHandler; } /** * Override to extract the principal information from the current request */ protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request); /** * Override to extract the credentials (if applicable) from the current request. * Should not return null for a valid principal, though some implementations may * return a dummy value. */ protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy