From 959f492ddf77cbfe84dc4d3f6633ebf4118019d7 Mon Sep 17 00:00:00 2001 From: Scott Frederick Date: Mon, 30 Mar 2020 14:13:49 -0500 Subject: [PATCH] Polish and add tests. Polish the code and add tests for SpringVaultClientConfiguration when a namespace is configured. Fixes gh-1589 --- .../vault/SpringVaultClientConfiguration.java | 12 +++-- .../SpringVaultClientConfigurationTests.java | 44 +++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfiguration.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfiguration.java index da7f8c34..5009583d 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfiguration.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfiguration.java @@ -130,11 +130,17 @@ public class SpringVaultClientConfiguration extends AbstractVaultConfiguration return new SslConfiguration(keyStoreConfiguration, trustStoreConfiguration); } + /** + * This method is a work-around for the Spring Vault issue documented in + * https://github.com/spring-projects/spring-vault/issues/546. The method should be + * removed when Spring Cloud Config is upgraded to the version of Spring Vault that + * includes the fix for the issue. + * @return the {@link RestOperations} to be used for Vault access + */ @Override public RestOperations restOperations() { - RestTemplate restOperations = (RestTemplate) super.restOperations(); - applyNamespaceInterceptor(restOperations); - return restOperations; + return restTemplateBuilder(vaultEndpointProvider(), + clientHttpRequestFactoryWrapper().getClientHttpRequestFactory()).build(); } private SslConfiguration.KeyStoreConfiguration getKeyStoreConfiguration( diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java index 2641a22c..2774ae58 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/environment/vault/SpringVaultClientConfigurationTests.java @@ -25,6 +25,7 @@ import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.context.annotation.UserConfigurations; @@ -45,6 +46,10 @@ import org.springframework.cloud.config.server.environment.vault.authentication. import org.springframework.cloud.config.server.environment.vault.authentication.PcfClientAuthenticationProvider; import org.springframework.cloud.config.server.environment.vault.authentication.TokenClientAuthenticationProvider; import org.springframework.core.io.ClassPathResource; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.mock.http.client.MockClientHttpRequest; import org.springframework.util.ClassUtils; import org.springframework.vault.authentication.AppRoleAuthentication; import org.springframework.vault.authentication.AwsEc2Authentication; @@ -58,8 +63,11 @@ import org.springframework.vault.authentication.GcpIamAuthentication; import org.springframework.vault.authentication.KubernetesAuthentication; import org.springframework.vault.authentication.PcfAuthentication; import org.springframework.vault.authentication.TokenAuthentication; +import org.springframework.vault.client.VaultHttpHeaders; import org.springframework.vault.support.SslConfiguration; import org.springframework.vault.support.SslConfiguration.KeyStoreConfiguration; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.cloud.config.server.environment.VaultEnvironmentProperties.AuthenticationMethod.APPROLE; @@ -280,6 +288,42 @@ class SpringVaultClientConfigurationTests { .isEqualTo("password"); } + @Test + public void namespaceHeaderNotAddedWhenNamespaceNotConfigured() throws IOException { + VaultEnvironmentProperties properties = new VaultEnvironmentProperties(); + + SpringVaultClientConfiguration configuration = getConfiguration(properties); + HttpRequest request = invokeInterceptors(configuration.restOperations()); + assertThat(request.getHeaders().getFirst(VaultHttpHeaders.VAULT_NAMESPACE)) + .isNull(); + } + + @Test + public void namespaceInterceptorAddedWhenNamespaceConfigured() throws IOException { + VaultEnvironmentProperties properties = new VaultEnvironmentProperties(); + properties.setNamespace("test-namespace"); + + SpringVaultClientConfiguration configuration = getConfiguration(properties); + HttpRequest request = invokeInterceptors(configuration.restOperations()); + assertThat(request.getHeaders().getFirst(VaultHttpHeaders.VAULT_NAMESPACE)) + .isEqualTo("test-namespace"); + } + + private HttpRequest invokeInterceptors(RestOperations restOperations) + throws IOException { + assertThat(restOperations).isInstanceOf(RestTemplate.class); + RestTemplate restTemplate = (RestTemplate) restOperations; + + MockClientHttpRequest request = new MockClientHttpRequest(); + ClientHttpRequestExecution execution = Mockito + .mock(ClientHttpRequestExecution.class); + byte[] body = new byte[] {}; + for (ClientHttpRequestInterceptor interceptor : restTemplate.getInterceptors()) { + interceptor.intercept(request, body, execution); + } + return request; + } + private void assertClientAuthenticationOfType(VaultEnvironmentProperties properties, Class type) { ClientAuthentication clientAuthentication = getConfiguration(properties)