diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java index 9528a9404c..d5eceea98d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java @@ -157,6 +157,14 @@ public final class EndpointRequest { protected abstract RequestMatcher createDelegate(WebApplicationContext context, RequestMatcherFactory requestMatcherFactory); + protected List getLinksMatchers( + RequestMatcherFactory requestMatcherFactory, String basePath) { + List linksMatchers = new ArrayList<>(); + linksMatchers.add(requestMatcherFactory.antPath(basePath)); + linksMatchers.add(requestMatcherFactory.antPath(basePath, "/")); + return linksMatchers; + } + } /** @@ -220,10 +228,10 @@ public final class EndpointRequest { streamPaths(this.excludes, pathMappedEndpoints).forEach(paths::remove); List delegateMatchers = getDelegateMatchers( requestMatcherFactory, paths); - if (this.includeLinks - && StringUtils.hasText(pathMappedEndpoints.getBasePath())) { - delegateMatchers.add( - requestMatcherFactory.antPath(pathMappedEndpoints.getBasePath())); + String basePath = pathMappedEndpoints.getBasePath(); + if (this.includeLinks && StringUtils.hasText(basePath)) { + delegateMatchers + .addAll(getLinksMatchers(requestMatcherFactory, basePath)); } return new OrRequestMatcher(delegateMatchers); } @@ -271,8 +279,10 @@ public final class EndpointRequest { RequestMatcherFactory requestMatcherFactory) { WebEndpointProperties properties = context .getBean(WebEndpointProperties.class); - if (StringUtils.hasText(properties.getBasePath())) { - return requestMatcherFactory.antPath(properties.getBasePath()); + String basePath = properties.getBasePath(); + if (StringUtils.hasText(basePath)) { + return new OrRequestMatcher( + getLinksMatchers(requestMatcherFactory, basePath)); } return EMPTY_MATCHER; } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequestTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequestTests.java index 509298333b..e8178c3f14 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequestTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequestTests.java @@ -59,6 +59,14 @@ public class EndpointRequestTests { assertMatcher(matcher).matches("/actuator"); } + @Test + public void toAnyEndpointShouldMatchEndpointPathWithTrailingSlash() { + ServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint(); + assertMatcher(matcher).matches("/actuator/foo/"); + assertMatcher(matcher).matches("/actuator/bar/"); + assertMatcher(matcher).matches("/actuator/"); + } + @Test public void toAnyEndpointWhenBasePathIsEmptyShouldNotMatchLinks() { ServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint(); @@ -104,6 +112,7 @@ public class EndpointRequestTests { assertMatcher(matcher).doesNotMatch("/actuator/foo"); assertMatcher(matcher).doesNotMatch("/actuator/bar"); assertMatcher(matcher).matches("/actuator"); + assertMatcher(matcher).matches("/actuator/"); } @Test diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java index d2682e30ea..20cdb11c0a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequestTests.java @@ -54,10 +54,20 @@ public class EndpointRequestTests { public void toAnyEndpointShouldMatchEndpointPath() { RequestMatcher matcher = EndpointRequest.toAnyEndpoint(); assertMatcher(matcher, "/actuator", "/").matches("/actuator/foo"); + assertMatcher(matcher, "/actuator", "/").matches("/actuator/foo/zoo/"); assertMatcher(matcher, "/actuator", "/").matches("/actuator/bar"); + assertMatcher(matcher, "/actuator", "/").matches("/actuator/bar/baz"); assertMatcher(matcher, "/actuator", "/").matches("/actuator"); } + @Test + public void toAnyEndpointShouldMatchEndpointPathWithTrailingSlash() { + RequestMatcher matcher = EndpointRequest.toAnyEndpoint(); + assertMatcher(matcher, "/actuator", "/").matches("/actuator/foo/"); + assertMatcher(matcher, "/actuator", "/").matches("/actuator/bar/"); + assertMatcher(matcher, "/actuator", "/").matches("/actuator/"); + } + @Test public void toAnyEndpointWhenBasePathIsEmptyShouldNotMatchLinks() { RequestMatcher matcher = EndpointRequest.toAnyEndpoint(); @@ -127,6 +137,7 @@ public class EndpointRequestTests { assertMatcher(matcher).doesNotMatch("/actuator/foo"); assertMatcher(matcher).doesNotMatch("/actuator/bar"); assertMatcher(matcher).matches("/actuator"); + assertMatcher(matcher).matches("/actuator/"); } @Test