From 86599afd4385854f92b0d5e95049dbf9bd6d9237 Mon Sep 17 00:00:00 2001 From: Josh Cummings <3627351+jzheaux@users.noreply.github.com> Date: Fri, 21 Mar 2025 12:00:43 -0600 Subject: [PATCH] Rename servletPath to basePath Closes gh-16765 --- .../AuthorizeHttpRequestsConfigurerTests.java | 2 +- .../matcher/PathPatternRequestMatcher.java | 43 +++++++++++-------- .../PathPatternRequestMatcherTests.java | 15 +++---- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java index 4d9c39c4b1..057deea40c 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java @@ -1364,7 +1364,7 @@ public class AuthorizeHttpRequestsConfigurerTests { @Bean SecurityFilterChain security(HttpSecurity http) throws Exception { - PathPatternRequestMatcher.Builder mvc = PathPatternRequestMatcher.withDefaults().servletPath("/mvc"); + PathPatternRequestMatcher.Builder mvc = PathPatternRequestMatcher.withDefaults().basePath("/mvc"); // @formatter:off http .authorizeHttpRequests((authorize) -> authorize diff --git a/web/src/main/java/org/springframework/security/web/servlet/util/matcher/PathPatternRequestMatcher.java b/web/src/main/java/org/springframework/security/web/servlet/util/matcher/PathPatternRequestMatcher.java index 6087a8b3fd..c9c92c2b4b 100644 --- a/web/src/main/java/org/springframework/security/web/servlet/util/matcher/PathPatternRequestMatcher.java +++ b/web/src/main/java/org/springframework/security/web/servlet/util/matcher/PathPatternRequestMatcher.java @@ -166,15 +166,18 @@ public final class PathPatternRequestMatcher implements RequestMatcher { * a {@link PathPatternRequestMatcher}. * *

- * For example, if Spring MVC is deployed to `/mvc` and another servlet to `/other`, - * then you can use this builder to do: - *

+ * To match a request URI like {@code /app/servlet/my/resource/**} where {@code /app} + * is the context path, you can do + * {@code PathPatternRequestMatcher.withDefaults().matcher("/servlet/my/resource/**")} * - * + *

+ * If you have many paths that have a common path prefix, you can use + * {@link #basePath} to reduce repetition like so: + * PathPatternRequestMatcher.Builder mvc = withDefaults().basePath("/mvc"); * http * .authorizeHttpRequests((authorize) -> authorize - * .requestMatchers(servletPath("/mvc").matcher("/user/**")).hasAuthority("user") - * .requestMatchers(servletPath("/other").matcher("/admin/**")).hasAuthority("admin") + * .requestMatchers(mvc.matcher("/user/**")).hasAuthority("user") + * .requestMatchers(mvc.matcher("/admin/**")).hasAuthority("admin") * ) * ... * @@ -183,7 +186,7 @@ public final class PathPatternRequestMatcher implements RequestMatcher { private final PathPatternParser parser; - private final String servletPath; + private final String basePath; Builder() { this(PathPatternParser.defaultInstance); @@ -193,22 +196,26 @@ public final class PathPatternRequestMatcher implements RequestMatcher { this(parser, ""); } - Builder(PathPatternParser parser, String servletPath) { + Builder(PathPatternParser parser, String basePath) { this.parser = parser; - this.servletPath = servletPath; + this.basePath = basePath; } /** - * Match requests starting with this {@code servletPath}. - * @param servletPath the servlet path prefix + * Match requests starting with this {@code basePath}. + * + *

+ * Prefixes should be of the form {@code /my/prefix}, starting with a slash, not + * ending in a slash, and not containing and wildcards + * @param basePath the path prefix * @return the {@link Builder} for more configuration */ - public Builder servletPath(String servletPath) { - Assert.notNull(servletPath, "servletPath cannot be null"); - Assert.isTrue(servletPath.startsWith("/"), "servletPath must start with '/'"); - Assert.isTrue(!servletPath.endsWith("/"), "servletPath must not end with a slash"); - Assert.isTrue(!servletPath.contains("*"), "servletPath must not contain a star"); - return new Builder(this.parser, servletPath); + public Builder basePath(String basePath) { + Assert.notNull(basePath, "basePath cannot be null"); + Assert.isTrue(basePath.startsWith("/"), "basePath must start with '/'"); + Assert.isTrue(!basePath.endsWith("/"), "basePath must not end with a slash"); + Assert.isTrue(!basePath.contains("*"), "basePath must not contain a star"); + return new Builder(this.parser, basePath); } /** @@ -279,7 +286,7 @@ public final class PathPatternRequestMatcher implements RequestMatcher { public PathPatternRequestMatcher matcher(@Nullable HttpMethod method, String path) { Assert.notNull(path, "pattern cannot be null"); Assert.isTrue(path.startsWith("/"), "pattern must start with a /"); - PathPattern pathPattern = this.parser.parse(this.servletPath + path); + PathPattern pathPattern = this.parser.parse(this.basePath + path); PathPatternRequestMatcher requestMatcher = new PathPatternRequestMatcher(pathPattern); if (method != null) { requestMatcher.setMethod(new HttpMethodRequestMatcher(method)); diff --git a/web/src/test/java/org/springframework/security/web/servlet/util/matcher/PathPatternRequestMatcherTests.java b/web/src/test/java/org/springframework/security/web/servlet/util/matcher/PathPatternRequestMatcherTests.java index cc669f45a8..5040ecb50f 100644 --- a/web/src/test/java/org/springframework/security/web/servlet/util/matcher/PathPatternRequestMatcherTests.java +++ b/web/src/test/java/org/springframework/security/web/servlet/util/matcher/PathPatternRequestMatcherTests.java @@ -87,8 +87,7 @@ public class PathPatternRequestMatcherTests { @Test void matcherWhenServletPathThenMatchesOnlyServletPath() { - PathPatternRequestMatcher.Builder servlet = PathPatternRequestMatcher.withDefaults() - .servletPath("/servlet/path"); + PathPatternRequestMatcher.Builder servlet = PathPatternRequestMatcher.withDefaults().basePath("/servlet/path"); RequestMatcher matcher = servlet.matcher(HttpMethod.GET, "/endpoint"); ServletContext servletContext = servletContext("/servlet/path"); MockHttpServletRequest mock = get("/servlet/path/endpoint").servletPath("/servlet/path") @@ -114,8 +113,7 @@ public class PathPatternRequestMatcherTests { @Test void matcherWhenMultiServletPathThenMatches() { - PathPatternRequestMatcher.Builder servlet = PathPatternRequestMatcher.withDefaults() - .servletPath("/servlet/path"); + PathPatternRequestMatcher.Builder servlet = PathPatternRequestMatcher.withDefaults().basePath("/servlet/path"); RequestMatcher matcher = servlet.matcher(HttpMethod.GET, "/endpoint"); MockHttpServletRequest mock = get("/servlet/path/endpoint").servletPath("/servlet/path").buildRequest(null); assertThat(matcher.matches(mock)).isTrue(); @@ -123,8 +121,7 @@ public class PathPatternRequestMatcherTests { @Test void matcherWhenMultiContextPathThenMatches() { - PathPatternRequestMatcher.Builder servlet = PathPatternRequestMatcher.withDefaults() - .servletPath("/servlet/path"); + PathPatternRequestMatcher.Builder servlet = PathPatternRequestMatcher.withDefaults().basePath("/servlet/path"); RequestMatcher matcher = servlet.matcher(HttpMethod.GET, "/endpoint"); assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> matcher.matches( get("/servlet/path/endpoint").servletPath("/servlet/path").contextPath("/app").buildRequest(null))); @@ -133,11 +130,11 @@ public class PathPatternRequestMatcherTests { @Test void servletPathWhenEndsWithSlashOrStarThenIllegalArgument() { assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> PathPatternRequestMatcher.withDefaults().servletPath("/path/**")); + .isThrownBy(() -> PathPatternRequestMatcher.withDefaults().basePath("/path/**")); assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> PathPatternRequestMatcher.withDefaults().servletPath("/path/*")); + .isThrownBy(() -> PathPatternRequestMatcher.withDefaults().basePath("/path/*")); assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> PathPatternRequestMatcher.withDefaults().servletPath("/path/")); + .isThrownBy(() -> PathPatternRequestMatcher.withDefaults().basePath("/path/")); } MockHttpServletRequest request(String uri) {