Merge branch 'gh-14503' into 2.0.x
This commit is contained in:
commit
1150f46b40
|
|
@ -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.annotation.Endpoint;
|
||||||
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
|
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
|
||||||
import org.springframework.boot.autoconfigure.security.servlet.RequestMatcherProvider;
|
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.boot.security.servlet.ApplicationContextRequestMatcher;
|
||||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
|
@ -139,23 +138,13 @@ public final class EndpointRequest {
|
||||||
|
|
||||||
private RequestMatcher createDelegate(WebApplicationContext context) {
|
private RequestMatcher createDelegate(WebApplicationContext context) {
|
||||||
try {
|
try {
|
||||||
String pathPrefix = getPathPrefix(context);
|
return createDelegate(context, new RequestMatcherFactory());
|
||||||
return createDelegate(context, new RequestMatcherFactory(pathPrefix));
|
|
||||||
}
|
}
|
||||||
catch (NoSuchBeanDefinitionException ex) {
|
catch (NoSuchBeanDefinitionException ex) {
|
||||||
return EMPTY_MATCHER;
|
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,
|
protected abstract RequestMatcher createDelegate(WebApplicationContext context,
|
||||||
RequestMatcherFactory requestMatcherFactory);
|
RequestMatcherFactory requestMatcherFactory);
|
||||||
|
|
||||||
|
|
@ -313,15 +302,9 @@ public final class EndpointRequest {
|
||||||
*/
|
*/
|
||||||
private static class RequestMatcherFactory {
|
private static class RequestMatcherFactory {
|
||||||
|
|
||||||
private final String prefix;
|
|
||||||
|
|
||||||
RequestMatcherFactory(String prefix) {
|
|
||||||
this.prefix = prefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RequestMatcher antPath(RequestMatcherProvider matcherProvider,
|
public RequestMatcher antPath(RequestMatcherProvider matcherProvider,
|
||||||
String... parts) {
|
String... parts) {
|
||||||
StringBuilder pattern = new StringBuilder(this.prefix);
|
StringBuilder pattern = new StringBuilder();
|
||||||
for (String part : parts) {
|
for (String part : parts) {
|
||||||
pattern.append(part);
|
pattern.append(part);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,184 @@
|
||||||
|
/*
|
||||||
|
* 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.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.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().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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -33,7 +33,6 @@ import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoint;
|
||||||
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
|
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
|
||||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint;
|
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint;
|
||||||
import org.springframework.boot.autoconfigure.security.servlet.RequestMatcherProvider;
|
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.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockServletContext;
|
import org.springframework.mock.web.MockServletContext;
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
|
|
@ -55,19 +54,19 @@ public class EndpointRequestTests {
|
||||||
@Test
|
@Test
|
||||||
public void toAnyEndpointShouldMatchEndpointPath() {
|
public void toAnyEndpointShouldMatchEndpointPath() {
|
||||||
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
||||||
assertMatcher(matcher, "/actuator", "/").matches("/actuator/foo");
|
assertMatcher(matcher, "/actuator").matches("/actuator/foo");
|
||||||
assertMatcher(matcher, "/actuator", "/").matches("/actuator/foo/zoo/");
|
assertMatcher(matcher, "/actuator").matches("/actuator/foo/zoo/");
|
||||||
assertMatcher(matcher, "/actuator", "/").matches("/actuator/bar");
|
assertMatcher(matcher, "/actuator").matches("/actuator/bar");
|
||||||
assertMatcher(matcher, "/actuator", "/").matches("/actuator/bar/baz");
|
assertMatcher(matcher, "/actuator").matches("/actuator/bar/baz");
|
||||||
assertMatcher(matcher, "/actuator", "/").matches("/actuator");
|
assertMatcher(matcher, "/actuator").matches("/actuator");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void toAnyEndpointShouldMatchEndpointPathWithTrailingSlash() {
|
public void toAnyEndpointShouldMatchEndpointPathWithTrailingSlash() {
|
||||||
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
||||||
assertMatcher(matcher, "/actuator", "/").matches("/actuator/foo/");
|
assertMatcher(matcher, "/actuator").matches("/actuator/foo/");
|
||||||
assertMatcher(matcher, "/actuator", "/").matches("/actuator/bar/");
|
assertMatcher(matcher, "/actuator").matches("/actuator/bar/");
|
||||||
assertMatcher(matcher, "/actuator", "/").matches("/actuator/");
|
assertMatcher(matcher, "/actuator").matches("/actuator/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -85,26 +84,13 @@ public class EndpointRequestTests {
|
||||||
assertMatcher(matcher).doesNotMatch("/actuator/baz");
|
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
|
@Test
|
||||||
public void toAnyEndpointWhenDispatcherServletPathProviderNotAvailableUsesEmptyPath() {
|
public void toAnyEndpointWhenDispatcherServletPathProviderNotAvailableUsesEmptyPath() {
|
||||||
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
||||||
assertMatcher(matcher, "/actuator", null).matches("/actuator/foo");
|
assertMatcher(matcher, "/actuator").matches("/actuator/foo");
|
||||||
assertMatcher(matcher, "/actuator", null).matches("/actuator/bar");
|
assertMatcher(matcher, "/actuator").matches("/actuator/bar");
|
||||||
assertMatcher(matcher, "/actuator", null).matches("/actuator");
|
assertMatcher(matcher, "/actuator").matches("/actuator");
|
||||||
assertMatcher(matcher, "/actuator", null).doesNotMatch("/actuator/baz");
|
assertMatcher(matcher, "/actuator").doesNotMatch("/actuator/baz");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -151,14 +137,6 @@ public class EndpointRequestTests {
|
||||||
assertMatcher.doesNotMatch("/");
|
assertMatcher.doesNotMatch("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void toLinksWhenServletPathNotEmptyShouldMatch() {
|
|
||||||
RequestMatcher matcher = EndpointRequest.toLinks();
|
|
||||||
RequestMatcherAssert assertMatcher = assertMatcher(matcher, "/actuator",
|
|
||||||
"/spring");
|
|
||||||
assertMatcher.matches("/spring/actuator");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void excludeByClassShouldNotMatchExcluded() {
|
public void excludeByClassShouldNotMatchExcluded() {
|
||||||
RequestMatcher matcher = EndpointRequest.toAnyEndpoint()
|
RequestMatcher matcher = EndpointRequest.toAnyEndpoint()
|
||||||
|
|
@ -221,7 +199,7 @@ public class EndpointRequestTests {
|
||||||
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
||||||
RequestMatcher mockRequestMatcher = (request) -> false;
|
RequestMatcher mockRequestMatcher = (request) -> false;
|
||||||
RequestMatcherAssert assertMatcher = assertMatcher(matcher,
|
RequestMatcherAssert assertMatcher = assertMatcher(matcher,
|
||||||
mockPathMappedEndpoints(""), "", (pattern) -> mockRequestMatcher);
|
mockPathMappedEndpoints(""), (pattern) -> mockRequestMatcher);
|
||||||
assertMatcher.doesNotMatch("/foo");
|
assertMatcher.doesNotMatch("/foo");
|
||||||
assertMatcher.doesNotMatch("/bar");
|
assertMatcher.doesNotMatch("/bar");
|
||||||
}
|
}
|
||||||
|
|
@ -231,8 +209,7 @@ public class EndpointRequestTests {
|
||||||
RequestMatcher matcher = EndpointRequest.toLinks();
|
RequestMatcher matcher = EndpointRequest.toLinks();
|
||||||
RequestMatcher mockRequestMatcher = (request) -> false;
|
RequestMatcher mockRequestMatcher = (request) -> false;
|
||||||
RequestMatcherAssert assertMatcher = assertMatcher(matcher,
|
RequestMatcherAssert assertMatcher = assertMatcher(matcher,
|
||||||
mockPathMappedEndpoints("/actuator"), "",
|
mockPathMappedEndpoints("/actuator"), (pattern) -> mockRequestMatcher);
|
||||||
(pattern) -> mockRequestMatcher);
|
|
||||||
assertMatcher.doesNotMatch("/actuator");
|
assertMatcher.doesNotMatch("/actuator");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,13 +225,7 @@ public class EndpointRequestTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, String basePath) {
|
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, String basePath) {
|
||||||
return assertMatcher(matcher, mockPathMappedEndpoints(basePath));
|
return assertMatcher(matcher, mockPathMappedEndpoints(basePath), null);
|
||||||
}
|
|
||||||
|
|
||||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, String basePath,
|
|
||||||
String servletPath) {
|
|
||||||
return assertMatcher(matcher, mockPathMappedEndpoints(basePath), servletPath,
|
|
||||||
null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PathMappedEndpoints mockPathMappedEndpoints(String basePath) {
|
private PathMappedEndpoints mockPathMappedEndpoints(String basePath) {
|
||||||
|
|
@ -273,11 +244,11 @@ public class EndpointRequestTests {
|
||||||
|
|
||||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
|
private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
|
||||||
PathMappedEndpoints pathMappedEndpoints) {
|
PathMappedEndpoints pathMappedEndpoints) {
|
||||||
return assertMatcher(matcher, pathMappedEndpoints, "", null);
|
return assertMatcher(matcher, pathMappedEndpoints, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
|
private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
|
||||||
PathMappedEndpoints pathMappedEndpoints, String dispatcherServletPath,
|
PathMappedEndpoints pathMappedEndpoints,
|
||||||
RequestMatcherProvider matcherProvider) {
|
RequestMatcherProvider matcherProvider) {
|
||||||
StaticWebApplicationContext context = new StaticWebApplicationContext();
|
StaticWebApplicationContext context = new StaticWebApplicationContext();
|
||||||
context.registerBean(WebEndpointProperties.class);
|
context.registerBean(WebEndpointProperties.class);
|
||||||
|
|
@ -289,10 +260,6 @@ public class EndpointRequestTests {
|
||||||
properties.setBasePath(pathMappedEndpoints.getBasePath());
|
properties.setBasePath(pathMappedEndpoints.getBasePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dispatcherServletPath != null) {
|
|
||||||
DispatcherServletPath path = () -> dispatcherServletPath;
|
|
||||||
context.registerBean(DispatcherServletPath.class, () -> path);
|
|
||||||
}
|
|
||||||
if (matcherProvider != null) {
|
if (matcherProvider != null) {
|
||||||
context.registerBean(RequestMatcherProvider.class, () -> matcherProvider);
|
context.registerBean(RequestMatcherProvider.class, () -> matcherProvider);
|
||||||
}
|
}
|
||||||
|
|
@ -314,10 +281,6 @@ public class EndpointRequestTests {
|
||||||
matches(mockRequest(servletPath));
|
matches(mockRequest(servletPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void matches(String servletPath, String pathInfo) {
|
|
||||||
matches(mockRequest(servletPath, pathInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void matches(HttpServletRequest request) {
|
private void matches(HttpServletRequest request) {
|
||||||
assertThat(this.matcher.matches(request))
|
assertThat(this.matcher.matches(request))
|
||||||
.as("Matches " + getRequestPath(request)).isTrue();
|
.as("Matches " + getRequestPath(request)).isTrue();
|
||||||
|
|
@ -327,20 +290,12 @@ public class EndpointRequestTests {
|
||||||
doesNotMatch(mockRequest(servletPath));
|
doesNotMatch(mockRequest(servletPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doesNotMatch(String servletPath, String pathInfo) {
|
|
||||||
doesNotMatch(mockRequest(servletPath, pathInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doesNotMatch(HttpServletRequest request) {
|
private void doesNotMatch(HttpServletRequest request) {
|
||||||
assertThat(this.matcher.matches(request))
|
assertThat(this.matcher.matches(request))
|
||||||
.as("Does not match " + getRequestPath(request)).isFalse();
|
.as("Does not match " + getRequestPath(request)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
private MockHttpServletRequest mockRequest(String servletPath) {
|
private MockHttpServletRequest mockRequest(String servletPath) {
|
||||||
return mockRequest(servletPath, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private MockHttpServletRequest mockRequest(String servletPath, String path) {
|
|
||||||
MockServletContext servletContext = new MockServletContext();
|
MockServletContext servletContext = new MockServletContext();
|
||||||
servletContext.setAttribute(
|
servletContext.setAttribute(
|
||||||
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
|
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
|
||||||
|
|
@ -349,7 +304,6 @@ public class EndpointRequestTests {
|
||||||
if (servletPath != null) {
|
if (servletPath != null) {
|
||||||
request.setServletPath(servletPath);
|
request.setServletPath(servletPath);
|
||||||
}
|
}
|
||||||
request.setPathInfo(path);
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* 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.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.PathMapper;
|
||||||
|
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.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,
|
||||||
|
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, PathMapper.useEndpointId(),
|
||||||
|
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,144 @@
|
||||||
|
/*
|
||||||
|
* 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.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.PathMapper;
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @author Madhura Bhave
|
||||||
|
*/
|
||||||
|
public class MvcEndpointRequestIntegrationTests
|
||||||
|
extends AbstractEndpointRequestIntegrationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toLinksWhenServletPathSetShouldMatch() {
|
||||||
|
getContextRunner().withPropertyValues("server.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("server.servlet.path=/admin")
|
||||||
|
.run((context) -> {
|
||||||
|
WebTestClient webTestClient = getWebTestClient(context);
|
||||||
|
webTestClient.get().uri("/admin/actuator/e1").exchange()
|
||||||
|
.expectStatus().isOk();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toAnyEndpointWhenServletPathSetShouldMatch() {
|
||||||
|
getContextRunner().withPropertyValues("server.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,
|
||||||
|
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, PathMapper.useEndpointId(),
|
||||||
|
Collections.emptyList(), Collections.emptyList());
|
||||||
|
return new WebMvcEndpointHandlerMapping(new EndpointMapping("/actuator"),
|
||||||
|
discoverer.getEndpoints(), endpointMediaTypes,
|
||||||
|
new CorsConfiguration(),
|
||||||
|
new EndpointLinksResolver(discoverer.getEndpoints()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue