From f3a161afdde5cfb7a815c83b9f67704e5fc0afb3 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 28 Nov 2024 14:07:27 +0000 Subject: [PATCH] Enable relaxed matching of enabled and access properties The lowercase form of the endpoint ID needs to be used so that relaxed matching of properties, as provided by ConfigurationPropertySources, works as intended. Without this change the id of the endpoint in a property had to be an exact match of the endpoint's ID. Closes gh-43302 --- .../PropertiesEndpointAccessResolver.java | 4 ++-- ...PropertiesEndpointAccessResolverTests.java | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolver.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolver.java index 0f05abef26..681516eb84 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolver.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolver.java @@ -80,10 +80,10 @@ public class PropertiesEndpointAccessResolver implements EndpointAccessResolver @Override public Access accessFor(EndpointId endpointId, Access defaultAccess) { return this.accessCache.computeIfAbsent(endpointId, - (key) -> resolveAccess(endpointId, defaultAccess).cap(this.maxPermittedAccess)); + (key) -> resolveAccess(endpointId.toLowerCaseString(), defaultAccess).cap(this.maxPermittedAccess)); } - private Access resolveAccess(EndpointId endpointId, Access defaultAccess) { + private Access resolveAccess(String endpointId, Access defaultAccess) { String accessKey = "management.endpoint.%s.access".formatted(endpointId); String enabledKey = "management.endpoint.%s.enabled".formatted(endpointId); Access access = this.properties.getProperty(accessKey, Access.class); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolverTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolverTests.java index 9907b4b712..cd15b1e6e2 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolverTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/PropertiesEndpointAccessResolverTests.java @@ -20,6 +20,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.actuate.endpoint.Access; import org.springframework.boot.actuate.endpoint.EndpointId; +import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.context.properties.source.MutuallyExclusiveConfigurationPropertiesException; import org.springframework.mock.env.MockEnvironment; @@ -35,6 +36,10 @@ class PropertiesEndpointAccessResolverTests { private final MockEnvironment environment = new MockEnvironment(); + PropertiesEndpointAccessResolverTests() { + ConfigurationPropertySources.attach(this.environment); + } + @Test void whenNoPropertiesAreConfiguredThenAccessForReturnsEndpointsDefaultAccess() { assertThat(accessResolver().accessFor(EndpointId.of("test"), Access.READ_ONLY)).isEqualTo(Access.READ_ONLY); @@ -52,6 +57,13 @@ class PropertiesEndpointAccessResolverTests { assertThat(accessResolver().accessFor(EndpointId.of("test"), Access.READ_ONLY)).isEqualTo(Access.UNRESTRICTED); } + @Test + void whenAccessForEndpointWithCamelCaseIdIsConfiguredThenAccessForReturnsIt() { + this.environment.withProperty("management.endpoint.alpha-bravo.access", Access.UNRESTRICTED.name()); + assertThat(accessResolver().accessFor(EndpointId.of("alphaBravo"), Access.READ_ONLY)) + .isEqualTo(Access.UNRESTRICTED); + } + @Test void whenAccessForEndpointAndDefaultAccessForAllEndpointsAreConfiguredAccessForReturnsAccessForEndpoint() { this.environment.withProperty("management.endpoint.test.access", Access.NONE.name()) @@ -83,6 +95,13 @@ class PropertiesEndpointAccessResolverTests { assertThat(accessResolver().accessFor(EndpointId.of("test"), Access.READ_ONLY)).isEqualTo(Access.UNRESTRICTED); } + @Test + void whenEndpointWithCamelCaseIdIsEnabledAccessForReturnsUnrestricted() { + this.environment.withProperty("management.endpoint.alpha-bravo.enabled", "true"); + assertThat(accessResolver().accessFor(EndpointId.of("alphaBravo"), Access.READ_ONLY)) + .isEqualTo(Access.UNRESTRICTED); + } + @Test void whenEnabledByDefaultAndDefaultAccessAreBothConfiguredResolverCreationThrows() { this.environment.withProperty("management.endpoints.enabled-by-default", "true")