mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-15 01:07:30 +08:00
Merge branch '2.1.x'
Closes gh-17980
This commit is contained in:
commit
2726540e76
@ -13,41 +13,48 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.servlet;
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.security.servlet;
|
||||
|
||||
import org.glassfish.jersey.server.ResourceConfig;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.AntPathRequestMatcherProvider;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.RequestMatcherProvider;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.JerseyApplicationPath;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* Auto-configuration for {@link RequestMatcherProvider}.
|
||||
* {@link ManagementContextConfiguration} that configures the appropriate
|
||||
* {@link RequestMatcherProvider}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.5
|
||||
* @since 2.1.8
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ManagementContextConfiguration
|
||||
@ConditionalOnClass({ RequestMatcher.class })
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
public class SecurityRequestMatcherProviderAutoConfiguration {
|
||||
public class SecurityRequestMatchersManagementContextConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(DispatcherServlet.class)
|
||||
@ConditionalOnBean(HandlerMappingIntrospector.class)
|
||||
@ConditionalOnBean(DispatcherServletPath.class)
|
||||
public static class MvcRequestMatcherConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnClass(DispatcherServlet.class)
|
||||
public RequestMatcherProvider requestMatcherProvider(HandlerMappingIntrospector introspector) {
|
||||
return new MvcRequestMatcherProvider(introspector);
|
||||
public RequestMatcherProvider requestMatcherProvider(DispatcherServletPath servletPath) {
|
||||
return new AntPathRequestMatcherProvider(servletPath::getRelativePath);
|
||||
}
|
||||
|
||||
}
|
||||
@ -60,7 +67,7 @@ public class SecurityRequestMatcherProviderAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public RequestMatcherProvider requestMatcherProvider(JerseyApplicationPath applicationPath) {
|
||||
return new JerseyRequestMatcherProvider(applicationPath);
|
||||
return new AntPathRequestMatcherProvider(applicationPath::getRelativePath);
|
||||
}
|
||||
|
||||
}
|
@ -95,6 +95,7 @@ org.springframework.boot.actuate.autoconfigure.endpoint.web.ServletEndpointManag
|
||||
org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.endpoint.web.jersey.JerseyWebEndpointManagementContextConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.security.servlet.SecurityRequestMatchersManagementContextConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.web.jersey.JerseySameManagementContextConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.web.jersey.JerseyChildManagementContextConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementChildContextConfiguration,\
|
||||
|
@ -15,20 +15,24 @@
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.security.servlet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jolokia.http.AgentServlet;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.EndpointId;
|
||||
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.Operation;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointServlet;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
|
||||
import org.springframework.boot.logging.LogLevel;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
@ -39,9 +43,6 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Abstract base class for {@link EndpointRequest} tests.
|
||||
*
|
||||
@ -49,8 +50,6 @@ import static org.mockito.Mockito.mock;
|
||||
*/
|
||||
abstract class AbstractEndpointRequestIntegrationTests {
|
||||
|
||||
protected abstract WebApplicationContextRunner getContextRunner();
|
||||
|
||||
@Test
|
||||
void toEndpointShouldMatch() {
|
||||
getContextRunner().run((context) -> {
|
||||
@ -79,6 +78,17 @@ abstract class AbstractEndpointRequestIntegrationTests {
|
||||
});
|
||||
}
|
||||
|
||||
protected final WebApplicationContextRunner getContextRunner() {
|
||||
return createContextRunner().withPropertyValues("management.endpoints.web.exposure.include=*")
|
||||
.withUserConfiguration(BaseConfiguration.class, SecurityConfiguration.class).withConfiguration(
|
||||
AutoConfigurations.of(JacksonAutoConfiguration.class, SecurityAutoConfiguration.class,
|
||||
UserDetailsServiceAutoConfiguration.class, EndpointAutoConfiguration.class,
|
||||
WebEndpointAutoConfiguration.class, ManagementContextAutoConfiguration.class));
|
||||
|
||||
}
|
||||
|
||||
protected abstract WebApplicationContextRunner createContextRunner();
|
||||
|
||||
protected WebTestClient getWebTestClient(AssertableWebApplicationContext context) {
|
||||
int port = context.getSourceApplicationContext(AnnotationConfigServletWebServerApplicationContext.class)
|
||||
.getWebServer().getPort();
|
||||
@ -108,19 +118,8 @@ abstract class AbstractEndpointRequestIntegrationTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
PathMappedEndpoints pathMappedEndpoints() {
|
||||
List<ExposableEndpoint<?>> endpoints = new ArrayList<>();
|
||||
endpoints.add(mockEndpoint("e1"));
|
||||
endpoints.add(mockEndpoint("e2"));
|
||||
endpoints.add(mockEndpoint("e3"));
|
||||
return new PathMappedEndpoints("/actuator", () -> endpoints);
|
||||
}
|
||||
|
||||
private TestPathMappedEndpoint mockEndpoint(String id) {
|
||||
TestPathMappedEndpoint endpoint = mock(TestPathMappedEndpoint.class);
|
||||
given(endpoint.getEndpointId()).willReturn(EndpointId.of(id));
|
||||
given(endpoint.getRootPath()).willReturn(id);
|
||||
return endpoint;
|
||||
TestServletEndpoint servletEndpoint() {
|
||||
return new TestServletEndpoint();
|
||||
}
|
||||
|
||||
}
|
||||
@ -155,7 +154,13 @@ abstract class AbstractEndpointRequestIntegrationTests {
|
||||
|
||||
}
|
||||
|
||||
public interface TestPathMappedEndpoint extends ExposableEndpoint<Operation>, PathMappedEndpoint {
|
||||
@ServletEndpoint(id = "se1")
|
||||
static class TestServletEndpoint implements Supplier<EndpointServlet> {
|
||||
|
||||
@Override
|
||||
public EndpointServlet get() {
|
||||
return new EndpointServlet(AgentServlet.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -15,38 +15,17 @@
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.security.servlet;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.glassfish.jersey.server.ResourceConfig;
|
||||
import org.glassfish.jersey.server.model.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||
import org.springframework.boot.actuate.endpoint.EndpointId;
|
||||
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
|
||||
import org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
|
||||
import org.springframework.boot.actuate.endpoint.web.jersey.JerseyEndpointResourceFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jersey.ResourceConfigCustomizer;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
@ -58,18 +37,6 @@ import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
*/
|
||||
class JerseyEndpointRequestIntegrationTests extends AbstractEndpointRequestIntegrationTests {
|
||||
|
||||
@Override
|
||||
protected WebApplicationContextRunner getContextRunner() {
|
||||
return new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
|
||||
.withUserConfiguration(JerseyEndpointConfiguration.class, SecurityConfiguration.class,
|
||||
BaseConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(SecurityAutoConfiguration.class,
|
||||
UserDetailsServiceAutoConfiguration.class,
|
||||
SecurityRequestMatcherProviderAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
JerseyAutoConfiguration.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void toLinksWhenApplicationPathSetShouldMatch() {
|
||||
getContextRunner().withPropertyValues("spring.jersey.application-path=/admin").run((context) -> {
|
||||
@ -99,16 +66,47 @@ class JerseyEndpointRequestIntegrationTests extends AbstractEndpointRequestInteg
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Test
|
||||
void toAnyEndpointShouldMatchServletEndpoint() {
|
||||
getContextRunner().withPropertyValues("spring.security.user.password=password",
|
||||
"management.endpoints.web.exposure.include=se1").run((context) -> {
|
||||
WebTestClient webTestClient = getWebTestClient(context);
|
||||
webTestClient.get().uri("/actuator/se1").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/actuator/se1").header("Authorization", getBasicAuth()).exchange()
|
||||
.expectStatus().isOk();
|
||||
webTestClient.get().uri("/actuator/se1/list").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/actuator/se1/list").header("Authorization", getBasicAuth()).exchange()
|
||||
.expectStatus().isOk();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void toAnyEndpointWhenApplicationPathSetShouldMatchServletEndpoint() {
|
||||
getContextRunner().withPropertyValues("spring.jersey.application-path=/admin",
|
||||
"spring.security.user.password=password", "management.endpoints.web.exposure.include=se1")
|
||||
.run((context) -> {
|
||||
WebTestClient webTestClient = getWebTestClient(context);
|
||||
webTestClient.get().uri("/admin/actuator/se1").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/admin/actuator/se1").header("Authorization", getBasicAuth()).exchange()
|
||||
.expectStatus().isOk();
|
||||
webTestClient.get().uri("/admin/actuator/se1/list").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/admin/actuator/se1/list").header("Authorization", getBasicAuth())
|
||||
.exchange().expectStatus().isOk();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WebApplicationContextRunner createContextRunner() {
|
||||
return new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
|
||||
.withUserConfiguration(JerseyEndpointConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(JerseyAutoConfiguration.class));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(WebEndpointProperties.class)
|
||||
static class JerseyEndpointConfiguration {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
JerseyEndpointConfiguration(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Bean
|
||||
TomcatServletWebServerFactory tomcat() {
|
||||
return new TomcatServletWebServerFactory(0);
|
||||
@ -119,24 +117,6 @@ class JerseyEndpointRequestIntegrationTests extends AbstractEndpointRequestInteg
|
||||
return new ResourceConfig();
|
||||
}
|
||||
|
||||
@Bean
|
||||
ResourceConfigCustomizer webEndpointRegistrar() {
|
||||
return this::customize;
|
||||
}
|
||||
|
||||
private void customize(ResourceConfig config) {
|
||||
List<String> mediaTypes = Arrays.asList(javax.ws.rs.core.MediaType.APPLICATION_JSON,
|
||||
ActuatorMediaType.V2_JSON);
|
||||
EndpointMediaTypes endpointMediaTypes = new EndpointMediaTypes(mediaTypes, mediaTypes);
|
||||
WebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(this.applicationContext,
|
||||
new ConversionServiceParameterValueMapper(), endpointMediaTypes,
|
||||
Arrays.asList(EndpointId::toString), Collections.emptyList(), Collections.emptyList());
|
||||
Collection<Resource> resources = new JerseyEndpointResourceFactory().createEndpointResources(
|
||||
new EndpointMapping("/actuator"), discoverer.getEndpoints(), endpointMediaTypes,
|
||||
new EndpointLinksResolver(discoverer.getEndpoints()), true);
|
||||
config.registerResources(new HashSet<>(resources));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,39 +15,20 @@
|
||||
*/
|
||||
package org.springframework.boot.actuate.autoconfigure.security.servlet;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||
import org.springframework.boot.actuate.endpoint.EndpointId;
|
||||
import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
|
||||
import org.springframework.boot.actuate.endpoint.invoke.convert.ConversionServiceParameterValueMapper;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
|
||||
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
|
||||
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link EndpointRequest} with Spring MVC.
|
||||
@ -85,44 +66,52 @@ class MvcEndpointRequestIntegrationTests extends AbstractEndpointRequestIntegrat
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void toAnyEndpointShouldMatchServletEndpoint() {
|
||||
getContextRunner().withPropertyValues("spring.security.user.password=password",
|
||||
"management.endpoints.web.exposure.include=se1").run((context) -> {
|
||||
WebTestClient webTestClient = getWebTestClient(context);
|
||||
webTestClient.get().uri("/actuator/se1").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/actuator/se1").header("Authorization", getBasicAuth()).exchange()
|
||||
.expectStatus().isOk();
|
||||
webTestClient.get().uri("/actuator/se1/list").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/actuator/se1/list").header("Authorization", getBasicAuth()).exchange()
|
||||
.expectStatus().isOk();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void toAnyEndpointWhenServletPathSetShouldMatchServletEndpoint() {
|
||||
getContextRunner().withPropertyValues("spring.mvc.servlet.path=/admin",
|
||||
"spring.security.user.password=password", "management.endpoints.web.exposure.include=se1")
|
||||
.run((context) -> {
|
||||
WebTestClient webTestClient = getWebTestClient(context);
|
||||
webTestClient.get().uri("/admin/actuator/se1").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/admin/actuator/se1").header("Authorization", getBasicAuth()).exchange()
|
||||
.expectStatus().isOk();
|
||||
webTestClient.get().uri("/admin/actuator/se1/list").exchange().expectStatus().isUnauthorized();
|
||||
webTestClient.get().uri("/admin/actuator/se1/list").header("Authorization", getBasicAuth())
|
||||
.exchange().expectStatus().isOk();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WebApplicationContextRunner getContextRunner() {
|
||||
protected WebApplicationContextRunner createContextRunner() {
|
||||
return new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
|
||||
.withUserConfiguration(WebMvcEndpointConfiguration.class, SecurityConfiguration.class,
|
||||
BaseConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(SecurityAutoConfiguration.class,
|
||||
UserDetailsServiceAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
SecurityRequestMatcherProviderAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, DispatcherServletAutoConfiguration.class));
|
||||
.withUserConfiguration(WebMvcEndpointConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(DispatcherServletAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, WebMvcAutoConfiguration.class));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(WebEndpointProperties.class)
|
||||
static class WebMvcEndpointConfiguration {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
WebMvcEndpointConfiguration(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Bean
|
||||
TomcatServletWebServerFactory tomcat() {
|
||||
return new TomcatServletWebServerFactory(0);
|
||||
}
|
||||
|
||||
@Bean
|
||||
WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping() {
|
||||
List<String> mediaTypes = Arrays.asList(MediaType.APPLICATION_JSON_VALUE, ActuatorMediaType.V2_JSON);
|
||||
EndpointMediaTypes endpointMediaTypes = new EndpointMediaTypes(mediaTypes, mediaTypes);
|
||||
WebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(this.applicationContext,
|
||||
new ConversionServiceParameterValueMapper(), endpointMediaTypes,
|
||||
Arrays.asList(EndpointId::toString), Collections.emptyList(), Collections.emptyList());
|
||||
return new WebMvcEndpointHandlerMapping(new EndpointMapping("/actuator"), discoverer.getEndpoints(),
|
||||
endpointMediaTypes, new CorsConfiguration(), new EndpointLinksResolver(discoverer.getEndpoints()),
|
||||
true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,35 +13,40 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.servlet;
|
||||
|
||||
package org.springframework.boot.actuate.autoconfigure.security.servlet;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.AntPathRequestMatcherProvider;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.RequestMatcherProvider;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.JerseyApplicationPath;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link SecurityRequestMatcherProviderAutoConfiguration}.
|
||||
* Tests for {@link SecurityRequestMatchersManagementContextConfiguration}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class SecurityRequestMatcherProviderAutoConfigurationTests {
|
||||
class SecurityRequestMatchersManagementContextConfigurationTests {
|
||||
|
||||
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatcherProviderAutoConfiguration.class));
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class));
|
||||
|
||||
@Test
|
||||
void configurationConditionalOnWebApplication() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatcherProviderAutoConfiguration.class))
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class))
|
||||
.withUserConfiguration(TestMvcConfiguration.class)
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(RequestMatcherProvider.class));
|
||||
}
|
||||
@ -55,51 +60,58 @@ class SecurityRequestMatcherProviderAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void registersMvcRequestMatcherProviderIfMvcPresent() {
|
||||
this.contextRunner.withUserConfiguration(TestMvcConfiguration.class).run((context) -> assertThat(context)
|
||||
.getBean(RequestMatcherProvider.class).isInstanceOf(MvcRequestMatcherProvider.class));
|
||||
void registersRequestMatcherProviderIfMvcPresent() {
|
||||
this.contextRunner.withUserConfiguration(TestMvcConfiguration.class).run((context) -> {
|
||||
AntPathRequestMatcherProvider matcherProvider = context.getBean(AntPathRequestMatcherProvider.class);
|
||||
RequestMatcher requestMatcher = matcherProvider.getRequestMatcher("/example");
|
||||
assertThat(ReflectionTestUtils.getField(requestMatcher, "pattern")).isEqualTo("/custom/example");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void registersRequestMatcherForJerseyProviderIfJerseyPresentAndMvcAbsent() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
|
||||
.withUserConfiguration(TestJerseyConfiguration.class).run((context) -> assertThat(context)
|
||||
.getBean(RequestMatcherProvider.class).isInstanceOf(JerseyRequestMatcherProvider.class));
|
||||
.withUserConfiguration(TestJerseyConfiguration.class).run((context) -> {
|
||||
AntPathRequestMatcherProvider matcherProvider = context
|
||||
.getBean(AntPathRequestMatcherProvider.class);
|
||||
RequestMatcher requestMatcher = matcherProvider.getRequestMatcher("/example");
|
||||
assertThat(ReflectionTestUtils.getField(requestMatcher, "pattern")).isEqualTo("/admin/example");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void mvcRequestMatcherProviderConditionalOnDispatcherServletClass() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(MvcRequestMatcherProvider.class));
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void mvcRequestMatcherProviderConditionalOnDispatcherServletPathBean() {
|
||||
new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void jerseyRequestMatcherProviderConditionalOnResourceConfigClass() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader("org.glassfish.jersey.server.ResourceConfig"))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(JerseyRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void mvcRequestMatcherProviderConditionalOnHandlerMappingIntrospectorBean() {
|
||||
new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatcherProviderAutoConfiguration.class))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(MvcRequestMatcherProvider.class));
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void jerseyRequestMatcherProviderConditionalOnJerseyApplicationPathBean() {
|
||||
new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatcherProviderAutoConfiguration.class))
|
||||
.withConfiguration(AutoConfigurations.of(SecurityRequestMatchersManagementContextConfiguration.class))
|
||||
.withClassLoader(new FilteredClassLoader("org.springframework.web.servlet.DispatcherServlet"))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(JerseyRequestMatcherProvider.class));
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(AntPathRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class TestMvcConfiguration {
|
||||
|
||||
@Bean
|
||||
HandlerMappingIntrospector introspector() {
|
||||
return new HandlerMappingIntrospector();
|
||||
DispatcherServletPath dispatcherServletPath() {
|
||||
return () -> "/custom";
|
||||
}
|
||||
|
||||
}
|
@ -13,30 +13,31 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.servlet;
|
||||
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
|
||||
|
||||
/**
|
||||
* {@link RequestMatcherProvider} that provides an {@link MvcRequestMatcher} that can be
|
||||
* used for Spring MVC applications.
|
||||
* {@link RequestMatcherProvider} that provides an {@link AntPathRequestMatcher}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.5
|
||||
* @since 2.1.8
|
||||
*/
|
||||
public class MvcRequestMatcherProvider implements RequestMatcherProvider {
|
||||
public class AntPathRequestMatcherProvider implements RequestMatcherProvider {
|
||||
|
||||
private final HandlerMappingIntrospector introspector;
|
||||
private final Function<String, String> pathFactory;
|
||||
|
||||
public MvcRequestMatcherProvider(HandlerMappingIntrospector introspector) {
|
||||
this.introspector = introspector;
|
||||
public AntPathRequestMatcherProvider(Function<String, String> pathFactory) {
|
||||
this.pathFactory = pathFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestMatcher getRequestMatcher(String pattern) {
|
||||
return new MvcRequestMatcher(this.introspector, pattern);
|
||||
return new AntPathRequestMatcher(this.pathFactory.apply(pattern));
|
||||
}
|
||||
|
||||
}
|
@ -25,7 +25,9 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.7
|
||||
* @deprecated since 2.1.8 in favor of {@link AntPathRequestMatcher}
|
||||
*/
|
||||
@Deprecated
|
||||
public class JerseyRequestMatcherProvider implements RequestMatcherProvider {
|
||||
|
||||
private final JerseyApplicationPath jerseyApplicationPath;
|
||||
|
@ -105,7 +105,6 @@ org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration
|
||||
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
|
||||
|
@ -71,6 +71,7 @@
|
||||
<module>spring-boot-smoke-test-reactive-oauth2-client</module>
|
||||
<module>spring-boot-smoke-test-reactive-oauth2-resource-server</module>
|
||||
<module>spring-boot-smoke-test-secure</module>
|
||||
<module>spring-boot-smoke-test-secure-jersey</module>
|
||||
<module>spring-boot-smoke-test-secure-webflux</module>
|
||||
<module>spring-boot-smoke-test-servlet</module>
|
||||
<module>spring-boot-smoke-test-session</module>
|
||||
|
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.actuator.customsecurity;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.test.web.client.LocalHostUriTemplateHandler;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Abstract base class for actuator tests with custom security.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
abstract class AbstractSampleActuatorCustomSecurityTests {
|
||||
|
||||
abstract String getPath();
|
||||
|
||||
abstract String getManagementPath();
|
||||
|
||||
abstract Environment getEnvironment();
|
||||
|
||||
@Test
|
||||
void homeIsSecure() {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = restTemplate().getForEntity(getPath() + "/", Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertThat(body.get("error")).isEqualTo("Unauthorized");
|
||||
assertThat(entity.getHeaders()).doesNotContainKey("Set-Cookie");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInsecureStaticResources() {
|
||||
ResponseEntity<String> entity = restTemplate().getForEntity(getPath() + "/css/bootstrap.min.css", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("body");
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorInsecureEndpoint() {
|
||||
ResponseEntity<String> entity = restTemplate().getForEntity(getManagementPath() + "/actuator/health",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("\"status\":\"UP\"");
|
||||
entity = restTemplate().getForEntity(getManagementPath() + "/actuator/health/diskSpace", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("\"status\":\"UP\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorLinksWithAnonymous() {
|
||||
ResponseEntity<Object> entity = restTemplate().getForEntity(getManagementPath() + "/actuator", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
entity = restTemplate().getForEntity(getManagementPath() + "/actuator/", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorLinksWithUnauthorizedUser() {
|
||||
ResponseEntity<Object> entity = userRestTemplate().getForEntity(getManagementPath() + "/actuator",
|
||||
Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
entity = userRestTemplate().getForEntity(getManagementPath() + "/actuator/", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorLinksWithAuthorizedUser() {
|
||||
ResponseEntity<Object> entity = adminRestTemplate().getForEntity(getManagementPath() + "/actuator",
|
||||
Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
adminRestTemplate().getForEntity(getManagementPath() + "/actuator/", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorSecureEndpointWithAnonymous() {
|
||||
ResponseEntity<Object> entity = restTemplate().getForEntity(getManagementPath() + "/actuator/env",
|
||||
Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
entity = restTemplate().getForEntity(
|
||||
getManagementPath() + "/actuator/env/management.endpoints.web.exposure.include", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorSecureEndpointWithUnauthorizedUser() {
|
||||
ResponseEntity<Object> entity = userRestTemplate().getForEntity(getManagementPath() + "/actuator/env",
|
||||
Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
entity = userRestTemplate().getForEntity(
|
||||
getManagementPath() + "/actuator/env/management.endpoints.web.exposure.include", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorSecureEndpointWithAuthorizedUser() {
|
||||
ResponseEntity<Object> entity = adminRestTemplate().getForEntity(getManagementPath() + "/actuator/env",
|
||||
Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
entity = adminRestTemplate().getForEntity(
|
||||
getManagementPath() + "/actuator/env/management.endpoints.web.exposure.include", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void secureServletEndpointWithAnonymous() {
|
||||
ResponseEntity<String> entity = restTemplate().getForEntity("/actuator/jolokia", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
entity = restTemplate().getForEntity(getManagementPath() + "/actuator/jolokia/list", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void secureServletEndpointWithUnauthorizedUser() {
|
||||
ResponseEntity<String> entity = userRestTemplate().getForEntity(getManagementPath() + "/actuator/jolokia",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
entity = userRestTemplate().getForEntity(getManagementPath() + "/actuator/jolokia/list", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void secureServletEndpointWithAuthorizedUser() {
|
||||
ResponseEntity<String> entity = adminRestTemplate().getForEntity(getManagementPath() + "/actuator/jolokia",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
entity = adminRestTemplate().getForEntity(getManagementPath() + "/actuator/jolokia/list", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorCustomMvcSecureEndpointWithAnonymous() {
|
||||
ResponseEntity<String> entity = restTemplate()
|
||||
.getForEntity(getManagementPath() + "/actuator/example/echo?text={t}", String.class, "test");
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorCustomMvcSecureEndpointWithUnauthorizedUser() {
|
||||
ResponseEntity<String> entity = userRestTemplate()
|
||||
.getForEntity(getManagementPath() + "/actuator/example/echo?text={t}", String.class, "test");
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorCustomMvcSecureEndpointWithAuthorizedUser() {
|
||||
ResponseEntity<String> entity = adminRestTemplate()
|
||||
.getForEntity(getManagementPath() + "/actuator/example/echo?text={t}", String.class, "test");
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).isEqualTo("test");
|
||||
assertThat(entity.getHeaders().getFirst("echo")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorExcludedFromEndpointRequestMatcher() {
|
||||
ResponseEntity<Object> entity = userRestTemplate().getForEntity(getManagementPath() + "/actuator/mappings",
|
||||
Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
TestRestTemplate restTemplate() {
|
||||
return configure(new TestRestTemplate());
|
||||
}
|
||||
|
||||
TestRestTemplate adminRestTemplate() {
|
||||
return configure(new TestRestTemplate("admin", "admin"));
|
||||
}
|
||||
|
||||
TestRestTemplate userRestTemplate() {
|
||||
return configure(new TestRestTemplate("user", "password"));
|
||||
}
|
||||
|
||||
TestRestTemplate beansRestTemplate() {
|
||||
return configure(new TestRestTemplate("beans", "beans"));
|
||||
}
|
||||
|
||||
private TestRestTemplate configure(TestRestTemplate restTemplate) {
|
||||
restTemplate.setUriTemplateHandler(new LocalHostUriTemplateHandler(getEnvironment()));
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.actuator.customsecurity;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Integration tests for actuator endpoints with custom dispatcher servlet path.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = "spring.mvc.servlet.path=/example")
|
||||
|
||||
class CustomServletPathSampleActuatorTests extends AbstractSampleActuatorCustomSecurityTests {
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@Override
|
||||
String getPath() {
|
||||
return "http://localhost:" + this.port + "/example";
|
||||
}
|
||||
|
||||
@Override
|
||||
String getManagementPath() {
|
||||
return "http://localhost:" + this.port + "/example";
|
||||
}
|
||||
|
||||
@Override
|
||||
Environment getEnvironment() {
|
||||
return this.environment;
|
||||
}
|
||||
|
||||
}
|
@ -18,25 +18,28 @@ package smoketest.actuator.customsecurity;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.LocalManagementPort;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for separate management and main service ports.
|
||||
* Integration tests for separate management and main service ports with custom management
|
||||
* context path.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
|
||||
properties = { "management.server.port=0", "management.server.servlet.context-path=/management" })
|
||||
class ManagementPortAndPathSampleActuatorApplicationTests {
|
||||
class ManagementPortAndPathSampleActuatorApplicationTests extends AbstractSampleActuatorCustomSecurityTests {
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
@ -44,35 +47,8 @@ class ManagementPortAndPathSampleActuatorApplicationTests {
|
||||
@LocalManagementPort
|
||||
private int managementPort;
|
||||
|
||||
@Test
|
||||
void testHome() {
|
||||
ResponseEntity<String> entity = new TestRestTemplate("user", "password")
|
||||
.getForEntity("http://localhost:" + this.port, String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("Hello World");
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorPathOnMainPortShouldNotMatch() {
|
||||
ResponseEntity<String> entity = new TestRestTemplate()
|
||||
.getForEntity("http://localhost:" + this.port + "/actuator/health", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSecureActuator() {
|
||||
ResponseEntity<String> entity = new TestRestTemplate()
|
||||
.getForEntity("http://localhost:" + this.managementPort + "/management/actuator/env", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInsecureActuator() {
|
||||
ResponseEntity<String> entity = new TestRestTemplate()
|
||||
.getForEntity("http://localhost:" + this.managementPort + "/management/actuator/health", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("\"status\":\"UP\"");
|
||||
}
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@Test
|
||||
void testMissing() {
|
||||
@ -82,4 +58,19 @@ class ManagementPortAndPathSampleActuatorApplicationTests {
|
||||
assertThat(entity.getBody()).contains("\"status\":404");
|
||||
}
|
||||
|
||||
@Override
|
||||
String getPath() {
|
||||
return "http://localhost:" + this.port;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getManagementPath() {
|
||||
return "http://localhost:" + this.managementPort + "/management";
|
||||
}
|
||||
|
||||
@Override
|
||||
Environment getEnvironment() {
|
||||
return this.environment;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.actuator.customsecurity;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.LocalManagementPort;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for separate management and main service ports with custom dispatcher
|
||||
* servlet path.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = { "management.server.port=0", "spring.mvc.servlet.path=/example" })
|
||||
class ManagementPortCustomServletPathSampleActuatorTests extends AbstractSampleActuatorCustomSecurityTests {
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@LocalManagementPort
|
||||
private int managementPort;
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@Test
|
||||
void actuatorPathOnMainPortShouldNotMatch() {
|
||||
ResponseEntity<String> entity = new TestRestTemplate()
|
||||
.getForEntity("http://localhost:" + this.port + "/example/actuator/health", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getPath() {
|
||||
return "http://localhost:" + this.port + "/example";
|
||||
}
|
||||
|
||||
@Override
|
||||
String getManagementPath() {
|
||||
return "http://localhost:" + this.managementPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
Environment getEnvironment() {
|
||||
return this.environment;
|
||||
}
|
||||
|
||||
}
|
@ -22,8 +22,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.boot.web.server.LocalServerPort;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@ -31,132 +30,52 @@ import org.springframework.http.ResponseEntity;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for actuator endpoints with custom security configuration.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
class SampleActuatorCustomSecurityApplicationTests {
|
||||
class SampleActuatorCustomSecurityApplicationTests extends AbstractSampleActuatorCustomSecurityTests {
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@Autowired
|
||||
private Environment environment;
|
||||
|
||||
@Test
|
||||
void homeIsSecure() {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = restTemplate().getForEntity("/", Map.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> body = entity.getBody();
|
||||
assertThat(body.get("error")).isEqualTo("Unauthorized");
|
||||
assertThat(entity.getHeaders()).doesNotContainKey("Set-Cookie");
|
||||
@Override
|
||||
String getPath() {
|
||||
return "http://localhost:" + this.port;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getManagementPath() {
|
||||
return "http://localhost:" + this.port;
|
||||
}
|
||||
|
||||
@Override
|
||||
Environment getEnvironment() {
|
||||
return this.environment;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInsecureApplicationPath() {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> entity = restTemplate().getForEntity("/foo", Map.class);
|
||||
ResponseEntity<Map> entity = restTemplate().getForEntity(getPath() + "/foo", Map.class);
|
||||
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");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInsecureStaticResources() {
|
||||
ResponseEntity<String> entity = restTemplate().getForEntity("/css/bootstrap.min.css", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("body");
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorInsecureEndpoint() {
|
||||
ResponseEntity<String> entity = restTemplate().getForEntity("/actuator/health", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("\"status\":\"UP\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorLinksIsSecure() {
|
||||
ResponseEntity<Object> entity = restTemplate().getForEntity("/actuator", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
entity = adminRestTemplate().getForEntity("/actuator", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorSecureEndpointWithAnonymous() {
|
||||
ResponseEntity<Object> entity = restTemplate().getForEntity("/actuator/env", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorSecureEndpointWithUnauthorizedUser() {
|
||||
ResponseEntity<Object> entity = userRestTemplate().getForEntity("/actuator/env", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorSecureEndpointWithAuthorizedUser() {
|
||||
ResponseEntity<Object> entity = adminRestTemplate().getForEntity("/actuator/env", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorCustomMvcSecureEndpointWithAnonymous() {
|
||||
ResponseEntity<String> entity = restTemplate().getForEntity("/actuator/example/echo?text={t}", String.class,
|
||||
"test");
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorCustomMvcSecureEndpointWithUnauthorizedUser() {
|
||||
ResponseEntity<String> entity = userRestTemplate().getForEntity("/actuator/example/echo?text={t}", String.class,
|
||||
"test");
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorCustomMvcSecureEndpointWithAuthorizedUser() {
|
||||
ResponseEntity<String> entity = adminRestTemplate().getForEntity("/actuator/example/echo?text={t}",
|
||||
String.class, "test");
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).isEqualTo("test");
|
||||
assertThat(entity.getHeaders().getFirst("echo")).isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorExcludedFromEndpointRequestMatcher() {
|
||||
ResponseEntity<Object> entity = userRestTemplate().getForEntity("/actuator/mappings", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void mvcMatchersCanBeUsedToSecureActuators() {
|
||||
ResponseEntity<Object> entity = beansRestTemplate().getForEntity("/actuator/beans", Object.class);
|
||||
ResponseEntity<Object> entity = beansRestTemplate().getForEntity(getManagementPath() + "/actuator/beans",
|
||||
Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
entity = beansRestTemplate().getForEntity("/actuator/beans/", Object.class);
|
||||
entity = beansRestTemplate().getForEntity(getManagementPath() + "/actuator/beans/", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
private TestRestTemplate restTemplate() {
|
||||
return configure(new TestRestTemplate());
|
||||
}
|
||||
|
||||
private TestRestTemplate adminRestTemplate() {
|
||||
return configure(new TestRestTemplate("admin", "admin"));
|
||||
}
|
||||
|
||||
private TestRestTemplate userRestTemplate() {
|
||||
return configure(new TestRestTemplate("user", "password"));
|
||||
}
|
||||
|
||||
private TestRestTemplate beansRestTemplate() {
|
||||
return configure(new TestRestTemplate("beans", "beans"));
|
||||
}
|
||||
|
||||
private TestRestTemplate configure(TestRestTemplate restTemplate) {
|
||||
restTemplate.setUriTemplateHandler(new LocalHostUriTemplateHandler(this.environment));
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,77 @@
|
||||
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-smoke-tests</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-smoke-test-secure-jersey</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Boot Secure Jersey Smoke Test</name>
|
||||
<description>Spring Boot Secure Jersey Smoke Test</description>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<!-- Compile -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jersey</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jolokia</groupId>
|
||||
<artifactId>jolokia-core</artifactId>
|
||||
</dependency>
|
||||
<!-- Provided -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</dependency>
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>generate build info</id>
|
||||
<goals>
|
||||
<goal>build-info</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>java9+</id>
|
||||
<activation>
|
||||
<jdk>[9,)</jdk>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.secure.jersey;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Path("/hello")
|
||||
public class Endpoint {
|
||||
|
||||
private final Service service;
|
||||
|
||||
public Endpoint(Service service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@GET
|
||||
public String message() {
|
||||
return "Hello " + this.service.message();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.secure.jersey;
|
||||
|
||||
import org.glassfish.jersey.server.ResourceConfig;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class JerseyConfig extends ResourceConfig {
|
||||
|
||||
public JerseyConfig() {
|
||||
register(Endpoint.class);
|
||||
register(ReverseEndpoint.class);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.secure.jersey;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.QueryParam;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Path("/reverse")
|
||||
public class ReverseEndpoint {
|
||||
|
||||
@GET
|
||||
public String reverse(@QueryParam("input") @NotNull String input) {
|
||||
return new StringBuilder(input).reverse().toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.secure.jersey;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SampleSecureJerseyApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SampleSecureJerseyApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.secure.jersey;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
|
||||
import org.springframework.boot.actuate.web.mappings.MappingsEndpoint;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
|
||||
@Configuration
|
||||
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Bean
|
||||
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
|
||||
return new InMemoryUserDetailsManager(
|
||||
User.withDefaultPasswordEncoder().username("user").password("password").authorities("ROLE_USER")
|
||||
.build(),
|
||||
User.withDefaultPasswordEncoder().username("admin").password("admin")
|
||||
.authorities("ROLE_ACTUATOR", "ROLE_USER").build());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http.authorizeRequests()
|
||||
.requestMatchers(EndpointRequest.to("health", "info")).permitAll()
|
||||
.requestMatchers(EndpointRequest.toAnyEndpoint().excluding(MappingsEndpoint.class)).hasRole("ACTUATOR")
|
||||
.antMatchers("/**").hasRole("USER")
|
||||
.and()
|
||||
.httpBasic();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.secure.jersey;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class Service {
|
||||
|
||||
@Value("${message:World}")
|
||||
private String msg;
|
||||
|
||||
public String message() {
|
||||
return this.msg;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
management.endpoints.web.exposure.include=*
|
||||
management.endpoint.health.show-details=always
|
||||
|
||||
|
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.secure.jersey;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Abstract base class for actuator tests with custom security.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
abstract class AbstractJerseySecureTests {
|
||||
|
||||
abstract String getPath();
|
||||
|
||||
abstract String getManagementPath();
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate testRestTemplate;
|
||||
|
||||
@Test
|
||||
void helloEndpointIsSecure() {
|
||||
ResponseEntity<String> entity = restTemplate().getForEntity(getPath() + "/hello", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorInsecureEndpoint() {
|
||||
ResponseEntity<String> entity = restTemplate().getForEntity(getManagementPath() + "/actuator/health",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("\"status\":\"UP\"");
|
||||
entity = restTemplate().getForEntity(getManagementPath() + "/actuator/health/diskSpace", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("\"status\":\"UP\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorLinksWithAnonymous() {
|
||||
ResponseEntity<String> entity = restTemplate().getForEntity(getManagementPath() + "/actuator", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
entity = restTemplate().getForEntity(getManagementPath() + "/actuator/", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorLinksWithUnauthorizedUser() {
|
||||
ResponseEntity<String> entity = userRestTemplate().getForEntity(getManagementPath() + "/actuator",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
entity = userRestTemplate().getForEntity(getManagementPath() + "/actuator/", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorLinksWithAuthorizedUser() {
|
||||
ResponseEntity<String> entity = adminRestTemplate().getForEntity(getManagementPath() + "/actuator",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
adminRestTemplate().getForEntity(getManagementPath() + "/actuator/", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorSecureEndpointWithAnonymous() {
|
||||
ResponseEntity<String> entity = restTemplate().getForEntity(getManagementPath() + "/actuator/env",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
entity = restTemplate().getForEntity(
|
||||
getManagementPath() + "/actuator/env/management.endpoints.web.exposure.include", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorSecureEndpointWithUnauthorizedUser() {
|
||||
ResponseEntity<String> entity = userRestTemplate().getForEntity(getManagementPath() + "/actuator/env",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
entity = userRestTemplate().getForEntity(
|
||||
getManagementPath() + "/actuator/env/management.endpoints.web.exposure.include", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorSecureEndpointWithAuthorizedUser() {
|
||||
ResponseEntity<String> entity = adminRestTemplate().getForEntity(getManagementPath() + "/actuator/env",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
entity = adminRestTemplate().getForEntity(
|
||||
getManagementPath() + "/actuator/env/management.endpoints.web.exposure.include", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void secureServletEndpointWithAnonymous() {
|
||||
ResponseEntity<String> entity = restTemplate().getForEntity(getManagementPath() + "/actuator/jolokia",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
entity = restTemplate().getForEntity(getManagementPath() + "/actuator/jolokia/list", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test
|
||||
void secureServletEndpointWithUnauthorizedUser() {
|
||||
ResponseEntity<String> entity = userRestTemplate().getForEntity(getManagementPath() + "/actuator/jolokia",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
entity = userRestTemplate().getForEntity(getManagementPath() + "/actuator/jolokia/list", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void secureServletEndpointWithAuthorizedUser() {
|
||||
ResponseEntity<String> entity = adminRestTemplate().getForEntity(getManagementPath() + "/actuator/jolokia",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
entity = adminRestTemplate().getForEntity(getManagementPath() + "/actuator/jolokia/list", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void actuatorExcludedFromEndpointRequestMatcher() {
|
||||
ResponseEntity<String> entity = userRestTemplate().getForEntity(getManagementPath() + "/actuator/mappings",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
TestRestTemplate restTemplate() {
|
||||
return this.testRestTemplate;
|
||||
}
|
||||
|
||||
TestRestTemplate adminRestTemplate() {
|
||||
return this.testRestTemplate.withBasicAuth("admin", "admin");
|
||||
}
|
||||
|
||||
TestRestTemplate userRestTemplate() {
|
||||
return this.testRestTemplate.withBasicAuth("user", "password");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.secure.jersey;
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
|
||||
/**
|
||||
* Integration tests for actuator endpoints with custom application path.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = "spring.jersey.application-path=/example")
|
||||
|
||||
class CustomApplicationPathActuatorTests extends AbstractJerseySecureTests {
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@Override
|
||||
String getPath() {
|
||||
return "http://localhost:" + this.port + "/example";
|
||||
}
|
||||
|
||||
@Override
|
||||
String getManagementPath() {
|
||||
return "http://localhost:" + this.port + "/example";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.secure.jersey;
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
|
||||
/**
|
||||
* Integration tests for actuator endpoints with custom security configuration.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
class JerseySecureApplicationTests extends AbstractJerseySecureTests {
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@Override
|
||||
String getPath() {
|
||||
return "http://localhost:" + this.port;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getManagementPath() {
|
||||
return "http://localhost:" + this.port;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.secure.jersey;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.LocalManagementPort;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for separate management and main service ports with custom management
|
||||
* context path.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
|
||||
properties = { "management.server.port=0", "management.server.servlet.context-path=/management" })
|
||||
class ManagementPortAndPathJerseyApplicationTests extends AbstractJerseySecureTests {
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@LocalManagementPort
|
||||
private int managementPort;
|
||||
|
||||
@Test
|
||||
void testMissing() {
|
||||
ResponseEntity<String> entity = new TestRestTemplate("admin", "admin")
|
||||
.getForEntity("http://localhost:" + this.managementPort + "/management/actuator/missing", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getPath() {
|
||||
return "http://localhost:" + this.port;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getManagementPath() {
|
||||
return "http://localhost:" + this.managementPort + "/management";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.secure.jersey;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.LocalManagementPort;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for separate management and main service ports with custom
|
||||
* application path.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = { "management.server.port=0", "spring.jersey.application-path=/example" })
|
||||
class ManagementPortCustomApplicationPathJerseyTests extends AbstractJerseySecureTests {
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@LocalManagementPort
|
||||
private int managementPort;
|
||||
|
||||
@Test
|
||||
void actuatorPathOnMainPortShouldNotMatch() {
|
||||
ResponseEntity<String> entity = new TestRestTemplate()
|
||||
.getForEntity("http://localhost:" + this.port + "/example/actuator/health", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getPath() {
|
||||
return "http://localhost:" + this.port + "/example";
|
||||
}
|
||||
|
||||
@Override
|
||||
String getManagementPath() {
|
||||
return "http://localhost:" + this.managementPort;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user