Remove concept of sensitivity from Actuator's endpoints
Closes gh-9924
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -41,7 +41,7 @@ class CloudFoundryDiscoveryMvcEndpoint extends AbstractMvcEndpoint {
|
||||
private final Set<NamedMvcEndpoint> endpoints;
|
||||
|
||||
CloudFoundryDiscoveryMvcEndpoint(Set<NamedMvcEndpoint> endpoints) {
|
||||
super("", false);
|
||||
super("");
|
||||
this.endpoints = endpoints;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ public class HeapdumpMvcEndpoint extends AbstractNamedMvcEndpoint {
|
||||
}
|
||||
|
||||
protected HeapdumpMvcEndpoint(long timeout) {
|
||||
super("heapdump", "/heapdump", true);
|
||||
super("heapdump", "/heapdump");
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public class LogFileMvcEndpoint extends AbstractNamedMvcEndpoint {
|
||||
private File externalFile;
|
||||
|
||||
public LogFileMvcEndpoint() {
|
||||
super("logfile", "/logfile", true);
|
||||
super("logfile", "/logfile");
|
||||
}
|
||||
|
||||
public File getExternalFile() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -867,11 +867,6 @@ public class EndpointWebMvcAutoConfigurationTests {
|
||||
return "/endpoint";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSensitive() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Class<? extends Endpoint> getEndpointType() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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\""));
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -43,7 +43,7 @@ public class ConfigurationPropertiesReportEndpointTests
|
||||
|
||||
public ConfigurationPropertiesReportEndpointTests() {
|
||||
super(Config.class, ConfigurationPropertiesReportEndpoint.class, "configprops",
|
||||
true, "endpoints.configprops");
|
||||
"endpoints.configprops");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user