Merge branch '2.0.x'
This commit is contained in:
commit
d724f154f4
|
@ -33,6 +33,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
|||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.RequestMatcherProvider;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
|
@ -158,13 +159,25 @@ public final class EndpointRequest {
|
|||
RequestMatcherFactory requestMatcherFactory);
|
||||
|
||||
protected List<RequestMatcher> getLinksMatchers(
|
||||
RequestMatcherFactory requestMatcherFactory, String basePath) {
|
||||
RequestMatcherFactory requestMatcherFactory,
|
||||
RequestMatcherProvider matcherProvider, String basePath) {
|
||||
List<RequestMatcher> linksMatchers = new ArrayList<>();
|
||||
linksMatchers.add(requestMatcherFactory.antPath(basePath));
|
||||
linksMatchers.add(requestMatcherFactory.antPath(basePath, "/"));
|
||||
linksMatchers.add(requestMatcherFactory.antPath(matcherProvider, basePath));
|
||||
linksMatchers
|
||||
.add(requestMatcherFactory.antPath(matcherProvider, basePath, "/"));
|
||||
return linksMatchers;
|
||||
}
|
||||
|
||||
protected RequestMatcherProvider getRequestMatcherProvider(
|
||||
WebApplicationContext context) {
|
||||
try {
|
||||
return context.getBean(RequestMatcherProvider.class);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException ex) {
|
||||
return AntPathRequestMatcher::new;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -220,6 +233,7 @@ public final class EndpointRequest {
|
|||
RequestMatcherFactory requestMatcherFactory) {
|
||||
PathMappedEndpoints pathMappedEndpoints = context
|
||||
.getBean(PathMappedEndpoints.class);
|
||||
RequestMatcherProvider matcherProvider = getRequestMatcherProvider(context);
|
||||
Set<String> paths = new LinkedHashSet<>();
|
||||
if (this.includes.isEmpty()) {
|
||||
paths.addAll(pathMappedEndpoints.getAllPaths());
|
||||
|
@ -227,11 +241,11 @@ public final class EndpointRequest {
|
|||
streamPaths(this.includes, pathMappedEndpoints).forEach(paths::add);
|
||||
streamPaths(this.excludes, pathMappedEndpoints).forEach(paths::remove);
|
||||
List<RequestMatcher> delegateMatchers = getDelegateMatchers(
|
||||
requestMatcherFactory, paths);
|
||||
requestMatcherFactory, matcherProvider, paths);
|
||||
String basePath = pathMappedEndpoints.getBasePath();
|
||||
if (this.includeLinks && StringUtils.hasText(basePath)) {
|
||||
delegateMatchers
|
||||
.addAll(getLinksMatchers(requestMatcherFactory, basePath));
|
||||
delegateMatchers.addAll(getLinksMatchers(requestMatcherFactory,
|
||||
matcherProvider, basePath));
|
||||
}
|
||||
return new OrRequestMatcher(delegateMatchers);
|
||||
}
|
||||
|
@ -261,9 +275,10 @@ public final class EndpointRequest {
|
|||
}
|
||||
|
||||
private List<RequestMatcher> getDelegateMatchers(
|
||||
RequestMatcherFactory requestMatcherFactory, Set<String> paths) {
|
||||
return paths.stream()
|
||||
.map((path) -> requestMatcherFactory.antPath(path, "/**"))
|
||||
RequestMatcherFactory requestMatcherFactory,
|
||||
RequestMatcherProvider matcherProvider, Set<String> paths) {
|
||||
return paths.stream().map(
|
||||
(path) -> requestMatcherFactory.antPath(matcherProvider, path, "/**"))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -281,8 +296,8 @@ public final class EndpointRequest {
|
|||
.getBean(WebEndpointProperties.class);
|
||||
String basePath = properties.getBasePath();
|
||||
if (StringUtils.hasText(basePath)) {
|
||||
return new OrRequestMatcher(
|
||||
getLinksMatchers(requestMatcherFactory, basePath));
|
||||
return new OrRequestMatcher(getLinksMatchers(requestMatcherFactory,
|
||||
getRequestMatcherProvider(context), basePath));
|
||||
}
|
||||
return EMPTY_MATCHER;
|
||||
}
|
||||
|
@ -300,12 +315,13 @@ public final class EndpointRequest {
|
|||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public RequestMatcher antPath(String... parts) {
|
||||
public RequestMatcher antPath(RequestMatcherProvider matcherProvider,
|
||||
String... parts) {
|
||||
String pattern = this.prefix;
|
||||
for (String part : parts) {
|
||||
pattern += part;
|
||||
}
|
||||
return new AntPathRequestMatcher(pattern);
|
||||
return matcherProvider.getRequestMatcher(pattern);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
|||
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.servlet.RequestMatcherProvider;
|
||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
|
@ -214,6 +215,26 @@ public class EndpointRequestTests {
|
|||
assertMatcher.matches("/bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endpointRequestMatcherShouldUseCustomRequestMatcherProvider() {
|
||||
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
||||
RequestMatcher mockRequestMatcher = (request) -> false;
|
||||
RequestMatcherAssert assertMatcher = assertMatcher(matcher,
|
||||
mockPathMappedEndpoints(""), "", (pattern) -> mockRequestMatcher);
|
||||
assertMatcher.doesNotMatch("/foo");
|
||||
assertMatcher.doesNotMatch("/bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linksRequestMatcherShouldUseCustomRequestMatcherProvider() {
|
||||
RequestMatcher matcher = EndpointRequest.toLinks();
|
||||
RequestMatcher mockRequestMatcher = (request) -> false;
|
||||
RequestMatcherAssert assertMatcher = assertMatcher(matcher,
|
||||
mockPathMappedEndpoints("/actuator"), "",
|
||||
(pattern) -> mockRequestMatcher);
|
||||
assertMatcher.doesNotMatch("/actuator");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noEndpointPathsBeansShouldNeverMatch() {
|
||||
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
||||
|
@ -231,7 +252,8 @@ public class EndpointRequestTests {
|
|||
|
||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, String basePath,
|
||||
String servletPath) {
|
||||
return assertMatcher(matcher, mockPathMappedEndpoints(basePath), servletPath);
|
||||
return assertMatcher(matcher, mockPathMappedEndpoints(basePath), servletPath,
|
||||
null);
|
||||
}
|
||||
|
||||
private PathMappedEndpoints mockPathMappedEndpoints(String basePath) {
|
||||
|
@ -250,11 +272,12 @@ public class EndpointRequestTests {
|
|||
|
||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
|
||||
PathMappedEndpoints pathMappedEndpoints) {
|
||||
return assertMatcher(matcher, pathMappedEndpoints, "");
|
||||
return assertMatcher(matcher, pathMappedEndpoints, "", null);
|
||||
}
|
||||
|
||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
|
||||
PathMappedEndpoints pathMappedEndpoints, String dispatcherServletPath) {
|
||||
PathMappedEndpoints pathMappedEndpoints, String dispatcherServletPath,
|
||||
RequestMatcherProvider matcherProvider) {
|
||||
StaticWebApplicationContext context = new StaticWebApplicationContext();
|
||||
context.registerBean(WebEndpointProperties.class);
|
||||
if (pathMappedEndpoints != null) {
|
||||
|
@ -269,6 +292,9 @@ public class EndpointRequestTests {
|
|||
DispatcherServletPath path = () -> dispatcherServletPath;
|
||||
context.registerBean(DispatcherServletPath.class, () -> path);
|
||||
}
|
||||
if (matcherProvider != null) {
|
||||
context.registerBean(RequestMatcherProvider.class, () -> matcherProvider);
|
||||
}
|
||||
return assertThat(new RequestMatcherAssert(context, matcher));
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Collection;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -49,6 +50,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.handler.MatchableHandlerMapping;
|
||||
import org.springframework.web.servlet.handler.RequestMatchResult;
|
||||
import org.springframework.web.servlet.mvc.condition.ConsumesRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
|
||||
import org.springframework.web.servlet.mvc.condition.ProducesRequestCondition;
|
||||
|
@ -66,7 +69,8 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMappi
|
|||
* @since 2.0.0
|
||||
*/
|
||||
public abstract class AbstractWebMvcEndpointHandlerMapping
|
||||
extends RequestMappingInfoHandlerMapping implements InitializingBean {
|
||||
extends RequestMappingInfoHandlerMapping
|
||||
implements InitializingBean, MatchableHandlerMapping {
|
||||
|
||||
private final EndpointMapping endpointMapping;
|
||||
|
||||
|
@ -82,6 +86,8 @@ public abstract class AbstractWebMvcEndpointHandlerMapping
|
|||
private final Method handleMethod = ReflectionUtils.findMethod(OperationHandler.class,
|
||||
"handle", HttpServletRequest.class, Map.class);
|
||||
|
||||
private static final RequestMappingInfo.BuilderConfiguration builderConfig = getBuilderConfig();
|
||||
|
||||
/**
|
||||
* Creates a new {@code WebEndpointHandlerMapping} that provides mappings for the
|
||||
* operations of the given {@code webEndpoints}.
|
||||
|
@ -125,6 +131,29 @@ public abstract class AbstractWebMvcEndpointHandlerMapping
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestMatchResult match(HttpServletRequest request, String pattern) {
|
||||
RequestMappingInfo info = RequestMappingInfo.paths(pattern).options(builderConfig)
|
||||
.build();
|
||||
RequestMappingInfo matchingInfo = info.getMatchingCondition(request);
|
||||
if (matchingInfo == null) {
|
||||
return null;
|
||||
}
|
||||
Set<String> patterns = matchingInfo.getPatternsCondition().getPatterns();
|
||||
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
|
||||
return new RequestMatchResult(patterns.iterator().next(), lookupPath,
|
||||
getPathMatcher());
|
||||
}
|
||||
|
||||
private static RequestMappingInfo.BuilderConfiguration getBuilderConfig() {
|
||||
RequestMappingInfo.BuilderConfiguration config = new RequestMappingInfo.BuilderConfiguration();
|
||||
config.setUrlPathHelper(null);
|
||||
config.setPathMatcher(null);
|
||||
config.setSuffixPatternMatch(false);
|
||||
config.setTrailingSlashMatch(true);
|
||||
return config;
|
||||
}
|
||||
|
||||
private void registerMappingForOperation(ExposableWebEndpoint endpoint,
|
||||
WebOperation operation) {
|
||||
OperationInvoker invoker = operation::invoke;
|
||||
|
@ -176,7 +205,9 @@ public abstract class AbstractWebMvcEndpointHandlerMapping
|
|||
|
||||
private PatternsRequestCondition patternsRequestConditionForPattern(String path) {
|
||||
String[] patterns = new String[] { this.endpointMapping.createSubPath(path) };
|
||||
return new PatternsRequestCondition(patterns, null, null, false, true);
|
||||
return new PatternsRequestCondition(patterns, builderConfig.getUrlPathHelper(),
|
||||
builderConfig.getPathMatcher(), builderConfig.useSuffixPatternMatch(),
|
||||
builderConfig.useTrailingSlashMatch());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -46,6 +46,7 @@ import org.springframework.context.annotation.Configuration;
|
|||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
|
@ -53,6 +54,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
|||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
import org.springframework.web.servlet.handler.RequestMatchResult;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
@ -104,6 +106,27 @@ public class MvcWebEndpointIntegrationTests extends
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchWhenRequestHasTrailingSlashShouldNotBeNull() {
|
||||
assertThat(getMatchResult("/spring/")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchWhenRequestHasSuffixShouldBeNull() {
|
||||
assertThat(getMatchResult("/spring.do")).isNull();
|
||||
}
|
||||
|
||||
private RequestMatchResult getMatchResult(String s) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath(s);
|
||||
AnnotationConfigServletWebServerApplicationContext context = createApplicationContext();
|
||||
context.register(TestEndpointConfiguration.class);
|
||||
context.refresh();
|
||||
WebMvcEndpointHandlerMapping bean = context
|
||||
.getBean(WebMvcEndpointHandlerMapping.class);
|
||||
return bean.match(request, "/spring");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPort(AnnotationConfigServletWebServerApplicationContext context) {
|
||||
return context.getWebServer().getPort();
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.autoconfigure.security.servlet;
|
||||
|
||||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
|
||||
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.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class MvcRequestMatcherProvider implements RequestMatcherProvider {
|
||||
|
||||
private final HandlerMappingIntrospector introspector;
|
||||
|
||||
public MvcRequestMatcherProvider(HandlerMappingIntrospector introspector) {
|
||||
this.introspector = introspector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestMatcher getRequestMatcher(String pattern) {
|
||||
return new MvcRequestMatcher(this.introspector, pattern);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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.autoconfigure.security.servlet;
|
||||
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
|
||||
/**
|
||||
* Interface that can be used to provide a {@link RequestMatcher} that can be used with
|
||||
* Spring Security.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.5
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RequestMatcherProvider {
|
||||
|
||||
RequestMatcher getRequestMatcher(String pattern);
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.autoconfigure.security.servlet;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
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}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.0.5
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ RequestMatcher.class, DispatcherServlet.class })
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@ConditionalOnBean(HandlerMappingIntrospector.class)
|
||||
public class SecurityRequestMatcherProviderAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public RequestMatcherProvider requestMatcherProvider(
|
||||
HandlerMappingIntrospector introspector) {
|
||||
return new MvcRequestMatcherProvider(introspector);
|
||||
}
|
||||
|
||||
}
|
|
@ -98,6 +98,7 @@ org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
|
|||
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
|
||||
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,\
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.autoconfigure.security.servlet;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
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 static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link SecurityRequestMatcherProviderAutoConfiguration}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class SecurityRequestMatcherProviderAutoConfigurationTests {
|
||||
|
||||
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations
|
||||
.of(SecurityRequestMatcherProviderAutoConfiguration.class))
|
||||
.withUserConfiguration(TestConfiguration.class);
|
||||
|
||||
@Test
|
||||
public void registersMvcRequestMatcherProviderForIfMvcPresent() {
|
||||
this.contextRunner.run((context) -> assertThat(context)
|
||||
.hasSingleBean(MvcRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcRequestMatcherProviderConditionalOnWebApplication() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations
|
||||
.of(SecurityRequestMatcherProviderAutoConfiguration.class))
|
||||
.withUserConfiguration(TestConfiguration.class)
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(MvcRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcRequestMatcherProviderConditionalOnDispatcherServletClass() {
|
||||
this.contextRunner
|
||||
.withClassLoader(new FilteredClassLoader(
|
||||
"org.springframework.web.servlet.DispatcherServlet"))
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(MvcRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcRequestMatcherProviderConditionalOnRequestMatcherClass() {
|
||||
this.contextRunner
|
||||
.withClassLoader(new FilteredClassLoader(
|
||||
"org.springframework.security.web.util.matcher.RequestMatcher"))
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(MvcRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcRequestMatcherProviderConditionalOnHandlerMappingIntrospectorBean() {
|
||||
new WebApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations
|
||||
.of(SecurityRequestMatcherProviderAutoConfiguration.class))
|
||||
.run((context) -> assertThat(context)
|
||||
.doesNotHaveBean(MvcRequestMatcherProvider.class));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
public HandlerMappingIntrospector introspector() {
|
||||
return new HandlerMappingIntrospector();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -35,6 +35,8 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
|||
return new InMemoryUserDetailsManager(
|
||||
User.withDefaultPasswordEncoder().username("user").password("password")
|
||||
.authorities("ROLE_USER").build(),
|
||||
User.withDefaultPasswordEncoder().username("beans").password("beans")
|
||||
.authorities("ROLE_BEANS").build(),
|
||||
User.withDefaultPasswordEncoder().username("admin").password("admin")
|
||||
.authorities("ROLE_ACTUATOR", "ROLE_USER").build());
|
||||
}
|
||||
|
@ -43,6 +45,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
|||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http.authorizeRequests()
|
||||
.mvcMatchers("/actuator/beans").hasRole("BEANS")
|
||||
.requestMatchers(EndpointRequest.to("health", "info")).permitAll()
|
||||
.requestMatchers(EndpointRequest.toAnyEndpoint().excluding(MappingsEndpoint.class)).hasRole("ACTUATOR")
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
|
||||
|
|
|
@ -141,6 +141,16 @@ public class SampleActuatorCustomSecurityApplicationTests {
|
|||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mvcMatchersCanBeUsedToSecureActuators() {
|
||||
ResponseEntity<Object> entity = beansRestTemplate()
|
||||
.getForEntity("/actuator/beans", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
entity = beansRestTemplate()
|
||||
.getForEntity("/actuator/beans/", Object.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
private TestRestTemplate restTemplate() {
|
||||
return configure(new TestRestTemplate());
|
||||
}
|
||||
|
@ -153,6 +163,10 @@ public class SampleActuatorCustomSecurityApplicationTests {
|
|||
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));
|
||||
|
|
Loading…
Reference in New Issue