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 ddd8106175..3bd7678862 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 @@ -125,13 +125,13 @@ public final class EndpointRequest { this.excludes = excludes; } - EndpointServerWebExchangeMatcher excluding(Class... endpoints) { + public EndpointServerWebExchangeMatcher excluding(Class... endpoints) { List excludes = new ArrayList<>(this.excludes); excludes.addAll(Arrays.asList((Object[]) endpoints)); return new EndpointServerWebExchangeMatcher(this.includes, excludes); } - EndpointServerWebExchangeMatcher excluding(String... endpoints) { + public EndpointServerWebExchangeMatcher excluding(String... endpoints) { List excludes = new ArrayList<>(this.excludes); excludes.addAll(Arrays.asList((Object[]) endpoints)); return new EndpointServerWebExchangeMatcher(this.includes, excludes); 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 0a0f8a71de..9c87b916f0 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 @@ -120,13 +120,13 @@ public final class EndpointRequest { this.excludes = excludes; } - EndpointRequestMatcher excluding(Class... endpoints) { + public EndpointRequestMatcher excluding(Class... endpoints) { List excludes = new ArrayList<>(this.excludes); excludes.addAll(Arrays.asList((Object[]) endpoints)); return new EndpointRequestMatcher(this.includes, excludes); } - EndpointRequestMatcher excluding(String... endpoints) { + public EndpointRequestMatcher excluding(String... endpoints) { List excludes = new ArrayList<>(this.excludes); excludes.addAll(Arrays.asList((Object[]) endpoints)); return new EndpointRequestMatcher(this.includes, excludes); diff --git a/spring-boot-samples/spring-boot-sample-actuator-custom-security/src/main/java/sample/actuator/customsecurity/SecurityConfiguration.java b/spring-boot-samples/spring-boot-sample-actuator-custom-security/src/main/java/sample/actuator/customsecurity/SecurityConfiguration.java index 86fdb250e1..69ffd45d33 100644 --- a/spring-boot-samples/spring-boot-sample-actuator-custom-security/src/main/java/sample/actuator/customsecurity/SecurityConfiguration.java +++ b/spring-boot-samples/spring-boot-sample-actuator-custom-security/src/main/java/sample/actuator/customsecurity/SecurityConfiguration.java @@ -17,6 +17,7 @@ package sample.actuator.customsecurity; import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; +import org.springframework.boot.actuate.web.mappings.MappingsEndpoint; import org.springframework.boot.autoconfigure.security.servlet.PathRequest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -43,7 +44,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { // @formatter:off http.authorizeRequests() .requestMatchers(EndpointRequest.to("health", "info")).permitAll() - .requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ACTUATOR") + .requestMatchers(EndpointRequest.toAnyEndpoint().excluding(MappingsEndpoint.class)).hasRole("ACTUATOR") .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() .antMatchers("/foo").permitAll() .antMatchers("/**").hasRole("USER") diff --git a/spring-boot-samples/spring-boot-sample-actuator-custom-security/src/test/java/sample/actuator/customsecurity/SampleActuatorCustomSecurityApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator-custom-security/src/test/java/sample/actuator/customsecurity/SampleActuatorCustomSecurityApplicationTests.java index 03fe0cdf34..b6e2e94b34 100644 --- a/spring-boot-samples/spring-boot-sample-actuator-custom-security/src/test/java/sample/actuator/customsecurity/SampleActuatorCustomSecurityApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator-custom-security/src/test/java/sample/actuator/customsecurity/SampleActuatorCustomSecurityApplicationTests.java @@ -125,6 +125,13 @@ public class SampleActuatorCustomSecurityApplicationTests { assertThat(entity.getHeaders().getFirst("echo")).isEqualTo("test"); } + @Test + public void actuatorExcludedFromEndpointRequestMatcher() { + ResponseEntity entity = userRestTemplate().getForEntity("/actuator/mappings", + Object.class); + assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); + } + private TestRestTemplate restTemplate() { return configure(new TestRestTemplate()); } diff --git a/spring-boot-samples/spring-boot-sample-secure-webflux/src/test/java/sample/secure/webflux/SampleSecureWebFluxCustomSecurityTests.java b/spring-boot-samples/spring-boot-sample-secure-webflux/src/test/java/sample/secure/webflux/SampleSecureWebFluxCustomSecurityTests.java index 2df08c38b7..23d5b7aee6 100644 --- a/spring-boot-samples/spring-boot-sample-secure-webflux/src/test/java/sample/secure/webflux/SampleSecureWebFluxCustomSecurityTests.java +++ b/spring-boot-samples/spring-boot-sample-secure-webflux/src/test/java/sample/secure/webflux/SampleSecureWebFluxCustomSecurityTests.java @@ -23,6 +23,7 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.autoconfigure.security.reactive.EndpointRequest; +import org.springframework.boot.actuate.web.mappings.MappingsEndpoint; import org.springframework.boot.autoconfigure.security.reactive.PathRequest; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; @@ -78,6 +79,13 @@ public class SampleSecureWebFluxCustomSecurityTests { .expectStatus().isOk(); } + @Test + public void actuatorExcludedFromEndpointRequestMatcher() { + this.webClient.get().uri("/actuator/mappings").accept(MediaType.APPLICATION_JSON) + .header("Authorization", "basic " + getBasicAuth()).exchange() + .expectStatus().isOk(); + } + @Test public void staticResourceShouldBeAccessible() { this.webClient.get().uri("/css/bootstrap.min.css") @@ -100,7 +108,7 @@ public class SampleSecureWebFluxCustomSecurityTests { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http.authorizeExchange().matchers(EndpointRequest.to("health", "info")) - .permitAll().matchers(EndpointRequest.toAnyEndpoint()) + .permitAll().matchers(EndpointRequest.toAnyEndpoint().excluding(MappingsEndpoint.class)) .hasRole("ACTUATOR") .matchers(PathRequest.toStaticResources().atCommonLocations()) .permitAll().pathMatchers("/login").permitAll().anyExchange()