Ver Fonte

Merge branch '5.8.x' into 6.0.x

Closes gh-13281
Marcus Da Coregio há 2 anos atrás
pai
commit
4e3517e03a

+ 6 - 0
config/src/main/java/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java

@@ -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

+ 45 - 0
config/src/test/java/org/springframework/security/config/annotation/web/AbstractConfiguredSecurityBuilderTests.java

@@ -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> {
 

+ 39 - 0
config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java

@@ -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;