commit
						4e3517e03a
					
				|  | @ -221,6 +221,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui | |||
| 		if (configs == null) { | ||||
| 			return new ArrayList<>(); | ||||
| 		} | ||||
| 		removeFromConfigurersAddedInInitializing(clazz); | ||||
| 		return new ArrayList<>(configs); | ||||
| 	} | ||||
| 
 | ||||
|  | @ -253,11 +254,16 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui | |||
| 		if (configs == null) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		removeFromConfigurersAddedInInitializing(clazz); | ||||
| 		Assert.state(configs.size() == 1, | ||||
| 				() -> "Only one configurer expected for type " + clazz + ", but got " + configs); | ||||
| 		return (C) configs.get(0); | ||||
| 	} | ||||
| 
 | ||||
| 	private <C extends SecurityConfigurer<O, B>> void removeFromConfigurersAddedInInitializing(Class<C> clazz) { | ||||
| 		this.configurersAddedInInitializing.removeIf(clazz::isInstance); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Specifies the {@link ObjectPostProcessor} to use. | ||||
| 	 * @param objectPostProcessor the {@link ObjectPostProcessor} to use. Cannot be null | ||||
|  |  | |||
|  | @ -30,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat; | |||
| import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; | ||||
| import static org.assertj.core.api.Assertions.assertThatIllegalStateException; | ||||
| import static org.mockito.Mockito.mock; | ||||
| import static org.mockito.Mockito.never; | ||||
| import static org.mockito.Mockito.verify; | ||||
| 
 | ||||
| /** | ||||
|  | @ -83,6 +84,24 @@ public class AbstractConfiguredSecurityBuilderTests { | |||
| 		verify(DelegateSecurityConfigurer.CONFIGURER).configure(this.builder); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void buildWhenConfigurerAppliesAndRemoveAnotherConfigurerThenNotConfigured() throws Exception { | ||||
| 		ApplyAndRemoveSecurityConfigurer.CONFIGURER = mock(SecurityConfigurer.class); | ||||
| 		this.builder.apply(new ApplyAndRemoveSecurityConfigurer()); | ||||
| 		this.builder.build(); | ||||
| 		verify(ApplyAndRemoveSecurityConfigurer.CONFIGURER, never()).init(this.builder); | ||||
| 		verify(ApplyAndRemoveSecurityConfigurer.CONFIGURER, never()).configure(this.builder); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void buildWhenConfigurerAppliesAndRemoveAnotherConfigurersThenNotConfigured() throws Exception { | ||||
| 		ApplyAndRemoveAllSecurityConfigurer.CONFIGURER = mock(SecurityConfigurer.class); | ||||
| 		this.builder.apply(new ApplyAndRemoveAllSecurityConfigurer()); | ||||
| 		this.builder.build(); | ||||
| 		verify(ApplyAndRemoveAllSecurityConfigurer.CONFIGURER, never()).init(this.builder); | ||||
| 		verify(ApplyAndRemoveAllSecurityConfigurer.CONFIGURER, never()).configure(this.builder); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void getConfigurerWhenMultipleConfigurersThenThrowIllegalStateException() throws Exception { | ||||
| 		TestConfiguredSecurityBuilder builder = new TestConfiguredSecurityBuilder(mock(ObjectPostProcessor.class), | ||||
|  | @ -130,6 +149,32 @@ public class AbstractConfiguredSecurityBuilderTests { | |||
| 		assertThat(builder.getConfigurers(DelegateSecurityConfigurer.class)).hasSize(2); | ||||
| 	} | ||||
| 
 | ||||
| 	private static class ApplyAndRemoveSecurityConfigurer | ||||
| 			extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> { | ||||
| 
 | ||||
| 		private static SecurityConfigurer<Object, TestConfiguredSecurityBuilder> CONFIGURER; | ||||
| 
 | ||||
| 		@Override | ||||
| 		public void init(TestConfiguredSecurityBuilder builder) throws Exception { | ||||
| 			builder.apply(CONFIGURER); | ||||
| 			builder.removeConfigurer(CONFIGURER.getClass()); | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	private static class ApplyAndRemoveAllSecurityConfigurer | ||||
| 			extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> { | ||||
| 
 | ||||
| 		private static SecurityConfigurer<Object, TestConfiguredSecurityBuilder> CONFIGURER; | ||||
| 
 | ||||
| 		@Override | ||||
| 		public void init(TestConfiguredSecurityBuilder builder) throws Exception { | ||||
| 			builder.apply(CONFIGURER); | ||||
| 			builder.removeConfigurers(CONFIGURER.getClass()); | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	private static class DelegateSecurityConfigurer | ||||
| 			extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> { | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ import java.util.concurrent.Callable; | |||
| 
 | ||||
| import com.google.common.net.HttpHeaders; | ||||
| import io.micrometer.observation.ObservationRegistry; | ||||
| import jakarta.servlet.Filter; | ||||
| import jakarta.servlet.http.HttpServletRequest; | ||||
| import jakarta.servlet.http.HttpServletResponse; | ||||
| import org.junit.jupiter.api.Test; | ||||
|  | @ -50,6 +51,7 @@ import org.springframework.security.config.annotation.SecurityContextChangedList | |||
| import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||||
| import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; | ||||
| import org.springframework.security.config.annotation.web.configurers.AnonymousConfigurer; | ||||
| import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer; | ||||
| import org.springframework.security.config.test.SpringTestContext; | ||||
| import org.springframework.security.config.test.SpringTestContextExtension; | ||||
| import org.springframework.security.core.Authentication; | ||||
|  | @ -61,6 +63,8 @@ import org.springframework.security.core.userdetails.UserDetailsService; | |||
| import org.springframework.security.provisioning.InMemoryUserDetailsManager; | ||||
| import org.springframework.security.test.web.servlet.RequestCacheResultMatcher; | ||||
| import org.springframework.security.web.SecurityFilterChain; | ||||
| import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; | ||||
| import org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter; | ||||
| import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter; | ||||
| import org.springframework.test.web.servlet.MockMvc; | ||||
| import org.springframework.test.web.servlet.MvcResult; | ||||
|  | @ -336,6 +340,16 @@ public class HttpSecurityConfigurationTests { | |||
| 		this.mockMvc.perform(get("/")); | ||||
| 	} | ||||
| 
 | ||||
| 	// gh-13203 | ||||
| 	@Test | ||||
| 	public void disableConfigurerWhenAppliedByAnotherConfigurerThenNotApplied() { | ||||
| 		this.spring.register(ApplyCustomDslConfig.class).autowire(); | ||||
| 		SecurityFilterChain filterChain = this.spring.getContext().getBean(SecurityFilterChain.class); | ||||
| 		List<Filter> filters = filterChain.getFilters(); | ||||
| 		assertThat(filters).doesNotHaveAnyElementsOfTypes(DefaultLoginPageGeneratingFilter.class, | ||||
| 				DefaultLogoutPageGeneratingFilter.class); | ||||
| 	} | ||||
| 
 | ||||
| 	@RestController | ||||
| 	static class NameController { | ||||
| 
 | ||||
|  | @ -575,6 +589,31 @@ public class HttpSecurityConfigurationTests { | |||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	@Configuration | ||||
| 	@EnableWebSecurity | ||||
| 	static class ApplyCustomDslConfig { | ||||
| 
 | ||||
| 		@Bean | ||||
| 		SecurityFilterChain filterChain(HttpSecurity http) throws Exception { | ||||
| 			http.apply(CustomDsl.customDsl()); | ||||
| 			return http.build(); | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	static class CustomDsl extends AbstractHttpConfigurer<CustomDsl, HttpSecurity> { | ||||
| 
 | ||||
| 		@Override | ||||
| 		public void init(HttpSecurity http) throws Exception { | ||||
| 			http.formLogin(FormLoginConfigurer::disable); | ||||
| 		} | ||||
| 
 | ||||
| 		static CustomDsl customDsl() { | ||||
| 			return new CustomDsl(); | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	static class DefaultConfigurer extends AbstractHttpConfigurer<DefaultConfigurer, HttpSecurity> { | ||||
| 
 | ||||
| 		boolean init; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue