Polish
This commit is contained in:
@@ -26,6 +26,8 @@ import org.springframework.context.annotation.Conditional;
|
||||
|
||||
/**
|
||||
* {@link Conditional} that matches based on the configuration of the management port.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
|
||||
@@ -35,6 +35,10 @@ import org.springframework.context.annotation.Import;
|
||||
@Import(ManagementContextConfigurationImportSelector.class)
|
||||
@interface EnableManagementContext {
|
||||
|
||||
/**
|
||||
* The management context type that should be enabled.
|
||||
* @return the management context type
|
||||
*/
|
||||
ManagementContextType value();
|
||||
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
|
||||
/**
|
||||
@@ -58,7 +59,7 @@ public class ManagementContextAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public ManagementServletContext managementServletContext(
|
||||
final ManagementServerProperties properties) {
|
||||
ManagementServerProperties properties) {
|
||||
return () -> properties.getContextPath();
|
||||
}
|
||||
|
||||
@@ -86,12 +87,11 @@ public class ManagementContextAutoConfiguration {
|
||||
}
|
||||
|
||||
private void verifySslConfiguration() {
|
||||
if (this.environment.getProperty("management.ssl.enabled", Boolean.class,
|
||||
false)) {
|
||||
throw new IllegalStateException(
|
||||
"Management-specific SSL cannot be configured as the management "
|
||||
+ "server is not listening on a separate port");
|
||||
}
|
||||
Boolean enabled = this.environment.getProperty("management.ssl.enabled",
|
||||
Boolean.class, false);
|
||||
Assert.state(!enabled,
|
||||
"Management-specific SSL cannot be configured as the management "
|
||||
+ "server is not listening on a separate port");
|
||||
}
|
||||
|
||||
private void verifyContextPathConfiguration() {
|
||||
@@ -112,6 +112,7 @@ public class ManagementContextAutoConfiguration {
|
||||
ConfigurableEnvironment environment) {
|
||||
environment.getPropertySources()
|
||||
.addLast(new PropertySource<Object>("Management Server") {
|
||||
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
if ("local.management.port".equals(name)) {
|
||||
@@ -119,6 +120,7 @@ public class ManagementContextAutoConfiguration {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -122,8 +122,8 @@ class ManagementContextConfigurationImportSelector
|
||||
Map<String, Object> annotationAttributes = annotationMetadata
|
||||
.getAnnotationAttributes(
|
||||
ManagementContextConfiguration.class.getName());
|
||||
return annotationAttributes == null ? ManagementContextType.ANY
|
||||
: (ManagementContextType) annotationAttributes.get("value");
|
||||
return (annotationAttributes == null ? ManagementContextType.ANY
|
||||
: (ManagementContextType) annotationAttributes.get("value"));
|
||||
}
|
||||
|
||||
private int readOrder(AnnotationMetadata annotationMetadata) {
|
||||
|
||||
@@ -27,7 +27,13 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||
*/
|
||||
interface ManagementContextFactory {
|
||||
|
||||
/**
|
||||
* Create the management application context.
|
||||
* @param parent the parent context
|
||||
* @param configurationClasses the configuration classes
|
||||
* @return a configured application context
|
||||
*/
|
||||
ConfigurableApplicationContext createManagementContext(ApplicationContext parent,
|
||||
Class<?>... configClasses);
|
||||
Class<?>... configurationClasses);
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,12 @@ package org.springframework.boot.actuate.autoconfigure;
|
||||
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* Port types that can be used to control how the management server is started.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public enum ManagementPortType {
|
||||
|
||||
/**
|
||||
|
||||
@@ -78,8 +78,8 @@ import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
|
||||
* @author Eddú Meléndez
|
||||
* @author Meang Akira Tanaka
|
||||
* @author Ben Hale
|
||||
* @since 2.0.0
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter({ FlywayAutoConfiguration.class, LiquibaseAutoConfiguration.class })
|
||||
|
||||
@@ -20,8 +20,8 @@ import org.springframework.boot.actuate.autoconfigure.web.ManagementServerProper
|
||||
import org.springframework.boot.endpoint.EndpointPathResolver;
|
||||
|
||||
/**
|
||||
* {@link EndpointPathResolver} implementation for resolving
|
||||
* actuator endpoint paths based on the endpoint id and management.context-path.
|
||||
* {@link EndpointPathResolver} implementation for resolving actuator endpoint paths based
|
||||
* on the endpoint id and management.context-path.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.0
|
||||
@@ -38,5 +38,5 @@ public class ManagementEndpointPathResolver implements EndpointPathResolver {
|
||||
public String resolvePath(String endpointId) {
|
||||
return this.contextPath + "/" + endpointId;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,9 +51,8 @@ class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory {
|
||||
|
||||
@Override
|
||||
public ObjectName generate(EndpointMBean mBean) throws MalformedObjectNameException {
|
||||
String baseObjectName = this.properties.getDomain() +
|
||||
":type=Endpoint" +
|
||||
",name=" + StringUtils.capitalize(mBean.getEndpointId());
|
||||
String baseObjectName = this.properties.getDomain() + ":type=Endpoint" + ",name="
|
||||
+ StringUtils.capitalize(mBean.getEndpointId());
|
||||
StringBuilder builder = new StringBuilder(baseObjectName);
|
||||
if (this.mBeanServer != null && hasMBean(baseObjectName)) {
|
||||
builder.append(",context=").append(this.contextId);
|
||||
@@ -76,7 +75,8 @@ class DefaultEndpointObjectNameFactory implements EndpointObjectNameFactory {
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (Map.Entry<Object, Object> name : this.properties.getStaticNames().entrySet()) {
|
||||
for (Map.Entry<Object, Object> name : this.properties.getStaticNames()
|
||||
.entrySet()) {
|
||||
builder.append(",").append(name.getKey()).append("=").append(name.getValue());
|
||||
}
|
||||
return builder.toString();
|
||||
|
||||
@@ -71,17 +71,20 @@ public class EndpointInfrastructureAutoConfiguration {
|
||||
@Bean
|
||||
public OperationParameterMapper operationParameterMapper() {
|
||||
DefaultConversionService conversionService = new DefaultConversionService();
|
||||
conversionService.addConverter(String.class, Date.class, (string) -> {
|
||||
if (StringUtils.hasLength(string)) {
|
||||
OffsetDateTime offsetDateTime = OffsetDateTime.parse(string,
|
||||
DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
return new Date(offsetDateTime.toEpochSecond() * 1000);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
conversionService.addConverter(String.class, Date.class, this::convertToDate);
|
||||
return new ConversionServiceOperationParameterMapper(conversionService);
|
||||
}
|
||||
|
||||
private Date convertToDate(String value) {
|
||||
if (StringUtils.hasLength(value)) {
|
||||
OffsetDateTime offsetDateTime = OffsetDateTime.parse(value,
|
||||
DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
return new Date(offsetDateTime.toEpochSecond() * 1000);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CachingConfigurationFactory cacheConfigurationFactory() {
|
||||
return new CachingConfigurationFactory(this.applicationContext.getEnvironment());
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -61,8 +61,9 @@ public class EndpointEnablementProvider {
|
||||
public EndpointEnablement getEndpointEnablement(String endpointId,
|
||||
boolean enabledByDefault, EndpointExposure exposure) {
|
||||
Assert.hasText(endpointId, "Endpoint id must have a value");
|
||||
Assert.isTrue(!endpointId.equals("default"), "Endpoint id 'default' is a reserved "
|
||||
+ "value and cannot be used by an endpoint");
|
||||
Assert.isTrue(!endpointId.equals("default"),
|
||||
"Endpoint id 'default' is a reserved "
|
||||
+ "value and cannot be used by an endpoint");
|
||||
EndpointEnablement result = findEnablement(endpointId, exposure);
|
||||
if (result != null) {
|
||||
return result;
|
||||
@@ -76,8 +77,7 @@ public class EndpointEnablementProvider {
|
||||
if (!enabledByDefault) {
|
||||
return getDefaultEndpointEnablement(endpointId, false, exposure);
|
||||
}
|
||||
return getGlobalEndpointEnablement(endpointId, enabledByDefault,
|
||||
exposure);
|
||||
return getGlobalEndpointEnablement(endpointId, enabledByDefault, exposure);
|
||||
}
|
||||
|
||||
private EndpointEnablement findEnablement(String endpointId,
|
||||
@@ -98,12 +98,10 @@ public class EndpointEnablementProvider {
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
return getDefaultEndpointEnablement(endpointId, enabledByDefault,
|
||||
exposure);
|
||||
return getDefaultEndpointEnablement(endpointId, enabledByDefault, exposure);
|
||||
}
|
||||
|
||||
private EndpointEnablement findGlobalEndpointEnablement(
|
||||
EndpointExposure exposure) {
|
||||
private EndpointEnablement findGlobalEndpointEnablement(EndpointExposure exposure) {
|
||||
if (exposure != null) {
|
||||
EndpointEnablement result = findEnablement(getKey("default", exposure));
|
||||
if (result != null) {
|
||||
@@ -136,8 +134,8 @@ public class EndpointEnablementProvider {
|
||||
|
||||
private EndpointEnablement getDefaultEndpointEnablement(String endpointId,
|
||||
boolean enabledByDefault, EndpointExposure exposure) {
|
||||
return new EndpointEnablement(enabledByDefault, createDefaultEnablementMessage(
|
||||
endpointId, enabledByDefault, exposure));
|
||||
return new EndpointEnablement(enabledByDefault,
|
||||
createDefaultEnablementMessage(endpointId, enabledByDefault, exposure));
|
||||
}
|
||||
|
||||
private String createDefaultEnablementMessage(String endpointId,
|
||||
@@ -145,8 +143,7 @@ public class EndpointEnablementProvider {
|
||||
StringBuilder message = new StringBuilder();
|
||||
message.append(String.format("endpoint '%s' ", endpointId));
|
||||
if (exposure != null) {
|
||||
message.append(
|
||||
String.format("(%s) ", exposure.name().toLowerCase()));
|
||||
message.append(String.format("(%s) ", exposure.name().toLowerCase()));
|
||||
}
|
||||
message.append(String.format("is %s by default",
|
||||
(enabledByDefault ? "enabled" : "disabled")));
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -32,12 +32,10 @@ import org.springframework.web.servlet.mvc.ServletWrappingController;
|
||||
/**
|
||||
* {@link ManagementContextConfiguration} for embedding Jolokia, a JMX-HTTP bridge giving
|
||||
* an alternative to JSR-160 connectors.
|
||||
*
|
||||
* <p>
|
||||
* This configuration will get automatically enabled as soon as the Jolokia
|
||||
* {@link AgentServlet} is on the classpath. To disable it set
|
||||
* {@code management.jolokia.enabled=false}.
|
||||
*
|
||||
* <p>
|
||||
* Additional configuration parameters for Jolokia can be provided by specifying
|
||||
* {@code management.jolokia.config.*} properties. See the
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
* Security configuration for management endpoints.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@@ -39,9 +40,9 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
public class ManagementWebSecurityAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public EndpointPathResolver managementEndpointPathResolver(ManagementServerProperties properties) {
|
||||
public EndpointPathResolver managementEndpointPathResolver(
|
||||
ManagementServerProperties properties) {
|
||||
return new ManagementEndpointPathResolver(properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -66,32 +66,33 @@ public class CloudFoundryActuatorAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public CloudFoundryWebEndpointServletHandlerMapping cloudFoundryWebEndpointServletHandlerMapping(
|
||||
EndpointProvider<WebEndpointOperation> provider,
|
||||
Environment environment, RestTemplateBuilder builder) {
|
||||
CloudFoundryWebEndpointServletHandlerMapping handlerMapping = new CloudFoundryWebEndpointServletHandlerMapping(
|
||||
EndpointProvider<WebEndpointOperation> provider, Environment environment,
|
||||
RestTemplateBuilder builder) {
|
||||
return new CloudFoundryWebEndpointServletHandlerMapping(
|
||||
"/cloudfoundryapplication", provider.getEndpoints(),
|
||||
getCorsConfiguration(), getSecurityInterceptor(builder, environment));
|
||||
return handlerMapping;
|
||||
}
|
||||
|
||||
private CloudFoundrySecurityInterceptor getSecurityInterceptor(
|
||||
RestTemplateBuilder restTemplateBuilder, Environment environment) {
|
||||
CloudFoundrySecurityService cloudfoundrySecurityService = getCloudFoundrySecurityService(
|
||||
restTemplateBuilder, environment);
|
||||
TokenValidator tokenValidator = new TokenValidator(cloudfoundrySecurityService);
|
||||
return new CloudFoundrySecurityInterceptor(
|
||||
tokenValidator, cloudfoundrySecurityService,
|
||||
TokenValidator tokenValidator = new TokenValidator(
|
||||
cloudfoundrySecurityService);
|
||||
return new CloudFoundrySecurityInterceptor(tokenValidator,
|
||||
cloudfoundrySecurityService,
|
||||
environment.getProperty("vcap.application.application_id"));
|
||||
}
|
||||
|
||||
private CloudFoundrySecurityService getCloudFoundrySecurityService(
|
||||
RestTemplateBuilder restTemplateBuilder, Environment environment) {
|
||||
String cloudControllerUrl = environment.getProperty("vcap.application.cf_api");
|
||||
String cloudControllerUrl = environment
|
||||
.getProperty("vcap.application.cf_api");
|
||||
boolean skipSslValidation = environment.getProperty(
|
||||
"management.cloudfoundry.skip-ssl-validation", Boolean.class, false);
|
||||
return cloudControllerUrl == null ? null
|
||||
: new CloudFoundrySecurityService(restTemplateBuilder, cloudControllerUrl,
|
||||
skipSslValidation);
|
||||
return (cloudControllerUrl == null ? null
|
||||
: new CloudFoundrySecurityService(restTemplateBuilder,
|
||||
cloudControllerUrl, skipSslValidation));
|
||||
}
|
||||
|
||||
private CorsConfiguration getCorsConfiguration() {
|
||||
@@ -107,9 +108,9 @@ public class CloudFoundryActuatorAutoConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link WebSecurityConfigurer} to tell Spring Security to
|
||||
* ignore cloudfoundry specific paths. The Cloud foundry endpoints
|
||||
* are protected by their own security interceptor.
|
||||
* {@link WebSecurityConfigurer} to tell Spring Security to ignore cloudfoundry
|
||||
* specific paths. The Cloud foundry endpoints are protected by their own security
|
||||
* interceptor.
|
||||
*/
|
||||
@ConditionalOnClass(WebSecurity.class)
|
||||
@Order(SecurityProperties.IGNORED_ORDER)
|
||||
@@ -119,7 +120,8 @@ public class CloudFoundryActuatorAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public void init(WebSecurity builder) throws Exception {
|
||||
builder.ignoring().requestMatchers(new AntPathRequestMatcher("/cloudfoundryapplication/**"));
|
||||
builder.ignoring().requestMatchers(
|
||||
new AntPathRequestMatcher("/cloudfoundryapplication/**"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -52,18 +52,19 @@ class CloudFoundrySecurityInterceptor {
|
||||
this.applicationId = applicationId;
|
||||
}
|
||||
|
||||
SecurityResponse preHandle(HttpServletRequest request,
|
||||
String endpointId) {
|
||||
SecurityResponse preHandle(HttpServletRequest request, String endpointId) {
|
||||
if (CorsUtils.isPreFlightRequest(request)) {
|
||||
return SecurityResponse.success();
|
||||
}
|
||||
try {
|
||||
if (!StringUtils.hasText(this.applicationId)) {
|
||||
throw new CloudFoundryAuthorizationException(CloudFoundryAuthorizationException.Reason.SERVICE_UNAVAILABLE,
|
||||
throw new CloudFoundryAuthorizationException(
|
||||
CloudFoundryAuthorizationException.Reason.SERVICE_UNAVAILABLE,
|
||||
"Application id is not available");
|
||||
}
|
||||
if (this.cloudFoundrySecurityService == null) {
|
||||
throw new CloudFoundryAuthorizationException(CloudFoundryAuthorizationException.Reason.SERVICE_UNAVAILABLE,
|
||||
throw new CloudFoundryAuthorizationException(
|
||||
CloudFoundryAuthorizationException.Reason.SERVICE_UNAVAILABLE,
|
||||
"Cloud controller URL is not available");
|
||||
}
|
||||
if (HttpMethod.OPTIONS.matches(request.getMethod())) {
|
||||
@@ -75,21 +76,23 @@ class CloudFoundrySecurityInterceptor {
|
||||
logger.error(ex);
|
||||
if (ex instanceof CloudFoundryAuthorizationException) {
|
||||
CloudFoundryAuthorizationException cfException = (CloudFoundryAuthorizationException) ex;
|
||||
return new SecurityResponse(cfException.getStatusCode(), "{\"security_error\":\"" + cfException.getMessage() + "\"}");
|
||||
return new SecurityResponse(cfException.getStatusCode(),
|
||||
"{\"security_error\":\"" + cfException.getMessage() + "\"}");
|
||||
}
|
||||
return new SecurityResponse(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage());
|
||||
return new SecurityResponse(HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
ex.getMessage());
|
||||
}
|
||||
return SecurityResponse.success();
|
||||
}
|
||||
|
||||
private void check(HttpServletRequest request, String path)
|
||||
throws Exception {
|
||||
private void check(HttpServletRequest request, String path) throws Exception {
|
||||
Token token = getToken(request);
|
||||
this.tokenValidator.validate(token);
|
||||
AccessLevel accessLevel = this.cloudFoundrySecurityService
|
||||
.getAccessLevel(token.toString(), this.applicationId);
|
||||
if (!accessLevel.isAccessAllowed(path)) {
|
||||
throw new CloudFoundryAuthorizationException(CloudFoundryAuthorizationException.Reason.ACCESS_DENIED,
|
||||
throw new CloudFoundryAuthorizationException(
|
||||
CloudFoundryAuthorizationException.Reason.ACCESS_DENIED,
|
||||
"Access denied");
|
||||
}
|
||||
accessLevel.put(request);
|
||||
@@ -100,7 +103,8 @@ class CloudFoundrySecurityInterceptor {
|
||||
String bearerPrefix = "bearer ";
|
||||
if (authorization == null
|
||||
|| !authorization.toLowerCase().startsWith(bearerPrefix)) {
|
||||
throw new CloudFoundryAuthorizationException(CloudFoundryAuthorizationException.Reason.MISSING_AUTHORIZATION,
|
||||
throw new CloudFoundryAuthorizationException(
|
||||
CloudFoundryAuthorizationException.Reason.MISSING_AUTHORIZATION,
|
||||
"Authorization header is missing or invalid");
|
||||
}
|
||||
return new Token(authorization.substring(bearerPrefix.length()));
|
||||
@@ -116,7 +120,7 @@ class CloudFoundrySecurityInterceptor {
|
||||
private final String message;
|
||||
|
||||
SecurityResponse(HttpStatus status) {
|
||||
this (status, null);
|
||||
this(status, null);
|
||||
}
|
||||
|
||||
SecurityResponse(HttpStatus status, String message) {
|
||||
@@ -135,7 +139,7 @@ class CloudFoundrySecurityInterceptor {
|
||||
static SecurityResponse success() {
|
||||
return new SecurityResponse(HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -50,18 +50,20 @@ import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
|
||||
|
||||
/**
|
||||
* A custom {@link RequestMappingInfoHandlerMapping} that makes web endpoints available
|
||||
* on Cloudfoundry specific URLS over HTTP using Spring MVC.
|
||||
* A custom {@link RequestMappingInfoHandlerMapping} that makes web endpoints available on
|
||||
* Cloudfoundry specific URLS over HTTP using Spring MVC.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebEndpointServletHandlerMapping {
|
||||
class CloudFoundryWebEndpointServletHandlerMapping
|
||||
extends AbstractWebEndpointServletHandlerMapping {
|
||||
|
||||
private final Method handle = ReflectionUtils.findMethod(OperationHandler.class,
|
||||
"handle", HttpServletRequest.class, Map.class);
|
||||
|
||||
private final Method links = ReflectionUtils.findMethod(
|
||||
CloudFoundryWebEndpointServletHandlerMapping.class, "links", HttpServletRequest.class, HttpServletResponse.class);
|
||||
CloudFoundryWebEndpointServletHandlerMapping.class, "links",
|
||||
HttpServletRequest.class, HttpServletResponse.class);
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(CloudFoundryWebEndpointServletHandlerMapping.class);
|
||||
@@ -70,7 +72,10 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebEndpointSe
|
||||
|
||||
private final EndpointLinksResolver endpointLinksResolver = new EndpointLinksResolver();
|
||||
|
||||
CloudFoundryWebEndpointServletHandlerMapping(String endpointPath, Collection<EndpointInfo<WebEndpointOperation>> webEndpoints, CorsConfiguration corsConfiguration, CloudFoundrySecurityInterceptor securityInterceptor) {
|
||||
CloudFoundryWebEndpointServletHandlerMapping(String endpointPath,
|
||||
Collection<EndpointInfo<WebEndpointOperation>> webEndpoints,
|
||||
CorsConfiguration corsConfiguration,
|
||||
CloudFoundrySecurityInterceptor securityInterceptor) {
|
||||
super(endpointPath, webEndpoints, corsConfiguration);
|
||||
this.securityInterceptor = securityInterceptor;
|
||||
}
|
||||
@@ -81,27 +86,32 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebEndpointSe
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
private Map<String, Map<String, Link>> links(HttpServletRequest request, HttpServletResponse response) {
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse securityResponse = this.securityInterceptor.preHandle(request, "");
|
||||
private Map<String, Map<String, Link>> links(HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse securityResponse = this.securityInterceptor
|
||||
.preHandle(request, "");
|
||||
if (!securityResponse.getStatus().equals(HttpStatus.OK)) {
|
||||
sendFailureResponse(response, securityResponse);
|
||||
}
|
||||
AccessLevel accessLevel = AccessLevel.get(request);
|
||||
Map<String, Link> links = this.endpointLinksResolver
|
||||
.resolveLinks(getEndpoints(), request.getRequestURL().toString());
|
||||
Map<String, Link> links = this.endpointLinksResolver.resolveLinks(getEndpoints(),
|
||||
request.getRequestURL().toString());
|
||||
Map<String, Link> filteredLinks = new LinkedHashMap<>();
|
||||
if (accessLevel == null) {
|
||||
return Collections.singletonMap("_links", filteredLinks);
|
||||
}
|
||||
filteredLinks = links.entrySet().stream()
|
||||
.filter(e -> e.getKey().equals("self") || accessLevel.isAccessAllowed(e.getKey()))
|
||||
.filter(e -> e.getKey().equals("self")
|
||||
|| accessLevel.isAccessAllowed(e.getKey()))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
return Collections.singletonMap("_links", filteredLinks);
|
||||
}
|
||||
|
||||
private void sendFailureResponse(HttpServletResponse response, CloudFoundrySecurityInterceptor.SecurityResponse securityResponse) {
|
||||
private void sendFailureResponse(HttpServletResponse response,
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse securityResponse) {
|
||||
try {
|
||||
response.sendError(securityResponse.getStatus().value(), securityResponse.getMessage());
|
||||
response.sendError(securityResponse.getStatus().value(),
|
||||
securityResponse.getMessage());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.debug("Failed to send error response", ex);
|
||||
@@ -111,7 +121,9 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebEndpointSe
|
||||
@Override
|
||||
protected void registerMappingForOperation(WebEndpointOperation operation) {
|
||||
registerMapping(createRequestMappingInfo(operation),
|
||||
new OperationHandler(operation.getInvoker(), operation.getId(), this.securityInterceptor), this.handle);
|
||||
new OperationHandler(operation.getInvoker(), operation.getId(),
|
||||
this.securityInterceptor),
|
||||
this.handle);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,7 +137,8 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebEndpointSe
|
||||
|
||||
private final CloudFoundrySecurityInterceptor securityInterceptor;
|
||||
|
||||
OperationHandler(OperationInvoker operationInvoker, String id, CloudFoundrySecurityInterceptor securityInterceptor) {
|
||||
OperationHandler(OperationInvoker operationInvoker, String id,
|
||||
CloudFoundrySecurityInterceptor securityInterceptor) {
|
||||
this.operationInvoker = operationInvoker;
|
||||
this.endpointId = id;
|
||||
this.securityInterceptor = securityInterceptor;
|
||||
@@ -135,7 +148,8 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebEndpointSe
|
||||
@ResponseBody
|
||||
public Object handle(HttpServletRequest request,
|
||||
@RequestBody(required = false) Map<String, String> body) {
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse securityResponse = this.securityInterceptor.preHandle(request, this.endpointId);
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse securityResponse = this.securityInterceptor
|
||||
.preHandle(request, this.endpointId);
|
||||
if (!securityResponse.getStatus().equals(HttpStatus.OK)) {
|
||||
return failureResponse(securityResponse);
|
||||
}
|
||||
@@ -155,8 +169,10 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebEndpointSe
|
||||
}
|
||||
}
|
||||
|
||||
private Object failureResponse(CloudFoundrySecurityInterceptor.SecurityResponse response) {
|
||||
return handleResult(new WebEndpointResponse<>(response.getMessage(), response.getStatus().value()));
|
||||
private Object failureResponse(
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response) {
|
||||
return handleResult(new WebEndpointResponse<>(response.getMessage(),
|
||||
response.getStatus().value()));
|
||||
}
|
||||
|
||||
private Object handleResult(Object result) {
|
||||
@@ -179,4 +195,3 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebEndpointSe
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -91,4 +91,3 @@ class SkipSslVerificationHttpRequestFactory extends SimpleClientHttpRequestFacto
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -123,4 +123,3 @@ class Token {
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -139,4 +139,3 @@ class TokenValidator {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -32,7 +32,7 @@ import java.util.regex.PatternSyntaxException;
|
||||
* @author Phillip Webb
|
||||
* @author Sergei Egorov
|
||||
* @author Andy Wilkinson
|
||||
* @since 2.0.0
|
||||
* @author Dylian Bego
|
||||
*/
|
||||
abstract class NamePatternFilter<T> {
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package org.springframework.boot.actuate.endpoint.web;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.management.ManagementFactory;
|
||||
@@ -206,12 +208,7 @@ public class HeapDumpWebEndpoint {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
readableChannel.close();
|
||||
}
|
||||
finally {
|
||||
deleteFile();
|
||||
}
|
||||
closeThenDeleteFile(readableChannel);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -224,62 +221,25 @@ public class HeapDumpWebEndpoint {
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
InputStream delegate = super.getInputStream();
|
||||
return new InputStream() {
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return delegate.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
return delegate.read(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
return delegate.read(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
return delegate.skip(n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return delegate.available();
|
||||
}
|
||||
return new FilterInputStream(super.getInputStream()) {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
delegate.close();
|
||||
}
|
||||
finally {
|
||||
deleteFile();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void mark(int readlimit) {
|
||||
delegate.mark(readlimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void reset() throws IOException {
|
||||
delegate.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean markSupported() {
|
||||
return delegate.markSupported();
|
||||
closeThenDeleteFile(this.in);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private void closeThenDeleteFile(Closeable closeable) throws IOException {
|
||||
try {
|
||||
closeable.close();
|
||||
}
|
||||
finally {
|
||||
deleteFile();
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteFile() {
|
||||
try {
|
||||
Files.delete(getFile().toPath());
|
||||
|
||||
@@ -35,8 +35,7 @@ public class HealthIndicatorFactory {
|
||||
* @return a {@link HealthIndicator} that delegates to the specified
|
||||
* {@code healthIndicators}.
|
||||
*/
|
||||
public HealthIndicator createHealthIndicator(
|
||||
HealthAggregator healthAggregator,
|
||||
public HealthIndicator createHealthIndicator(HealthAggregator healthAggregator,
|
||||
Map<String, HealthIndicator> healthIndicators) {
|
||||
Assert.notNull(healthAggregator, "HealthAggregator must not be null");
|
||||
Assert.notNull(healthIndicators, "HealthIndicators must not be null");
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -118,10 +118,9 @@ public class ConditionalOnEnabledEndpointTests {
|
||||
|
||||
@Test
|
||||
public void disabledEvenWithEnabledGeneralProperties() {
|
||||
this.contextRunner.withUserConfiguration(FooConfig.class)
|
||||
.withPropertyValues("endpoints.default.enabled=true",
|
||||
"endpoints.default.web.enabled=true",
|
||||
"endpoints.default.jmx.enabled=true", "endpoints.foo.enabled=false")
|
||||
this.contextRunner.withUserConfiguration(FooConfig.class).withPropertyValues(
|
||||
"endpoints.default.enabled=true", "endpoints.default.web.enabled=true",
|
||||
"endpoints.default.jmx.enabled=true", "endpoints.foo.enabled=false")
|
||||
.run((context) -> assertThat(context).doesNotHaveBean("foo"));
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,8 @@ public class DefaultEndpointObjectNameFactoryTests {
|
||||
|
||||
private final MockEnvironment environment = new MockEnvironment();
|
||||
|
||||
private final JmxEndpointExporterProperties properties = new JmxEndpointExporterProperties(this.environment);
|
||||
private final JmxEndpointExporterProperties properties = new JmxEndpointExporterProperties(
|
||||
this.environment);
|
||||
|
||||
private final MBeanServer mBeanServer = mock(MBeanServer.class);
|
||||
|
||||
@@ -50,23 +51,23 @@ public class DefaultEndpointObjectNameFactoryTests {
|
||||
@Test
|
||||
public void generateObjectName() {
|
||||
ObjectName objectName = generateObjectName(endpoint("Test"));
|
||||
assertThat(objectName.toString()).isEqualTo(
|
||||
"org.springframework.boot:type=Endpoint,name=Test");
|
||||
assertThat(objectName.toString())
|
||||
.isEqualTo("org.springframework.boot:type=Endpoint,name=Test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateObjectNameWithCapitalizedId() {
|
||||
ObjectName objectName = generateObjectName(endpoint("test"));
|
||||
assertThat(objectName.toString()).isEqualTo(
|
||||
"org.springframework.boot:type=Endpoint,name=Test");
|
||||
assertThat(objectName.toString())
|
||||
.isEqualTo("org.springframework.boot:type=Endpoint,name=Test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateObjectNameWithCustomDomain() {
|
||||
this.properties.setDomain("com.example.acme");
|
||||
ObjectName objectName = generateObjectName(endpoint("test"));
|
||||
assertThat(objectName.toString()).isEqualTo(
|
||||
"com.example.acme:type=Endpoint,name=Test");
|
||||
assertThat(objectName.toString())
|
||||
.isEqualTo("com.example.acme:type=Endpoint,name=Test");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -86,17 +87,18 @@ public class DefaultEndpointObjectNameFactoryTests {
|
||||
ObjectName objectName = generateObjectName(endpoint("test"));
|
||||
assertThat(objectName.getKeyProperty("counter")).isEqualTo("42");
|
||||
assertThat(objectName.getKeyProperty("foo")).isEqualTo("bar");
|
||||
assertThat(objectName.toString()).startsWith(
|
||||
"org.springframework.boot:type=Endpoint,name=Test,");
|
||||
assertThat(objectName.toString())
|
||||
.startsWith("org.springframework.boot:type=Endpoint,name=Test,");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateObjectNameWithDuplicate() throws MalformedObjectNameException {
|
||||
this.contextId = "testContext";
|
||||
given(this.mBeanServer.queryNames(new ObjectName(
|
||||
"org.springframework.boot:type=Endpoint,name=Test,*"), null))
|
||||
.willReturn(Collections.singleton(
|
||||
new ObjectName("org.springframework.boot:type=Endpoint,name=Test")));
|
||||
given(this.mBeanServer.queryNames(
|
||||
new ObjectName("org.springframework.boot:type=Endpoint,name=Test,*"),
|
||||
null)).willReturn(
|
||||
Collections.singleton(new ObjectName(
|
||||
"org.springframework.boot:type=Endpoint,name=Test")));
|
||||
ObjectName objectName = generateObjectName(endpoint("test"));
|
||||
assertThat(objectName.toString()).isEqualTo(
|
||||
"org.springframework.boot:type=Endpoint,name=Test,context=testContext");
|
||||
|
||||
@@ -57,25 +57,18 @@ public class WebMvcEndpointInfrastructureAutoConfigurationTests {
|
||||
@Test
|
||||
public void webEndpointsAreDisabledByDefault() {
|
||||
this.contextRunner.run(context -> {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/autoconfig"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/beans")).isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/configprops"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/env")).isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/health"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/info")).isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/mappings"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/metrics"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.POST, "/application/shutdown"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/threaddump"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/trace")).isFalse();
|
||||
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).build();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "autoconfig")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "beans")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "configprops")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "env")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "health")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "metrics")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "trace")).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -84,60 +77,45 @@ public class WebMvcEndpointInfrastructureAutoConfigurationTests {
|
||||
WebApplicationContextRunner contextRunner = this.contextRunner
|
||||
.withPropertyValues("endpoints.default.web.enabled=true");
|
||||
contextRunner.run(context -> {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/autoconfig"))
|
||||
.isTrue();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/beans"))
|
||||
.isTrue();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/configprops"))
|
||||
.isTrue();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/env")).isTrue();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/health"))
|
||||
.isTrue();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/info")).isTrue();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/mappings"))
|
||||
.isTrue();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/metrics"))
|
||||
.isTrue();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.POST, "/application/shutdown"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/threaddump"))
|
||||
.isTrue();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/trace"))
|
||||
.isTrue();
|
||||
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).build();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "autoconfig")).isTrue();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "beans")).isTrue();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "configprops")).isTrue();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "env")).isTrue();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "health")).isTrue();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isTrue();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isTrue();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "metrics")).isTrue();
|
||||
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isTrue();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "trace")).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleWebEndpointCanBeEnabled() {
|
||||
WebApplicationContextRunner contextRunner = this.contextRunner.withPropertyValues(
|
||||
"endpoints.default.web.enabled=false", "endpoints.beans.web.enabled=true");
|
||||
"endpoints.default.web.enabled=false",
|
||||
"endpoints.beans.web.enabled=true");
|
||||
contextRunner.run((context) -> {
|
||||
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/autoconfig"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/beans")).isTrue();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/configprops"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/env")).isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/health"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/info")).isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/mappings"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/metrics"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.POST, "/application/shutdown"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/threaddump"))
|
||||
.isFalse();
|
||||
assertThat(isExposed(mockMvc, HttpMethod.GET, "/application/trace"))
|
||||
.isFalse();
|
||||
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).build();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "autoconfig")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "beans")).isTrue();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "configprops")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "env")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "health")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "info")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "mappings")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "metrics")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.POST, "shutdown")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "threaddump")).isFalse();
|
||||
assertThat(isExposed(mvc, HttpMethod.GET, "trace")).isFalse();
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isExposed(MockMvc mockMvc, HttpMethod method, String path)
|
||||
throws Exception {
|
||||
path = "/application/" + path;
|
||||
MvcResult mvcResult = mockMvc.perform(request(method, path)).andReturn();
|
||||
int status = mvcResult.getResponse().getStatus();
|
||||
if (status == HttpStatus.SC_OK) {
|
||||
|
||||
@@ -254,9 +254,8 @@ public class EndpointEnablementProviderTests {
|
||||
|
||||
@Test
|
||||
public void specificEnabledOverrideHasNoEffectWithUnrelatedTechProperty() {
|
||||
validate(
|
||||
getEndpointEnablement("foo", true, EndpointExposure.JMX,
|
||||
"endpoints.default.enabled=false", "endpoints.default.web.enabled=true"),
|
||||
validate(getEndpointEnablement("foo", true, EndpointExposure.JMX,
|
||||
"endpoints.default.enabled=false", "endpoints.default.web.enabled=true"),
|
||||
false, "found property endpoints.default.enabled");
|
||||
}
|
||||
|
||||
@@ -264,8 +263,8 @@ public class EndpointEnablementProviderTests {
|
||||
public void specificDisabledWithEndpointPropertyEvenWithEnabledGeneralProperties() {
|
||||
EndpointEnablement enablement = getEndpointEnablement("foo", true,
|
||||
EndpointExposure.WEB, "endpoints.default.enabled=true",
|
||||
"endpoints.default.web.enabled=true", "endpoints.default.jmx.enabled=true",
|
||||
"endpoints.foo.enabled=false");
|
||||
"endpoints.default.web.enabled=true",
|
||||
"endpoints.default.jmx.enabled=true", "endpoints.foo.enabled=false");
|
||||
validate(enablement, false, "found property endpoints.foo.enabled");
|
||||
}
|
||||
|
||||
@@ -273,8 +272,9 @@ public class EndpointEnablementProviderTests {
|
||||
public void specificDisabledWithTechPropertyEvenWithEnabledGeneralProperties() {
|
||||
EndpointEnablement enablement = getEndpointEnablement("foo", true,
|
||||
EndpointExposure.WEB, "endpoints.default.enabled=true",
|
||||
"endpoints.default.web.enabled=true", "endpoints.default.jmx.enabled=true",
|
||||
"endpoints.foo.enabled=true", "endpoints.foo.web.enabled=false");
|
||||
"endpoints.default.web.enabled=true",
|
||||
"endpoints.default.jmx.enabled=true", "endpoints.foo.enabled=true",
|
||||
"endpoints.foo.web.enabled=false");
|
||||
validate(enablement, false, "found property endpoints.foo.web.enabled");
|
||||
}
|
||||
|
||||
|
||||
@@ -73,9 +73,7 @@ public class WebEndpointManagementContextConfigurationTests {
|
||||
contextRunner.run((context) -> {
|
||||
HealthWebEndpointExtension extension = context
|
||||
.getBean(HealthWebEndpointExtension.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Integer> statusMappings = ((HealthStatusHttpMapper) ReflectionTestUtils
|
||||
.getField(extension, "statusHttpMapper")).getStatusMapping();
|
||||
Map<String, Integer> statusMappings = getStatusMapping(extension);
|
||||
assertThat(statusMappings).containsEntry("DOWN", 503);
|
||||
assertThat(statusMappings).containsEntry("OUT_OF_SERVICE", 503);
|
||||
assertThat(statusMappings).containsEntry("CUSTOM", 500);
|
||||
@@ -102,9 +100,7 @@ public class WebEndpointManagementContextConfigurationTests {
|
||||
contextRunner.run((context) -> {
|
||||
StatusWebEndpointExtension extension = context
|
||||
.getBean(StatusWebEndpointExtension.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Integer> statusMappings = ((HealthStatusHttpMapper) ReflectionTestUtils
|
||||
.getField(extension, "statusHttpMapper")).getStatusMapping();
|
||||
Map<String, Integer> statusMappings = getStatusMapping(extension);
|
||||
assertThat(statusMappings).containsEntry("DOWN", 503);
|
||||
assertThat(statusMappings).containsEntry("OUT_OF_SERVICE", 503);
|
||||
assertThat(statusMappings).containsEntry("CUSTOM", 500);
|
||||
@@ -161,8 +157,7 @@ public class WebEndpointManagementContextConfigurationTests {
|
||||
}
|
||||
|
||||
private void beanIsAutoConfigured(Class<?> beanType, Class<?>... config) {
|
||||
contextRunner()
|
||||
.withPropertyValues("endpoints.default.web.enabled:true")
|
||||
contextRunner().withPropertyValues("endpoints.default.web.enabled:true")
|
||||
.withUserConfiguration(config)
|
||||
.run((context) -> assertThat(context).hasSingleBean(beanType));
|
||||
}
|
||||
@@ -178,6 +173,11 @@ public class WebEndpointManagementContextConfigurationTests {
|
||||
AutoConfigurations.of(WebEndpointManagementContextConfiguration.class));
|
||||
}
|
||||
|
||||
private Map<String, Integer> getStatusMapping(Object extension) {
|
||||
return ((HealthStatusHttpMapper) ReflectionTestUtils.getField(extension,
|
||||
"statusHttpMapper")).getStatusMapping();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class HealthEndpointConfiguration {
|
||||
|
||||
|
||||
@@ -63,28 +63,30 @@ public class JolokiaManagementContextConfigurationTests {
|
||||
|
||||
@Test
|
||||
public void customPath() {
|
||||
this.contextRunner.withPropertyValues("management.jolokia.enabled=true",
|
||||
"management.jolokia.path=/lokia").run(
|
||||
isDefinedOnPath("/application/lokia/*"));
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.jolokia.enabled=true",
|
||||
"management.jolokia.path=/lokia")
|
||||
.run(isDefinedOnPath("/application/lokia/*"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customManagementPath() {
|
||||
this.contextRunner.withPropertyValues("management.jolokia.enabled=true",
|
||||
"management.context-path=/admin").run(
|
||||
isDefinedOnPath("/admin/jolokia/*"));
|
||||
this.contextRunner
|
||||
.withPropertyValues("management.jolokia.enabled=true",
|
||||
"management.context-path=/admin")
|
||||
.run(isDefinedOnPath("/admin/jolokia/*"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customInitParameters() {
|
||||
this.contextRunner.withPropertyValues("management.jolokia.enabled=true",
|
||||
"management.jolokia.config.debug=true").run((context) -> {
|
||||
assertThat(context).hasSingleBean(ServletRegistrationBean.class);
|
||||
ServletRegistrationBean<?> registrationBean = context
|
||||
.getBean(ServletRegistrationBean.class);
|
||||
assertThat(registrationBean.getInitParameters())
|
||||
.containsOnly(entry("debug", "true"));
|
||||
});
|
||||
assertThat(context).hasSingleBean(ServletRegistrationBean.class);
|
||||
ServletRegistrationBean<?> registrationBean = context
|
||||
.getBean(ServletRegistrationBean.class);
|
||||
assertThat(registrationBean.getInitParameters())
|
||||
.containsOnly(entry("debug", "true"));
|
||||
});
|
||||
}
|
||||
|
||||
private ContextConsumer<AssertableWebApplicationContext> isDefinedOnPath(
|
||||
|
||||
@@ -385,8 +385,10 @@ public class MetricFilterAutoConfigurationTests {
|
||||
public void doesNotRecordRolledUpMetricsIfConfigured() throws Exception {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(Config.class, MetricFilterAutoConfiguration.class);
|
||||
TestPropertyValues.of("management.metrics.filter.gauge-submissions=",
|
||||
"management.metrics.filter.counter-submissions=").applyTo(context);
|
||||
TestPropertyValues
|
||||
.of("management.metrics.filter.gauge-submissions=",
|
||||
"management.metrics.filter.counter-submissions=")
|
||||
.applyTo(context);
|
||||
context.refresh();
|
||||
Filter filter = context.getBean(Filter.class);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/test/path");
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
@@ -39,11 +39,10 @@ final class AuthorizationExceptionMatcher {
|
||||
public boolean matches(Object object) {
|
||||
return ((object instanceof CloudFoundryAuthorizationException)
|
||||
&& ((CloudFoundryAuthorizationException) object)
|
||||
.getReason() == reason);
|
||||
.getReason() == reason);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -59,8 +59,7 @@ public class CloudFoundryActuatorAutoConfigurationTests {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class,
|
||||
JacksonAutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class,
|
||||
@@ -80,7 +79,8 @@ public class CloudFoundryActuatorAutoConfigurationTests {
|
||||
@Test
|
||||
public void cloudFoundryPlatformActive() throws Exception {
|
||||
CloudFoundryWebEndpointServletHandlerMapping handlerMapping = getHandlerMapping();
|
||||
assertThat(handlerMapping.getEndpointPath()).isEqualTo("/cloudfoundryapplication");
|
||||
assertThat(handlerMapping.getEndpointPath())
|
||||
.isEqualTo("/cloudfoundryapplication");
|
||||
CorsConfiguration corsConfiguration = (CorsConfiguration) ReflectionTestUtils
|
||||
.getField(handlerMapping, "corsConfiguration");
|
||||
assertThat(corsConfiguration.getAllowedOrigins()).contains("*");
|
||||
@@ -136,9 +136,9 @@ public class CloudFoundryActuatorAutoConfigurationTests {
|
||||
.of("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id")
|
||||
.applyTo(this.context);
|
||||
this.context.refresh();
|
||||
CloudFoundryWebEndpointServletHandlerMapping handlerMapping = this.context.getBean(
|
||||
"cloudFoundryWebEndpointServletHandlerMapping",
|
||||
CloudFoundryWebEndpointServletHandlerMapping.class);
|
||||
CloudFoundryWebEndpointServletHandlerMapping handlerMapping = this.context
|
||||
.getBean("cloudFoundryWebEndpointServletHandlerMapping",
|
||||
CloudFoundryWebEndpointServletHandlerMapping.class);
|
||||
Object securityInterceptor = ReflectionTestUtils.getField(handlerMapping,
|
||||
"securityInterceptor");
|
||||
Object interceptorSecurityService = ReflectionTestUtils
|
||||
@@ -152,7 +152,8 @@ public class CloudFoundryActuatorAutoConfigurationTests {
|
||||
.of("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id")
|
||||
.applyTo(this.context);
|
||||
this.context.refresh();
|
||||
FilterChainProxy securityFilterChain = (FilterChainProxy) this.context.getBean("springSecurityFilterChain");
|
||||
FilterChainProxy securityFilterChain = (FilterChainProxy) this.context
|
||||
.getBean("springSecurityFilterChain");
|
||||
SecurityFilterChain chain = securityFilterChain.getFilterChains().get(0);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/cloudfoundryapplication/my-path");
|
||||
@@ -165,8 +166,9 @@ public class CloudFoundryActuatorAutoConfigurationTests {
|
||||
@Test
|
||||
public void cloudFoundryPlatformInactive() throws Exception {
|
||||
this.context.refresh();
|
||||
assertThat(this.context.containsBean("cloudFoundryWebEndpointServletHandlerMapping"))
|
||||
.isFalse();
|
||||
assertThat(
|
||||
this.context.containsBean("cloudFoundryWebEndpointServletHandlerMapping"))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@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.
|
||||
|
||||
@@ -23,8 +23,6 @@ import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.BDDMockito;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.boot.endpoint.CachingConfiguration;
|
||||
import org.springframework.boot.endpoint.ConversionServiceOperationParameterMapper;
|
||||
@@ -52,39 +50,40 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.willThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Integration tests for web endpoints exposed using Spring MVC
|
||||
* on CloudFoundry.
|
||||
* Integration tests for web endpoints exposed using Spring MVC on CloudFoundry.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class CloudFoundryMvcWebEndpointIntegrationTests {
|
||||
|
||||
private static TokenValidator tokenValidator = Mockito.mock(TokenValidator.class);
|
||||
private static TokenValidator tokenValidator = mock(TokenValidator.class);
|
||||
|
||||
private static CloudFoundrySecurityService securityService = Mockito.mock(CloudFoundrySecurityService.class);
|
||||
private static CloudFoundrySecurityService securityService = mock(
|
||||
CloudFoundrySecurityService.class);
|
||||
|
||||
@Test
|
||||
public void operationWithSecurityInterceptorForbidden() throws Exception {
|
||||
BDDMockito.doNothing().when(tokenValidator).validate(any());
|
||||
given(securityService.getAccessLevel(any(), eq("app-id"))).willReturn(AccessLevel.RESTRICTED);
|
||||
given(securityService.getAccessLevel(any(), eq("app-id")))
|
||||
.willReturn(AccessLevel.RESTRICTED);
|
||||
load(TestEndpointConfiguration.class, (client) -> {
|
||||
client.get().uri("/cfApplication/test").accept(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "bearer " + mockAccessToken())
|
||||
.exchange().expectStatus().isEqualTo(HttpStatus.FORBIDDEN);
|
||||
.header("Authorization", "bearer " + mockAccessToken()).exchange()
|
||||
.expectStatus().isEqualTo(HttpStatus.FORBIDDEN);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void operationWithSecurityInterceptorSuccess() throws Exception {
|
||||
BDDMockito.doNothing().when(tokenValidator).validate(any());
|
||||
given(securityService.getAccessLevel(any(), eq("app-id"))).willReturn(AccessLevel.FULL);
|
||||
given(securityService.getAccessLevel(any(), eq("app-id")))
|
||||
.willReturn(AccessLevel.FULL);
|
||||
load(TestEndpointConfiguration.class, (client) -> {
|
||||
client.get().uri("/cfApplication/test").accept(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "bearer " + mockAccessToken())
|
||||
.exchange().expectStatus().isEqualTo(HttpStatus.OK);
|
||||
.header("Authorization", "bearer " + mockAccessToken()).exchange()
|
||||
.expectStatus().isEqualTo(HttpStatus.OK);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -103,14 +102,14 @@ public class CloudFoundryMvcWebEndpointIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void linksToOtherEndpointsWithFullAccess() {
|
||||
BDDMockito.doNothing().when(tokenValidator).validate(any());
|
||||
given(securityService.getAccessLevel(any(), eq("app-id"))).willReturn(AccessLevel.FULL);
|
||||
given(securityService.getAccessLevel(any(), eq("app-id")))
|
||||
.willReturn(AccessLevel.FULL);
|
||||
load(TestEndpointConfiguration.class,
|
||||
(client) -> client.get().uri("/cfApplication").accept(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "bearer " + mockAccessToken())
|
||||
.exchange().expectStatus().isOk().expectBody()
|
||||
.jsonPath("_links.length()").isEqualTo(5)
|
||||
.jsonPath("_links.self.href").isNotEmpty()
|
||||
(client) -> client.get().uri("/cfApplication")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "bearer " + mockAccessToken()).exchange()
|
||||
.expectStatus().isOk().expectBody().jsonPath("_links.length()")
|
||||
.isEqualTo(5).jsonPath("_links.self.href").isNotEmpty()
|
||||
.jsonPath("_links.self.templated").isEqualTo(false)
|
||||
.jsonPath("_links.info.href").isNotEmpty()
|
||||
.jsonPath("_links.info.templated").isEqualTo(false)
|
||||
@@ -124,33 +123,35 @@ public class CloudFoundryMvcWebEndpointIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void linksToOtherEndpointsForbidden() {
|
||||
CloudFoundryAuthorizationException exception = new CloudFoundryAuthorizationException(CloudFoundryAuthorizationException.Reason.INVALID_TOKEN, "invalid-token");
|
||||
BDDMockito.doThrow(exception).when(tokenValidator).validate(any());
|
||||
CloudFoundryAuthorizationException exception = new CloudFoundryAuthorizationException(
|
||||
CloudFoundryAuthorizationException.Reason.INVALID_TOKEN, "invalid-token");
|
||||
willThrow(exception).given(tokenValidator).validate(any());
|
||||
load(TestEndpointConfiguration.class,
|
||||
(client) -> client.get().uri("/cfApplication").accept(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "bearer " + mockAccessToken())
|
||||
.exchange().expectStatus().isUnauthorized());
|
||||
(client) -> client.get().uri("/cfApplication")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "bearer " + mockAccessToken()).exchange()
|
||||
.expectStatus().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linksToOtherEndpointsWithRestrictedAccess() {
|
||||
BDDMockito.doNothing().when(tokenValidator).validate(any());
|
||||
given(securityService.getAccessLevel(any(), eq("app-id"))).willReturn(AccessLevel.RESTRICTED);
|
||||
given(securityService.getAccessLevel(any(), eq("app-id")))
|
||||
.willReturn(AccessLevel.RESTRICTED);
|
||||
load(TestEndpointConfiguration.class,
|
||||
(client) -> client.get().uri("/cfApplication").accept(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "bearer " + mockAccessToken())
|
||||
.exchange().expectStatus().isOk().expectBody()
|
||||
.jsonPath("_links.length()").isEqualTo(2)
|
||||
.jsonPath("_links.self.href").isNotEmpty()
|
||||
(client) -> client.get().uri("/cfApplication")
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.header("Authorization", "bearer " + mockAccessToken()).exchange()
|
||||
.expectStatus().isOk().expectBody().jsonPath("_links.length()")
|
||||
.isEqualTo(2).jsonPath("_links.self.href").isNotEmpty()
|
||||
.jsonPath("_links.self.templated").isEqualTo(false)
|
||||
.jsonPath("_links.info.href").isNotEmpty()
|
||||
.jsonPath("_links.info.templated").isEqualTo(false)
|
||||
.jsonPath("_links.env").doesNotExist()
|
||||
.jsonPath("_links.test").doesNotExist()
|
||||
.jsonPath("_links.test-part").doesNotExist());
|
||||
.jsonPath("_links.env").doesNotExist().jsonPath("_links.test")
|
||||
.doesNotExist().jsonPath("_links.test-part").doesNotExist());
|
||||
}
|
||||
|
||||
private AnnotationConfigServletWebServerApplicationContext createApplicationContext(Class<?>... config) {
|
||||
private AnnotationConfigServletWebServerApplicationContext createApplicationContext(
|
||||
Class<?>... config) {
|
||||
return new AnnotationConfigServletWebServerApplicationContext(config);
|
||||
}
|
||||
|
||||
@@ -159,14 +160,13 @@ public class CloudFoundryMvcWebEndpointIntegrationTests {
|
||||
}
|
||||
|
||||
private void load(Class<?> configuration, Consumer<WebTestClient> clientConsumer) {
|
||||
BiConsumer<ApplicationContext, WebTestClient> consumer = (context, client) -> clientConsumer.accept(client);
|
||||
AnnotationConfigServletWebServerApplicationContext context = createApplicationContext(configuration, CloudFoundryMvcConfiguration.class);
|
||||
BiConsumer<ApplicationContext, WebTestClient> consumer = (context,
|
||||
client) -> clientConsumer.accept(client);
|
||||
AnnotationConfigServletWebServerApplicationContext context = createApplicationContext(
|
||||
configuration, CloudFoundryMvcConfiguration.class);
|
||||
try {
|
||||
consumer.accept(context,
|
||||
WebTestClient.bindToServer()
|
||||
.baseUrl(
|
||||
"http://localhost:" + getPort(context))
|
||||
.build());
|
||||
consumer.accept(context, WebTestClient.bindToServer()
|
||||
.baseUrl("http://localhost:" + getPort(context)).build());
|
||||
}
|
||||
finally {
|
||||
context.close();
|
||||
@@ -185,17 +185,20 @@ public class CloudFoundryMvcWebEndpointIntegrationTests {
|
||||
|
||||
@Bean
|
||||
public CloudFoundrySecurityInterceptor interceptor() {
|
||||
return new CloudFoundrySecurityInterceptor(tokenValidator, securityService, "app-id");
|
||||
return new CloudFoundrySecurityInterceptor(tokenValidator, securityService,
|
||||
"app-id");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CloudFoundryWebEndpointServletHandlerMapping cloudFoundryWebEndpointServletHandlerMapping(
|
||||
WebAnnotationEndpointDiscoverer webEndpointDiscoverer, CloudFoundrySecurityInterceptor interceptor) {
|
||||
WebAnnotationEndpointDiscoverer webEndpointDiscoverer,
|
||||
CloudFoundrySecurityInterceptor interceptor) {
|
||||
CorsConfiguration corsConfiguration = new CorsConfiguration();
|
||||
corsConfiguration.setAllowedOrigins(Arrays.asList("http://example.com"));
|
||||
corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST"));
|
||||
return new CloudFoundryWebEndpointServletHandlerMapping("/cfApplication",
|
||||
webEndpointDiscoverer.discoverEndpoints(), corsConfiguration, interceptor);
|
||||
webEndpointDiscoverer.discoverEndpoints(), corsConfiguration,
|
||||
interceptor);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -302,4 +305,3 @@ public class CloudFoundryMvcWebEndpointIntegrationTests {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -19,7 +19,6 @@ package org.springframework.boot.actuate.cloudfoundry;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.BDDMockito;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@@ -30,6 +29,7 @@ import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.util.Base64Utils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
@@ -62,13 +62,15 @@ public class CloudFoundrySecurityInterceptorTests {
|
||||
this.request.setMethod("OPTIONS");
|
||||
this.request.addHeader(HttpHeaders.ORIGIN, "http://example.com");
|
||||
this.request.addHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET");
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor.preHandle(this.request, "/a");
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor
|
||||
.preHandle(this.request, "/a");
|
||||
assertThat(response.getStatus()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preHandleWhenTokenIsMissingShouldReturnFalse() throws Exception {
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor.preHandle(this.request, "/a");
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor
|
||||
.preHandle(this.request, "/a");
|
||||
assertThat(response.getStatus())
|
||||
.isEqualTo(Reason.MISSING_AUTHORIZATION.getStatus());
|
||||
}
|
||||
@@ -76,7 +78,8 @@ public class CloudFoundrySecurityInterceptorTests {
|
||||
@Test
|
||||
public void preHandleWhenTokenIsNotBearerShouldReturnFalse() throws Exception {
|
||||
this.request.addHeader("Authorization", mockAccessToken());
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor.preHandle(this.request, "/a");
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor
|
||||
.preHandle(this.request, "/a");
|
||||
assertThat(response.getStatus())
|
||||
.isEqualTo(Reason.MISSING_AUTHORIZATION.getStatus());
|
||||
}
|
||||
@@ -86,7 +89,8 @@ public class CloudFoundrySecurityInterceptorTests {
|
||||
this.interceptor = new CloudFoundrySecurityInterceptor(this.tokenValidator,
|
||||
this.securityService, null);
|
||||
this.request.addHeader("Authorization", "bearer " + mockAccessToken());
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor.preHandle(this.request, "/a");
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor
|
||||
.preHandle(this.request, "/a");
|
||||
assertThat(response.getStatus())
|
||||
.isEqualTo(Reason.SERVICE_UNAVAILABLE.getStatus());
|
||||
}
|
||||
@@ -97,7 +101,8 @@ public class CloudFoundrySecurityInterceptorTests {
|
||||
this.interceptor = new CloudFoundrySecurityInterceptor(this.tokenValidator, null,
|
||||
"my-app-id");
|
||||
this.request.addHeader("Authorization", "bearer " + mockAccessToken());
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor.preHandle(this.request, "/a");
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor
|
||||
.preHandle(this.request, "/a");
|
||||
assertThat(response.getStatus())
|
||||
.isEqualTo(Reason.SERVICE_UNAVAILABLE.getStatus());
|
||||
}
|
||||
@@ -106,20 +111,21 @@ public class CloudFoundrySecurityInterceptorTests {
|
||||
public void preHandleWhenAccessIsNotAllowedShouldReturnFalse() throws Exception {
|
||||
String accessToken = mockAccessToken();
|
||||
this.request.addHeader("Authorization", "bearer " + accessToken);
|
||||
BDDMockito.given(this.securityService.getAccessLevel(accessToken, "my-app-id"))
|
||||
given(this.securityService.getAccessLevel(accessToken, "my-app-id"))
|
||||
.willReturn(AccessLevel.RESTRICTED);
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor.preHandle(this.request, "/a");
|
||||
assertThat(response.getStatus())
|
||||
.isEqualTo(Reason.ACCESS_DENIED.getStatus());
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor
|
||||
.preHandle(this.request, "/a");
|
||||
assertThat(response.getStatus()).isEqualTo(Reason.ACCESS_DENIED.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preHandleSuccessfulWithFullAccess() throws Exception {
|
||||
String accessToken = mockAccessToken();
|
||||
this.request.addHeader("Authorization", "Bearer " + accessToken);
|
||||
BDDMockito.given(this.securityService.getAccessLevel(accessToken, "my-app-id"))
|
||||
given(this.securityService.getAccessLevel(accessToken, "my-app-id"))
|
||||
.willReturn(AccessLevel.FULL);
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor.preHandle(this.request, "/a");
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor
|
||||
.preHandle(this.request, "/a");
|
||||
ArgumentCaptor<Token> tokenArgumentCaptor = ArgumentCaptor.forClass(Token.class);
|
||||
verify(this.tokenValidator).validate(tokenArgumentCaptor.capture());
|
||||
Token token = tokenArgumentCaptor.getValue();
|
||||
@@ -133,9 +139,10 @@ public class CloudFoundrySecurityInterceptorTests {
|
||||
public void preHandleSuccessfulWithRestrictedAccess() throws Exception {
|
||||
String accessToken = mockAccessToken();
|
||||
this.request.addHeader("Authorization", "Bearer " + accessToken);
|
||||
BDDMockito.given(this.securityService.getAccessLevel(accessToken, "my-app-id"))
|
||||
given(this.securityService.getAccessLevel(accessToken, "my-app-id"))
|
||||
.willReturn(AccessLevel.RESTRICTED);
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor.preHandle(this.request, "info");
|
||||
CloudFoundrySecurityInterceptor.SecurityResponse response = this.interceptor
|
||||
.preHandle(this.request, "info");
|
||||
ArgumentCaptor<Token> tokenArgumentCaptor = ArgumentCaptor.forClass(Token.class);
|
||||
verify(this.tokenValidator).validate(tokenArgumentCaptor.capture());
|
||||
Token token = tokenArgumentCaptor.getValue();
|
||||
|
||||
@@ -137,4 +137,3 @@ public class TokenTests {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -266,4 +266,3 @@ public class TokenValidatorTests {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ public class HealthEndpointTests {
|
||||
.withDetail("first", "1").build());
|
||||
healthIndicators.put("upAgain", () -> new Health.Builder().status(Status.UP)
|
||||
.withDetail("second", "2").build());
|
||||
HealthEndpoint endpoint = new HealthEndpoint(createHealthIndicator(
|
||||
healthIndicators));
|
||||
HealthEndpoint endpoint = new HealthEndpoint(
|
||||
createHealthIndicator(healthIndicators));
|
||||
Health health = endpoint.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(health.getDetails()).containsOnlyKeys("up", "upAgain");
|
||||
@@ -59,8 +59,8 @@ public class HealthEndpointTests {
|
||||
|
||||
private HealthIndicator createHealthIndicator(
|
||||
Map<String, HealthIndicator> healthIndicators) {
|
||||
return new HealthIndicatorFactory().createHealthIndicator(
|
||||
new OrderedHealthAggregator(), healthIndicators);
|
||||
return new HealthIndicatorFactory()
|
||||
.createHealthIndicator(new OrderedHealthAggregator(), healthIndicators);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,8 +43,8 @@ public class StatusEndpointTests {
|
||||
.withDetail("first", "1").build());
|
||||
healthIndicators.put("upAgain", () -> new Health.Builder().status(Status.UP)
|
||||
.withDetail("second", "2").build());
|
||||
StatusEndpoint endpoint = new StatusEndpoint(createHealthIndicator(
|
||||
healthIndicators));
|
||||
StatusEndpoint endpoint = new StatusEndpoint(
|
||||
createHealthIndicator(healthIndicators));
|
||||
Health health = endpoint.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(health.getDetails()).isEmpty();
|
||||
@@ -52,8 +52,8 @@ public class StatusEndpointTests {
|
||||
|
||||
private HealthIndicator createHealthIndicator(
|
||||
Map<String, HealthIndicator> healthIndicators) {
|
||||
return new HealthIndicatorFactory().createHealthIndicator(
|
||||
new OrderedHealthAggregator(), healthIndicators);
|
||||
return new HealthIndicatorFactory()
|
||||
.createHealthIndicator(new OrderedHealthAggregator(), healthIndicators);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -65,8 +65,7 @@ public class MvcEndpointCorsIntegrationTests {
|
||||
EndpointInfrastructureAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class, ManagementContextAutoConfiguration.class,
|
||||
ServletEndpointAutoConfiguration.class);
|
||||
TestPropertyValues.of("endpoints.default.web.enabled:true")
|
||||
.applyTo(this.context);
|
||||
TestPropertyValues.of("endpoints.default.web.enabled:true").applyTo(this.context);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -144,8 +143,10 @@ public class MvcEndpointCorsIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void allowedMethodsCanBeConfigured() throws Exception {
|
||||
TestPropertyValues.of("management.endpoints.cors.allowed-origins:foo.example.com",
|
||||
"management.endpoints.cors.allowed-methods:GET,HEAD").applyTo(this.context);
|
||||
TestPropertyValues
|
||||
.of("management.endpoints.cors.allowed-origins:foo.example.com",
|
||||
"management.endpoints.cors.allowed-methods:GET,HEAD")
|
||||
.applyTo(this.context);
|
||||
createMockMvc()
|
||||
.perform(options("/application/beans")
|
||||
.header(HttpHeaders.ORIGIN, "foo.example.com")
|
||||
@@ -156,16 +157,20 @@ public class MvcEndpointCorsIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void credentialsCanBeAllowed() throws Exception {
|
||||
TestPropertyValues.of("management.endpoints.cors.allowed-origins:foo.example.com",
|
||||
"management.endpoints.cors.allow-credentials:true").applyTo(this.context);
|
||||
TestPropertyValues
|
||||
.of("management.endpoints.cors.allowed-origins:foo.example.com",
|
||||
"management.endpoints.cors.allow-credentials:true")
|
||||
.applyTo(this.context);
|
||||
performAcceptedCorsRequest().andExpect(
|
||||
header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void credentialsCanBeDisabled() throws Exception {
|
||||
TestPropertyValues.of("management.endpoints.cors.allowed-origins:foo.example.com",
|
||||
"management.endpoints.cors.allow-credentials:false").applyTo(this.context);
|
||||
TestPropertyValues
|
||||
.of("management.endpoints.cors.allowed-origins:foo.example.com",
|
||||
"management.endpoints.cors.allow-credentials:false")
|
||||
.applyTo(this.context);
|
||||
performAcceptedCorsRequest().andExpect(
|
||||
header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS));
|
||||
}
|
||||
|
||||
@@ -69,8 +69,8 @@ public class MvcEndpointIntegrationTests {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.register(SecureConfiguration.class);
|
||||
MockMvc mockMvc = createSecureMockMvc();
|
||||
mockMvc.perform(get("/application/beans")
|
||||
.accept(MediaType.APPLICATION_JSON)).andExpect(status().isUnauthorized());
|
||||
mockMvc.perform(get("/application/beans").accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -80,8 +80,8 @@ public class MvcEndpointIntegrationTests {
|
||||
TestPropertyValues.of("management.context-path:/management")
|
||||
.applyTo(this.context);
|
||||
MockMvc mockMvc = createSecureMockMvc();
|
||||
mockMvc.perform(get("/management/beans")
|
||||
.accept(MediaType.APPLICATION_JSON)).andExpect(status().isUnauthorized());
|
||||
mockMvc.perform(get("/management/beans").accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -92,8 +92,7 @@ public class MvcEndpointIntegrationTests {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.register(SecureConfiguration.class);
|
||||
TestPropertyValues.of("management.context-path:/management",
|
||||
"endpoints.default.web.enabled=true")
|
||||
.applyTo(this.context);
|
||||
"endpoints.default.web.enabled=true").applyTo(this.context);
|
||||
MockMvc mockMvc = createSecureMockMvc();
|
||||
mockMvc.perform(get("/management/beans")).andExpect(status().isOk());
|
||||
}
|
||||
@@ -137,7 +136,7 @@ public class MvcEndpointIntegrationTests {
|
||||
}
|
||||
|
||||
@Import(DefaultConfiguration.class)
|
||||
@ImportAutoConfiguration({ SecurityAutoConfiguration.class})
|
||||
@ImportAutoConfiguration({ SecurityAutoConfiguration.class })
|
||||
static class SecureConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ public class StatusEndpointWebIntegrationTests {
|
||||
context.getBean("alphaHealthIndicator", TestHealthIndicator.class)
|
||||
.setHealth(Health.down().build());
|
||||
client.get().uri("/application/status").exchange().expectStatus()
|
||||
.isEqualTo(HttpStatus.SERVICE_UNAVAILABLE)
|
||||
.expectBody().json("{\"status\":\"DOWN\"}");
|
||||
.isEqualTo(HttpStatus.SERVICE_UNAVAILABLE).expectBody()
|
||||
.json("{\"status\":\"DOWN\"}");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
@@ -78,9 +78,8 @@ import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
|
||||
* The {@link PropertySource PropertySources} that belong to the application context's
|
||||
* {@link org.springframework.core.env.Environment} are reset at the end of every test.
|
||||
* This means that {@link TestPropertyValues} can be used in a test without affecting the
|
||||
* {@code Environment} of other tests in the same class.
|
||||
* The runner always sets the flag `endpoints.default.web.enabled` to true so that web
|
||||
* endpoints are enabled.
|
||||
* {@code Environment} of other tests in the same class. The runner always sets the flag
|
||||
* `endpoints.default.web.enabled` to true so that web endpoints are enabled.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@@ -266,7 +265,8 @@ public class WebEndpointsRunner extends Suite {
|
||||
private ReactiveWebEndpointsRunner(Class<?> klass) throws InitializationError {
|
||||
super(klass, "Reactive", (classes) -> {
|
||||
ReactiveWebServerApplicationContext context = new ReactiveWebServerApplicationContext();
|
||||
TestPropertyValues.of("endpoints.default.web.enabled:true").applyTo(context);
|
||||
TestPropertyValues.of("endpoints.default.web.enabled:true")
|
||||
.applyTo(context);
|
||||
classes.add(ReactiveInfrastructureConfiguration.class);
|
||||
context.register(classes.toArray(new Class<?>[classes.size()]));
|
||||
context.refresh();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -62,8 +62,8 @@ public class HealthIndicatorFactoryTests {
|
||||
|
||||
private HealthIndicator createHealthIndicator(
|
||||
Map<String, HealthIndicator> healthIndicators) {
|
||||
return new HealthIndicatorFactory().createHealthIndicator(
|
||||
new OrderedHealthAggregator(), healthIndicators);
|
||||
return new HealthIndicatorFactory()
|
||||
.createHealthIndicator(new OrderedHealthAggregator(), healthIndicators);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,12 +51,14 @@ public class RedisHealthIndicatorTests {
|
||||
|
||||
@Test
|
||||
public void indicatorExists() {
|
||||
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(
|
||||
RedisAutoConfiguration.class, EndpointAutoConfiguration.class,
|
||||
HealthIndicatorAutoConfiguration.class)).run((context) -> {
|
||||
assertThat(context).hasSingleBean(RedisConnectionFactory.class);
|
||||
assertThat(context).hasSingleBean(RedisHealthIndicator.class);
|
||||
});
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(RedisAutoConfiguration.class,
|
||||
EndpointAutoConfiguration.class,
|
||||
HealthIndicatorAutoConfiguration.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(RedisConnectionFactory.class);
|
||||
assertThat(context).hasSingleBean(RedisHealthIndicator.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -74,8 +76,8 @@ public class RedisHealthIndicatorTests {
|
||||
@Test
|
||||
public void redisIsDown() throws Exception {
|
||||
RedisConnection redisConnection = mock(RedisConnection.class);
|
||||
given(redisConnection.info()).willThrow(
|
||||
new RedisConnectionFailureException("Connection failed"));
|
||||
given(redisConnection.info())
|
||||
.willThrow(new RedisConnectionFailureException("Connection failed"));
|
||||
RedisHealthIndicator healthIndicator = createHealthIndicator(redisConnection);
|
||||
Health health = healthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
|
||||
@@ -83,9 +85,9 @@ public class RedisHealthIndicatorTests {
|
||||
.contains("Connection failed");
|
||||
}
|
||||
|
||||
private RedisHealthIndicator createHealthIndicator(
|
||||
RedisConnection redisConnection) {
|
||||
RedisConnectionFactory redisConnectionFactory = mock(RedisConnectionFactory.class);
|
||||
private RedisHealthIndicator createHealthIndicator(RedisConnection redisConnection) {
|
||||
RedisConnectionFactory redisConnectionFactory = mock(
|
||||
RedisConnectionFactory.class);
|
||||
given(redisConnectionFactory.getConnection()).willReturn(redisConnection);
|
||||
return new RedisHealthIndicator(redisConnectionFactory);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user