Skip to content

Commit a939fa6

Browse files
Merge branch '6.0.x'
Closes gh-13282
2 parents 528ec31 + 4e3517e commit a939fa6

File tree

3 files changed

+90
-0
lines changed

3 files changed

+90
-0
lines changed

config/src/main/java/org/springframework/security/config/annotation/AbstractConfiguredSecurityBuilder.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ public <C extends SecurityConfigurer<O, B>> List<C> removeConfigurers(Class<C> c
221221
if (configs == null) {
222222
return new ArrayList<>();
223223
}
224+
removeFromConfigurersAddedInInitializing(clazz);
224225
return new ArrayList<>(configs);
225226
}
226227

@@ -253,11 +254,16 @@ public <C extends SecurityConfigurer<O, B>> C removeConfigurer(Class<C> clazz) {
253254
if (configs == null) {
254255
return null;
255256
}
257+
removeFromConfigurersAddedInInitializing(clazz);
256258
Assert.state(configs.size() == 1,
257259
() -> "Only one configurer expected for type " + clazz + ", but got " + configs);
258260
return (C) configs.get(0);
259261
}
260262

263+
private <C extends SecurityConfigurer<O, B>> void removeFromConfigurersAddedInInitializing(Class<C> clazz) {
264+
this.configurersAddedInInitializing.removeIf(clazz::isInstance);
265+
}
266+
261267
/**
262268
* Specifies the {@link ObjectPostProcessor} to use.
263269
* @param objectPostProcessor the {@link ObjectPostProcessor} to use. Cannot be null

config/src/test/java/org/springframework/security/config/annotation/web/AbstractConfiguredSecurityBuilderTests.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
3131
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
3232
import static org.mockito.Mockito.mock;
33+
import static org.mockito.Mockito.never;
3334
import static org.mockito.Mockito.verify;
3435

3536
/**
@@ -83,6 +84,24 @@ public void buildWhenConfigurerAppliesAnotherConfigurerThenObjectStillBuilds() t
8384
verify(DelegateSecurityConfigurer.CONFIGURER).configure(this.builder);
8485
}
8586

87+
@Test
88+
public void buildWhenConfigurerAppliesAndRemoveAnotherConfigurerThenNotConfigured() throws Exception {
89+
ApplyAndRemoveSecurityConfigurer.CONFIGURER = mock(SecurityConfigurer.class);
90+
this.builder.apply(new ApplyAndRemoveSecurityConfigurer());
91+
this.builder.build();
92+
verify(ApplyAndRemoveSecurityConfigurer.CONFIGURER, never()).init(this.builder);
93+
verify(ApplyAndRemoveSecurityConfigurer.CONFIGURER, never()).configure(this.builder);
94+
}
95+
96+
@Test
97+
public void buildWhenConfigurerAppliesAndRemoveAnotherConfigurersThenNotConfigured() throws Exception {
98+
ApplyAndRemoveAllSecurityConfigurer.CONFIGURER = mock(SecurityConfigurer.class);
99+
this.builder.apply(new ApplyAndRemoveAllSecurityConfigurer());
100+
this.builder.build();
101+
verify(ApplyAndRemoveAllSecurityConfigurer.CONFIGURER, never()).init(this.builder);
102+
verify(ApplyAndRemoveAllSecurityConfigurer.CONFIGURER, never()).configure(this.builder);
103+
}
104+
86105
@Test
87106
public void getConfigurerWhenMultipleConfigurersThenThrowIllegalStateException() throws Exception {
88107
TestConfiguredSecurityBuilder builder = new TestConfiguredSecurityBuilder(mock(ObjectPostProcessor.class),
@@ -130,6 +149,32 @@ public void getConfigurersWhenMultipleConfigurersThenConfigurersReturned() throw
130149
assertThat(builder.getConfigurers(DelegateSecurityConfigurer.class)).hasSize(2);
131150
}
132151

152+
private static class ApplyAndRemoveSecurityConfigurer
153+
extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> {
154+
155+
private static SecurityConfigurer<Object, TestConfiguredSecurityBuilder> CONFIGURER;
156+
157+
@Override
158+
public void init(TestConfiguredSecurityBuilder builder) throws Exception {
159+
builder.apply(CONFIGURER);
160+
builder.removeConfigurer(CONFIGURER.getClass());
161+
}
162+
163+
}
164+
165+
private static class ApplyAndRemoveAllSecurityConfigurer
166+
extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> {
167+
168+
private static SecurityConfigurer<Object, TestConfiguredSecurityBuilder> CONFIGURER;
169+
170+
@Override
171+
public void init(TestConfiguredSecurityBuilder builder) throws Exception {
172+
builder.apply(CONFIGURER);
173+
builder.removeConfigurers(CONFIGURER.getClass());
174+
}
175+
176+
}
177+
133178
private static class DelegateSecurityConfigurer
134179
extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> {
135180

config/src/test/java/org/springframework/security/config/annotation/web/configuration/HttpSecurityConfigurationTests.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import com.google.common.net.HttpHeaders;
2525
import io.micrometer.observation.ObservationRegistry;
26+
import jakarta.servlet.Filter;
2627
import jakarta.servlet.http.HttpServletRequest;
2728
import jakarta.servlet.http.HttpServletResponse;
2829
import org.junit.jupiter.api.Test;
@@ -50,6 +51,7 @@
5051
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
5152
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
5253
import org.springframework.security.config.annotation.web.configurers.AnonymousConfigurer;
54+
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
5355
import org.springframework.security.config.test.SpringTestContext;
5456
import org.springframework.security.config.test.SpringTestContextExtension;
5557
import org.springframework.security.core.Authentication;
@@ -61,6 +63,8 @@
6163
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
6264
import org.springframework.security.test.web.servlet.RequestCacheResultMatcher;
6365
import org.springframework.security.web.SecurityFilterChain;
66+
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
67+
import org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter;
6468
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
6569
import org.springframework.test.web.servlet.MockMvc;
6670
import org.springframework.test.web.servlet.MvcResult;
@@ -336,6 +340,16 @@ public void configureWhenNoAuthenticationManagerAndObservationRegistryNotNoOpThe
336340
this.mockMvc.perform(get("/"));
337341
}
338342

343+
// gh-13203
344+
@Test
345+
public void disableConfigurerWhenAppliedByAnotherConfigurerThenNotApplied() {
346+
this.spring.register(ApplyCustomDslConfig.class).autowire();
347+
SecurityFilterChain filterChain = this.spring.getContext().getBean(SecurityFilterChain.class);
348+
List<Filter> filters = filterChain.getFilters();
349+
assertThat(filters).doesNotHaveAnyElementsOfTypes(DefaultLoginPageGeneratingFilter.class,
350+
DefaultLogoutPageGeneratingFilter.class);
351+
}
352+
339353
@RestController
340354
static class NameController {
341355

@@ -575,6 +589,31 @@ ObservationRegistry observationRegistry() {
575589

576590
}
577591

592+
@Configuration
593+
@EnableWebSecurity
594+
static class ApplyCustomDslConfig {
595+
596+
@Bean
597+
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
598+
http.apply(CustomDsl.customDsl());
599+
return http.build();
600+
}
601+
602+
}
603+
604+
static class CustomDsl extends AbstractHttpConfigurer<CustomDsl, HttpSecurity> {
605+
606+
@Override
607+
public void init(HttpSecurity http) throws Exception {
608+
http.formLogin(FormLoginConfigurer::disable);
609+
}
610+
611+
static CustomDsl customDsl() {
612+
return new CustomDsl();
613+
}
614+
615+
}
616+
578617
static class DefaultConfigurer extends AbstractHttpConfigurer<DefaultConfigurer, HttpSecurity> {
579618

580619
boolean init;

0 commit comments

Comments
 (0)