Polish SecurityContextHolderStrategy for Defaults

gh-11060
This commit is contained in:
Josh Cummings 2022-06-21 16:43:41 -06:00
parent c29b91cec7
commit a7b58c2299
No known key found for this signature in database
GPG Key ID: A306A51F43B8E5A5
6 changed files with 86 additions and 11 deletions

View File

@ -26,6 +26,7 @@ import org.springframework.core.log.LogMessage;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -45,6 +46,9 @@ public class SecurityContextLogoutHandler implements LogoutHandler {
protected final Log logger = LogFactory.getLog(this.getClass()); protected final Log logger = LogFactory.getLog(this.getClass());
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
private boolean invalidateHttpSession = true; private boolean invalidateHttpSession = true;
private boolean clearAuthentication = true; private boolean clearAuthentication = true;
@ -67,8 +71,8 @@ public class SecurityContextLogoutHandler implements LogoutHandler {
} }
} }
} }
SecurityContext context = SecurityContextHolder.getContext(); SecurityContext context = this.securityContextHolderStrategy.getContext();
SecurityContextHolder.clearContext(); this.securityContextHolderStrategy.clearContext();
if (this.clearAuthentication) { if (this.clearAuthentication) {
context.setAuthentication(null); context.setAuthentication(null);
} }
@ -78,6 +82,17 @@ public class SecurityContextLogoutHandler implements LogoutHandler {
return this.invalidateHttpSession; 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 * Causes the {@link HttpSession} to be invalidated when this {@link LogoutHandler} is
* invoked. Defaults to true. * invoked. Defaults to true.

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.annotation.CurrentSecurityContext;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -75,6 +76,9 @@ import org.springframework.web.method.support.ModelAndViewContainer;
*/ */
public final class CurrentSecurityContextArgumentResolver implements HandlerMethodArgumentResolver { public final class CurrentSecurityContextArgumentResolver implements HandlerMethodArgumentResolver {
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
private ExpressionParser parser = new SpelExpressionParser(); private ExpressionParser parser = new SpelExpressionParser();
private BeanResolver beanResolver; private BeanResolver beanResolver;
@ -87,7 +91,7 @@ public final class CurrentSecurityContextArgumentResolver implements HandlerMeth
@Override @Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
SecurityContext securityContext = SecurityContextHolder.getContext(); SecurityContext securityContext = this.securityContextHolderStrategy.getContext();
if (securityContext == null) { if (securityContext == null) {
return null; return null;
} }
@ -113,6 +117,17 @@ public final class CurrentSecurityContextArgumentResolver implements HandlerMeth
return securityContextResult; 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 * Set the {@link BeanResolver} to be used on the expressions
* @param beanResolver the {@link BeanResolver} to use * @param beanResolver the {@link BeanResolver} to use

View File

@ -41,6 +41,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder; 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.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.security.web.authentication.logout.LogoutHandler;
@ -76,6 +77,9 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
private Log logger = LogFactory.getLog(getClass()); private Log logger = LogFactory.getLog(getClass());
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
private final String rolePrefix; private final String rolePrefix;
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
@ -161,9 +165,17 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
this.trustResolver = trustResolver; this.trustResolver = trustResolver;
} }
void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
this.securityContextHolderStrategy = securityContextHolderStrategy;
}
@Override @Override
public HttpServletRequest create(HttpServletRequest request, HttpServletResponse response) { 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 { private class Servlet3SecurityContextHolderAwareRequestWrapper extends SecurityContextHolderAwareRequestWrapper {
@ -228,9 +240,10 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
return; return;
} }
Authentication authentication = getAuthentication(authManager, username, password); Authentication authentication = getAuthentication(authManager, username, password);
SecurityContext context = SecurityContextHolder.createEmptyContext(); SecurityContext context = HttpServlet3RequestFactory.this.securityContextHolderStrategy
.createEmptyContext();
context.setAuthentication(authentication); context.setAuthentication(authentication);
SecurityContextHolder.setContext(context); HttpServlet3RequestFactory.this.securityContextHolderStrategy.setContext(context);
} }
private Authentication getAuthentication(AuthenticationManager authManager, String username, String password) private Authentication getAuthentication(AuthenticationManager authManager, String username, String password)
@ -243,7 +256,7 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
return authManager.authenticate(authentication); return authManager.authenticate(authentication);
} }
catch (AuthenticationException ex) { catch (AuthenticationException ex) {
SecurityContextHolder.clearContext(); HttpServlet3RequestFactory.this.securityContextHolderStrategy.clearContext();
throw new ServletException(ex.getMessage(), ex); throw new ServletException(ex.getMessage(), ex);
} }
} }
@ -257,7 +270,8 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
super.logout(); super.logout();
return; return;
} }
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Authentication authentication = HttpServlet3RequestFactory.this.securityContextHolderStrategy.getContext()
.getAuthentication();
for (LogoutHandler handler : handlers) { for (LogoutHandler handler : handlers) {
handler.logout(this, this.response, authentication); handler.logout(this, this.response, authentication);
} }

View File

@ -32,6 +32,7 @@ import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl; import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder; 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.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -68,6 +69,9 @@ import org.springframework.web.filter.GenericFilterBean;
*/ */
public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean { public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
private String rolePrefix = "ROLE_"; private String rolePrefix = "ROLE_";
private HttpServletRequestFactory requestFactory; private HttpServletRequestFactory requestFactory;
@ -80,6 +84,17 @@ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); 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) { public void setRolePrefix(String rolePrefix) {
Assert.notNull(rolePrefix, "Role prefix must not be null"); Assert.notNull(rolePrefix, "Role prefix must not be null");
this.rolePrefix = rolePrefix; this.rolePrefix = rolePrefix;
@ -178,6 +193,7 @@ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {
factory.setAuthenticationEntryPoint(this.authenticationEntryPoint); factory.setAuthenticationEntryPoint(this.authenticationEntryPoint);
factory.setAuthenticationManager(this.authenticationManager); factory.setAuthenticationManager(this.authenticationManager);
factory.setLogoutHandlers(this.logoutHandlers); factory.setLogoutHandlers(this.logoutHandlers);
factory.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
return factory; return factory;
} }

View File

@ -28,6 +28,7 @@ import org.springframework.security.authentication.AuthenticationTrustResolverIm
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -50,6 +51,9 @@ import org.springframework.util.Assert;
*/ */
public class SecurityContextHolderAwareRequestWrapper extends HttpServletRequestWrapper { public class SecurityContextHolderAwareRequestWrapper extends HttpServletRequestWrapper {
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
.getContextHolderStrategy();
private final AuthenticationTrustResolver trustResolver; private final AuthenticationTrustResolver trustResolver;
/** /**
@ -88,7 +92,7 @@ public class SecurityContextHolderAwareRequestWrapper extends HttpServletRequest
* @return the authentication object or <code>null</code> * @return the authentication object or <code>null</code>
*/ */
private Authentication getAuthentication() { private Authentication getAuthentication() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication(); Authentication auth = this.securityContextHolderStrategy.getContext().getAuthentication();
return (!this.trustResolver.isAnonymous(auth)) ? auth : null; return (!this.trustResolver.isAnonymous(auth)) ? auth : null;
} }
@ -169,4 +173,15 @@ public class SecurityContextHolderAwareRequestWrapper extends HttpServletRequest
return "SecurityContextHolderAwareRequestWrapper[ " + getRequest() + "]"; 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;
}
} }