From 59829321a8045c26f19c725f3ae081ac297e4079 Mon Sep 17 00:00:00 2001 From: Evgeniy Cheban Date: Wed, 18 Jan 2023 12:50:27 +0100 Subject: [PATCH] Allow configuring SecurityContextRepository for BasicAuthenticationFilter Closes gh-12031 --- .../web/configurers/HttpBasicConfigurer.java | 23 ++++++++++++- .../configurers/HttpBasicConfigurerTests.java | 32 ++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurer.java index 5ca0a5e2ec..c968508a2d 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -36,6 +36,8 @@ import org.springframework.security.web.authentication.WebAuthenticationDetailsS import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler; import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.security.web.context.RequestAttributeSecurityContextRepository; +import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.security.web.util.matcher.AndRequestMatcher; import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher; import org.springframework.security.web.util.matcher.NegatedRequestMatcher; @@ -75,6 +77,7 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy; * * * @author Rob Winch + * @author Evgeniy Cheban * @since 3.2 */ public final class HttpBasicConfigurer> @@ -91,6 +94,8 @@ public final class HttpBasicConfigurer> private BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint(); + private SecurityContextRepository securityContextRepository; + /** * Creates a new instance * @see HttpSecurity#httpBasic() @@ -142,6 +147,19 @@ public final class HttpBasicConfigurer> return this; } + /** + * Specifies a custom {@link SecurityContextRepository} to use for basic + * authentication. The default is {@link RequestAttributeSecurityContextRepository}. + * @param securityContextRepository the custom {@link SecurityContextRepository} to + * use + * @return {@link HttpBasicConfigurer} for additional customization + * @since 6.1 + */ + public HttpBasicConfigurer securityContextRepository(SecurityContextRepository securityContextRepository) { + this.securityContextRepository = securityContextRepository; + return this; + } + @Override public void init(B http) { registerDefaults(http); @@ -195,6 +213,9 @@ public final class HttpBasicConfigurer> if (this.authenticationDetailsSource != null) { basicAuthenticationFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource); } + if (this.securityContextRepository != null) { + basicAuthenticationFilter.setSecurityContextRepository(this.securityContextRepository); + } RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class); if (rememberMeServices != null) { basicAuthenticationFilter.setRememberMeServices(rememberMeServices); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java index e7bd6cd4e0..fc8138ece0 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -34,6 +34,7 @@ import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContextExtension; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextChangedListener; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; @@ -42,6 +43,7 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.security.web.context.SecurityContextRepository; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.web.bind.annotation.GetMapping; @@ -66,6 +68,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. * * @author Rob Winch * @author Eleftheria Stein + * @author Evgeniy Cheban */ @ExtendWith(SpringTestContextExtension.class) public class HttpBasicConfigurerTests { @@ -145,6 +148,15 @@ public class HttpBasicConfigurerTests { verify(listener).securityContextChanged(setAuthentication(UsernamePasswordAuthenticationToken.class)); } + @Test + public void httpBasicWhenUsingCustomSecurityContextRepositoryThenUses() throws Exception { + this.spring.register(CustomSecurityContextRepositoryConfig.class, Users.class, Home.class).autowire(); + this.mvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isOk()) + .andExpect(content().string("user")); + verify(CustomSecurityContextRepositoryConfig.SECURITY_CONTEXT_REPOSITORY) + .saveContext(any(SecurityContext.class), any(HttpServletRequest.class), any(HttpServletResponse.class)); + } + @Configuration @EnableWebSecurity static class ObjectPostProcessorConfig { @@ -321,6 +333,24 @@ public class HttpBasicConfigurerTests { } + @Configuration + @EnableWebSecurity + static class CustomSecurityContextRepositoryConfig { + + static final SecurityContextRepository SECURITY_CONTEXT_REPOSITORY = mock(SecurityContextRepository.class); + + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + // @formatter:off + http + .httpBasic() + .securityContextRepository(SECURITY_CONTEXT_REPOSITORY); + // @formatter:on + return http.build(); + } + + } + @Configuration static class Users {