From a7b58c229996a7e928c21902ca348a5c6badc28a Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Tue, 21 Jun 2022 16:43:41 -0600 Subject: [PATCH] Polish SecurityContextHolderStrategy for Defaults gh-11060 --- .../logout/SecurityContextLogoutHandler.java | 19 +++++++++++++-- ...thenticationPrincipalArgumentResolver.java | 2 +- ...urrentSecurityContextArgumentResolver.java | 19 +++++++++++++-- .../HttpServlet3RequestFactory.java | 24 +++++++++++++++---- ...curityContextHolderAwareRequestFilter.java | 16 +++++++++++++ ...urityContextHolderAwareRequestWrapper.java | 17 ++++++++++++- 6 files changed, 86 insertions(+), 11 deletions(-) diff --git a/web/src/main/java/org/springframework/security/web/authentication/logout/SecurityContextLogoutHandler.java b/web/src/main/java/org/springframework/security/web/authentication/logout/SecurityContextLogoutHandler.java index 68ef1187c5..fe2b41a0e0 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/logout/SecurityContextLogoutHandler.java +++ b/web/src/main/java/org/springframework/security/web/authentication/logout/SecurityContextLogoutHandler.java @@ -26,6 +26,7 @@ import org.springframework.core.log.LogMessage; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.util.Assert; /** @@ -45,6 +46,9 @@ public class SecurityContextLogoutHandler implements LogoutHandler { protected final Log logger = LogFactory.getLog(this.getClass()); + private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder + .getContextHolderStrategy(); + private boolean invalidateHttpSession = true; private boolean clearAuthentication = true; @@ -67,8 +71,8 @@ public class SecurityContextLogoutHandler implements LogoutHandler { } } } - SecurityContext context = SecurityContextHolder.getContext(); - SecurityContextHolder.clearContext(); + SecurityContext context = this.securityContextHolderStrategy.getContext(); + this.securityContextHolderStrategy.clearContext(); if (this.clearAuthentication) { context.setAuthentication(null); } @@ -78,6 +82,17 @@ public class SecurityContextLogoutHandler implements LogoutHandler { return this.invalidateHttpSession; } + /** + * Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use + * the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}. + * + * @since 5.8 + */ + public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) { + Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null"); + this.securityContextHolderStrategy = securityContextHolderStrategy; + } + /** * Causes the {@link HttpSession} to be invalidated when this {@link LogoutHandler} is * invoked. Defaults to true. diff --git a/web/src/main/java/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolver.java b/web/src/main/java/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolver.java index 0bae10f2cf..2f8009ad5b 100644 --- a/web/src/main/java/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolver.java +++ b/web/src/main/java/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 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. diff --git a/web/src/main/java/org/springframework/security/web/method/annotation/CurrentSecurityContextArgumentResolver.java b/web/src/main/java/org/springframework/security/web/method/annotation/CurrentSecurityContextArgumentResolver.java index 304d16e824..b3b643c6ee 100644 --- a/web/src/main/java/org/springframework/security/web/method/annotation/CurrentSecurityContextArgumentResolver.java +++ b/web/src/main/java/org/springframework/security/web/method/annotation/CurrentSecurityContextArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 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. @@ -28,6 +28,7 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.security.core.annotation.CurrentSecurityContext; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.stereotype.Controller; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -75,6 +76,9 @@ import org.springframework.web.method.support.ModelAndViewContainer; */ public final class CurrentSecurityContextArgumentResolver implements HandlerMethodArgumentResolver { + private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder + .getContextHolderStrategy(); + private ExpressionParser parser = new SpelExpressionParser(); private BeanResolver beanResolver; @@ -87,7 +91,7 @@ public final class CurrentSecurityContextArgumentResolver implements HandlerMeth @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { - SecurityContext securityContext = SecurityContextHolder.getContext(); + SecurityContext securityContext = this.securityContextHolderStrategy.getContext(); if (securityContext == null) { return null; } @@ -113,6 +117,17 @@ public final class CurrentSecurityContextArgumentResolver implements HandlerMeth return securityContextResult; } + /** + * Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use + * the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}. + * + * @since 5.8 + */ + public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) { + Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null"); + this.securityContextHolderStrategy = securityContextHolderStrategy; + } + /** * Set the {@link BeanResolver} to be used on the expressions * @param beanResolver the {@link BeanResolver} to use diff --git a/web/src/main/java/org/springframework/security/web/servletapi/HttpServlet3RequestFactory.java b/web/src/main/java/org/springframework/security/web/servletapi/HttpServlet3RequestFactory.java index 923cd0c046..5f189fe87b 100644 --- a/web/src/main/java/org/springframework/security/web/servletapi/HttpServlet3RequestFactory.java +++ b/web/src/main/java/org/springframework/security/web/servletapi/HttpServlet3RequestFactory.java @@ -41,6 +41,7 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.security.web.authentication.logout.LogoutHandler; @@ -76,6 +77,9 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory { private Log logger = LogFactory.getLog(getClass()); + private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder + .getContextHolderStrategy(); + private final String rolePrefix; private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); @@ -161,9 +165,17 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory { this.trustResolver = trustResolver; } + void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) { + Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null"); + this.securityContextHolderStrategy = securityContextHolderStrategy; + } + @Override public HttpServletRequest create(HttpServletRequest request, HttpServletResponse response) { - return new Servlet3SecurityContextHolderAwareRequestWrapper(request, this.rolePrefix, response); + Servlet3SecurityContextHolderAwareRequestWrapper wrapper = new Servlet3SecurityContextHolderAwareRequestWrapper( + request, this.rolePrefix, response); + wrapper.setSecurityContextHolderStrategy(this.securityContextHolderStrategy); + return wrapper; } private class Servlet3SecurityContextHolderAwareRequestWrapper extends SecurityContextHolderAwareRequestWrapper { @@ -228,9 +240,10 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory { return; } Authentication authentication = getAuthentication(authManager, username, password); - SecurityContext context = SecurityContextHolder.createEmptyContext(); + SecurityContext context = HttpServlet3RequestFactory.this.securityContextHolderStrategy + .createEmptyContext(); context.setAuthentication(authentication); - SecurityContextHolder.setContext(context); + HttpServlet3RequestFactory.this.securityContextHolderStrategy.setContext(context); } private Authentication getAuthentication(AuthenticationManager authManager, String username, String password) @@ -243,7 +256,7 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory { return authManager.authenticate(authentication); } catch (AuthenticationException ex) { - SecurityContextHolder.clearContext(); + HttpServlet3RequestFactory.this.securityContextHolderStrategy.clearContext(); throw new ServletException(ex.getMessage(), ex); } } @@ -257,7 +270,8 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory { super.logout(); return; } - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + Authentication authentication = HttpServlet3RequestFactory.this.securityContextHolderStrategy.getContext() + .getAuthentication(); for (LogoutHandler handler : handlers) { handler.logout(this, this.response, authentication); } diff --git a/web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestFilter.java b/web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestFilter.java index eeb4f4de82..22673b8453 100644 --- a/web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestFilter.java +++ b/web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestFilter.java @@ -32,6 +32,7 @@ import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.authentication.AuthenticationTrustResolverImpl; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.util.Assert; @@ -68,6 +69,9 @@ import org.springframework.web.filter.GenericFilterBean; */ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean { + private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder + .getContextHolderStrategy(); + private String rolePrefix = "ROLE_"; private HttpServletRequestFactory requestFactory; @@ -80,6 +84,17 @@ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean { private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); + /** + * Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use + * the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}. + * + * @since 5.8 + */ + public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) { + Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null"); + this.securityContextHolderStrategy = securityContextHolderStrategy; + } + public void setRolePrefix(String rolePrefix) { Assert.notNull(rolePrefix, "Role prefix must not be null"); this.rolePrefix = rolePrefix; @@ -178,6 +193,7 @@ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean { factory.setAuthenticationEntryPoint(this.authenticationEntryPoint); factory.setAuthenticationManager(this.authenticationManager); factory.setLogoutHandlers(this.logoutHandlers); + factory.setSecurityContextHolderStrategy(this.securityContextHolderStrategy); return factory; } diff --git a/web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestWrapper.java b/web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestWrapper.java index e2057add22..089c1096a8 100644 --- a/web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestWrapper.java +++ b/web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestWrapper.java @@ -28,6 +28,7 @@ import org.springframework.security.authentication.AuthenticationTrustResolverIm import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.util.Assert; @@ -50,6 +51,9 @@ import org.springframework.util.Assert; */ public class SecurityContextHolderAwareRequestWrapper extends HttpServletRequestWrapper { + private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder + .getContextHolderStrategy(); + private final AuthenticationTrustResolver trustResolver; /** @@ -88,7 +92,7 @@ public class SecurityContextHolderAwareRequestWrapper extends HttpServletRequest * @return the authentication object or null */ private Authentication getAuthentication() { - Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + Authentication auth = this.securityContextHolderStrategy.getContext().getAuthentication(); return (!this.trustResolver.isAnonymous(auth)) ? auth : null; } @@ -169,4 +173,15 @@ public class SecurityContextHolderAwareRequestWrapper extends HttpServletRequest return "SecurityContextHolderAwareRequestWrapper[ " + getRequest() + "]"; } + /** + * Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use + * the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}. + * + * @since 5.8 + */ + public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) { + Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null"); + this.securityContextHolderStrategy = securityContextHolderStrategy; + } + }