Make /error the error page in child context as well as parent
If user set the management.port *and* the management.context-path then the /error path was in the wrong place because formerly it was implemented (in this case) by an MvcEndpoint. If we switch it to a regular @Controller (which are now supported in the child context if there is one) then it won't disappear under the management.context-path. Also use lazy request matching in ignores as well as secure paths. The problem was that the ignores were constructed eagerly from the actuator paths before they were available (the EndpointHandlerMapping needs to be lazily accessed to avoid a security-induced bean creation cascade). Fixes gh-4624
This commit is contained in:
parent
754642e0cf
commit
2de48a35ab
|
@ -24,22 +24,17 @@ import javax.servlet.Filter;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.HierarchicalBeanFactory;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.autoconfigure.ManagementWebSecurityAutoConfiguration.ManagementWebSecurityConfigurerAdapter;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.ManagementErrorEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoints;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.boot.autoconfigure.hateoas.HypermediaHttpMessageConverterConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
|
||||
|
@ -57,7 +52,6 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
|||
import org.springframework.hateoas.LinkDiscoverer;
|
||||
import org.springframework.hateoas.config.EnableHypermediaSupport;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.HandlerAdapter;
|
||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
|
@ -80,9 +74,6 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
|||
@Import(ManagementContextConfigurationsImportSelector.class)
|
||||
public class EndpointWebMvcChildContextConfiguration {
|
||||
|
||||
private static Log logger = LogFactory
|
||||
.getLog(EndpointWebMvcChildContextConfiguration.class);
|
||||
|
||||
@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
|
||||
public DispatcherServlet dispatcherServlet() {
|
||||
DispatcherServlet dispatcherServlet = new DispatcherServlet();
|
||||
|
@ -121,19 +112,14 @@ public class EndpointWebMvcChildContextConfiguration {
|
|||
*/
|
||||
@Bean
|
||||
@ConditionalOnBean(ErrorAttributes.class)
|
||||
public ManagementErrorEndpoint errorEndpoint(ServerProperties serverProperties,
|
||||
ErrorAttributes errorAttributes) {
|
||||
return new ManagementErrorEndpoint(serverProperties.getError().getPath(),
|
||||
errorAttributes);
|
||||
public ManagementErrorEndpoint errorEndpoint(ErrorAttributes errorAttributes) {
|
||||
return new ManagementErrorEndpoint(errorAttributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration to add {@link HandlerMapping} for {@link MvcEndpoint}s. See
|
||||
* {@link SecureEndpointHandlerMappingConfiguration} for an extended version that also
|
||||
* configures the security filter.
|
||||
* Configuration to add {@link HandlerMapping} for {@link MvcEndpoint}s.
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnMissingClass("org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter")
|
||||
protected static class EndpointHandlerMappingConfiguration {
|
||||
|
||||
@Autowired
|
||||
|
@ -141,45 +127,6 @@ public class EndpointWebMvcChildContextConfiguration {
|
|||
ListableBeanFactory beanFactory, EndpointHandlerMapping mapping) {
|
||||
// In a child context we definitely want to see the parent endpoints
|
||||
mapping.setDetectHandlerMethodsInAncestorContexts(true);
|
||||
postProcessMapping(beanFactory, mapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to allow additional post processing of {@link EndpointHandlerMapping}.
|
||||
* @param beanFactory the source bean factory
|
||||
* @param mapping the mapping to customize
|
||||
*/
|
||||
protected void postProcessMapping(ListableBeanFactory beanFactory,
|
||||
EndpointHandlerMapping mapping) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension of {@link EndpointHandlerMappingConfiguration} that also configures the
|
||||
* security filter.
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
|
||||
protected static class SecureEndpointHandlerMappingConfiguration
|
||||
extends EndpointHandlerMappingConfiguration {
|
||||
|
||||
@Override
|
||||
protected void postProcessMapping(ListableBeanFactory beanFactory,
|
||||
EndpointHandlerMapping mapping) {
|
||||
// The parent context has the security filter, so we need to get it injected
|
||||
// with our EndpointHandlerMapping if we can.
|
||||
if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory,
|
||||
ManagementWebSecurityConfigurerAdapter.class).length == 1) {
|
||||
ManagementWebSecurityConfigurerAdapter bean = beanFactory
|
||||
.getBean(ManagementWebSecurityConfigurerAdapter.class);
|
||||
bean.setEndpointHandlerMapping(mapping);
|
||||
}
|
||||
else {
|
||||
logger.warn("No single bean of type "
|
||||
+ ManagementWebSecurityConfigurerAdapter.class.getSimpleName()
|
||||
+ " found (this might make some endpoints inaccessible without authentication)");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
@ -133,14 +132,14 @@ public class ManagementWebSecurityAutoConfiguration {
|
|||
@Autowired(required = false)
|
||||
private ErrorController errorController;
|
||||
|
||||
@Autowired(required = false)
|
||||
private EndpointHandlerMapping endpointHandlerMapping;
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@Autowired
|
||||
private ManagementServerProperties management;
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
@Autowired(required = false)
|
||||
private ManagementContextResolver contextResolver;
|
||||
|
||||
@Autowired(required = false)
|
||||
private ServerProperties server;
|
||||
|
@ -151,25 +150,35 @@ public class ManagementWebSecurityAutoConfiguration {
|
|||
|
||||
@Override
|
||||
public void init(WebSecurity builder) throws Exception {
|
||||
IgnoredRequestConfigurer ignoring = builder.ignoring();
|
||||
// The ignores are not cumulative, so to prevent overwriting the defaults we
|
||||
// add them back.
|
||||
List<String> ignored = SpringBootWebSecurityConfiguration
|
||||
.getIgnored(this.security);
|
||||
if (!this.management.getSecurity().isEnabled()) {
|
||||
ignored.addAll(Arrays
|
||||
.asList(EndpointPaths.ALL.getPaths(this.endpointHandlerMapping)));
|
||||
}
|
||||
if (ignored.contains("none")) {
|
||||
ignored.remove("none");
|
||||
}
|
||||
if (this.errorController != null) {
|
||||
ignored.add(normalizePath(this.errorController.getErrorPath()));
|
||||
}
|
||||
if (this.server != null) {
|
||||
IgnoredRequestConfigurer ignoring = builder.ignoring();
|
||||
// The ignores are not cumulative, so to prevent overwriting the defaults
|
||||
// we add them back.
|
||||
Set<String> ignored = new LinkedHashSet<String>(
|
||||
SpringBootWebSecurityConfiguration.getIgnored(this.security));
|
||||
if (ignored.contains("none")) {
|
||||
ignored.remove("none");
|
||||
}
|
||||
if (this.errorController != null) {
|
||||
ignored.add(normalizePath(this.errorController.getErrorPath()));
|
||||
}
|
||||
String[] paths = this.server.getPathsArray(ignored);
|
||||
RequestMatcher requestMatcher = this.management.getSecurity().isEnabled()
|
||||
? null
|
||||
: LazyEndpointPathRequestMatcher
|
||||
.getRequestMatcher(this.contextResolver);
|
||||
if (!ObjectUtils.isEmpty(paths)) {
|
||||
ignoring.antMatchers(paths);
|
||||
List<RequestMatcher> matchers = new ArrayList<RequestMatcher>();
|
||||
for (String pattern : paths) {
|
||||
matchers.add(new AntPathRequestMatcher(pattern, null));
|
||||
}
|
||||
if (requestMatcher != null) {
|
||||
matchers.add(requestMatcher);
|
||||
}
|
||||
requestMatcher = new OrRequestMatcher(matchers);
|
||||
}
|
||||
if (requestMatcher != null) {
|
||||
ignoring.requestMatchers(requestMatcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -227,38 +236,13 @@ public class ManagementWebSecurityAutoConfiguration {
|
|||
@Autowired(required = false)
|
||||
private ManagementContextResolver contextResolver;
|
||||
|
||||
@Autowired(required = false)
|
||||
private ServerProperties server;
|
||||
|
||||
@Autowired(required = false)
|
||||
private EndpointHandlerMapping endpointHandlerMapping;
|
||||
|
||||
public void setEndpointHandlerMapping(
|
||||
EndpointHandlerMapping endpointHandlerMapping) {
|
||||
this.endpointHandlerMapping = endpointHandlerMapping;
|
||||
}
|
||||
|
||||
protected final EndpointHandlerMapping getRequiredEndpointHandlerMapping() {
|
||||
if (this.endpointHandlerMapping == null) {
|
||||
ApplicationContext context = (this.contextResolver == null ? null
|
||||
: this.contextResolver.getApplicationContext());
|
||||
if (context != null && context
|
||||
.getBeanNamesForType(EndpointHandlerMapping.class).length > 0) {
|
||||
this.endpointHandlerMapping = context
|
||||
.getBean(EndpointHandlerMapping.class);
|
||||
}
|
||||
if (this.endpointHandlerMapping == null) {
|
||||
this.endpointHandlerMapping = new EndpointHandlerMapping(
|
||||
Collections.<MvcEndpoint>emptySet());
|
||||
}
|
||||
}
|
||||
return this.endpointHandlerMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// secure endpoints
|
||||
RequestMatcher matcher = getRequestMatcher();
|
||||
RequestMatcher matcher = this.management.getSecurity().isEnabled()
|
||||
? LazyEndpointPathRequestMatcher
|
||||
.getRequestMatcher(this.contextResolver)
|
||||
: null;
|
||||
if (matcher != null) {
|
||||
// Always protect them if present
|
||||
if (this.security.isRequireSsl()) {
|
||||
|
@ -280,20 +264,6 @@ public class ManagementWebSecurityAutoConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
private RequestMatcher getRequestMatcher() {
|
||||
if (!this.management.getSecurity().isEnabled()) {
|
||||
return null;
|
||||
}
|
||||
String path = this.management.getContextPath();
|
||||
if (StringUtils.hasText(path)) {
|
||||
AntPathRequestMatcher matcher = new AntPathRequestMatcher(
|
||||
this.server.getPath(path) + "/**");
|
||||
return matcher;
|
||||
}
|
||||
// Match everything, including the sensitive and non-sensitive paths
|
||||
return new EndpointPathRequestMatcher(EndpointPaths.ALL);
|
||||
}
|
||||
|
||||
private AuthenticationEntryPoint entryPoint() {
|
||||
BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
|
||||
entryPoint.setRealmName(this.security.getBasic().getRealm());
|
||||
|
@ -303,44 +273,12 @@ public class ManagementWebSecurityAutoConfiguration {
|
|||
private void configurePermittedRequests(
|
||||
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry requests) {
|
||||
// Permit access to the non-sensitive endpoints
|
||||
requests.requestMatchers(
|
||||
new EndpointPathRequestMatcher(EndpointPaths.NON_SENSITIVE))
|
||||
.permitAll();
|
||||
requests.requestMatchers(new LazyEndpointPathRequestMatcher(
|
||||
this.contextResolver, EndpointPaths.NON_SENSITIVE)).permitAll();
|
||||
// Restrict the rest to the configured role
|
||||
requests.anyRequest().hasRole(this.management.getSecurity().getRole());
|
||||
}
|
||||
|
||||
private final class EndpointPathRequestMatcher implements RequestMatcher {
|
||||
|
||||
private final EndpointPaths endpointPaths;
|
||||
|
||||
private RequestMatcher delegate;
|
||||
|
||||
EndpointPathRequestMatcher(EndpointPaths endpointPaths) {
|
||||
this.endpointPaths = endpointPaths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
if (this.delegate == null) {
|
||||
this.delegate = createDelegate();
|
||||
}
|
||||
return this.delegate.matches(request);
|
||||
}
|
||||
|
||||
private RequestMatcher createDelegate() {
|
||||
ServerProperties server = ManagementWebSecurityConfigurerAdapter.this.server;
|
||||
List<RequestMatcher> matchers = new ArrayList<RequestMatcher>();
|
||||
EndpointHandlerMapping endpointHandlerMapping = ManagementWebSecurityConfigurerAdapter.this
|
||||
.getRequiredEndpointHandlerMapping();
|
||||
for (String path : this.endpointPaths.getPaths(endpointHandlerMapping)) {
|
||||
matchers.add(new AntPathRequestMatcher(server.getPath(path)));
|
||||
}
|
||||
return (matchers.isEmpty() ? MATCH_NONE : new OrRequestMatcher(matchers));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private enum EndpointPaths {
|
||||
|
@ -386,4 +324,72 @@ public class ManagementWebSecurityAutoConfiguration {
|
|||
|
||||
}
|
||||
|
||||
private static class LazyEndpointPathRequestMatcher implements RequestMatcher {
|
||||
|
||||
private final EndpointPaths endpointPaths;
|
||||
|
||||
private final ManagementContextResolver contextResolver;
|
||||
|
||||
private RequestMatcher delegate;
|
||||
|
||||
public static RequestMatcher getRequestMatcher(
|
||||
ManagementContextResolver contextResolver) {
|
||||
if (contextResolver == null) {
|
||||
return null;
|
||||
}
|
||||
ManagementServerProperties management = contextResolver
|
||||
.getApplicationContext().getBean(ManagementServerProperties.class);
|
||||
ServerProperties server = contextResolver.getApplicationContext()
|
||||
.getBean(ServerProperties.class);
|
||||
String path = management.getContextPath();
|
||||
if (StringUtils.hasText(path)) {
|
||||
AntPathRequestMatcher matcher = new AntPathRequestMatcher(
|
||||
server.getPath(path) + "/**");
|
||||
return matcher;
|
||||
}
|
||||
// Match everything, including the sensitive and non-sensitive paths
|
||||
return new LazyEndpointPathRequestMatcher(contextResolver, EndpointPaths.ALL);
|
||||
}
|
||||
|
||||
LazyEndpointPathRequestMatcher(ManagementContextResolver contextResolver,
|
||||
EndpointPaths endpointPaths) {
|
||||
this.contextResolver = contextResolver;
|
||||
this.endpointPaths = endpointPaths;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
if (this.delegate == null) {
|
||||
this.delegate = createDelegate();
|
||||
}
|
||||
return this.delegate.matches(request);
|
||||
}
|
||||
|
||||
private RequestMatcher createDelegate() {
|
||||
ServerProperties server = this.contextResolver.getApplicationContext()
|
||||
.getBean(ServerProperties.class);
|
||||
List<RequestMatcher> matchers = new ArrayList<RequestMatcher>();
|
||||
EndpointHandlerMapping endpointHandlerMapping = getRequiredEndpointHandlerMapping();
|
||||
for (String path : this.endpointPaths.getPaths(endpointHandlerMapping)) {
|
||||
matchers.add(new AntPathRequestMatcher(server.getPath(path)));
|
||||
}
|
||||
return (matchers.isEmpty() ? MATCH_NONE : new OrRequestMatcher(matchers));
|
||||
}
|
||||
|
||||
private EndpointHandlerMapping getRequiredEndpointHandlerMapping() {
|
||||
EndpointHandlerMapping endpointHandlerMapping = null;
|
||||
ApplicationContext context = this.contextResolver.getApplicationContext();
|
||||
if (context.getBeanNamesForType(EndpointHandlerMapping.class).length > 0) {
|
||||
endpointHandlerMapping = context.getBean(EndpointHandlerMapping.class);
|
||||
}
|
||||
if (endpointHandlerMapping == null) {
|
||||
// Maybe there are actually no endpoints (e.g. management.port=-1)
|
||||
endpointHandlerMapping = new EndpointHandlerMapping(
|
||||
Collections.<MvcEndpoint>emptySet());
|
||||
}
|
||||
return endpointHandlerMapping;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ package org.springframework.boot.actuate.endpoint.mvc;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.autoconfigure.web.ErrorAttributes;
|
||||
import org.springframework.boot.autoconfigure.web.ErrorController;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
@ -33,39 +33,21 @@ import org.springframework.web.context.request.RequestContextHolder;
|
|||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class ManagementErrorEndpoint implements MvcEndpoint {
|
||||
@Controller
|
||||
public class ManagementErrorEndpoint {
|
||||
|
||||
private final ErrorAttributes errorAttributes;
|
||||
|
||||
private final String path;
|
||||
|
||||
public ManagementErrorEndpoint(String path, ErrorAttributes errorAttributes) {
|
||||
public ManagementErrorEndpoint(ErrorAttributes errorAttributes) {
|
||||
Assert.notNull(errorAttributes, "ErrorAttributes must not be null");
|
||||
this.path = path;
|
||||
this.errorAttributes = errorAttributes;
|
||||
}
|
||||
|
||||
@RequestMapping
|
||||
@RequestMapping("${server.path:/error}")
|
||||
@ResponseBody
|
||||
public Map<String, Object> invoke() {
|
||||
return this.errorAttributes.getErrorAttributes(
|
||||
RequestContextHolder.currentRequestAttributes(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSensitive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Class<? extends Endpoint> getEndpointType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -182,7 +182,7 @@ public class EndpointWebMvcAutoConfigurationTests {
|
|||
this.applicationContext.refresh();
|
||||
assertContent("/controller", ports.get().server, "controlleroutput");
|
||||
assertContent("/admin/endpoint", ports.get().management, "endpointoutput");
|
||||
assertContent("/admin/error", ports.get().management, startsWith("{"));
|
||||
assertContent("/error", ports.get().management, startsWith("{"));
|
||||
this.applicationContext.close();
|
||||
assertAllClosed();
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ public class EndpointWebMvcAutoConfigurationTests {
|
|||
this.applicationContext.refresh();
|
||||
assertContent("/spring/controller", ports.get().server, "controlleroutput");
|
||||
assertContent("/admin/endpoint", ports.get().management, "endpointoutput");
|
||||
assertContent("/admin/error", ports.get().management, startsWith("{"));
|
||||
assertContent("/error", ports.get().management, startsWith("{"));
|
||||
this.applicationContext.close();
|
||||
assertAllClosed();
|
||||
}
|
||||
|
|
|
@ -98,8 +98,8 @@ public class ManagementWebSecurityAutoConfigurationTests {
|
|||
this.context.refresh();
|
||||
assertNotNull(this.context.getBean(AuthenticationManagerBuilder.class));
|
||||
FilterChainProxy filterChainProxy = this.context.getBean(FilterChainProxy.class);
|
||||
// 4 for static resources, one for management endpoints and one for the rest
|
||||
assertThat(filterChainProxy.getFilterChains(), hasSize(6));
|
||||
// 1 for static resources, one for management endpoints and one for the rest
|
||||
assertThat(filterChainProxy.getFilterChains(), hasSize(3));
|
||||
assertThat(filterChainProxy.getFilters("/beans"), hasSize(greaterThan(0)));
|
||||
assertThat(filterChainProxy.getFilters("/beans/"), hasSize(greaterThan(0)));
|
||||
assertThat(filterChainProxy.getFilters("/beans.foo"), hasSize(greaterThan(0)));
|
||||
|
@ -160,7 +160,7 @@ public class ManagementWebSecurityAutoConfigurationTests {
|
|||
this.context.refresh();
|
||||
// Just the management endpoints (one filter) and ignores now plus the backup
|
||||
// filter on app endpoints
|
||||
assertEquals(6,
|
||||
assertEquals(3,
|
||||
this.context.getBean(FilterChainProxy.class).getFilterChains().size());
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ public class EndpointsPropertiesSampleActuatorApplicationTests {
|
|||
@Test
|
||||
public void testCustomErrorPath() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = new TestRestTemplate("user", "password")
|
||||
ResponseEntity<Map> entity = new TestRestTemplate("user", getPassword())
|
||||
.getForEntity("http://localhost:" + this.port + "/oops", Map.class);
|
||||
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, entity.getStatusCode());
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright 2012-2014 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 sample.actuator;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.boot.test.TestRestTemplate;
|
||||
import org.springframework.boot.test.WebIntegrationTest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Integration tests for separate management and main service ports.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(SampleActuatorApplication.class)
|
||||
@WebIntegrationTest(value = { "management.port=0",
|
||||
"management.context-path=/admin" }, randomPort = true)
|
||||
@DirtiesContext
|
||||
public class ManagementPortAndPathSampleActuatorApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private SecurityProperties security;
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private int port = 9010;
|
||||
|
||||
@Value("${local.management.port}")
|
||||
private int managementPort = 9011;
|
||||
|
||||
@Test
|
||||
public void testHome() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = new TestRestTemplate("user", getPassword())
|
||||
.getForEntity("http://localhost:" + this.port, Map.class);
|
||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertEquals("Hello Phil", body.get("message"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetrics() throws Exception {
|
||||
testHome(); // makes sure some requests have been made
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(
|
||||
"http://localhost:" + this.managementPort + "/admin/metrics", Map.class);
|
||||
assertEquals(HttpStatus.UNAUTHORIZED, entity.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHealth() throws Exception {
|
||||
ResponseEntity<String> entity = new TestRestTemplate().getForEntity(
|
||||
"http://localhost:" + this.managementPort + "/admin/health",
|
||||
String.class);
|
||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||
assertTrue("Wrong body: " + entity.getBody(),
|
||||
entity.getBody().contains("\"status\":\"UP\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissing() throws Exception {
|
||||
ResponseEntity<String> entity = new TestRestTemplate("user", getPassword())
|
||||
.getForEntity(
|
||||
"http://localhost:" + this.managementPort + "/admin/missing",
|
||||
String.class);
|
||||
assertEquals(HttpStatus.NOT_FOUND, entity.getStatusCode());
|
||||
assertTrue("Wrong body: " + entity.getBody(),
|
||||
entity.getBody().contains("\"status\":404"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorPage() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = new TestRestTemplate()
|
||||
.getForEntity("http://localhost:" + this.port + "/error", Map.class);
|
||||
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, entity.getStatusCode());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertEquals(999, body.get("status"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManagementErrorPage() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(
|
||||
"http://localhost:" + this.managementPort + "/error", Map.class);
|
||||
// TODO: should be 500?
|
||||
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertEquals(999, body.get("status"));
|
||||
}
|
||||
|
||||
private String getPassword() {
|
||||
return this.security.getUser().getPassword();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue