Add PathPatterRequestMatcher
Closes gh-16429 Clsoes gh-16430
This commit is contained in:
@@ -48,6 +48,7 @@ import org.springframework.security.web.firewall.FirewalledRequest;
|
||||
import org.springframework.security.web.firewall.HttpFirewall;
|
||||
import org.springframework.security.web.firewall.RequestRejectedException;
|
||||
import org.springframework.security.web.firewall.RequestRejectedHandler;
|
||||
import org.springframework.security.web.servlet.TestMockHttpServletMappings;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -166,6 +167,7 @@ public class FilterChainProxyTests {
|
||||
FirewalledRequest fwr = mock(FirewalledRequest.class);
|
||||
given(fwr.getRequestURI()).willReturn("/");
|
||||
given(fwr.getContextPath()).willReturn("");
|
||||
given(fwr.getHttpServletMapping()).willReturn(TestMockHttpServletMappings.defaultMapping());
|
||||
this.fcp.setFirewall(fw);
|
||||
given(fw.getFirewalledRequest(this.request)).willReturn(fwr);
|
||||
given(this.matcher.matches(any(HttpServletRequest.class))).willReturn(false);
|
||||
@@ -183,9 +185,11 @@ public class FilterChainProxyTests {
|
||||
FirewalledRequest firstFwr = mock(FirewalledRequest.class, "firstFwr");
|
||||
given(firstFwr.getRequestURI()).willReturn("/");
|
||||
given(firstFwr.getContextPath()).willReturn("");
|
||||
given(firstFwr.getHttpServletMapping()).willReturn(TestMockHttpServletMappings.defaultMapping());
|
||||
FirewalledRequest fwr = mock(FirewalledRequest.class, "fwr");
|
||||
given(fwr.getRequestURI()).willReturn("/");
|
||||
given(fwr.getContextPath()).willReturn("");
|
||||
given(fwr.getHttpServletMapping()).willReturn(TestMockHttpServletMappings.defaultMapping());
|
||||
given(fw.getFirewalledRequest(this.request)).willReturn(firstFwr);
|
||||
given(fw.getFirewalledRequest(firstFwr)).willReturn(fwr);
|
||||
given(fwr.getRequest()).willReturn(firstFwr);
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.web.servlet.util.matcher;
|
||||
|
||||
import jakarta.servlet.Servlet;
|
||||
import jakarta.servlet.ServletContext;
|
||||
import jakarta.servlet.ServletRegistration;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.security.web.servlet.MockServletContext;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.web.util.ServletRequestPathUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
|
||||
/**
|
||||
* Tests for {@link PathPatternRequestMatcher}
|
||||
*/
|
||||
public class PathPatternRequestMatcherTests {
|
||||
|
||||
@Test
|
||||
void matcherWhenPatternMatchesRequestThenMatchResult() {
|
||||
RequestMatcher matcher = PathPatternRequestMatcher.withDefaults().matcher("/uri");
|
||||
assertThat(matcher.matches(request("/uri"))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matcherWhenPatternContainsPlaceholdersThenMatchResult() {
|
||||
RequestMatcher matcher = PathPatternRequestMatcher.withDefaults().matcher("/uri/{username}");
|
||||
assertThat(matcher.matcher(request("/uri/bob")).getVariables()).containsEntry("username", "bob");
|
||||
}
|
||||
|
||||
@Test
|
||||
void matcherWhenOnlyPathInfoMatchesThenMatches() {
|
||||
RequestMatcher matcher = PathPatternRequestMatcher.withDefaults().matcher("/uri");
|
||||
assertThat(matcher.matches(request("GET", "/mvc/uri", "/mvc"))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matcherWhenUriContainsServletPathThenNoMatch() {
|
||||
RequestMatcher matcher = PathPatternRequestMatcher.withDefaults().matcher("/mvc/uri");
|
||||
assertThat(matcher.matches(request("GET", "/mvc/uri", "/mvc"))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matcherWhenSameMethodThenMatchResult() {
|
||||
RequestMatcher matcher = PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, "/uri");
|
||||
assertThat(matcher.matches(request("/uri"))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matcherWhenDifferentPathThenNoMatch() {
|
||||
RequestMatcher matcher = PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, "/uri");
|
||||
assertThat(matcher.matches(request("GET", "/urj", ""))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matcherWhenDifferentMethodThenNoMatch() {
|
||||
RequestMatcher matcher = PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, "/uri");
|
||||
assertThat(matcher.matches(request("POST", "/mvc/uri", "/mvc"))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matcherWhenNoMethodThenMatches() {
|
||||
RequestMatcher matcher = PathPatternRequestMatcher.withDefaults().matcher("/uri");
|
||||
assertThat(matcher.matches(request("POST", "/uri", ""))).isTrue();
|
||||
assertThat(matcher.matches(request("GET", "/uri", ""))).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matcherWhenServletPathThenMatchesOnlyServletPath() {
|
||||
PathPatternRequestMatcher.Builder servlet = PathPatternRequestMatcher.withDefaults()
|
||||
.servletPath("/servlet/path");
|
||||
RequestMatcher matcher = servlet.matcher(HttpMethod.GET, "/endpoint");
|
||||
ServletContext servletContext = servletContext("/servlet/path");
|
||||
MockHttpServletRequest mock = get("/servlet/path/endpoint").servletPath("/servlet/path")
|
||||
.buildRequest(servletContext);
|
||||
ServletRequestPathUtils.parseAndCache(mock);
|
||||
assertThat(matcher.matches(mock)).isTrue();
|
||||
mock = get("/endpoint").servletPath("/endpoint").buildRequest(servletContext);
|
||||
ServletRequestPathUtils.parseAndCache(mock);
|
||||
assertThat(matcher.matches(mock)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matcherWhenRequestPathThenIgnoresServletPath() {
|
||||
PathPatternRequestMatcher.Builder request = PathPatternRequestMatcher.withDefaults();
|
||||
RequestMatcher matcher = request.matcher(HttpMethod.GET, "/endpoint");
|
||||
MockHttpServletRequest mock = get("/servlet/path/endpoint").servletPath("/servlet/path").buildRequest(null);
|
||||
ServletRequestPathUtils.parseAndCache(mock);
|
||||
assertThat(matcher.matches(mock)).isTrue();
|
||||
mock = get("/endpoint").servletPath("/endpoint").buildRequest(null);
|
||||
ServletRequestPathUtils.parseAndCache(mock);
|
||||
assertThat(matcher.matches(mock)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void matcherWhenServletPathThenRequiresServletPathToExist() {
|
||||
PathPatternRequestMatcher.Builder servlet = PathPatternRequestMatcher.withDefaults()
|
||||
.servletPath("/servlet/path");
|
||||
RequestMatcher matcher = servlet.matcher(HttpMethod.GET, "/endpoint");
|
||||
assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(
|
||||
() -> matcher.matches(get("/servlet/path/endpoint").servletPath("/servlet/path").buildRequest(null)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletPathWhenEndsWithSlashOrStarThenIllegalArgument() {
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> PathPatternRequestMatcher.withDefaults().servletPath("/path/**"));
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> PathPatternRequestMatcher.withDefaults().servletPath("/path/*"));
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> PathPatternRequestMatcher.withDefaults().servletPath("/path/"));
|
||||
}
|
||||
|
||||
MockHttpServletRequest request(String uri) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", uri);
|
||||
ServletRequestPathUtils.parseAndCache(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
MockHttpServletRequest request(String method, String uri, String servletPath) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method, uri);
|
||||
request.setServletPath(servletPath);
|
||||
ServletRequestPathUtils.parseAndCache(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
MockServletContext servletContext(String... servletPath) {
|
||||
MockServletContext servletContext = new MockServletContext();
|
||||
ServletRegistration.Dynamic registration = servletContext.addServlet("servlet", Servlet.class);
|
||||
for (String s : servletPath) {
|
||||
registration.addMapping(s + "/*");
|
||||
}
|
||||
return servletContext;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user