Merge branch '2.0.x'

pull/14859/head
Andy Wilkinson 6 years ago
commit bd0a41d82d

@ -35,7 +35,6 @@ import org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
import org.springframework.boot.autoconfigure.security.web.servlet.RequestMatcherProvider;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@ -139,23 +138,13 @@ public final class EndpointRequest {
private RequestMatcher createDelegate(WebApplicationContext context) {
try {
String pathPrefix = getPathPrefix(context);
return createDelegate(context, new RequestMatcherFactory(pathPrefix));
return createDelegate(context, new RequestMatcherFactory());
}
catch (NoSuchBeanDefinitionException ex) {
return EMPTY_MATCHER;
}
}
private String getPathPrefix(WebApplicationContext context) {
try {
return context.getBean(DispatcherServletPath.class).getPrefix();
}
catch (NoSuchBeanDefinitionException ex) {
return "";
}
}
protected abstract RequestMatcher createDelegate(WebApplicationContext context,
RequestMatcherFactory requestMatcherFactory);
@ -313,15 +302,9 @@ public final class EndpointRequest {
*/
private static class RequestMatcherFactory {
private final String prefix;
RequestMatcherFactory(String prefix) {
this.prefix = prefix;
}
public RequestMatcher antPath(RequestMatcherProvider matcherProvider,
String... parts) {
StringBuilder pattern = new StringBuilder(this.prefix);
StringBuilder pattern = new StringBuilder();
for (String part : parts) {
pattern.append(part);
}

@ -0,0 +1,190 @@
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.security.servlet;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.security.web.servlet.EndpointRequest;
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.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.autoconfigure.logging.ConditionEvaluationReportLoggingListener;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
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.test.web.reactive.server.WebTestClient;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Abstract base class for {@link EndpointRequest} tests.
*
* @author Madhura Bhave
*/
public abstract class AbstractEndpointRequestIntegrationTests {
protected abstract WebApplicationContextRunner getContextRunner();
@Test
public void toEndpointShouldMatch() {
getContextRunner().run((context) -> {
WebTestClient webTestClient = getWebTestClient(context);
webTestClient.get().uri("/actuator/e1").exchange().expectStatus().isOk();
});
}
@Test
public void toAllEndpointsShouldMatch() {
getContextRunner()
.withInitializer(
new ConditionEvaluationReportLoggingListener(LogLevel.INFO))
.withPropertyValues("spring.security.user.password=password")
.run((context) -> {
WebTestClient webTestClient = getWebTestClient(context);
webTestClient.get().uri("/actuator/e2").exchange().expectStatus()
.isUnauthorized();
webTestClient.get().uri("/actuator/e2")
.header("Authorization", getBasicAuth()).exchange()
.expectStatus().isOk();
});
}
@Test
public void toLinksShouldMatch() {
getContextRunner().run((context) -> {
WebTestClient webTestClient = getWebTestClient(context);
webTestClient.get().uri("/actuator").exchange().expectStatus().isOk();
webTestClient.get().uri("/actuator/").exchange().expectStatus().isOk();
});
}
protected WebTestClient getWebTestClient(AssertableWebApplicationContext context) {
int port = context
.getSourceApplicationContext(
AnnotationConfigServletWebServerApplicationContext.class)
.getWebServer().getPort();
return WebTestClient.bindToServer().baseUrl("http://localhost:" + port).build();
}
String getBasicAuth() {
return "Basic " + Base64.getEncoder().encodeToString("user:password".getBytes());
}
static class BaseConfiguration {
@Bean
public TestEndpoint1 endpoint1() {
return new TestEndpoint1();
}
@Bean
public TestEndpoint2 endpoint2() {
return new TestEndpoint2();
}
@Bean
public TestEndpoint3 endpoint3() {
return new TestEndpoint3();
}
@Bean
public 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;
}
}
@Endpoint(id = "e1")
static class TestEndpoint1 {
@ReadOperation
public Object getAll() {
return "endpoint 1";
}
}
@Endpoint(id = "e2")
static class TestEndpoint2 {
@ReadOperation
public Object getAll() {
return "endpoint 2";
}
}
@Endpoint(id = "e3")
static class TestEndpoint3 {
@ReadOperation
public Object getAll() {
return null;
}
}
interface TestPathMappedEndpoint
extends ExposableEndpoint<Operation>, PathMappedEndpoint {
}
@Configuration
static class SecurityConfiguration {
@Bean
public WebSecurityConfigurerAdapter webSecurityConfigurerAdapter() {
return new WebSecurityConfigurerAdapter() {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().requestMatchers(EndpointRequest.toLinks())
.permitAll()
.requestMatchers(EndpointRequest.to(TestEndpoint1.class))
.permitAll().requestMatchers(EndpointRequest.toAnyEndpoint())
.authenticated().anyRequest().hasRole("ADMIN").and()
.httpBasic();
}
};
}
}
}

@ -34,7 +34,6 @@ import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoint;
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint;
import org.springframework.boot.autoconfigure.security.web.servlet.RequestMatcherProvider;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockServletContext;
import org.springframework.security.web.util.matcher.RequestMatcher;
@ -56,19 +55,19 @@ public class EndpointRequestTests {
@Test
public void toAnyEndpointShouldMatchEndpointPath() {
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
assertMatcher(matcher, "/actuator", "/").matches("/actuator/foo");
assertMatcher(matcher, "/actuator", "/").matches("/actuator/foo/zoo/");
assertMatcher(matcher, "/actuator", "/").matches("/actuator/bar");
assertMatcher(matcher, "/actuator", "/").matches("/actuator/bar/baz");
assertMatcher(matcher, "/actuator", "/").matches("/actuator");
assertMatcher(matcher, "/actuator").matches("/actuator/foo");
assertMatcher(matcher, "/actuator").matches("/actuator/foo/zoo/");
assertMatcher(matcher, "/actuator").matches("/actuator/bar");
assertMatcher(matcher, "/actuator").matches("/actuator/bar/baz");
assertMatcher(matcher, "/actuator").matches("/actuator");
}
@Test
public void toAnyEndpointShouldMatchEndpointPathWithTrailingSlash() {
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
assertMatcher(matcher, "/actuator", "/").matches("/actuator/foo/");
assertMatcher(matcher, "/actuator", "/").matches("/actuator/bar/");
assertMatcher(matcher, "/actuator", "/").matches("/actuator/");
assertMatcher(matcher, "/actuator").matches("/actuator/foo/");
assertMatcher(matcher, "/actuator").matches("/actuator/bar/");
assertMatcher(matcher, "/actuator").matches("/actuator/");
}
@Test
@ -86,26 +85,13 @@ public class EndpointRequestTests {
assertMatcher(matcher).doesNotMatch("/actuator/baz");
}
@Test
public void toAnyEndpointWhenServletPathNotEmptyShouldMatch() {
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
assertMatcher(matcher, "/actuator", "/spring").matches("/spring",
"/actuator/foo");
assertMatcher(matcher, "/actuator", "/spring").matches("/spring",
"/actuator/bar");
assertMatcher(matcher, "/actuator", "/spring").matches("/spring", "/actuator");
assertMatcher(matcher, "/actuator", "/spring").doesNotMatch("/spring",
"/actuator/baz");
assertMatcher(matcher, "/actuator", "/spring").doesNotMatch("", "/actuator/foo");
}
@Test
public void toAnyEndpointWhenDispatcherServletPathProviderNotAvailableUsesEmptyPath() {
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
assertMatcher(matcher, "/actuator", null).matches("/actuator/foo");
assertMatcher(matcher, "/actuator", null).matches("/actuator/bar");
assertMatcher(matcher, "/actuator", null).matches("/actuator");
assertMatcher(matcher, "/actuator", null).doesNotMatch("/actuator/baz");
assertMatcher(matcher, "/actuator").matches("/actuator/foo");
assertMatcher(matcher, "/actuator").matches("/actuator/bar");
assertMatcher(matcher, "/actuator").matches("/actuator");
assertMatcher(matcher, "/actuator").doesNotMatch("/actuator/baz");
}
@Test
@ -152,14 +138,6 @@ public class EndpointRequestTests {
assertMatcher.doesNotMatch("/");
}
@Test
public void toLinksWhenServletPathNotEmptyShouldMatch() {
RequestMatcher matcher = EndpointRequest.toLinks();
RequestMatcherAssert assertMatcher = assertMatcher(matcher, "/actuator",
"/spring");
assertMatcher.matches("/spring/actuator");
}
@Test
public void excludeByClassShouldNotMatchExcluded() {
RequestMatcher matcher = EndpointRequest.toAnyEndpoint()
@ -222,7 +200,7 @@ public class EndpointRequestTests {
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
RequestMatcher mockRequestMatcher = (request) -> false;
RequestMatcherAssert assertMatcher = assertMatcher(matcher,
mockPathMappedEndpoints(""), "", (pattern) -> mockRequestMatcher);
mockPathMappedEndpoints(""), (pattern) -> mockRequestMatcher);
assertMatcher.doesNotMatch("/foo");
assertMatcher.doesNotMatch("/bar");
}
@ -232,8 +210,7 @@ public class EndpointRequestTests {
RequestMatcher matcher = EndpointRequest.toLinks();
RequestMatcher mockRequestMatcher = (request) -> false;
RequestMatcherAssert assertMatcher = assertMatcher(matcher,
mockPathMappedEndpoints("/actuator"), "",
(pattern) -> mockRequestMatcher);
mockPathMappedEndpoints("/actuator"), (pattern) -> mockRequestMatcher);
assertMatcher.doesNotMatch("/actuator");
}
@ -249,13 +226,7 @@ public class EndpointRequestTests {
}
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, String basePath) {
return assertMatcher(matcher, mockPathMappedEndpoints(basePath));
}
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, String basePath,
String servletPath) {
return assertMatcher(matcher, mockPathMappedEndpoints(basePath), servletPath,
null);
return assertMatcher(matcher, mockPathMappedEndpoints(basePath), null);
}
private PathMappedEndpoints mockPathMappedEndpoints(String basePath) {
@ -274,11 +245,11 @@ public class EndpointRequestTests {
private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
PathMappedEndpoints pathMappedEndpoints) {
return assertMatcher(matcher, pathMappedEndpoints, "", null);
return assertMatcher(matcher, pathMappedEndpoints, null);
}
private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
PathMappedEndpoints pathMappedEndpoints, String dispatcherServletPath,
PathMappedEndpoints pathMappedEndpoints,
RequestMatcherProvider matcherProvider) {
StaticWebApplicationContext context = new StaticWebApplicationContext();
context.registerBean(WebEndpointProperties.class);
@ -290,10 +261,6 @@ public class EndpointRequestTests {
properties.setBasePath(pathMappedEndpoints.getBasePath());
}
}
if (dispatcherServletPath != null) {
DispatcherServletPath path = () -> dispatcherServletPath;
context.registerBean(DispatcherServletPath.class, () -> path);
}
if (matcherProvider != null) {
context.registerBean(RequestMatcherProvider.class, () -> matcherProvider);
}
@ -315,10 +282,6 @@ public class EndpointRequestTests {
matches(mockRequest(servletPath));
}
public void matches(String servletPath, String pathInfo) {
matches(mockRequest(servletPath, pathInfo));
}
private void matches(HttpServletRequest request) {
assertThat(this.matcher.matches(request))
.as("Matches " + getRequestPath(request)).isTrue();
@ -328,20 +291,12 @@ public class EndpointRequestTests {
doesNotMatch(mockRequest(servletPath));
}
public void doesNotMatch(String servletPath, String pathInfo) {
doesNotMatch(mockRequest(servletPath, pathInfo));
}
private void doesNotMatch(HttpServletRequest request) {
assertThat(this.matcher.matches(request))
.as("Does not match " + getRequestPath(request)).isFalse();
}
private MockHttpServletRequest mockRequest(String servletPath) {
return mockRequest(servletPath, null);
}
private MockHttpServletRequest mockRequest(String servletPath, String path) {
MockServletContext servletContext = new MockServletContext();
servletContext.setAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
@ -350,7 +305,6 @@ public class EndpointRequestTests {
if (servletPath != null) {
request.setServletPath(servletPath);
}
request.setPathInfo(path);
return request;
}

@ -0,0 +1,119 @@
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package 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.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.security.web.servlet.EndpointRequest;
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.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.UserDetailsServiceAutoConfiguration;
import org.springframework.boot.autoconfigure.security.web.servlet.SecurityRequestMatcherProviderAutoConfiguration;
import org.springframework.boot.autoconfigure.security.web.servlet.ServletWebSecurityAutoConfiguration;
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;
/**
* Integration tests for {@link EndpointRequest} with Jersey.
*
* @author Madhura Bhave
*/
public class JerseyEndpointRequestIntegrationTests
extends AbstractEndpointRequestIntegrationTests {
@Override
protected WebApplicationContextRunner getContextRunner() {
return new WebApplicationContextRunner(
AnnotationConfigServletWebServerApplicationContext::new)
.withUserConfiguration(JerseyEndpointConfiguration.class,
SecurityConfiguration.class, BaseConfiguration.class)
.withConfiguration(AutoConfigurations.of(
SecurityAutoConfiguration.class,
ServletWebSecurityAutoConfiguration.class,
UserDetailsServiceAutoConfiguration.class,
SecurityRequestMatcherProviderAutoConfiguration.class,
JacksonAutoConfiguration.class,
JerseyAutoConfiguration.class));
}
@Configuration
@EnableConfigurationProperties(WebEndpointProperties.class)
static class JerseyEndpointConfiguration {
private final ApplicationContext applicationContext;
JerseyEndpointConfiguration(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
public TomcatServletWebServerFactory tomcat() {
return new TomcatServletWebServerFactory(0);
}
@Bean
public ResourceConfig resourceConfig() {
return new ResourceConfig();
}
@Bean
public 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((id) -> id.toString()),
Collections.emptyList(), Collections.emptyList());
Collection<Resource> resources = new JerseyEndpointResourceFactory()
.createEndpointResources(new EndpointMapping("/actuator"),
discoverer.getEndpoints(), endpointMediaTypes,
new EndpointLinksResolver(discoverer.getEndpoints()));
config.registerResources(new HashSet<>(resources));
}
}
}

@ -0,0 +1,146 @@
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.security.servlet;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.security.web.servlet.EndpointRequest;
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.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.UserDetailsServiceAutoConfiguration;
import org.springframework.boot.autoconfigure.security.web.servlet.SecurityRequestMatcherProviderAutoConfiguration;
import org.springframework.boot.autoconfigure.security.web.servlet.ServletWebSecurityAutoConfiguration;
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.
*
* @author Madhura Bhave
*/
public class MvcEndpointRequestIntegrationTests
extends AbstractEndpointRequestIntegrationTests {
@Test
public void toLinksWhenServletPathSetShouldMatch() {
getContextRunner().withPropertyValues("spring.mvc.servlet.path=/admin")
.run((context) -> {
WebTestClient webTestClient = getWebTestClient(context);
webTestClient.get().uri("/admin/actuator/").exchange().expectStatus()
.isOk();
webTestClient.get().uri("/admin/actuator").exchange().expectStatus()
.isOk();
});
}
@Test
public void toEndpointWhenServletPathSetShouldMatch() {
getContextRunner().withPropertyValues("spring.mvc.servlet.path=/admin")
.run((context) -> {
WebTestClient webTestClient = getWebTestClient(context);
webTestClient.get().uri("/admin/actuator/e1").exchange()
.expectStatus().isOk();
});
}
@Test
public void toAnyEndpointWhenServletPathSetShouldMatch() {
getContextRunner().withPropertyValues("spring.mvc.servlet.path=/admin",
"spring.security.user.password=password").run((context) -> {
WebTestClient webTestClient = getWebTestClient(context);
webTestClient.get().uri("/admin/actuator/e2").exchange()
.expectStatus().isUnauthorized();
webTestClient.get().uri("/admin/actuator/e2")
.header("Authorization", getBasicAuth()).exchange()
.expectStatus().isOk();
});
}
@Override
protected WebApplicationContextRunner getContextRunner() {
return new WebApplicationContextRunner(
AnnotationConfigServletWebServerApplicationContext::new)
.withUserConfiguration(WebMvcEndpointConfiguration.class,
SecurityConfiguration.class, BaseConfiguration.class)
.withConfiguration(AutoConfigurations.of(
SecurityAutoConfiguration.class,
ServletWebSecurityAutoConfiguration.class,
UserDetailsServiceAutoConfiguration.class,
WebMvcAutoConfiguration.class,
SecurityRequestMatcherProviderAutoConfiguration.class,
JacksonAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
DispatcherServletAutoConfiguration.class));
}
@Configuration
@EnableConfigurationProperties(WebEndpointProperties.class)
static class WebMvcEndpointConfiguration {
private final ApplicationContext applicationContext;
WebMvcEndpointConfiguration(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
public TomcatServletWebServerFactory tomcat() {
return new TomcatServletWebServerFactory(0);
}
@Bean
public 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((id) -> id.toString()),
Collections.emptyList(), Collections.emptyList());
return new WebMvcEndpointHandlerMapping(new EndpointMapping("/actuator"),
discoverer.getEndpoints(), endpointMediaTypes,
new CorsConfiguration(),
new EndpointLinksResolver(discoverer.getEndpoints()));
}
}
}

@ -17,10 +17,12 @@
package org.springframework.boot.autoconfigure.security.web.servlet;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.autoconfigure.security.UserDetailsServiceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@ -37,6 +39,7 @@ import org.springframework.security.authentication.DefaultAuthenticationEventPub
@EnableConfigurationProperties(SecurityProperties.class)
@ConditionalOnClass(DefaultAuthenticationEventPublisher.class)
@AutoConfigureAfter(SecurityAutoConfiguration.class)
@AutoConfigureBefore(UserDetailsServiceAutoConfiguration.class)
@Import({ SpringBootWebSecurityConfiguration.class,
EnableWebSecurityConfiguration.class })
public class ServletWebSecurityAutoConfiguration {

Loading…
Cancel
Save