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

org.springframework.security.web.access.ExceptionTranslationFilter Maven / Gradle / Ivy

There is a newer version: 6.2.4
Show newest version
/*
 * Copyright 2004-2016 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
 *
 *      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.access;

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.support.MessageSourceAccessor;
import org.springframework.core.log.LogMessage;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.authentication.InsufficientAuthenticationException;
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.AuthenticationEntryPoint;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.util.ThrowableAnalyzer;
import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean;

/**
 * Handles any AccessDeniedException and AuthenticationException
 * thrown within the filter chain.
 * 

* This filter is necessary because it provides the bridge between Java exceptions and * HTTP responses. It is solely concerned with maintaining the user interface. This filter * does not do any actual security enforcement. *

* If an {@link AuthenticationException} is detected, the filter will launch the * authenticationEntryPoint. This allows common handling of authentication * failures originating from any subclass of * {@link org.springframework.security.access.intercept.AbstractSecurityInterceptor}. *

* If an {@link AccessDeniedException} is detected, the filter will determine whether or * not the user is an anonymous user. If they are an anonymous user, the * authenticationEntryPoint will be launched. If they are not an anonymous * user, the filter will delegate to the * {@link org.springframework.security.web.access.AccessDeniedHandler}. By default the * filter will use * {@link org.springframework.security.web.access.AccessDeniedHandlerImpl}. *

* To use this filter, it is necessary to specify the following properties: *

    *
  • authenticationEntryPoint indicates the handler that should commence * the authentication process if an AuthenticationException is detected. Note * that this may also switch the current protocol from http to https for an SSL * login.
  • *
  • requestCache determines the strategy used to save a request during the * authentication process in order that it may be retrieved and reused once the user has * authenticated. The default implementation is {@link HttpSessionRequestCache}.
  • *
* * @author Ben Alex * @author colin sampaleanu */ public class ExceptionTranslationFilter extends GenericFilterBean { private AccessDeniedHandler accessDeniedHandler = new AccessDeniedHandlerImpl(); private AuthenticationEntryPoint authenticationEntryPoint; private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl(); private ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer(); private RequestCache requestCache = new HttpSessionRequestCache(); private final MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); public ExceptionTranslationFilter(AuthenticationEntryPoint authenticationEntryPoint) { this(authenticationEntryPoint, new HttpSessionRequestCache()); } public ExceptionTranslationFilter(AuthenticationEntryPoint authenticationEntryPoint, RequestCache requestCache) { Assert.notNull(authenticationEntryPoint, "authenticationEntryPoint cannot be null"); Assert.notNull(requestCache, "requestCache cannot be null"); this.authenticationEntryPoint = authenticationEntryPoint; this.requestCache = requestCache; } @Override public void afterPropertiesSet() { Assert.notNull(this.authenticationEntryPoint, "authenticationEntryPoint must be specified"); } @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 { try { chain.doFilter(request, response); } catch (IOException ex) { throw ex; } catch (Exception ex) { // Try to extract a SpringSecurityException from the stacktrace Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(ex); RuntimeException securityException = (AuthenticationException) this.throwableAnalyzer .getFirstThrowableOfType(AuthenticationException.class, causeChain); if (securityException == null) { securityException = (AccessDeniedException) this.throwableAnalyzer .getFirstThrowableOfType(AccessDeniedException.class, causeChain); } if (securityException == null) { rethrow(ex); } if (response.isCommitted()) { throw new ServletException("Unable to handle the Spring Security Exception " + "because the response is already committed.", ex); } handleSpringSecurityException(request, response, chain, securityException); } } private void rethrow(Exception ex) throws ServletException { // Rethrow ServletExceptions and RuntimeExceptions as-is if (ex instanceof ServletException) { throw (ServletException) ex; } if (ex instanceof RuntimeException) { throw (RuntimeException) ex; } // Wrap other Exceptions. This shouldn't actually happen // as we've already covered all the possibilities for doFilter throw new RuntimeException(ex); } public AuthenticationEntryPoint getAuthenticationEntryPoint() { return this.authenticationEntryPoint; } protected AuthenticationTrustResolver getAuthenticationTrustResolver() { return this.authenticationTrustResolver; } private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response, FilterChain chain, RuntimeException exception) throws IOException, ServletException { if (exception instanceof AuthenticationException) { handleAuthenticationException(request, response, chain, (AuthenticationException) exception); } else if (exception instanceof AccessDeniedException) { handleAccessDeniedException(request, response, chain, (AccessDeniedException) exception); } } private void handleAuthenticationException(HttpServletRequest request, HttpServletResponse response, FilterChain chain, AuthenticationException exception) throws ServletException, IOException { this.logger.trace("Sending to authentication entry point since authentication failed", exception); sendStartAuthentication(request, response, chain, exception); } private void handleAccessDeniedException(HttpServletRequest request, HttpServletResponse response, FilterChain chain, AccessDeniedException exception) throws ServletException, IOException { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); boolean isAnonymous = this.authenticationTrustResolver.isAnonymous(authentication); if (isAnonymous || this.authenticationTrustResolver.isRememberMe(authentication)) { if (logger.isTraceEnabled()) { logger.trace(LogMessage.format("Sending %s to authentication entry point since access is denied", authentication), exception); } sendStartAuthentication(request, response, chain, new InsufficientAuthenticationException( this.messages.getMessage("ExceptionTranslationFilter.insufficientAuthentication", "Full authentication is required to access this resource"))); } else { if (logger.isTraceEnabled()) { logger.trace( LogMessage.format("Sending %s to access denied handler since access is denied", authentication), exception); } this.accessDeniedHandler.handle(request, response, exception); } } protected void sendStartAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, AuthenticationException reason) throws ServletException, IOException { // SEC-112: Clear the SecurityContextHolder's Authentication, as the // existing Authentication is no longer considered valid SecurityContextHolder.getContext().setAuthentication(null); this.requestCache.saveRequest(request, response); this.authenticationEntryPoint.commence(request, response, reason); } public void setAccessDeniedHandler(AccessDeniedHandler accessDeniedHandler) { Assert.notNull(accessDeniedHandler, "AccessDeniedHandler required"); this.accessDeniedHandler = accessDeniedHandler; } public void setAuthenticationTrustResolver(AuthenticationTrustResolver authenticationTrustResolver) { Assert.notNull(authenticationTrustResolver, "authenticationTrustResolver must not be null"); this.authenticationTrustResolver = authenticationTrustResolver; } public void setThrowableAnalyzer(ThrowableAnalyzer throwableAnalyzer) { Assert.notNull(throwableAnalyzer, "throwableAnalyzer must not be null"); this.throwableAnalyzer = throwableAnalyzer; } /** * Default implementation of ThrowableAnalyzer which is capable of also * unwrapping ServletExceptions. */ private static final class DefaultThrowableAnalyzer extends ThrowableAnalyzer { /** * @see org.springframework.security.web.util.ThrowableAnalyzer#initExtractorMap() */ @Override protected void initExtractorMap() { super.initExtractorMap(); registerExtractor(ServletException.class, (throwable) -> { ThrowableAnalyzer.verifyThrowableHierarchy(throwable, ServletException.class); return ((ServletException) throwable).getRootCause(); }); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy