Skip to content

Commit 4c780bf

Browse files
Max Batischevjzheaux
Max Batischev
authored andcommitted
Add support checking AnyRequestMatcher securityFilterChains
Closes gh-15220
1 parent 470cb46 commit 4c780bf

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/builders/WebSecurity.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -63,6 +63,7 @@
6363
import org.springframework.security.web.firewall.ObservationMarkingRequestRejectedHandler;
6464
import org.springframework.security.web.firewall.RequestRejectedHandler;
6565
import org.springframework.security.web.firewall.StrictHttpFirewall;
66+
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
6667
import org.springframework.security.web.util.matcher.RequestMatcher;
6768
import org.springframework.security.web.util.matcher.RequestMatcherEntry;
6869
import org.springframework.util.Assert;
@@ -296,8 +297,20 @@ protected Filter performBuild() throws Exception {
296297
requestMatcherPrivilegeEvaluatorsEntries
297298
.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
298299
}
300+
boolean anyRequestConfigured = false;
301+
RequestMatcher matcher = null;
299302
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
300303
SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
304+
Assert.isTrue(!anyRequestConfigured,
305+
"A filter chain that matches any request has already been configured, which means that this filter chain for ["
306+
+ matcher
307+
+ "] will never get invoked. Please use `HttpSecurity#securityMatcher` to ensure that there is only one filter chain configured for 'any request' and that the 'any request' filter chain is published last.");
308+
if (securityFilterChain instanceof DefaultSecurityFilterChain defaultSecurityFilterChain) {
309+
matcher = defaultSecurityFilterChain.getRequestMatcher();
310+
if (matcher instanceof AnyRequestMatcher) {
311+
anyRequestConfigured = true;
312+
}
313+
}
301314
securityFilterChains.add(securityFilterChain);
302315
requestMatcherPrivilegeEvaluatorsEntries
303316
.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -318,6 +318,14 @@ public void loadConfigWhenMultipleSecurityFilterChainAndIgnoringThenWebInvocatio
318318
assertThat(privilegeEvaluator.isAllowed("/ignoring1/child", null)).isTrue();
319319
}
320320

321+
@Test
322+
public void loadConfigWhenTwoSecurityFilterChainsPresentAndSecondWithAnyRequestThenException() {
323+
assertThatExceptionOfType(BeanCreationException.class)
324+
.isThrownBy(() -> this.spring.register(MultipleAnyRequestSecurityFilterChainConfig.class).autowire())
325+
.havingRootCause()
326+
.isExactlyInstanceOf(IllegalArgumentException.class);
327+
}
328+
321329
private void assertAnotherUserPermission(WebInvocationPrivilegeEvaluator privilegeEvaluator) {
322330
Authentication anotherUser = new TestingAuthenticationToken("anotherUser", "password", "ROLE_ANOTHER");
323331
assertThat(privilegeEvaluator.isAllowed("/user", anotherUser)).isFalse();
@@ -819,4 +827,26 @@ public SecurityFilterChain permitAll(HttpSecurity http) throws Exception {
819827

820828
}
821829

830+
@Configuration
831+
@EnableWebSecurity
832+
@EnableWebMvc
833+
@Import(AuthenticationTestConfiguration.class)
834+
static class MultipleAnyRequestSecurityFilterChainConfig {
835+
836+
@Bean
837+
@Order(0)
838+
SecurityFilterChain api1(HttpSecurity http) throws Exception {
839+
http.authorizeHttpRequests((auth) -> auth.anyRequest().authenticated());
840+
return http.build();
841+
}
842+
843+
@Bean
844+
@Order(1)
845+
SecurityFilterChain api2(HttpSecurity http) throws Exception {
846+
http.securityMatcher("/app/**").authorizeHttpRequests((auth) -> auth.anyRequest().authenticated());
847+
return http.build();
848+
}
849+
850+
}
851+
822852
}

0 commit comments

Comments
 (0)