commit
						4e3517e03a
					
				|  | @ -221,6 +221,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui | ||||||
| 		if (configs == null) { | 		if (configs == null) { | ||||||
| 			return new ArrayList<>(); | 			return new ArrayList<>(); | ||||||
| 		} | 		} | ||||||
|  | 		removeFromConfigurersAddedInInitializing(clazz); | ||||||
| 		return new ArrayList<>(configs); | 		return new ArrayList<>(configs); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -253,11 +254,16 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui | ||||||
| 		if (configs == null) { | 		if (configs == null) { | ||||||
| 			return null; | 			return null; | ||||||
| 		} | 		} | ||||||
|  | 		removeFromConfigurersAddedInInitializing(clazz); | ||||||
| 		Assert.state(configs.size() == 1, | 		Assert.state(configs.size() == 1, | ||||||
| 				() -> "Only one configurer expected for type " + clazz + ", but got " + configs); | 				() -> "Only one configurer expected for type " + clazz + ", but got " + configs); | ||||||
| 		return (C) configs.get(0); | 		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. | 	 * Specifies the {@link ObjectPostProcessor} to use. | ||||||
| 	 * @param objectPostProcessor the {@link ObjectPostProcessor} to use. Cannot be null | 	 * @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.assertThatIllegalArgumentException; | ||||||
| import static org.assertj.core.api.Assertions.assertThatIllegalStateException; | import static org.assertj.core.api.Assertions.assertThatIllegalStateException; | ||||||
| import static org.mockito.Mockito.mock; | import static org.mockito.Mockito.mock; | ||||||
|  | import static org.mockito.Mockito.never; | ||||||
| import static org.mockito.Mockito.verify; | import static org.mockito.Mockito.verify; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | @ -83,6 +84,24 @@ public class AbstractConfiguredSecurityBuilderTests { | ||||||
| 		verify(DelegateSecurityConfigurer.CONFIGURER).configure(this.builder); | 		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 | 	@Test | ||||||
| 	public void getConfigurerWhenMultipleConfigurersThenThrowIllegalStateException() throws Exception { | 	public void getConfigurerWhenMultipleConfigurersThenThrowIllegalStateException() throws Exception { | ||||||
| 		TestConfiguredSecurityBuilder builder = new TestConfiguredSecurityBuilder(mock(ObjectPostProcessor.class), | 		TestConfiguredSecurityBuilder builder = new TestConfiguredSecurityBuilder(mock(ObjectPostProcessor.class), | ||||||
|  | @ -130,6 +149,32 @@ public class AbstractConfiguredSecurityBuilderTests { | ||||||
| 		assertThat(builder.getConfigurers(DelegateSecurityConfigurer.class)).hasSize(2); | 		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 | 	private static class DelegateSecurityConfigurer | ||||||
| 			extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> { | 			extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> { | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -23,6 +23,7 @@ import java.util.concurrent.Callable; | ||||||
| 
 | 
 | ||||||
| import com.google.common.net.HttpHeaders; | import com.google.common.net.HttpHeaders; | ||||||
| import io.micrometer.observation.ObservationRegistry; | import io.micrometer.observation.ObservationRegistry; | ||||||
|  | import jakarta.servlet.Filter; | ||||||
| import jakarta.servlet.http.HttpServletRequest; | import jakarta.servlet.http.HttpServletRequest; | ||||||
| import jakarta.servlet.http.HttpServletResponse; | import jakarta.servlet.http.HttpServletResponse; | ||||||
| import org.junit.jupiter.api.Test; | 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.builders.HttpSecurity; | ||||||
| import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; | 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.AnonymousConfigurer; | ||||||
|  | import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer; | ||||||
| import org.springframework.security.config.test.SpringTestContext; | import org.springframework.security.config.test.SpringTestContext; | ||||||
| import org.springframework.security.config.test.SpringTestContextExtension; | import org.springframework.security.config.test.SpringTestContextExtension; | ||||||
| import org.springframework.security.core.Authentication; | 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.provisioning.InMemoryUserDetailsManager; | ||||||
| import org.springframework.security.test.web.servlet.RequestCacheResultMatcher; | import org.springframework.security.test.web.servlet.RequestCacheResultMatcher; | ||||||
| import org.springframework.security.web.SecurityFilterChain; | 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.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter; | ||||||
| import org.springframework.test.web.servlet.MockMvc; | import org.springframework.test.web.servlet.MockMvc; | ||||||
| import org.springframework.test.web.servlet.MvcResult; | import org.springframework.test.web.servlet.MvcResult; | ||||||
|  | @ -336,6 +340,16 @@ public class HttpSecurityConfigurationTests { | ||||||
| 		this.mockMvc.perform(get("/")); | 		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 | 	@RestController | ||||||
| 	static class NameController { | 	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> { | 	static class DefaultConfigurer extends AbstractHttpConfigurer<DefaultConfigurer, HttpSecurity> { | ||||||
| 
 | 
 | ||||||
| 		boolean init; | 		boolean init; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue