From 5d757919a222e4e5b4676b4fd748ce0cd7a45dcc Mon Sep 17 00:00:00 2001 From: Steve Riesenberg Date: Thu, 22 Sep 2022 15:23:13 -0500 Subject: [PATCH] Add SecurityContextHolderStrategy to new repository In 6.0, RequestAttributeSecurityContextRepository will be the default implementation of SecurityContextRepository. This commit adds the ability to configure a custom SecurityContextHolderStrategy, similar to other components. Issue gh-11060 Closes gh-11895 --- ...estAttributeSecurityContextRepository.java | 17 +++++++++++- ...tributeSecurityContextRepositoryTests.java | 27 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/web/src/main/java/org/springframework/security/web/context/RequestAttributeSecurityContextRepository.java b/web/src/main/java/org/springframework/security/web/context/RequestAttributeSecurityContextRepository.java index 102450203d..2b99901a54 100644 --- a/web/src/main/java/org/springframework/security/web/context/RequestAttributeSecurityContextRepository.java +++ b/web/src/main/java/org/springframework/security/web/context/RequestAttributeSecurityContextRepository.java @@ -23,6 +23,8 @@ import javax.servlet.http.HttpServletResponse; 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; /** * Stores the {@link SecurityContext} on a @@ -48,6 +50,9 @@ public final class RequestAttributeSecurityContextRepository implements Security private final String requestAttributeName; + private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder + .getContextHolderStrategy(); + /** * Creates a new instance using {@link #DEFAULT_REQUEST_ATTR_NAME}. */ @@ -81,7 +86,7 @@ public final class RequestAttributeSecurityContextRepository implements Security private SecurityContext getContextOrEmpty(HttpServletRequest request) { SecurityContext context = getContext(request); - return (context != null) ? context : SecurityContextHolder.createEmptyContext(); + return (context != null) ? context : this.securityContextHolderStrategy.createEmptyContext(); } private SecurityContext getContext(HttpServletRequest request) { @@ -93,4 +98,14 @@ public final class RequestAttributeSecurityContextRepository implements Security request.setAttribute(this.requestAttributeName, context); } + /** + * 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; + } + } diff --git a/web/src/test/java/org/springframework/security/web/context/RequestAttributeSecurityContextRepositoryTests.java b/web/src/test/java/org/springframework/security/web/context/RequestAttributeSecurityContextRepositoryTests.java index 93390cf836..aa43ef9836 100644 --- a/web/src/test/java/org/springframework/security/web/context/RequestAttributeSecurityContextRepositoryTests.java +++ b/web/src/test/java/org/springframework/security/web/context/RequestAttributeSecurityContextRepositoryTests.java @@ -25,9 +25,15 @@ import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.authentication.TestAuthentication; 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.core.context.SecurityContextImpl; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; /** * @author Rob Winch @@ -42,6 +48,15 @@ class RequestAttributeSecurityContextRepositoryTests { private SecurityContext expectedSecurityContext = new SecurityContextImpl(TestAuthentication.authenticatedUser()); + @Test + void setSecurityContextHolderStrategyWhenNullThenThrowsIllegalArgumentException() { + // @formatter:off + assertThatIllegalArgumentException() + .isThrownBy(() -> this.repository.setSecurityContextHolderStrategy(null)) + .withMessage("securityContextHolderStrategy cannot be null"); + // @formatter:on + } + @Test void saveContextAndLoadContextThenFound() { this.repository.saveContext(this.expectedSecurityContext, this.request, this.response); @@ -82,4 +97,16 @@ class RequestAttributeSecurityContextRepositoryTests { assertThat(context).isEqualTo(SecurityContextHolder.createEmptyContext()); } + @Test + void loadContextWhenCustomSecurityContextHolderStrategySetThenUsed() { + SecurityContextHolderStrategy securityContextHolderStrategy = mock(SecurityContextHolderStrategy.class); + given(securityContextHolderStrategy.createEmptyContext()).willReturn(new SecurityContextImpl()); + this.repository.setSecurityContextHolderStrategy(securityContextHolderStrategy); + + Supplier deferredContext = this.repository.loadContext(this.request); + assertThat(deferredContext.get()).isNotNull(); + verify(securityContextHolderStrategy).createEmptyContext(); + verifyNoMoreInteractions(securityContextHolderStrategy); + } + }