Commit d1b85584 authored by Madhura Bhave's avatar Madhura Bhave

Make /health and /info insecure by default

Closes gh-13722
parent 42bba4e1
/*
* Copyright 2012-2018 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.security.reactive;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.info.InfoEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration;
import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.WebFilterChainProxy;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Reactive Spring Security when
* actuator is on the classpath. Specifically, it permits access to the health and info
* endpoints while securing everything else.
*
* @author Madhura Bhave
* @since 2.1.0
*/
@Configuration
@ConditionalOnClass({ EnableWebFluxSecurity.class, WebFilterChainProxy.class })
@ConditionalOnMissingBean({ SecurityWebFilterChain.class, WebFilterChainProxy.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@AutoConfigureBefore(ReactiveSecurityAutoConfiguration.class)
@AutoConfigureAfter({ HealthEndpointAutoConfiguration.class,
InfoEndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
ReactiveOAuth2ClientAutoConfiguration.class })
public class ReactiveManagementWebSecurityAutoConfiguration {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http.authorizeExchange()
.matchers(EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class))
.permitAll().anyExchange().authenticated().and().httpBasic().and()
.formLogin().and().build();
}
}
/*
* Copyright 2012-2018 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.security.servlet;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.WebSecurityEnablerConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Security when actuator is
* on the classpath. Specifically, it permits access to the health and info endpoints
* while securing everything else.
*
* @author Madhura Bhave
* @since 2.1.0
*/
@Configuration
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@AutoConfigureBefore(SecurityAutoConfiguration.class)
@AutoConfigureAfter({ HealthEndpointAutoConfiguration.class,
InfoEndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
OAuth2ClientAutoConfiguration.class })
@Import({ ManagementWebSecurityConfigurerAdapter.class,
WebSecurityEnablerConfiguration.class })
public class ManagementWebSecurityAutoConfiguration {
}
/*
* Copyright 2012-2018 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.security.servlet;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.info.InfoEndpoint;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/**
* The default configuration for web security when the actuator dependency is on the
* classpath. It is different from
* {@link org.springframework.boot.autoconfigure.security.servlet.SpringBootWebSecurityConfiguration}
* in that it allows unauthenticated access to the {@link HealthEndpoint} and
* {@link InfoEndpoint}. If the user specifies their own
* {@link WebSecurityConfigurerAdapter}, this will back-off completely and the user should
* specify all the bits that they want to configure as part of the custom security
* configuration.
*
* @author Madhura Bhave
* @since 2.0.1
*/
@Configuration
class ManagementWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.requestMatchers(
EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class))
.permitAll().anyRequest().authenticated().and().formLogin().and()
.httpBasic();
}
}
...@@ -61,6 +61,8 @@ org.springframework.boot.actuate.autoconfigure.mongo.MongoHealthIndicatorAutoCon ...@@ -61,6 +61,8 @@ org.springframework.boot.actuate.autoconfigure.mongo.MongoHealthIndicatorAutoCon
org.springframework.boot.actuate.autoconfigure.neo4j.Neo4jHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.neo4j.Neo4jHealthIndicatorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.redis.RedisHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.redis.RedisHealthIndicatorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.scheduling.ScheduledTasksEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.scheduling.ScheduledTasksEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.session.SessionsEndpointAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.session.SessionsEndpointAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.solr.SolrHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.solr.SolrHealthIndicatorAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthIndicatorAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthIndicatorAutoConfiguration,\
......
/*
* Copyright 2012-2018 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.security.reactive;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.beans.BeansException;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.MockServerHttpResponse;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.WebFilterChainProxy;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebHandler;
import org.springframework.web.server.adapter.HttpWebHandlerAdapter;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link ReactiveManagementWebSecurityAutoConfiguration}.
*
* @author Madhura Bhave
*/
public class ReactiveManagementWebSecurityAutoConfigurationTests {
private ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
HealthIndicatorAutoConfiguration.class,
HealthEndpointAutoConfiguration.class,
InfoEndpointAutoConfiguration.class,
EnvironmentEndpointAutoConfiguration.class,
EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
ReactiveSecurityAutoConfiguration.class,
ReactiveUserDetailsServiceAutoConfiguration.class,
ReactiveManagementWebSecurityAutoConfiguration.class));
@Test
public void permitAllForHealth() {
this.contextRunner.run((
context) -> assertThat(getAuthenticateHeader(context, "/actuator/health"))
.isNull());
}
@Test
public void permitAllForInfo() {
this.contextRunner.run(
(context) -> assertThat(getAuthenticateHeader(context, "/actuator/info"))
.isNull());
}
@Test
public void securesEverythingElse() {
this.contextRunner.run((context) -> {
assertThat(getAuthenticateHeader(context, "/actuator").get(0))
.contains("Basic realm=");
assertThat(getAuthenticateHeader(context, "/foo").toString())
.contains("Basic realm=");
});
}
@Test
public void usesMatchersBasedOffConfiguredActuatorBasePath() {
this.contextRunner.withPropertyValues("management.endpoints.web.base-path=/")
.run((context) -> {
assertThat(getAuthenticateHeader(context, "/health")).isNull();
assertThat(getAuthenticateHeader(context, "/foo").get(0))
.contains("Basic realm=");
});
}
@Test
public void backsOffIfCustomSecurityIsAdded() {
this.contextRunner.withUserConfiguration(CustomSecurityConfiguration.class)
.run((context) -> {
assertThat(getLocationHeader(context, "/actuator/health").toString())
.contains("/login");
assertThat(getLocationHeader(context, "/foo")).isNull();
});
}
@Test
public void backsOffWhenWebFilterChainProxyBeanPresent() {
this.contextRunner
.withConfiguration(
AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class))
.withUserConfiguration(WebFilterChainProxyConfiguration.class)
.run((context) -> {
assertThat(getLocationHeader(context, "/health").toString())
.contains("/login");
assertThat(getLocationHeader(context, "/foo").toString())
.contains("/login");
});
}
private List<String> getAuthenticateHeader(
AssertableReactiveWebApplicationContext context, String path) {
ServerWebExchange exchange = performFilter(context, path);
return exchange.getResponse().getHeaders().get(HttpHeaders.WWW_AUTHENTICATE);
}
private ServerWebExchange performFilter(
AssertableReactiveWebApplicationContext context, String path) {
ServerWebExchange exchange = webHandler(context).createExchange(
MockServerHttpRequest.get(path).build(), new MockServerHttpResponse());
WebFilterChainProxy proxy = context.getBean(WebFilterChainProxy.class);
proxy.filter(exchange, (serverWebExchange) -> Mono.empty()).block();
return exchange;
}
private URI getLocationHeader(AssertableReactiveWebApplicationContext context,
String path) {
ServerWebExchange exchange = performFilter(context, path);
return exchange.getResponse().getHeaders().getLocation();
}
private TestHttpWebHandlerAdapter webHandler(
AssertableReactiveWebApplicationContext context) {
TestHttpWebHandlerAdapter adapter = new TestHttpWebHandlerAdapter(
mock(WebHandler.class));
adapter.setApplicationContext(context);
return adapter;
}
private static class TestHttpWebHandlerAdapter extends HttpWebHandlerAdapter {
TestHttpWebHandlerAdapter(WebHandler delegate) {
super(delegate);
}
@Override
protected ServerWebExchange createExchange(ServerHttpRequest request,
ServerHttpResponse response) {
return super.createExchange(request, response);
}
}
@Configuration
static class CustomSecurityConfiguration {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http.authorizeExchange().pathMatchers("/foo").permitAll().anyExchange()
.authenticated().and().formLogin().and().build();
}
}
@Configuration
static class WebFilterChainProxyConfiguration {
@Bean
public ReactiveAuthenticationManager authenticationManager() {
return mock(ReactiveAuthenticationManager.class);
}
@Bean
public WebFilterChainProxy webFilterChainProxy(ServerHttpSecurity http) {
return new WebFilterChainProxy(getFilterChains(http));
}
@Bean
public TestServerHttpSecurity http(
ReactiveAuthenticationManager authenticationManager) {
TestServerHttpSecurity httpSecurity = new TestServerHttpSecurity();
httpSecurity.authenticationManager(authenticationManager);
return httpSecurity;
}
private List<SecurityWebFilterChain> getFilterChains(ServerHttpSecurity http) {
return Collections.singletonList(http.authorizeExchange().anyExchange()
.authenticated().and().formLogin().and().build());
}
private static class TestServerHttpSecurity extends ServerHttpSecurity
implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
super.setApplicationContext(applicationContext);
}
}
}
}
/*
* Copyright 2012-2018 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.security.servlet;
import java.io.IOException;
import org.junit.Test;
import org.testcontainers.shaded.org.apache.http.HttpStatus;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.web.context.WebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ManagementWebSecurityAutoConfiguration}.
*
* @author Madhura Bhave
*/
public class ManagementWebSecurityAutoConfigurationTests {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
HealthIndicatorAutoConfiguration.class,
HealthEndpointAutoConfiguration.class,
InfoEndpointAutoConfiguration.class,
EnvironmentEndpointAutoConfiguration.class,
EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
SecurityAutoConfiguration.class,
ManagementWebSecurityAutoConfiguration.class));
@Test
public void permitAllForHealth() {
this.contextRunner.run((context) -> {
int status = getResponseStatus(context, "/actuator/health");
assertThat(status).isEqualTo(HttpStatus.SC_OK);
});
}
@Test
public void permitAllForInfo() {
this.contextRunner.run((context) -> {
int status = getResponseStatus(context, "/actuator/info");
assertThat(status).isEqualTo(HttpStatus.SC_OK);
});
}
@Test
public void securesEverythingElse() {
this.contextRunner.run((context) -> {
int status = getResponseStatus(context, "/actuator");
assertThat(status).isEqualTo(HttpStatus.SC_UNAUTHORIZED);
status = getResponseStatus(context, "/foo");
assertThat(status).isEqualTo(HttpStatus.SC_UNAUTHORIZED);
});
}
@Test
public void usesMatchersBasedOffConfiguredActuatorBasePath() {
this.contextRunner.withPropertyValues("management.endpoints.web.base-path=/")
.run((context) -> {
int status = getResponseStatus(context, "/health");
assertThat(status).isEqualTo(HttpStatus.SC_OK);
});
}
@Test
public void backOffIfCustomSecurityIsAdded() {
this.contextRunner.withUserConfiguration(CustomSecurityConfiguration.class)
.run((context) -> {
int status = getResponseStatus(context, "/actuator/health");
assertThat(status).isEqualTo(HttpStatus.SC_UNAUTHORIZED);
status = getResponseStatus(context, "/foo");
assertThat(status).isEqualTo(HttpStatus.SC_OK);
});
}
private int getResponseStatus(AssertableWebApplicationContext context, String path)
throws IOException, javax.servlet.ServletException {
FilterChainProxy filterChainProxy = context.getBean(FilterChainProxy.class);
MockServletContext servletContext = new MockServletContext();
MockHttpServletResponse response = new MockHttpServletResponse();
servletContext.setAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
MockHttpServletRequest request = new MockHttpServletRequest(servletContext);
request.setServletPath(path);
request.setMethod("GET");
filterChainProxy.doFilter(request, response, new MockFilterChain());
return response.getStatus();
}
@Configuration
static class CustomSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/foo").permitAll().anyRequest()
.authenticated().and().formLogin().and().httpBasic();
}
}
}
...@@ -119,20 +119,18 @@ public class SampleActuatorApplicationTests { ...@@ -119,20 +119,18 @@ public class SampleActuatorApplicationTests {
} }
@Test @Test
public void testHealth() { public void healthInsecureByDefault() {
ResponseEntity<String> entity = this.restTemplate ResponseEntity<String> entity = this.restTemplate.getForEntity("/actuator/health",
.withBasicAuth("user", getPassword()) String.class);
.getForEntity("/actuator/health", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).contains("\"status\":\"UP\""); assertThat(entity.getBody()).contains("\"status\":\"UP\"");
assertThat(entity.getBody()).doesNotContain("\"hello\":\"1\""); assertThat(entity.getBody()).doesNotContain("\"hello\":\"1\"");
} }
@Test @Test
public void testInfo() { public void infoInsecureByDefault() {
ResponseEntity<String> entity = this.restTemplate ResponseEntity<String> entity = this.restTemplate.getForEntity("/actuator/info",
.withBasicAuth("user", getPassword()) String.class);
.getForEntity("/actuator/info", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()) assertThat(entity.getBody())
.contains("\"artifact\":\"spring-boot-sample-actuator\""); .contains("\"artifact\":\"spring-boot-sample-actuator\"");
......
...@@ -47,8 +47,20 @@ public class SampleSecureWebFluxApplicationTests { ...@@ -47,8 +47,20 @@ public class SampleSecureWebFluxApplicationTests {
} }
@Test @Test
public void actuatorsSecureByDefault() { public void healthInsecureByDefault() {
this.webClient.get().uri("/actuator/health").accept(MediaType.APPLICATION_JSON) this.webClient.get().uri("/actuator/health").accept(MediaType.APPLICATION_JSON)
.exchange().expectStatus().isOk();
}
@Test
public void infoInsecureByDefault() {
this.webClient.get().uri("/actuator/info").accept(MediaType.APPLICATION_JSON)
.exchange().expectStatus().isOk();
}
@Test
public void otherActuatorsSecureByDefault() {
this.webClient.get().uri("/actuator/env").accept(MediaType.APPLICATION_JSON)
.exchange().expectStatus().isUnauthorized(); .exchange().expectStatus().isUnauthorized();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment