From 6a0a61f1ce1e9e1114b6674474d48a67a55249ee Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 9 Jan 2023 14:38:54 -0800 Subject: [PATCH 1/3] Refine EndpointRequest matcher `toString` and apply to reactive variant Refine the recently introduced `EndpointRequest` matcher `toString()` to use lower-case item names. Also applied the same logic to the reactive variant. See gh-33690 --- .../security/reactive/EndpointRequest.java | 33 +++++++++----- .../security/servlet/EndpointRequest.java | 43 ++++++++----------- .../reactive/EndpointRequestTests.java | 26 ++++++++++- .../servlet/EndpointRequestTests.java | 22 ++++------ 4 files changed, 74 insertions(+), 50 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequest.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequest.java index 0097d5299a..50dc4a97d8 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequest.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2023 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. @@ -226,6 +226,27 @@ public final class EndpointRequest { return source.stream().filter(Objects::nonNull).map(this::getEndpointId).map(pathMappedEndpoints::getPath); } + @Override + protected Mono matches(ServerWebExchange exchange, Supplier context) { + return this.delegate.matches(exchange); + } + + private List getDelegateMatchers(Set paths) { + return paths.stream().map((path) -> new PathPatternParserServerWebExchangeMatcher(path + "/**")) + .collect(Collectors.toList()); + } + + @Override + public String toString() { + return String.format("EndpointRequestMatcher includes=%s, excludes=%s, includeLinks=%s", + toString(this.includes, "[*]"), toString(this.excludes, "[]"), this.includeLinks); + } + + private String toString(List endpoints, String emptyValue) { + return (!endpoints.isEmpty()) ? endpoints.stream().map(this::getEndpointId).map(Object::toString) + .collect(Collectors.joining(", ", "[", "]")) : emptyValue; + } + private EndpointId getEndpointId(Object source) { if (source instanceof EndpointId) { return (EndpointId) source; @@ -245,16 +266,6 @@ public final class EndpointRequest { return EndpointId.of(annotation.getString("id")); } - private List getDelegateMatchers(Set paths) { - return paths.stream().map((path) -> new PathPatternParserServerWebExchangeMatcher(path + "/**")) - .collect(Collectors.toList()); - } - - @Override - protected Mono matches(ServerWebExchange exchange, Supplier context) { - return this.delegate.matches(exchange); - } - } /** 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 69afad4091..5cf798ea84 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2023 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. @@ -248,6 +248,23 @@ public final class EndpointRequest { return source.stream().filter(Objects::nonNull).map(this::getEndpointId).map(pathMappedEndpoints::getPath); } + private List getDelegateMatchers(RequestMatcherFactory requestMatcherFactory, + RequestMatcherProvider matcherProvider, Set paths) { + return paths.stream().map((path) -> requestMatcherFactory.antPath(matcherProvider, path, "/**")) + .collect(Collectors.toList()); + } + + @Override + public String toString() { + return String.format("EndpointRequestMatcher includes=%s, excludes=%s, includeLinks=%s", + toString(this.includes, "[*]"), toString(this.excludes, "[]"), this.includeLinks); + } + + private String toString(List endpoints, String emptyValue) { + return (!endpoints.isEmpty()) ? endpoints.stream().map(this::getEndpointId).map(Object::toString) + .collect(Collectors.joining(", ", "[", "]")) : emptyValue; + } + private EndpointId getEndpointId(Object source) { if (source instanceof EndpointId) { return (EndpointId) source; @@ -267,30 +284,6 @@ public final class EndpointRequest { return EndpointId.of(annotation.getString("id")); } - private List getDelegateMatchers(RequestMatcherFactory requestMatcherFactory, - RequestMatcherProvider matcherProvider, Set paths) { - return paths.stream().map((path) -> requestMatcherFactory.antPath(matcherProvider, path, "/**")) - .collect(Collectors.toList()); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - if (this.includes.isEmpty()) { - sb.append("EndpointRequest [includes='[").append("*").append("]'"); - } - else { - sb.append("EndpointRequest [includes='") - .append(this.includes.stream().map(this::getEndpointId).collect(Collectors.toList())) - .append("'"); - } - sb.append(", Excludes='") - .append(this.excludes.stream().map(this::getEndpointId).collect(Collectors.toList())).append("'"); - sb.append(", IncludeLinks='").append(this.includeLinks).append("'"); - sb.append("]"); - return sb.toString(); - } - } /** 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 bcc85a8d7c..a3dce33bb2 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2023 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. @@ -188,6 +188,30 @@ class EndpointRequestTests { assertMatcher(matcher, (PathMappedEndpoints) null).doesNotMatch("/actuator/bar"); } + @Test + void toStringWhenIncludedEndpoints() { + ServerWebExchangeMatcher matcher = EndpointRequest.to("foo", "bar"); + assertThat(matcher).hasToString("EndpointRequestMatcher includes=[foo, bar], excludes=[], includeLinks=false"); + } + + @Test + void toStringWhenEmptyIncludedEndpoints() { + ServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint(); + assertThat(matcher).hasToString("EndpointRequestMatcher includes=[*], excludes=[], includeLinks=true"); + } + + @Test + void toStringWhenIncludedEndpointsClasses() { + ServerWebExchangeMatcher matcher = EndpointRequest.to(FooEndpoint.class).excluding("bar"); + assertThat(matcher).hasToString("EndpointRequestMatcher includes=[foo], excludes=[bar], includeLinks=false"); + } + + @Test + void toStringWhenIncludedExcludedEndpoints() { + ServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint().excluding("bar").excludingLinks(); + assertThat(matcher).hasToString("EndpointRequestMatcher includes=[*], excludes=[bar], includeLinks=false"); + } + private RequestMatcherAssert assertMatcher(ServerWebExchangeMatcher matcher) { return assertMatcher(matcher, mockPathMappedEndpoints("/actuator")); } 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 7bb3cf50c3..72cf454efe 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2023 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. @@ -217,31 +217,27 @@ class EndpointRequestTests { } @Test - void toStringIncludedEndpoints() { + void toStringWhenIncludedEndpoints() { RequestMatcher matcher = EndpointRequest.to("foo", "bar"); - assertThat(matcher.toString()) - .isEqualTo("EndpointRequest [includes='[foo, bar]', Excludes='[]', IncludeLinks='false']"); + assertThat(matcher).hasToString("EndpointRequestMatcher includes=[foo, bar], excludes=[], includeLinks=false"); } @Test - void toStringEmptyIncludedEndpoints() { + void toStringWhenEmptyIncludedEndpoints() { RequestMatcher matcher = EndpointRequest.toAnyEndpoint(); - assertThat(matcher.toString()) - .isEqualTo("EndpointRequest [includes='[*]', Excludes='[]', IncludeLinks='true']"); + assertThat(matcher).hasToString("EndpointRequestMatcher includes=[*], excludes=[], includeLinks=true"); } @Test - void toStringIncludedEndpointsClasses() { + void toStringWhenIncludedEndpointsClasses() { RequestMatcher matcher = EndpointRequest.to(FooEndpoint.class).excluding("bar"); - assertThat(matcher.toString()) - .isEqualTo("EndpointRequest [includes='[foo]', Excludes='[bar]', IncludeLinks='false']"); + assertThat(matcher).hasToString("EndpointRequestMatcher includes=[foo], excludes=[bar], includeLinks=false"); } @Test - void toStringIncludedExcludedEndpoints() { + void toStringWhenIncludedExcludedEndpoints() { RequestMatcher matcher = EndpointRequest.toAnyEndpoint().excluding("bar").excludingLinks(); - assertThat(matcher.toString()) - .isEqualTo("EndpointRequest [includes='[*]', Excludes='[bar]', IncludeLinks='false']"); + assertThat(matcher).hasToString("EndpointRequestMatcher includes=[*], excludes=[bar], includeLinks=false"); } private RequestMatcherAssert assertMatcher(RequestMatcher matcher) { From 232807d388df1c64657e74e5a11eb03dacb35798 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 9 Jan 2023 15:16:20 -0800 Subject: [PATCH 2/3] Increase block timeout --- .../neo4j/Neo4jReactiveHealthIndicatorIntegrationTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/Neo4jReactiveHealthIndicatorIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/Neo4jReactiveHealthIndicatorIntegrationTests.java index 44e66cc10c..46911127d1 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/Neo4jReactiveHealthIndicatorIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/neo4j/Neo4jReactiveHealthIndicatorIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 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. @@ -64,7 +64,7 @@ public class Neo4jReactiveHealthIndicatorIntegrationTests { @Test void health() { - Health health = this.healthIndicator.getHealth(true).block(Duration.ofSeconds(5)); + Health health = this.healthIndicator.getHealth(true).block(Duration.ofSeconds(20)); assertThat(health.getStatus()).isEqualTo(Status.UP); assertThat(health.getDetails()).containsEntry("edition", "community"); } From 80cfcb71ec99e465d418fd633c31fd4182f6c35e Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 9 Jan 2023 15:18:10 -0800 Subject: [PATCH 3/3] Update copyright year of changed files --- .../boot/build/artifactory/ArtifactoryRepository.java | 2 +- .../boot/build/cli/AbstractPackageManagerDefinitionTask.java | 2 +- .../spring/concourse/releasescripts/sdkman/SdkmanService.java | 2 +- .../org/springframework/boot/web/server/LocalServerPort.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/buildSrc/src/main/java/org/springframework/boot/build/artifactory/ArtifactoryRepository.java b/buildSrc/src/main/java/org/springframework/boot/build/artifactory/ArtifactoryRepository.java index 1e0a7d675e..2ca1a3c18d 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/artifactory/ArtifactoryRepository.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/artifactory/ArtifactoryRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2023 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. diff --git a/buildSrc/src/main/java/org/springframework/boot/build/cli/AbstractPackageManagerDefinitionTask.java b/buildSrc/src/main/java/org/springframework/boot/build/cli/AbstractPackageManagerDefinitionTask.java index 775e3f2d66..a0d090c2cd 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/cli/AbstractPackageManagerDefinitionTask.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/cli/AbstractPackageManagerDefinitionTask.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2023 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. diff --git a/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/sdkman/SdkmanService.java b/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/sdkman/SdkmanService.java index cb5ccb437f..0a37de5451 100644 --- a/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/sdkman/SdkmanService.java +++ b/ci/images/releasescripts/src/main/java/io/spring/concourse/releasescripts/sdkman/SdkmanService.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 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. diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/LocalServerPort.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/LocalServerPort.java index eda9b71736..c694be7f69 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/LocalServerPort.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/LocalServerPort.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 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.