diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java index 1d6139dbfb..70d9d1846b 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java @@ -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)"); - } } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java index 01bcef9e90..d1f42286e6 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java @@ -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 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 ignored = new LinkedHashSet( + 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 matchers = new ArrayList(); + 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.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.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 matchers = new ArrayList(); - 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 matchers = new ArrayList(); + 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.emptySet()); + } + return endpointHandlerMapping; + } + + } + } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ManagementErrorEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ManagementErrorEndpoint.java index 597bcaa341..e795bd1f76 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ManagementErrorEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/ManagementErrorEndpoint.java @@ -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 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 getEndpointType() { - return null; - } - } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java index add60af539..ee165039dc 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfigurationTests.java @@ -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(); } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfigurationTests.java index 33cd9ef78a..40b806ca18 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfigurationTests.java @@ -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()); } diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/EndpointsPropertiesSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/EndpointsPropertiesSampleActuatorApplicationTests.java index c9d64c131a..d6a6c56c45 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/EndpointsPropertiesSampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/EndpointsPropertiesSampleActuatorApplicationTests.java @@ -57,7 +57,7 @@ public class EndpointsPropertiesSampleActuatorApplicationTests { @Test public void testCustomErrorPath() throws Exception { @SuppressWarnings("rawtypes") - ResponseEntity entity = new TestRestTemplate("user", "password") + ResponseEntity entity = new TestRestTemplate("user", getPassword()) .getForEntity("http://localhost:" + this.port + "/oops", Map.class); assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, entity.getStatusCode()); @SuppressWarnings("unchecked") diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortAndPathSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortAndPathSampleActuatorApplicationTests.java new file mode 100644 index 0000000000..57e01a1350 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortAndPathSampleActuatorApplicationTests.java @@ -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 entity = new TestRestTemplate("user", getPassword()) + .getForEntity("http://localhost:" + this.port, Map.class); + assertEquals(HttpStatus.OK, entity.getStatusCode()); + @SuppressWarnings("unchecked") + Map 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 entity = new TestRestTemplate().getForEntity( + "http://localhost:" + this.managementPort + "/admin/metrics", Map.class); + assertEquals(HttpStatus.UNAUTHORIZED, entity.getStatusCode()); + } + + @Test + public void testHealth() throws Exception { + ResponseEntity 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 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 entity = new TestRestTemplate() + .getForEntity("http://localhost:" + this.port + "/error", Map.class); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, entity.getStatusCode()); + @SuppressWarnings("unchecked") + Map body = entity.getBody(); + assertEquals(999, body.get("status")); + } + + @Test + public void testManagementErrorPage() throws Exception { + @SuppressWarnings("rawtypes") + ResponseEntity entity = new TestRestTemplate().getForEntity( + "http://localhost:" + this.managementPort + "/error", Map.class); + // TODO: should be 500? + assertEquals(HttpStatus.OK, entity.getStatusCode()); + @SuppressWarnings("unchecked") + Map body = entity.getBody(); + assertEquals(999, body.get("status")); + } + + private String getPassword() { + return this.security.getUser().getPassword(); + } + +}