Merge branch '2.0.x'
commit
bd0a41d82d
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue