Polish
This commit is contained in:
parent
b02edd2e81
commit
2c97d3a5e9
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -50,12 +50,12 @@ import org.springframework.util.ReflectionUtils;
|
|||
|
||||
/**
|
||||
* Configuration for a Spring Security in-memory {@link AuthenticationManager}. Can be
|
||||
* disabled by providing a bean of type {@link AuthenticationManager}, {@link AuthenticationProvider}
|
||||
* or {@link UserDetailsService}. The value provided by this configuration will become the "global"
|
||||
* authentication manager (from Spring Security), or the parent of the global instance.
|
||||
* Thus it acts as a fallback when no others are provided, is used by method security if
|
||||
* enabled, and as a parent authentication manager for "local" authentication managers in
|
||||
* individual filter chains.
|
||||
* disabled by providing a bean of type {@link AuthenticationManager},
|
||||
* {@link AuthenticationProvider} or {@link UserDetailsService}. The value provided by
|
||||
* this configuration will become the "global" authentication manager (from Spring
|
||||
* Security), or the parent of the global instance. Thus it acts as a fallback when no
|
||||
* others are provided, is used by method security if enabled, and as a parent
|
||||
* authentication manager for "local" authentication managers in individual filter chains.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Rob Winch
|
||||
|
@ -63,8 +63,8 @@ import org.springframework.util.ReflectionUtils;
|
|||
*/
|
||||
@Configuration
|
||||
@ConditionalOnBean(ObjectPostProcessor.class)
|
||||
@ConditionalOnMissingBean({ AuthenticationManager.class,
|
||||
AuthenticationProvider.class, UserDetailsService.class})
|
||||
@ConditionalOnMissingBean({ AuthenticationManager.class, AuthenticationProvider.class,
|
||||
UserDetailsService.class })
|
||||
@Order(0)
|
||||
public class AuthenticationManagerConfiguration {
|
||||
|
||||
|
@ -102,8 +102,8 @@ public class AuthenticationManagerConfiguration {
|
|||
* {@link GlobalAuthenticationConfigurerAdapter#init(AuthenticationManagerBuilder)}
|
||||
* exists that adds a {@link SecurityConfigurer} to the
|
||||
* {@link AuthenticationManagerBuilder}.</li>
|
||||
* <li>{@link AuthenticationManagerConfiguration}
|
||||
* adds {@link SpringBootAuthenticationConfigurerAdapter} so it is after the
|
||||
* <li>{@link AuthenticationManagerConfiguration} adds
|
||||
* {@link SpringBootAuthenticationConfigurerAdapter} so it is after the
|
||||
* {@link SecurityConfigurer} in the first step.</li>
|
||||
* <li>We then can default an {@link AuthenticationProvider} if necessary. Note we can
|
||||
* only invoke the
|
||||
|
@ -169,10 +169,9 @@ public class AuthenticationManagerConfiguration {
|
|||
return;
|
||||
}
|
||||
String password = UUID.randomUUID().toString();
|
||||
logger.info(String.format("%n%nUsing default security password: %s%n",
|
||||
password));
|
||||
withUser("user").password(password)
|
||||
.roles();
|
||||
logger.info(
|
||||
String.format("%n%nUsing default security password: %s%n", password));
|
||||
withUser("user").password(password).roles();
|
||||
setField(auth, "defaultUserDetailsService", getUserDetailsService());
|
||||
super.configure(auth);
|
||||
}
|
||||
|
|
|
@ -63,9 +63,11 @@ public class SecurityAutoConfiguration {
|
|||
}
|
||||
|
||||
@Bean
|
||||
public SpringBootSecurity springBootSecurity(EndpointPathResolver endpointPathResolver,
|
||||
public SpringBootSecurity springBootSecurity(
|
||||
EndpointPathResolver endpointPathResolver,
|
||||
ObjectProvider<ErrorController> errorController) {
|
||||
return new SpringBootSecurity(endpointPathResolver, errorController.getIfAvailable());
|
||||
return new SpringBootSecurity(endpointPathResolver,
|
||||
errorController.getIfAvailable());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
|
@ -73,8 +73,7 @@ public class SecurityFilterAutoConfiguration {
|
|||
return null;
|
||||
}
|
||||
return securityProperties.getFilterDispatcherTypes().stream()
|
||||
.map((type) -> DispatcherType.valueOf(type.name()))
|
||||
.collect(Collectors
|
||||
.map((type) -> DispatcherType.valueOf(type.name())).collect(Collectors
|
||||
.collectingAndThen(Collectors.toSet(), EnumSet::copyOf));
|
||||
}
|
||||
|
||||
|
|
|
@ -66,8 +66,8 @@ public class SecurityProperties implements SecurityPrerequisite {
|
|||
/**
|
||||
* Security filter chain dispatcher types.
|
||||
*/
|
||||
private Set<DispatcherType> filterDispatcherTypes = new HashSet<>(Arrays.asList(
|
||||
DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.REQUEST));
|
||||
private Set<DispatcherType> filterDispatcherTypes = new HashSet<>(Arrays
|
||||
.asList(DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.REQUEST));
|
||||
|
||||
public Basic getBasic() {
|
||||
return this.basic;
|
||||
|
|
|
@ -31,7 +31,6 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
|
|||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Provides request matchers that can be used to configure security for static resources
|
||||
* and the error controller path in a custom {@link WebSecurityConfigurerAdapter}.
|
||||
|
@ -68,8 +67,8 @@ public final class SpringBootSecurity {
|
|||
Assert.notEmpty(ids, "At least one endpoint id must be specified.");
|
||||
List<String> pathList = Arrays.asList(ids);
|
||||
if (pathList.contains(ALL_ENDPOINTS)) {
|
||||
return new AntPathRequestMatcher(this.endpointPathResolver.resolvePath(
|
||||
ALL_ENDPOINTS), null);
|
||||
return new AntPathRequestMatcher(
|
||||
this.endpointPathResolver.resolvePath(ALL_ENDPOINTS), null);
|
||||
}
|
||||
return getEndpointsRequestMatcher(pathList);
|
||||
}
|
||||
|
@ -140,4 +139,3 @@ public final class SpringBootSecurity {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -29,10 +29,10 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
|||
|
||||
/**
|
||||
* The default configuration for web security. It relies on Spring Security's
|
||||
* content-negotiation strategy to determine what sort of authentication to use.
|
||||
* If the user specifies their own {@link WebSecurityConfigurerAdapter}, this will
|
||||
* back-off completely and the users should specify all the bits that they want to
|
||||
* configure as part of the custom security configuration.
|
||||
* content-negotiation strategy to determine what sort of authentication to use. If the
|
||||
* user specifies their own {@link WebSecurityConfigurerAdapter}, this will back-off
|
||||
* completely and the users should specify all the bits that they want to configure as
|
||||
* part of the custom security configuration.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.0
|
||||
|
@ -52,6 +52,7 @@ public class SpringBootWebSecurityConfiguration {
|
|||
super.configure(http);
|
||||
http.csrf().disable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,5 +39,5 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
|||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@EnableWebSecurity
|
||||
public class WebSecurityEnablerConfiguration {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -86,7 +86,7 @@ public class OAuth2RestOperationsConfiguration {
|
|||
|
||||
@Configuration
|
||||
@ConditionalOnBean(OAuth2ClientConfiguration.class)
|
||||
@Conditional({OAuth2ClientIdCondition.class, NoClientCredentialsCondition.class})
|
||||
@Conditional({ OAuth2ClientIdCondition.class, NoClientCredentialsCondition.class })
|
||||
@Import(OAuth2ProtectedResourceDetailsConfiguration.class)
|
||||
protected static class SessionScopedConfiguration {
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -55,8 +55,7 @@ class SessionRepositoryFilterConfiguration {
|
|||
return null;
|
||||
}
|
||||
return servletProperties.getFilterDispatcherTypes().stream()
|
||||
.map((type) -> DispatcherType.valueOf(type.name()))
|
||||
.collect(Collectors
|
||||
.map((type) -> DispatcherType.valueOf(type.name())).collect(Collectors
|
||||
.collectingAndThen(Collectors.toSet(), EnumSet::copyOf));
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -95,8 +95,8 @@ public class FlywayAutoConfigurationTests {
|
|||
|
||||
@Test
|
||||
public void createDataSource() throws Exception {
|
||||
TestPropertyValues.of("spring.flyway.url:jdbc:hsqldb:mem:flywaytest", "spring.flyway.user:sa")
|
||||
.applyTo(this.context);
|
||||
TestPropertyValues.of("spring.flyway.url:jdbc:hsqldb:mem:flywaytest",
|
||||
"spring.flyway.user:sa").applyTo(this.context);
|
||||
registerAndRefresh(EmbeddedDataSourceConfiguration.class,
|
||||
FlywayAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
|
@ -162,7 +162,8 @@ public class FlywayAutoConfigurationTests {
|
|||
|
||||
@Test
|
||||
public void changeLogDoesNotExist() throws Exception {
|
||||
TestPropertyValues.of("spring.flyway.locations:file:no-such-dir").applyTo(this.context);
|
||||
TestPropertyValues.of("spring.flyway.locations:file:no-such-dir")
|
||||
.applyTo(this.context);
|
||||
this.thrown.expect(BeanCreationException.class);
|
||||
registerAndRefresh(EmbeddedDataSourceConfiguration.class,
|
||||
FlywayAutoConfiguration.class,
|
||||
|
|
|
@ -318,7 +318,8 @@ public class DataSourceAutoConfigurationTests {
|
|||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve)
|
||||
throws ClassNotFoundException {
|
||||
for (EmbeddedDatabaseConnection candidate : EmbeddedDatabaseConnection.values()) {
|
||||
for (EmbeddedDatabaseConnection candidate : EmbeddedDatabaseConnection
|
||||
.values()) {
|
||||
if (name.equals(candidate.getDriverClassName())) {
|
||||
throw new ClassNotFoundException();
|
||||
}
|
||||
|
@ -328,5 +329,4 @@ public class DataSourceAutoConfigurationTests {
|
|||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -160,7 +160,8 @@ public class LiquibaseAutoConfigurationTests {
|
|||
|
||||
@Test
|
||||
public void testOverrideDefaultSchema() throws Exception {
|
||||
TestPropertyValues.of("spring.liquibase.default-schema:public").applyTo(this.context);
|
||||
TestPropertyValues.of("spring.liquibase.default-schema:public")
|
||||
.applyTo(this.context);
|
||||
this.context.register(EmbeddedDataSourceConfiguration.class,
|
||||
LiquibaseAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
|
@ -182,9 +183,8 @@ public class LiquibaseAutoConfigurationTests {
|
|||
|
||||
@Test
|
||||
public void testOverrideDataSource() throws Exception {
|
||||
TestPropertyValues
|
||||
.of("spring.liquibase.url:jdbc:hsqldb:mem:liquibase", "spring.liquibase.user:sa")
|
||||
.applyTo(this.context);
|
||||
TestPropertyValues.of("spring.liquibase.url:jdbc:hsqldb:mem:liquibase",
|
||||
"spring.liquibase.user:sa").applyTo(this.context);
|
||||
this.context.register(EmbeddedDataSourceConfiguration.class,
|
||||
LiquibaseAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
|
@ -198,7 +198,8 @@ public class LiquibaseAutoConfigurationTests {
|
|||
|
||||
@Test(expected = BeanCreationException.class)
|
||||
public void testChangeLogDoesNotExist() throws Exception {
|
||||
TestPropertyValues.of("spring.liquibase.change-log:classpath:/no-such-changelog.yaml")
|
||||
TestPropertyValues
|
||||
.of("spring.liquibase.change-log:classpath:/no-such-changelog.yaml")
|
||||
.applyTo(this.context);
|
||||
this.context.register(EmbeddedDataSourceConfiguration.class,
|
||||
LiquibaseAutoConfiguration.class,
|
||||
|
@ -220,7 +221,8 @@ public class LiquibaseAutoConfigurationTests {
|
|||
|
||||
@Test
|
||||
public void testOverrideLabels() throws Exception {
|
||||
TestPropertyValues.of("spring.liquibase.labels:test, production").applyTo(this.context);
|
||||
TestPropertyValues.of("spring.liquibase.labels:test, production")
|
||||
.applyTo(this.context);
|
||||
this.context.register(EmbeddedDataSourceConfiguration.class,
|
||||
LiquibaseAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
|
@ -232,7 +234,8 @@ public class LiquibaseAutoConfigurationTests {
|
|||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testOverrideParameters() throws Exception {
|
||||
TestPropertyValues.of("spring.liquibase.parameters.foo:bar").applyTo(this.context);
|
||||
TestPropertyValues.of("spring.liquibase.parameters.foo:bar")
|
||||
.applyTo(this.context);
|
||||
this.context.register(EmbeddedDataSourceConfiguration.class,
|
||||
LiquibaseAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
|
|
|
@ -298,8 +298,8 @@ public class SecurityAutoConfigurationTests {
|
|||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(SecurityAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
String password = this.outputCapture.toString().split("Using default security password: ")[1]
|
||||
.split("\n")[0].trim();
|
||||
String password = this.outputCapture.toString()
|
||||
.split("Using default security password: ")[1].split("\n")[0].trim();
|
||||
AuthenticationManager manager = this.context.getBean(AuthenticationManager.class);
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
"user", password);
|
||||
|
@ -307,16 +307,17 @@ public class SecurityAutoConfigurationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testCustomAuthenticationDoesNotCreateDefaultUser()
|
||||
throws Exception {
|
||||
public void testCustomAuthenticationDoesNotCreateDefaultUser() throws Exception {
|
||||
this.context = new AnnotationConfigWebApplicationContext();
|
||||
this.context.setServletContext(new MockServletContext());
|
||||
this.context.register(AuthenticationManagerCustomizer.class,
|
||||
SecurityAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
AuthenticationManager manager = this.context.getBean(AuthenticationManager.class);
|
||||
assertThat(this.outputCapture.toString()).doesNotContain("Using default security password: ");
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("foo", "bar");
|
||||
assertThat(this.outputCapture.toString())
|
||||
.doesNotContain("Using default security password: ");
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
"foo", "bar");
|
||||
assertThat(manager.authenticate(token)).isNotNull();
|
||||
}
|
||||
|
||||
|
|
|
@ -61,13 +61,12 @@ public class SecurityFilterAutoConfigurationEarlyInitializationTests {
|
|||
@Test
|
||||
public void testSecurityFilterDoesNotCauseEarlyInitialization() throws Exception {
|
||||
try (AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext()) {
|
||||
TestPropertyValues.of("server.port:0")
|
||||
.applyTo(context);
|
||||
TestPropertyValues.of("server.port:0").applyTo(context);
|
||||
context.register(Config.class);
|
||||
context.refresh();
|
||||
int port = context.getWebServer().getPort();
|
||||
String password = this.outputCapture.toString().split("Using default security password: ")[1]
|
||||
.split("\n")[0].trim();
|
||||
String password = this.outputCapture.toString()
|
||||
.split("Using default security password: ")[1].split("\n")[0].trim();
|
||||
new TestRestTemplate("user", password)
|
||||
.getForEntity("http://localhost:" + port, Object.class);
|
||||
// If early initialization occurred a ConverterNotFoundException is thrown
|
||||
|
@ -80,8 +79,8 @@ public class SecurityFilterAutoConfigurationEarlyInitializationTests {
|
|||
ConverterBean.class })
|
||||
@ImportAutoConfiguration({ WebMvcAutoConfiguration.class,
|
||||
JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class,
|
||||
SecurityAutoConfiguration.class, SecurityFilterAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, SecurityAutoConfiguration.class,
|
||||
SecurityFilterAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
static class Config {
|
||||
|
||||
|
|
|
@ -46,15 +46,16 @@ public class SpringBootSecurityTests {
|
|||
|
||||
private MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
private static String[] STATIC_RESOURCES = new String[]{"/css/**", "/js/**",
|
||||
"/images/**", "/webjars/**", "/**/favicon.ico"};
|
||||
private static String[] STATIC_RESOURCES = new String[] { "/css/**", "/js/**",
|
||||
"/images/**", "/webjars/**", "/**/favicon.ico" };
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.bootSecurity = new SpringBootSecurity(this.endpointPathResolver, this.errorController);
|
||||
this.bootSecurity = new SpringBootSecurity(this.endpointPathResolver,
|
||||
this.errorController);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -65,7 +66,8 @@ public class SpringBootSecurityTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void endpointIdsShouldReturnRequestMatcherWithEndpointPaths() throws Exception {
|
||||
public void endpointIdsShouldReturnRequestMatcherWithEndpointPaths()
|
||||
throws Exception {
|
||||
RequestMatcher requestMatcher = this.bootSecurity.endpointIds("id-1", "id-2");
|
||||
assertThat(requestMatcher).isInstanceOf(OrRequestMatcher.class);
|
||||
this.request.setServletPath("/test/id-1");
|
||||
|
@ -77,8 +79,10 @@ public class SpringBootSecurityTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void endpointIdsShouldReturnRequestMatcherWithAllEndpointPaths() throws Exception {
|
||||
RequestMatcher requestMatcher = this.bootSecurity.endpointIds(SpringBootSecurity.ALL_ENDPOINTS);
|
||||
public void endpointIdsShouldReturnRequestMatcherWithAllEndpointPaths()
|
||||
throws Exception {
|
||||
RequestMatcher requestMatcher = this.bootSecurity
|
||||
.endpointIds(SpringBootSecurity.ALL_ENDPOINTS);
|
||||
this.request.setServletPath("/test/id-1");
|
||||
assertThat(requestMatcher.matches(this.request)).isTrue();
|
||||
this.request.setServletPath("/test/id-2");
|
||||
|
@ -112,7 +116,8 @@ public class SpringBootSecurityTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void staticResourcesShouldReturnRequestMatcherWithStaticResources() throws Exception {
|
||||
public void staticResourcesShouldReturnRequestMatcherWithStaticResources()
|
||||
throws Exception {
|
||||
RequestMatcher requestMatcher = this.bootSecurity.staticResources();
|
||||
assertThat(requestMatcher).isInstanceOf(OrRequestMatcher.class);
|
||||
for (String resource : STATIC_RESOURCES) {
|
||||
|
@ -122,7 +127,8 @@ public class SpringBootSecurityTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void errorShouldReturnRequestMatcherWithErrorControllerPath() throws Exception {
|
||||
public void errorShouldReturnRequestMatcherWithErrorControllerPath()
|
||||
throws Exception {
|
||||
RequestMatcher requestMatcher = this.bootSecurity.error();
|
||||
assertThat(requestMatcher).isInstanceOf(AntPathRequestMatcher.class);
|
||||
this.request.setServletPath("/test/error");
|
||||
|
@ -152,6 +158,7 @@ public class SpringBootSecurityTests {
|
|||
public String getErrorPath() {
|
||||
return "/test/error";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Endpoint(id = "id-1")
|
||||
|
@ -167,4 +174,5 @@ public class SpringBootSecurityTests {
|
|||
static class FakeEndpoint {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.junit.rules.ExpectedException;
|
|||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.MockServletWebServerFactory;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
|
@ -77,8 +78,7 @@ public class OAuth2RestOperationsConfigurationTests {
|
|||
TestPropertyValues.of("security.oauth2.client.client-id=acme")
|
||||
.applyTo(this.environment);
|
||||
initializeContext(ConfigForRequestScopedConfiguration.class, false);
|
||||
assertThat(this.context.containsBean("oauth2ClientContext"))
|
||||
.isTrue();
|
||||
assertThat(this.context.containsBean("oauth2ClientContext")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -93,8 +93,7 @@ public class OAuth2RestOperationsConfigurationTests {
|
|||
TestPropertyValues.of("security.oauth2.client.client-id=acme")
|
||||
.applyTo(this.environment);
|
||||
initializeContext(ConfigForSessionScopedConfiguration.class, false);
|
||||
assertThat(this.context.containsBean("oauth2ClientContext"))
|
||||
.isTrue();
|
||||
assertThat(this.context.containsBean("oauth2ClientContext")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -104,10 +103,11 @@ public class OAuth2RestOperationsConfigurationTests {
|
|||
this.context.getBean(DefaultOAuth2ClientContext.class);
|
||||
}
|
||||
|
||||
private void initializeContext(Class<?> configuration, boolean isClientCredentials) {
|
||||
private void initializeContext(Class<?> configuration, boolean clientCredentials) {
|
||||
this.context = new SpringApplicationBuilder(configuration)
|
||||
.environment(this.environment)
|
||||
.web(!isClientCredentials).run();
|
||||
.environment(this.environment).web(clientCredentials
|
||||
? WebApplicationType.NONE : WebApplicationType.SERVLET)
|
||||
.run();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
@ -123,7 +123,8 @@ public class OAuth2RestOperationsConfigurationTests {
|
|||
|
||||
@Configuration
|
||||
@Import({ OAuth2ClientConfiguration.class, OAuth2RestOperationsConfiguration.class })
|
||||
protected static class ConfigForSessionScopedConfiguration extends WebApplicationConfiguration {
|
||||
protected static class ConfigForSessionScopedConfiguration
|
||||
extends WebApplicationConfiguration {
|
||||
|
||||
@Bean
|
||||
public SecurityProperties securityProperties() {
|
||||
|
@ -133,7 +134,8 @@ public class OAuth2RestOperationsConfigurationTests {
|
|||
}
|
||||
|
||||
@Configuration
|
||||
protected static class ConfigForRequestScopedConfiguration extends WebApplicationConfiguration {
|
||||
protected static class ConfigForRequestScopedConfiguration
|
||||
extends WebApplicationConfiguration {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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-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.
|
||||
|
@ -29,7 +29,8 @@ public class HelloWebSecurityApplication {
|
|||
@Bean
|
||||
public UserDetailsService userDetailsService() throws Exception {
|
||||
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
|
||||
manager.createUser(
|
||||
User.withUsername("user").password("password").roles("USER").build());
|
||||
return manager;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<!-- Your own application should inherit from spring-boot-starter-parent -->
|
||||
|
|
|
@ -4,7 +4,6 @@ import org.springframework.boot.autoconfigure.security.SpringBootSecurity;
|
|||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
|
||||
@Configuration
|
||||
|
@ -18,13 +17,14 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
|||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication()
|
||||
.withUser("user").password("password").authorities("ROLE_USER").and()
|
||||
.withUser("admin").password("admin").authorities("ROLE_ACTUATOR", "ROLE_USER");
|
||||
auth.inMemoryAuthentication().withUser("user").password("password")
|
||||
.authorities("ROLE_USER").and().withUser("admin").password("admin")
|
||||
.authorities("ROLE_ACTUATOR", "ROLE_USER");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http.authorizeRequests()
|
||||
.requestMatchers(this.bootSecurity.endpointIds("status", "info")).permitAll()
|
||||
.requestMatchers(this.bootSecurity.endpointIds(SpringBootSecurity.ALL_ENDPOINTS)).hasRole("ACTUATOR")
|
||||
|
@ -35,6 +35,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
|||
.cors()
|
||||
.and()
|
||||
.httpBasic();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,14 +12,10 @@ import org.springframework.boot.test.context.SpringBootTest;
|
|||
import org.springframework.boot.test.web.client.LocalHostUriTemplateHandler;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
@ -41,7 +37,7 @@ public class CorsSampleActuatorApplicationTests {
|
|||
private TestRestTemplate testRestTemplate;
|
||||
|
||||
@Autowired
|
||||
ApplicationContext applicationContext;
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
|
|
@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {
|
||||
"management.port=0", "management.context-path=/admin"})
|
||||
"management.port=0", "management.context-path=/admin" })
|
||||
@DirtiesContext
|
||||
public class InsecureManagementPortAndPathSampleActuatorApplicationTests {
|
||||
|
||||
|
@ -51,7 +51,6 @@ public class InsecureManagementPortAndPathSampleActuatorApplicationTests {
|
|||
|
||||
@Test
|
||||
public void testHome() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<String> entity = new TestRestTemplate("user", "password")
|
||||
.getForEntity("http://localhost:" + this.port, String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
|
@ -77,9 +76,10 @@ public class InsecureManagementPortAndPathSampleActuatorApplicationTests {
|
|||
|
||||
@Test
|
||||
public void testMissing() throws Exception {
|
||||
ResponseEntity<String> entity = new TestRestTemplate("admin", "admin").getForEntity(
|
||||
"http://localhost:" + this.managementPort + "/admin/missing",
|
||||
String.class);
|
||||
ResponseEntity<String> entity = new TestRestTemplate("admin", "admin")
|
||||
.getForEntity(
|
||||
"http://localhost:" + this.managementPort + "/admin/missing",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
assertThat(entity.getBody()).contains("\"status\":404");
|
||||
}
|
||||
|
|
|
@ -44,22 +44,22 @@ public class SampleActuatorCustomSecurityApplicationTests {
|
|||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertThat((String)body.get("message")).contains("Expected exception in controller");
|
||||
assertThat((String) body.get("message"))
|
||||
.contains("Expected exception in controller");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsecureStaticResources() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<String> entity = this.restTemplate.getForEntity("/css/bootstrap.min.css", String.class);
|
||||
ResponseEntity<String> entity = this.restTemplate
|
||||
.getForEntity("/css/bootstrap.min.css", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("body");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insecureActuator() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<String> entity = this.restTemplate.getForEntity("/application/status",
|
||||
String.class);
|
||||
ResponseEntity<String> entity = this.restTemplate
|
||||
.getForEntity("/application/status", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("\"status\":\"UP\"");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2014 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.
|
||||
|
@ -29,7 +29,8 @@ public class SampleActuatorLog4J2Application {
|
|||
@Bean
|
||||
public UserDetailsService userDetailsService() throws Exception {
|
||||
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
|
||||
manager.createUser(
|
||||
User.withUsername("user").password("password").roles("USER").build());
|
||||
return manager;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,17 +65,16 @@ public class SampleActuatorLog4J2ApplicationTests {
|
|||
|
||||
@Test
|
||||
public void validateLoggersEndpoint() throws Exception {
|
||||
this.mvc.perform(get("/application/loggers/org.apache.coyote.http11.Http11NioProtocol")
|
||||
.header("Authorization", "Basic " + getBasicAuth()))
|
||||
this.mvc.perform(
|
||||
get("/application/loggers/org.apache.coyote.http11.Http11NioProtocol")
|
||||
.header("Authorization", "Basic " + getBasicAuth()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(equalTo("{\"configuredLevel\":\"WARN\","
|
||||
+ "\"effectiveLevel\":\"WARN\"}")));
|
||||
}
|
||||
|
||||
private String getBasicAuth() {
|
||||
return new String(Base64.getEncoder()
|
||||
.encode(("user:password").getBytes()));
|
||||
return new String(Base64.getEncoder().encode(("user:password").getBytes()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,8 @@ public class SampleActuatorUiApplication {
|
|||
@Bean
|
||||
public UserDetailsService userDetailsService() throws Exception {
|
||||
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
|
||||
manager.createUser(
|
||||
User.withUsername("user").password("password").roles("USER").build());
|
||||
return manager;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,9 +54,9 @@ public class SampleActuatorUiApplicationTests {
|
|||
public void testHome() throws Exception {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
ResponseEntity<String> entity = this.restTemplate.withBasicAuth("user", getPassword())
|
||||
.exchange("/", HttpMethod.GET,
|
||||
new HttpEntity<Void>(headers), String.class);
|
||||
ResponseEntity<String> entity = this.restTemplate
|
||||
.withBasicAuth("user", getPassword()).exchange("/", HttpMethod.GET,
|
||||
new HttpEntity<Void>(headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("<title>Hello");
|
||||
}
|
||||
|
@ -72,8 +72,8 @@ public class SampleActuatorUiApplicationTests {
|
|||
@Test
|
||||
public void testMetrics() throws Exception {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = this.restTemplate.getForEntity("/application/metrics",
|
||||
Map.class);
|
||||
ResponseEntity<Map> entity = this.restTemplate
|
||||
.getForEntity("/application/metrics", Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
|
@ -81,9 +81,9 @@ public class SampleActuatorUiApplicationTests {
|
|||
public void testError() throws Exception {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
|
||||
ResponseEntity<String> entity = this.restTemplate.withBasicAuth("user", getPassword())
|
||||
.exchange("/error",
|
||||
HttpMethod.GET, new HttpEntity<Void>(headers), String.class);
|
||||
ResponseEntity<String> entity = this.restTemplate
|
||||
.withBasicAuth("user", getPassword()).exchange("/error", HttpMethod.GET,
|
||||
new HttpEntity<Void>(headers), String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
assertThat(entity.getBody()).contains("<html>").contains("<body>")
|
||||
.contains("Please contact the operator with the above information");
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.springframework.boot.actuate.health.HealthIndicator;
|
|||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
|
@ -38,17 +37,20 @@ public class SampleActuatorApplication {
|
|||
@Bean
|
||||
public UserDetailsService userDetailsService() throws Exception {
|
||||
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
|
||||
manager.createUser(
|
||||
User.withUsername("user").password("password").roles("USER").build());
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HealthIndicator helloHealthIndicator() {
|
||||
return new HealthIndicator() {
|
||||
|
||||
@Override
|
||||
public Health health() {
|
||||
return Health.up().withDetail("hello", "world").build();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue