Kaynağa Gözat

Allow configuring SecurityContextRepository for BasicAuthenticationFilter

Closes gh-12031
Evgeniy Cheban 2 yıl önce
ebeveyn
işleme
59829321a8

+ 22 - 1
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;
  * </ul>
  *
  * @author Rob Winch
+ * @author Evgeniy Cheban
  * @since 3.2
  */
 public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>>
@@ -91,6 +94,8 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>>
 
 	private BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
 
+	private SecurityContextRepository securityContextRepository;
+
 	/**
 	 * Creates a new instance
 	 * @see HttpSecurity#httpBasic()
@@ -142,6 +147,19 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>>
 		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<B> securityContextRepository(SecurityContextRepository securityContextRepository) {
+		this.securityContextRepository = securityContextRepository;
+		return this;
+	}
+
 	@Override
 	public void init(B http) {
 		registerDefaults(http);
@@ -195,6 +213,9 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>>
 		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);

+ 31 - 1
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 {