Add option to skip ssl for reactive CF actuators
Fixes gh-10898
This commit is contained in:
parent
fee9dacab1
commit
e9fe918d25
|
@ -127,6 +127,11 @@
|
|||
<artifactId>micrometer-registry-statsd</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor.ipc</groupId>
|
||||
<artifactId>reactor-netty</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.searchbox</groupId>
|
||||
<artifactId>jest</artifactId>
|
||||
|
@ -379,11 +384,6 @@
|
|||
<artifactId>json-path</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor.ipc</groupId>
|
||||
<artifactId>reactor-netty</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.undertow</groupId>
|
||||
<artifactId>undertow-core</artifactId>
|
||||
|
|
|
@ -111,9 +111,9 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
|
|||
}
|
||||
|
||||
private CloudFoundrySecurityInterceptor getSecurityInterceptor(
|
||||
WebClient.Builder restTemplateBuilder, Environment environment) {
|
||||
WebClient.Builder webClientBuilder, Environment environment) {
|
||||
ReactiveCloudFoundrySecurityService cloudfoundrySecurityService = getCloudFoundrySecurityService(
|
||||
restTemplateBuilder, environment);
|
||||
webClientBuilder, environment);
|
||||
ReactiveTokenValidator tokenValidator = new ReactiveTokenValidator(
|
||||
cloudfoundrySecurityService);
|
||||
return new CloudFoundrySecurityInterceptor(tokenValidator,
|
||||
|
@ -124,9 +124,11 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
|
|||
private ReactiveCloudFoundrySecurityService getCloudFoundrySecurityService(
|
||||
WebClient.Builder webClientBuilder, Environment environment) {
|
||||
String cloudControllerUrl = environment.getProperty("vcap.application.cf_api");
|
||||
boolean skipSslValidation = environment.getProperty(
|
||||
"management.cloudfoundry.skip-ssl-validation", Boolean.class, false);
|
||||
return (cloudControllerUrl == null ? null
|
||||
: new ReactiveCloudFoundrySecurityService(webClientBuilder,
|
||||
cloudControllerUrl));
|
||||
cloudControllerUrl, skipSslValidation));
|
||||
}
|
||||
|
||||
private CorsConfiguration getCorsConfiguration() {
|
||||
|
|
|
@ -20,6 +20,8 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.netty.handler.ssl.SslProvider;
|
||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel;
|
||||
|
@ -27,6 +29,7 @@ import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryA
|
|||
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryAuthorizationException.Reason;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec;
|
||||
|
@ -50,13 +53,24 @@ class ReactiveCloudFoundrySecurityService {
|
|||
private Mono<String> uaaUrl;
|
||||
|
||||
ReactiveCloudFoundrySecurityService(WebClient.Builder webClientBuilder,
|
||||
String cloudControllerUrl) {
|
||||
String cloudControllerUrl, boolean skipSslValidation) {
|
||||
Assert.notNull(webClientBuilder, "Webclient must not be null");
|
||||
Assert.notNull(cloudControllerUrl, "CloudControllerUrl must not be null");
|
||||
if (skipSslValidation) {
|
||||
webClientBuilder.clientConnector(buildTrustAllSslConnector());
|
||||
}
|
||||
this.webClient = webClientBuilder.build();
|
||||
this.cloudControllerUrl = cloudControllerUrl;
|
||||
}
|
||||
|
||||
protected ReactorClientHttpConnector buildTrustAllSslConnector() {
|
||||
return new ReactorClientHttpConnector(
|
||||
(options) -> options.sslSupport((sslContextBuilder) -> {
|
||||
sslContextBuilder.sslProvider(SslProvider.JDK)
|
||||
.trustManager(InsecureTrustManagerFactory.INSTANCE);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Mono of the access level that should be granted to the given token.
|
||||
* @param token the token
|
||||
|
|
|
@ -21,9 +21,14 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import reactor.ipc.netty.http.HttpResources;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
|
@ -56,8 +61,10 @@ import org.springframework.security.web.server.WebFilterChainProxy;
|
|||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
|
@ -69,6 +76,9 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
|
|||
|
||||
private AnnotationConfigReactiveWebApplicationContext context;
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.context = new AnnotationConfigReactiveWebApplicationContext();
|
||||
|
@ -76,6 +86,7 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
|
|||
|
||||
@After
|
||||
public void close() {
|
||||
HttpResources.reset();
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
|
@ -233,6 +244,38 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
|
|||
.isInstanceOf(CloudFoundryReactiveHealthEndpointWebExtension.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipSslValidation() {
|
||||
setupContextWithCloudEnabled();
|
||||
TestPropertyValues
|
||||
.of("management.cloudfoundry.skip-ssl-validation:true")
|
||||
.applyTo(this.context);
|
||||
this.context.refresh();
|
||||
CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping();
|
||||
Object interceptor = ReflectionTestUtils.getField(handlerMapping,
|
||||
"securityInterceptor");
|
||||
Object interceptorSecurityService = ReflectionTestUtils.getField(interceptor,
|
||||
"cloudFoundrySecurityService");
|
||||
WebClient webClient = (WebClient) ReflectionTestUtils
|
||||
.getField(interceptorSecurityService, "webClient");
|
||||
webClient.get().uri("https://self-signed.badssl.com/").exchange().block();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sslValidationNotSkippedByDefault() {
|
||||
setupContextWithCloudEnabled();
|
||||
this.context.refresh();
|
||||
CloudFoundryWebFluxEndpointHandlerMapping handlerMapping = getHandlerMapping();
|
||||
Object interceptor = ReflectionTestUtils.getField(handlerMapping,
|
||||
"securityInterceptor");
|
||||
Object interceptorSecurityService = ReflectionTestUtils.getField(interceptor,
|
||||
"cloudFoundrySecurityService");
|
||||
WebClient webClient = (WebClient) ReflectionTestUtils
|
||||
.getField(interceptorSecurityService, "webClient");
|
||||
this.thrown.expectCause(instanceOf(SSLException.class));
|
||||
webClient.get().uri("https://self-signed.badssl.com/").exchange().block();
|
||||
}
|
||||
|
||||
private void setupContextWithCloudEnabled() {
|
||||
TestPropertyValues
|
||||
.of("VCAP_APPLICATION:---", "vcap.application.application_id:my-app-id",
|
||||
|
|
|
@ -59,7 +59,7 @@ public class ReactiveCloudFoundrySecurityServiceTests {
|
|||
this.server = new MockWebServer();
|
||||
this.builder = WebClient.builder().baseUrl(this.server.url("/").toString());
|
||||
this.securityService = new ReactiveCloudFoundrySecurityService(this.builder,
|
||||
CLOUD_CONTROLLER);
|
||||
CLOUD_CONTROLLER, false);
|
||||
}
|
||||
|
||||
@After
|
||||
|
|
Loading…
Reference in New Issue