Remove concept of sensitivity from Actuator's endpoints

Closes gh-9924
This commit is contained in:
Andy Wilkinson
2017-08-01 10:05:09 +01:00
parent 847f6d1b2c
commit bb55f49396
55 changed files with 173 additions and 606 deletions

View File

@@ -26,7 +26,6 @@ import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.NamedMvcEndpoint;
@@ -62,7 +61,6 @@ import org.springframework.security.config.annotation.web.builders.WebSecurity.I
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
@@ -77,11 +75,7 @@ import org.springframework.util.StringUtils;
* {@link EnableAutoConfiguration Auto-configuration} for security of framework endpoints.
* Many aspects of the behavior can be controller with {@link ManagementServerProperties}
* via externalized application properties (or via an bean definition of that type to set
* the defaults).
* <p>
* The framework {@link Endpoint}s (used to expose application information to operations)
* include a {@link Endpoint#isSensitive() sensitive} configuration option which will be
* used as a security hint by the filter created here.
* the defaults)..
*
* @author Dave Syer
* @author Andy Wilkinson
@@ -126,7 +120,6 @@ public class ManagementWebSecurityAutoConfiguration {
.getRequestMatcher(this.contextResolver);
configurer.requestMatchers(requestMatcher);
}
}
}
@@ -223,8 +216,6 @@ public class ManagementWebSecurityAutoConfiguration {
http.exceptionHandling().authenticationEntryPoint(entryPoint);
// Match all the requests for actuator endpoints ...
http.requestMatcher(matcher);
// ... but permitAll() for the non-sensitive ones
configurePermittedRequests(http.authorizeRequests());
http.httpBasic().authenticationEntryPoint(entryPoint).and().cors();
// No cookies for management endpoints by default
http.csrf().disable();
@@ -258,38 +249,9 @@ public class ManagementWebSecurityAutoConfiguration {
return entryPoint;
}
private void configurePermittedRequests(
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry requests) {
requests.requestMatchers(new LazyEndpointPathRequestMatcher(
this.contextResolver, EndpointPaths.SENSITIVE)).authenticated();
// Permit access to the non-sensitive endpoints
requests.requestMatchers(new LazyEndpointPathRequestMatcher(
this.contextResolver, EndpointPaths.NON_SENSITIVE)).permitAll();
}
}
private enum EndpointPaths {
ALL,
NON_SENSITIVE {
@Override
protected boolean isIncluded(MvcEndpoint endpoint) {
return !endpoint.isSensitive();
}
},
SENSITIVE {
@Override
protected boolean isIncluded(MvcEndpoint endpoint) {
return endpoint.isSensitive();
}
};
private static class EndpointPaths {
public String[] getPaths(EndpointHandlerMapping endpointHandlerMapping) {
if (endpointHandlerMapping == null) {
@@ -298,24 +260,18 @@ public class ManagementWebSecurityAutoConfiguration {
Set<? extends MvcEndpoint> endpoints = endpointHandlerMapping.getEndpoints();
Set<String> paths = new LinkedHashSet<>(endpoints.size());
for (MvcEndpoint endpoint : endpoints) {
if (isIncluded(endpoint)) {
String path = endpointHandlerMapping.getPath(endpoint.getPath());
paths.add(path);
if (!path.equals("")) {
paths.add(path + "/**");
// Add Spring MVC-generated additional paths
paths.add(path + ".*");
}
paths.add(path + "/");
String path = endpointHandlerMapping.getPath(endpoint.getPath());
paths.add(path);
if (!path.equals("")) {
paths.add(path + "/**");
// Add Spring MVC-generated additional paths
paths.add(path + ".*");
}
paths.add(path + "/");
}
return paths.toArray(new String[paths.size()]);
}
protected boolean isIncluded(MvcEndpoint endpoint) {
return true;
}
}
private static class LazyEndpointPathRequestMatcher implements RequestMatcher {
@@ -342,7 +298,8 @@ public class ManagementWebSecurityAutoConfiguration {
return matcher;
}
// Match everything, including the sensitive and non-sensitive paths
return new LazyEndpointPathRequestMatcher(contextResolver, EndpointPaths.ALL);
return new LazyEndpointPathRequestMatcher(contextResolver,
new EndpointPaths());
}
LazyEndpointPathRequestMatcher(ManagementContextResolver contextResolver,

View File

@@ -41,7 +41,7 @@ class CloudFoundryDiscoveryMvcEndpoint extends AbstractMvcEndpoint {
private final Set<NamedMvcEndpoint> endpoints;
CloudFoundryDiscoveryMvcEndpoint(Set<NamedMvcEndpoint> endpoints) {
super("", false);
super("");
this.endpoints = endpoints;
}

View File

@@ -41,47 +41,27 @@ public abstract class AbstractEndpoint<T> implements Endpoint<T>, EnvironmentAwa
*/
private String id;
private final boolean sensitiveDefault;
/**
* Mark if the endpoint exposes sensitive information.
*/
private Boolean sensitive;
/**
* Enable the endpoint.
*/
private Boolean enabled;
/**
* Create a new sensitive endpoint instance. The endpoint will enabled flag will be
* based on the spring {@link Environment} unless explicitly set.
* @param id the endpoint ID
*/
public AbstractEndpoint(String id) {
this(id, true);
}
/**
* Create a new endpoint instance. The endpoint will enabled flag will be based on the
* spring {@link Environment} unless explicitly set.
* @param id the endpoint ID
* @param sensitive if the endpoint is sensitive by default
*/
public AbstractEndpoint(String id, boolean sensitive) {
public AbstractEndpoint(String id) {
setId(id);
this.sensitiveDefault = sensitive;
}
/**
* Create a new endpoint instance.
* @param id the endpoint ID
* @param sensitive if the endpoint is sensitive
* @param enabled if the endpoint is enabled or not.
*/
public AbstractEndpoint(String id, boolean sensitive, boolean enabled) {
public AbstractEndpoint(String id, boolean enabled) {
setId(id);
this.sensitiveDefault = sensitive;
this.enabled = enabled;
}
@@ -115,14 +95,4 @@ public abstract class AbstractEndpoint<T> implements Endpoint<T>, EnvironmentAwa
this.enabled = enabled;
}
@Override
public boolean isSensitive() {
return EndpointProperties.isSensitive(this.environment, this.sensitive,
this.sensitiveDefault);
}
public void setSensitive(Boolean sensitive) {
this.sensitive = sensitive;
}
}

View File

@@ -42,13 +42,6 @@ public interface Endpoint<T> {
*/
boolean isEnabled();
/**
* Return if the endpoint is sensitive, i.e. may return data that the average user
* should not see. Mappings can use this as a security hint.
* @return if the endpoint is sensitive
*/
boolean isSensitive();
/**
* Called to invoke the endpoint.
* @return the results of the invocation

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2017 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.
@@ -30,18 +30,11 @@ public class EndpointProperties {
private static final String ENDPOINTS_ENABLED_PROPERTY = "endpoints.enabled";
private static final String ENDPOINTS_SENSITIVE_PROPERTY = "endpoints.sensitive";
/**
* Enable endpoints.
*/
private Boolean enabled = true;
/**
* Default endpoint sensitive setting.
*/
private Boolean sensitive;
public Boolean getEnabled() {
return this.enabled;
}
@@ -50,14 +43,6 @@ public class EndpointProperties {
this.enabled = enabled;
}
public Boolean getSensitive() {
return this.sensitive;
}
public void setSensitive(Boolean sensitive) {
this.sensitive = sensitive;
}
/**
* Determine if an endpoint is enabled based on its specific property and taking into
* account the global default.
@@ -76,25 +61,4 @@ public class EndpointProperties {
return true;
}
/**
* Determine if an endpoint is sensitive based on its specific property and taking
* into account the global default.
* @param environment the Spring environment or {@code null}.
* @param sensitive the endpoint property or {@code null}
* @param sensitiveDefault the default setting to use if no environment property is
* defined
* @return if the endpoint is sensitive
*/
public static boolean isSensitive(Environment environment, Boolean sensitive,
boolean sensitiveDefault) {
if (sensitive != null) {
return sensitive;
}
if (environment != null
&& environment.containsProperty(ENDPOINTS_SENSITIVE_PROPERTY)) {
return environment.getProperty(ENDPOINTS_SENSITIVE_PROPERTY, Boolean.class);
}
return sensitiveDefault;
}
}

View File

@@ -49,7 +49,7 @@ public class HealthEndpoint extends AbstractEndpoint<Health> {
*/
public HealthEndpoint(HealthAggregator healthAggregator,
Map<String, HealthIndicator> healthIndicators) {
super("health", false);
super("health");
Assert.notNull(healthAggregator, "HealthAggregator must not be null");
Assert.notNull(healthIndicators, "HealthIndicators must not be null");
CompositeHealthIndicator healthIndicator = new CompositeHealthIndicator(

View File

@@ -41,7 +41,7 @@ public class InfoEndpoint extends AbstractEndpoint<Map<String, Object>> {
* @param infoContributors the info contributors to use
*/
public InfoEndpoint(List<InfoContributor> infoContributors) {
super("info", false);
super("info");
Assert.notNull(infoContributors, "Info contributors must not be null");
this.infoContributors = infoContributors;
}

View File

@@ -50,7 +50,7 @@ public class ShutdownEndpoint extends AbstractEndpoint<Map<String, Object>>
* Create a new {@link ShutdownEndpoint} instance.
*/
public ShutdownEndpoint() {
super("shutdown", true, false);
super("shutdown", false);
}
@Override

View File

@@ -64,11 +64,6 @@ public abstract class EndpointMBean implements JmxEndpoint {
return this.endpoint.isEnabled();
}
@ManagedAttribute(description = "Indicates whether the underlying endpoint exposes sensitive information")
public boolean isSensitive() {
return this.endpoint.isSensitive();
}
@Override
public String getIdentity() {
return ObjectUtils.getIdentityHexString(getEndpoint());

View File

@@ -80,11 +80,6 @@ public abstract class AbstractEndpointMvcAdapter<E extends Endpoint<?>>
this.path = path;
}
@Override
public boolean isSensitive() {
return this.delegate.isSensitive();
}
@Override
@SuppressWarnings("rawtypes")
public Class<? extends Endpoint> getEndpointType() {

View File

@@ -46,22 +46,8 @@ public abstract class AbstractMvcEndpoint
*/
private Boolean enabled;
/**
* Mark if the endpoint exposes sensitive information.
*/
private Boolean sensitive;
private final boolean sensitiveDefault;
public AbstractMvcEndpoint(String path, boolean sensitive) {
public AbstractMvcEndpoint(String path) {
setPath(path);
this.sensitiveDefault = sensitive;
}
public AbstractMvcEndpoint(String path, boolean sensitive, boolean enabled) {
setPath(path);
this.sensitiveDefault = sensitive;
this.enabled = enabled;
}
@Override
@@ -93,16 +79,6 @@ public abstract class AbstractMvcEndpoint
this.enabled = enabled;
}
@Override
public boolean isSensitive() {
return EndpointProperties.isSensitive(this.environment, this.sensitive,
this.sensitiveDefault);
}
public void setSensitive(Boolean sensitive) {
this.sensitive = sensitive;
}
@Override
@SuppressWarnings("rawtypes")
public Class<? extends Endpoint> getEndpointType() {

View File

@@ -31,15 +31,8 @@ public abstract class AbstractNamedMvcEndpoint extends AbstractMvcEndpoint
private final String name;
public AbstractNamedMvcEndpoint(String name, String path, boolean sensitive) {
super(path, sensitive);
Assert.hasLength(name, "Name must not be empty");
this.name = name;
}
public AbstractNamedMvcEndpoint(String name, String path, boolean sensitive,
boolean enabled) {
super(path, sensitive, enabled);
public AbstractNamedMvcEndpoint(String name, String path) {
super(path);
Assert.hasLength(name, "Name must not be empty");
this.name = name;
}

View File

@@ -42,7 +42,7 @@ public class AuditEventsMvcEndpoint extends AbstractNamedMvcEndpoint {
private final AuditEventRepository auditEventRepository;
public AuditEventsMvcEndpoint(AuditEventRepository auditEventRepository) {
super("auditevents", "/auditevents", true);
super("auditevents", "/auditevents");
Assert.notNull(auditEventRepository, "AuditEventRepository must not be null");
this.auditEventRepository = auditEventRepository;
}

View File

@@ -91,7 +91,7 @@ public class EndpointHandlerMapping extends AbstractEndpointHandlerMapping<MvcEn
private final Set<NamedMvcEndpoint> endpoints;
private EndpointLinksMvcEndpoint(Set<NamedMvcEndpoint> endpoints) {
super("", false);
super("");
this.endpoints = endpoints;
}

View File

@@ -68,7 +68,7 @@ public class HeapdumpMvcEndpoint extends AbstractNamedMvcEndpoint {
}
protected HeapdumpMvcEndpoint(long timeout) {
super("heapdump", "/heapdump", true);
super("heapdump", "/heapdump");
this.timeout = timeout;
}

View File

@@ -50,7 +50,7 @@ public class JolokiaMvcEndpoint extends AbstractNamedMvcEndpoint implements
private final ServletWrappingController controller = new ServletWrappingController();
public JolokiaMvcEndpoint() {
super("jolokia", "/jolokia", true);
super("jolokia", "/jolokia");
this.controller.setServletClass(AgentServlet.class);
this.controller.setServletName("jolokia");
}

View File

@@ -58,7 +58,7 @@ public class LogFileMvcEndpoint extends AbstractNamedMvcEndpoint {
private File externalFile;
public LogFileMvcEndpoint() {
super("logfile", "/logfile", true);
super("logfile", "/logfile");
}
public File getExternalFile() {

View File

@@ -48,12 +48,6 @@ public interface MvcEndpoint {
*/
String getPath();
/**
* Return if the endpoint exposes sensitive information.
* @return if the endpoint is sensitive
*/
boolean isSensitive();
/**
* Return the type of {@link Endpoint} exposed, or {@code null} if this
* {@link MvcEndpoint} exposes information that cannot be represented as a traditional

View File

@@ -69,10 +69,6 @@ public class MvcEndpointSecurityInterceptor extends HandlerInterceptorAdapter {
&& !(handlerMethod.getBean() instanceof MvcEndpoint)) {
return true;
}
MvcEndpoint mvcEndpoint = (MvcEndpoint) handlerMethod.getBean();
if (!mvcEndpoint.isSensitive()) {
return true;
}
if (isUserAllowedAccess(request)) {
return true;
}

View File

@@ -178,7 +178,7 @@ public class EndpointMBeanExportAutoConfigurationTests {
public static class ManagedEndpoint extends AbstractEndpoint<Boolean> {
public ManagedEndpoint() {
super("managed", true);
super("managed");
}
@Override
@@ -200,7 +200,7 @@ public class EndpointMBeanExportAutoConfigurationTests {
class Nested extends AbstractEndpoint<Boolean> {
Nested() {
super("managed", true);
super("managed");
}
@Override

View File

@@ -867,11 +867,6 @@ public class EndpointWebMvcAutoConfigurationTests {
return "/endpoint";
}
@Override
public boolean isSensitive() {
return true;
}
@Override
@SuppressWarnings("rawtypes")
public Class<? extends Endpoint> getEndpointType() {

View File

@@ -64,7 +64,7 @@ public class LinksEnhancerTests {
@Test
public void usePathAsRelIfNameNotAvailable() throws Exception {
MvcEndpoint endpoint = new NoNameTestMvcEndpoint("/a", false);
MvcEndpoint endpoint = new NoNameTestMvcEndpoint("/a");
LinksEnhancer enhancer = getLinksEnhancer(Collections.singletonList(endpoint));
ResourceSupport support = new ResourceSupport();
enhancer.addEndpointLinks(support, "");
@@ -143,8 +143,8 @@ public class LinksEnhancerTests {
private static class NoNameTestMvcEndpoint extends AbstractMvcEndpoint {
NoNameTestMvcEndpoint(String path, boolean sensitive) {
super(path, sensitive);
NoNameTestMvcEndpoint(String path) {
super(path);
}
}

View File

@@ -57,9 +57,6 @@ import org.springframework.util.StringUtils;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests for {@link ManagementWebSecurityAutoConfiguration}.
@@ -226,27 +223,6 @@ public class ManagementWebSecurityAutoConfigurationTests {
.andExpect(springAuthenticateRealmHeader());
}
@Test
public void testMarkAllEndpointsSensitive() throws Exception {
// gh-4368
this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext());
this.context.register(WebConfiguration.class);
TestPropertyValues.of("endpoints.sensitive:true").applyTo(this.context);
this.context.refresh();
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context) //
.apply(springSecurity()) //
.build();
mockMvc //
.perform(get("/health")) //
.andExpect(status().isUnauthorized());
mockMvc //
.perform(get("/info")) //
.andExpect(status().isUnauthorized());
}
private ResultMatcher springAuthenticateRealmHeader() {
return MockMvcResultMatchers.header().string("www-authenticate",
Matchers.containsString("realm=\"Spring\""));

View File

@@ -41,7 +41,6 @@ public class CloudFoundryHealthMvcEndpointTests {
CloudFoundryHealthMvcEndpoint mvc = new CloudFoundryHealthMvcEndpoint(endpoint);
given(endpoint.invoke())
.willReturn(new Health.Builder().up().withDetail("foo", "bar").build());
given(endpoint.isSensitive()).willReturn(false);
Object result = mvc.invoke(null, null);
assertThat(result instanceof Health).isTrue();
assertThat(((Health) result).getStatus() == Status.UP).isTrue();

View File

@@ -49,16 +49,13 @@ public abstract class AbstractEndpointTests<T extends Endpoint<?>> {
private final String id;
private final boolean sensitive;
private final String property;
public AbstractEndpointTests(Class<?> configClass, Class<?> type, String id,
boolean sensitive, String property) {
String property) {
this.configClass = configClass;
this.type = type;
this.id = id;
this.sensitive = sensitive;
this.property = property;
}
@@ -81,11 +78,6 @@ public abstract class AbstractEndpointTests<T extends Endpoint<?>> {
assertThat(getEndpointBean().getId()).isEqualTo(this.id);
}
@Test
public void isSensitive() throws Exception {
assertThat(getEndpointBean().isSensitive()).isEqualTo(this.sensitive);
}
@Test
public void idOverride() throws Exception {
this.context = new AnnotationConfigApplicationContext();
@@ -95,31 +87,6 @@ public abstract class AbstractEndpointTests<T extends Endpoint<?>> {
assertThat(getEndpointBean().getId()).isEqualTo("myid");
}
@Test
public void isSensitiveOverride() throws Exception {
this.context = new AnnotationConfigApplicationContext();
PropertySource<?> propertySource = new MapPropertySource("test",
Collections.<String, Object>singletonMap(this.property + ".sensitive",
String.valueOf(!this.sensitive)));
this.context.getEnvironment().getPropertySources().addFirst(propertySource);
this.context.register(this.configClass);
this.context.refresh();
assertThat(getEndpointBean().isSensitive()).isEqualTo(!this.sensitive);
}
@Test
public void isSensitiveOverrideWithGlobal() throws Exception {
this.context = new AnnotationConfigApplicationContext();
Map<String, Object> properties = new HashMap<>();
properties.put("endpoint.sensitive", this.sensitive);
properties.put(this.property + ".sensitive", String.valueOf(!this.sensitive));
PropertySource<?> propertySource = new MapPropertySource("test", properties);
this.context.getEnvironment().getPropertySources().addFirst(propertySource);
this.context.register(this.configClass);
this.context.refresh();
assertThat(getEndpointBean().isSensitive()).isEqualTo(!this.sensitive);
}
@Test
public void isEnabledByDefault() throws Exception {
assertThat(getEndpointBean().isEnabled()).isTrue();
@@ -181,26 +148,6 @@ public abstract class AbstractEndpointTests<T extends Endpoint<?>> {
}
}
@Test
public void isAllEndpointsSensitive() throws Exception {
testGlobalEndpointsSensitive(true);
}
@Test
public void isAllEndpointsNotSensitive() throws Exception {
testGlobalEndpointsSensitive(false);
}
private void testGlobalEndpointsSensitive(boolean sensitive) {
this.context = new AnnotationConfigApplicationContext();
PropertySource<?> propertySource = new MapPropertySource("test", Collections
.<String, Object>singletonMap("endpoints.sensitive", sensitive));
this.context.getEnvironment().getPropertySources().addFirst(propertySource);
this.context.register(this.configClass);
this.context.refresh();
assertThat(getEndpointBean().isSensitive()).isEqualTo(sensitive);
}
@SuppressWarnings("unchecked")
protected T getEndpointBean() {
return (T) this.context.getBean(this.type);

View File

@@ -47,7 +47,7 @@ public class AutoConfigurationReportEndpointTests
extends AbstractEndpointTests<AutoConfigurationReportEndpoint> {
public AutoConfigurationReportEndpointTests() {
super(Config.class, AutoConfigurationReportEndpoint.class, "autoconfig", true,
super(Config.class, AutoConfigurationReportEndpoint.class, "autoconfig",
"endpoints.autoconfig");
}

View File

@@ -35,7 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class BeansEndpointTests extends AbstractEndpointTests<BeansEndpoint> {
public BeansEndpointTests() {
super(Config.class, BeansEndpoint.class, "beans", true, "endpoints.beans");
super(Config.class, BeansEndpoint.class, "beans", "endpoints.beans");
}
@Test

View File

@@ -43,7 +43,7 @@ public class ConfigurationPropertiesReportEndpointTests
public ConfigurationPropertiesReportEndpointTests() {
super(Config.class, ConfigurationPropertiesReportEndpoint.class, "configprops",
true, "endpoints.configprops");
"endpoints.configprops");
}
@Test

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 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.
@@ -35,7 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class DumpEndpointTests extends AbstractEndpointTests<DumpEndpoint> {
public DumpEndpointTests() {
super(Config.class, DumpEndpoint.class, "dump", true, "endpoints.dump");
super(Config.class, DumpEndpoint.class, "dump", "endpoints.dump");
}
@Test

View File

@@ -50,7 +50,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class EnvironmentEndpointTests extends AbstractEndpointTests<EnvironmentEndpoint> {
public EnvironmentEndpointTests() {
super(Config.class, EnvironmentEndpoint.class, "env", true, "endpoints.env");
super(Config.class, EnvironmentEndpoint.class, "env", "endpoints.env");
}
@Override

View File

@@ -35,7 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class FlywayEndpointTests extends AbstractEndpointTests<FlywayEndpoint> {
public FlywayEndpointTests() {
super(Config.class, FlywayEndpoint.class, "flyway", true, "endpoints.flyway");
super(Config.class, FlywayEndpoint.class, "flyway", "endpoints.flyway");
}
@Test

View File

@@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class HealthEndpointTests extends AbstractEndpointTests<HealthEndpoint> {
public HealthEndpointTests() {
super(Config.class, HealthEndpoint.class, "health", false, "endpoints.health");
super(Config.class, HealthEndpoint.class, "health", "endpoints.health");
}
@Test

View File

@@ -38,7 +38,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class InfoEndpointTests extends AbstractEndpointTests<InfoEndpoint> {
public InfoEndpointTests() {
super(Config.class, InfoEndpoint.class, "info", false, "endpoints.info");
super(Config.class, InfoEndpoint.class, "info", "endpoints.info");
}
@Test

View File

@@ -38,8 +38,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class LiquibaseEndpointTests extends AbstractEndpointTests<LiquibaseEndpoint> {
public LiquibaseEndpointTests() {
super(Config.class, LiquibaseEndpoint.class, "liquibase", true,
"endpoints.liquibase");
super(Config.class, LiquibaseEndpoint.class, "liquibase", "endpoints.liquibase");
}
@Test

View File

@@ -44,7 +44,7 @@ import static org.mockito.Mockito.verify;
public class LoggersEndpointTests extends AbstractEndpointTests<LoggersEndpoint> {
public LoggersEndpointTests() {
super(Config.class, LoggersEndpoint.class, "loggers", true, "endpoints.loggers");
super(Config.class, LoggersEndpoint.class, "loggers", "endpoints.loggers");
}
@Test

View File

@@ -49,7 +49,7 @@ public class MetricsEndpointTests extends AbstractEndpointTests<MetricsEndpoint>
private Metric<Number> metric3 = new Metric<>("c", 3);
public MetricsEndpointTests() {
super(Config.class, MetricsEndpoint.class, "metrics", true, "endpoints.metrics");
super(Config.class, MetricsEndpoint.class, "metrics", "endpoints.metrics");
}
@Test

View File

@@ -42,8 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class ShutdownEndpointTests extends AbstractEndpointTests<ShutdownEndpoint> {
public ShutdownEndpointTests() {
super(Config.class, ShutdownEndpoint.class, "shutdown", true,
"endpoints.shutdown");
super(Config.class, ShutdownEndpoint.class, "shutdown", "endpoints.shutdown");
}
@Override

View File

@@ -37,7 +37,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class TraceEndpointTests extends AbstractEndpointTests<TraceEndpoint> {
public TraceEndpointTests() {
super(Config.class, TraceEndpoint.class, "trace", true, "endpoints.trace");
super(Config.class, TraceEndpoint.class, "trace", "endpoints.trace");
}
@Test

View File

@@ -86,8 +86,8 @@ public class EndpointMBeanExporterTests {
MBeanInfo mbeanInfo = mbeanExporter.getServer()
.getMBeanInfo(getObjectName("endpoint1", this.context));
assertThat(mbeanInfo).isNotNull();
assertThat(mbeanInfo.getOperations().length).isEqualTo(3);
assertThat(mbeanInfo.getAttributes().length).isEqualTo(3);
assertThat(mbeanInfo.getOperations().length).isEqualTo(2);
assertThat(mbeanInfo.getAttributes().length).isEqualTo(2);
}
@Test

View File

@@ -58,7 +58,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*/
@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(properties = { "info.app.name=MyService" })
@TestPropertySource(properties = { "info.app.name=MyService",
"management.security.enabled=false" })
public class InfoMvcEndpointTests {
@Autowired

View File

@@ -34,6 +34,7 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
@@ -50,6 +51,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*/
@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(properties = "management.security.enabled=false")
public class InfoMvcEndpointWithNoInfoContributorsTests {
@Autowired

View File

@@ -112,28 +112,7 @@ public class MvcEndpointIntegrationTests {
}
@Test
public void nonSensitiveEndpointsAreNotSecureByDefault() throws Exception {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(SecureConfiguration.class);
MockMvc mockMvc = createSecureMockMvc();
mockMvc.perform(get("/application/info")).andExpect(status().isOk());
mockMvc.perform(get("/application")).andExpect(status().isOk());
}
@Test
public void nonSensitiveEndpointsAreNotSecureByDefaultWithCustomContextPath()
throws Exception {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(SecureConfiguration.class);
TestPropertyValues.of("management.context-path:/management")
.applyTo(this.context);
MockMvc mockMvc = createSecureMockMvc();
mockMvc.perform(get("/management/info")).andExpect(status().isOk());
mockMvc.perform(get("/management")).andExpect(status().isOk());
}
@Test
public void sensitiveEndpointsAreSecureByDefault() throws Exception {
public void endpointsAreSecureByDefault() throws Exception {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(SecureConfiguration.class);
MockMvc mockMvc = createSecureMockMvc();
@@ -141,8 +120,7 @@ public class MvcEndpointIntegrationTests {
}
@Test
public void sensitiveEndpointsAreSecureByDefaultWithCustomContextPath()
throws Exception {
public void endpointsAreSecureByDefaultWithCustomContextPath() throws Exception {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(SecureConfiguration.class);
TestPropertyValues.of("management.context-path:/management")
@@ -152,7 +130,7 @@ public class MvcEndpointIntegrationTests {
}
@Test
public void sensitiveEndpointsAreSecureWithNonActuatorRoleWithCustomContextPath()
public void endpointsAreSecureWithNonActuatorRoleWithCustomContextPath()
throws Exception {
TestSecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "N/A", "ROLE_USER"));
@@ -165,7 +143,7 @@ public class MvcEndpointIntegrationTests {
}
@Test
public void sensitiveEndpointsAreSecureWithActuatorRoleWithCustomContextPath()
public void endpointsAreSecureWithActuatorRoleWithCustomContextPath()
throws Exception {
TestSecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "N/A", "ROLE_ACTUATOR"));

View File

@@ -89,22 +89,14 @@ public class MvcEndpointSecurityInterceptorTests {
}
@Test
public void endpointNotSensitiveShouldAllowAccess() throws Exception {
this.endpoint.setSensitive(false);
assertThat(this.securityInterceptor.preHandle(this.request, this.response,
this.handlerMethod)).isTrue();
}
@Test
public void sensitiveEndpointIfRoleIsPresentShouldAllowAccess() throws Exception {
public void endpointIfRoleIsPresentShouldAllowAccess() throws Exception {
this.servletContext.declareRoles("SUPER_HERO");
assertThat(this.securityInterceptor.preHandle(this.request, this.response,
this.handlerMethod)).isTrue();
}
@Test
public void sensitiveEndpointIfNotAuthenticatedShouldNotAllowAccess()
throws Exception {
public void endpointIfNotAuthenticatedShouldNotAllowAccess() throws Exception {
assertThat(this.securityInterceptor.preHandle(this.request, this.response,
this.handlerMethod)).isFalse();
verify(this.response).sendError(HttpStatus.UNAUTHORIZED.value(),
@@ -118,8 +110,7 @@ public class MvcEndpointSecurityInterceptorTests {
}
@Test
public void sensitiveEndpointIfRoleIsNotCorrectShouldNotAllowAccess()
throws Exception {
public void endpointIfRoleIsNotCorrectShouldNotAllowAccess() throws Exception {
Principal principal = mock(Principal.class);
this.request.setUserPrincipal(principal);
this.servletContext.declareRoles("HERO");
@@ -130,8 +121,7 @@ public class MvcEndpointSecurityInterceptorTests {
}
@Test
public void sensitiveEndpointIfRoleNotCorrectShouldCheckAuthorities()
throws Exception {
public void endpointIfRoleNotCorrectShouldCheckAuthorities() throws Exception {
Principal principal = mock(Principal.class);
this.request.setUserPrincipal(principal);
Authentication authentication = mock(Authentication.class);
@@ -144,7 +134,7 @@ public class MvcEndpointSecurityInterceptorTests {
}
@Test
public void sensitiveEndpointIfRoleAndAuthoritiesNotCorrectShouldNotAllowAccess()
public void endpointIfRoleAndAuthoritiesNotCorrectShouldNotAllowAccess()
throws Exception {
Principal principal = mock(Principal.class);
this.request.setUserPrincipal(principal);

View File

@@ -16,8 +16,6 @@
package org.springframework.boot.actuate.endpoint.mvc;
import java.security.Principal;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,12 +36,10 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import static org.hamcrest.CoreMatchers.containsString;
import static org.mockito.Mockito.mock;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -65,19 +61,6 @@ public class NoSpringSecurityHealthMvcEndpointIntegrationTests {
this.context.close();
}
@Test
public void healthWhenRightRoleNotPresentShouldNotExposeHealthDetails()
throws Exception {
this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext());
this.context.register(TestConfiguration.class);
this.context.refresh();
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
mockMvc.perform(get("/application/health").with(getRequestPostProcessor()))
.andExpect(status().isOk())
.andExpect(content().string("{\"status\":\"UP\"}"));
}
@Test
public void healthDetailPresent() throws Exception {
this.context = new AnnotationConfigWebApplicationContext();
@@ -91,14 +74,6 @@ public class NoSpringSecurityHealthMvcEndpointIntegrationTests {
"\"status\":\"UP\",\"test\":{\"status\":\"UP\",\"hello\":\"world\"}")));
}
private RequestPostProcessor getRequestPostProcessor() {
return (request) -> {
Principal principal = mock(Principal.class);
request.setUserPrincipal(principal);
return request;
};
}
@ImportAutoConfiguration({ JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, EndpointAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class,

View File

@@ -74,8 +74,7 @@ public class NoSpringSecurityMvcEndpointSecurityInterceptorTests {
}
@Test
public void sensitiveEndpointIfRoleNotPresentShouldNotValidateAuthorities()
throws Exception {
public void endpointIfRoleNotPresentShouldNotValidateAuthorities() throws Exception {
Principal principal = mock(Principal.class);
this.request.setUserPrincipal(principal);
this.servletContext.declareRoles("HERO");