Skip to content

Commit 33dcd85

Browse files
committed
Ensure that health endpoint remains insecure without Spring Security
The changes made in 6a2ac08 mean that getSecurity() on ManagementServerProperties will no longer return null when Spring Security is on the classpath. This had the unwanted side-effect of causing the health endpoint to hide its details when Spring Security was not on the classpath. This commit reinstates the previous behaviour by only considering the health endpoint to be secure if Spring Security is on the classpath and management.security.enabled is true. Closes gh-7345
1 parent 808185a commit 33dcd85

File tree

2 files changed

+109
-4
lines changed

2 files changed

+109
-4
lines changed

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcManagementContextConfiguration.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import java.util.Set;
2121

2222
import org.springframework.beans.factory.annotation.Autowired;
23-
import org.springframework.boot.actuate.autoconfigure.ManagementServerProperties.Security;
2423
import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint;
2524
import org.springframework.boot.actuate.endpoint.Endpoint;
2625
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
@@ -49,6 +48,7 @@
4948
import org.springframework.context.annotation.Conditional;
5049
import org.springframework.core.env.Environment;
5150
import org.springframework.core.type.AnnotatedTypeMetadata;
51+
import org.springframework.util.ClassUtils;
5252
import org.springframework.util.CollectionUtils;
5353
import org.springframework.util.StringUtils;
5454
import org.springframework.web.cors.CorsConfiguration;
@@ -145,9 +145,8 @@ public HeapdumpMvcEndpoint heapdumpMvcEndpoint() {
145145
@ConditionalOnBean(HealthEndpoint.class)
146146
@ConditionalOnEnabledEndpoint("health")
147147
public HealthMvcEndpoint healthMvcEndpoint(HealthEndpoint delegate) {
148-
Security security = this.managementServerProperties.getSecurity();
149-
boolean secure = (security != null && security.isEnabled());
150-
HealthMvcEndpoint healthMvcEndpoint = new HealthMvcEndpoint(delegate, secure);
148+
HealthMvcEndpoint healthMvcEndpoint = new HealthMvcEndpoint(delegate,
149+
isHealthSecure());
151150
if (this.healthMvcEndpointProperties.getMapping() != null) {
152151
healthMvcEndpoint
153152
.addStatusMapping(this.healthMvcEndpointProperties.getMapping());
@@ -176,6 +175,17 @@ public ShutdownMvcEndpoint shutdownMvcEndpoint(ShutdownEndpoint delegate) {
176175
return new ShutdownMvcEndpoint(delegate);
177176
}
178177

178+
private boolean isHealthSecure() {
179+
return isSpringSecurityAvailable()
180+
&& this.managementServerProperties.getSecurity().isEnabled();
181+
}
182+
183+
private boolean isSpringSecurityAvailable() {
184+
return ClassUtils.isPresent(
185+
"org.springframework.security.config.annotation.web.WebSecurityConfigurer",
186+
getClass().getClassLoader());
187+
}
188+
179189
private static class LogFileCondition extends SpringBootCondition {
180190

181191
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright 2012-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.endpoint.mvc;
18+
19+
import org.junit.After;
20+
import org.junit.Test;
21+
import org.junit.runner.RunWith;
22+
23+
import org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration;
24+
import org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration;
25+
import org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration;
26+
import org.springframework.boot.actuate.health.Health;
27+
import org.springframework.boot.actuate.health.HealthIndicator;
28+
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
29+
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
30+
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
31+
import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
32+
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
33+
import org.springframework.boot.testutil.ClassPathExclusions;
34+
import org.springframework.boot.testutil.FilteredClassPathRunner;
35+
import org.springframework.context.annotation.Bean;
36+
import org.springframework.context.annotation.Configuration;
37+
import org.springframework.mock.web.MockServletContext;
38+
import org.springframework.test.web.servlet.MockMvc;
39+
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
40+
41+
import static org.hamcrest.CoreMatchers.containsString;
42+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
43+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
44+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
45+
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
46+
47+
/**
48+
* Integration tests for the health endpoint when Spring Security is not available.
49+
*
50+
* @author Andy Wilkinson
51+
*/
52+
@RunWith(FilteredClassPathRunner.class)
53+
@ClassPathExclusions("spring-security-*.jar")
54+
public class NoSpringSecurityHealthMvcEndpointIntegrationTests {
55+
56+
private AnnotationConfigWebApplicationContext context;
57+
58+
@After
59+
public void closeContext() {
60+
this.context.close();
61+
}
62+
63+
@Test
64+
public void healthDetailIsPresent() throws Exception {
65+
this.context = new AnnotationConfigWebApplicationContext();
66+
this.context.setServletContext(new MockServletContext());
67+
this.context.register(TestConfiguration.class);
68+
this.context.refresh();
69+
MockMvc mockMvc = webAppContextSetup(this.context).build();
70+
mockMvc.perform(get("/health")).andExpect(status().isOk())
71+
.andExpect(content().string(containsString("\"hello\":\"world\"")));
72+
}
73+
74+
@ImportAutoConfiguration({ JacksonAutoConfiguration.class,
75+
HttpMessageConvertersAutoConfiguration.class, EndpointAutoConfiguration.class,
76+
EndpointWebMvcAutoConfiguration.class,
77+
ManagementServerPropertiesAutoConfiguration.class,
78+
PropertyPlaceholderAutoConfiguration.class, WebMvcAutoConfiguration.class })
79+
@Configuration
80+
static class TestConfiguration {
81+
82+
@Bean
83+
public HealthIndicator testHealthIndicator() {
84+
return new HealthIndicator() {
85+
86+
@Override
87+
public Health health() {
88+
return Health.up().withDetail("hello", "world").build();
89+
}
90+
};
91+
}
92+
93+
}
94+
95+
}

0 commit comments

Comments
 (0)