Skip to content

Commit 773e867

Browse files
committed
Add ParameterRequestMatcher
Closes gh-15342
1 parent 207680b commit 773e867

File tree

4 files changed

+159
-40
lines changed

4 files changed

+159
-40
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/configurers/saml2/Saml2LogoutConfigurer.java

+2-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 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.
@@ -18,8 +18,6 @@
1818

1919
import java.util.ArrayList;
2020
import java.util.List;
21-
import java.util.Objects;
22-
import java.util.function.Predicate;
2321

2422
import jakarta.servlet.http.HttpServletRequest;
2523

@@ -60,6 +58,7 @@
6058
import org.springframework.security.web.csrf.CsrfTokenRepository;
6159
import org.springframework.security.web.util.matcher.AndRequestMatcher;
6260
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
61+
import org.springframework.security.web.util.matcher.ParameterRequestMatcher;
6362
import org.springframework.security.web.util.matcher.RequestMatcher;
6463

6564
/**
@@ -508,23 +507,6 @@ public boolean matches(HttpServletRequest request) {
508507

509508
}
510509

511-
private static class ParameterRequestMatcher implements RequestMatcher {
512-
513-
Predicate<String> test = Objects::nonNull;
514-
515-
String name;
516-
517-
ParameterRequestMatcher(String name) {
518-
this.name = name;
519-
}
520-
521-
@Override
522-
public boolean matches(HttpServletRequest request) {
523-
return this.test.test(request.getParameter(this.name));
524-
}
525-
526-
}
527-
528510
private static class Saml2RelyingPartyInitiatedLogoutFilter extends LogoutFilter {
529511

530512
Saml2RelyingPartyInitiatedLogoutFilter(LogoutSuccessHandler logoutSuccessHandler, LogoutHandler... handlers) {

config/src/main/java/org/springframework/security/config/http/Saml2LogoutBeanDefinitionParser.java

+2-20
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.
@@ -18,8 +18,6 @@
1818

1919
import java.util.Arrays;
2020
import java.util.List;
21-
import java.util.Objects;
22-
import java.util.function.Predicate;
2321

2422
import jakarta.servlet.http.HttpServletRequest;
2523
import org.w3c.dom.Element;
@@ -44,6 +42,7 @@
4442
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
4543
import org.springframework.security.web.util.matcher.AndRequestMatcher;
4644
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
45+
import org.springframework.security.web.util.matcher.ParameterRequestMatcher;
4746
import org.springframework.security.web.util.matcher.RequestMatcher;
4847
import org.springframework.util.CollectionUtils;
4948
import org.springframework.util.StringUtils;
@@ -228,23 +227,6 @@ BeanDefinition getLogoutFilter() {
228227
return this.logoutFilter;
229228
}
230229

231-
private static class ParameterRequestMatcher implements RequestMatcher {
232-
233-
Predicate<String> test = Objects::nonNull;
234-
235-
String name;
236-
237-
ParameterRequestMatcher(String name) {
238-
this.name = name;
239-
}
240-
241-
@Override
242-
public boolean matches(HttpServletRequest request) {
243-
return this.test.test(request.getParameter(this.name));
244-
}
245-
246-
}
247-
248230
public static class Saml2RequestMatcher implements RequestMatcher {
249231

250232
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright 2002-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.web.util.matcher;
18+
19+
import java.util.Map;
20+
import java.util.Objects;
21+
22+
import jakarta.servlet.http.HttpServletRequest;
23+
24+
/**
25+
* A {@link RequestMatcher} for matching on a request parameter and its value.
26+
*
27+
* <p>
28+
* The value may also be specified as a placeholder in order to match on any value,
29+
* returning the value as part of the {@link MatchResult}.
30+
*
31+
* @author Josh Cummings
32+
* @since 6.4
33+
*/
34+
public final class ParameterRequestMatcher implements RequestMatcher {
35+
36+
private static final MatchesValueMatcher NON_NULL = Objects::nonNull;
37+
38+
private final String name;
39+
40+
private final ValueMatcher matcher;
41+
42+
public ParameterRequestMatcher(String name) {
43+
this.name = name;
44+
this.matcher = NON_NULL;
45+
}
46+
47+
public ParameterRequestMatcher(String name, String value) {
48+
this.name = name;
49+
MatchesValueMatcher matcher = value::equals;
50+
if (value.startsWith("{") && value.endsWith("}")) {
51+
String key = value.substring(1, value.length() - 1);
52+
this.matcher = (v) -> (v != null) ? MatchResult.match(Map.of(key, v)) : MatchResult.notMatch();
53+
}
54+
else {
55+
this.matcher = matcher;
56+
}
57+
}
58+
59+
@Override
60+
public boolean matches(HttpServletRequest request) {
61+
return matcher(request).isMatch();
62+
}
63+
64+
@Override
65+
public MatchResult matcher(HttpServletRequest request) {
66+
String parameterValue = request.getParameter(this.name);
67+
return this.matcher.matcher(parameterValue);
68+
}
69+
70+
private interface ValueMatcher {
71+
72+
MatchResult matcher(String value);
73+
74+
}
75+
76+
private interface MatchesValueMatcher extends ValueMatcher {
77+
78+
default MatchResult matcher(String value) {
79+
if (matches(value)) {
80+
return MatchResult.match();
81+
}
82+
else {
83+
return MatchResult.notMatch();
84+
}
85+
}
86+
87+
boolean matches(String value);
88+
89+
}
90+
91+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2002-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.web.util.matcher;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.junit.jupiter.api.extension.ExtendWith;
21+
import org.mockito.junit.jupiter.MockitoExtension;
22+
23+
import org.springframework.mock.web.MockHttpServletRequest;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
27+
/**
28+
* Tests for {@link ParameterRequestMatcher}
29+
*
30+
* @author Josh Cummings
31+
*/
32+
@ExtendWith(MockitoExtension.class)
33+
public class ParameterRequestMatcherTests {
34+
35+
@Test
36+
public void matchesWhenNameThenMatchesOnParameterName() {
37+
ParameterRequestMatcher matcher = new ParameterRequestMatcher("name");
38+
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo/bar");
39+
assertThat(matcher.matches(request)).isFalse();
40+
request.setParameter("name", "value");
41+
assertThat(matcher.matches(request)).isTrue();
42+
}
43+
44+
@Test
45+
public void matchesWhenNameAndValueThenMatchesOnBoth() {
46+
ParameterRequestMatcher matcher = new ParameterRequestMatcher("name", "value");
47+
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo/bar");
48+
request.setParameter("name", "value");
49+
assertThat(matcher.matches(request)).isTrue();
50+
request.setParameter("name", "wrong");
51+
assertThat(matcher.matches(request)).isFalse();
52+
}
53+
54+
@Test
55+
public void matchesWhenValuePlaceholderThenMatchesOnName() {
56+
ParameterRequestMatcher matcher = new ParameterRequestMatcher("name", "{placeholder}");
57+
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo/bar");
58+
request.setParameter("name", "value");
59+
RequestMatcher.MatchResult result = matcher.matcher(request);
60+
assertThat(result.isMatch()).isTrue();
61+
assertThat(result.getVariables().get("placeholder")).isEqualTo("value");
62+
}
63+
64+
}

0 commit comments

Comments
 (0)