Merge branch '2.2.x'

This commit is contained in:
Spencer Gibb
2020-04-08 17:13:56 -04:00
4 changed files with 122 additions and 4 deletions

View File

@@ -525,10 +525,28 @@ public class VaultEnvironmentProperties implements HttpEnvironmentRepositoryProp
*/
private String role = "";
/**
* URI to the Azure MSI Identity Service.
*/
private String identityTokenService = "";
/**
* URI to the Azure MSI Metadata Service.
*/
private String metadataService = "";
public String getAzurePath() {
return this.azurePath;
}
public String getIdentityTokenService() {
return identityTokenService;
}
public String getMetadataService() {
return metadataService;
}
public String getRole() {
return this.role;
}
@@ -537,6 +555,14 @@ public class VaultEnvironmentProperties implements HttpEnvironmentRepositoryProp
this.azurePath = azurePath;
}
public void setIdentityTokenService(String identityTokenService) {
this.identityTokenService = identityTokenService;
}
public void setMetadataService(String metadataService) {
this.metadataService = metadataService;
}
public void setRole(String role) {
this.role = role;
}

View File

@@ -103,9 +103,7 @@ public class SpringVaultClientConfiguration extends AbstractVaultConfiguration
endpointProvider, requestFactory);
if (vaultProperties.getNamespace() != null) {
restTemplateBuilder.customizers(
restTemplate -> restTemplate.getInterceptors().add(VaultClients
.createNamespaceInterceptor(vaultProperties.getNamespace())));
restTemplateBuilder.customizers(this::applyNamespaceInterceptor);
}
return restTemplateBuilder;
@@ -132,6 +130,19 @@ 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() {
return restTemplateBuilder(vaultEndpointProvider(),
clientHttpRequestFactoryWrapper().getClientHttpRequestFactory()).build();
}
private SslConfiguration.KeyStoreConfiguration getKeyStoreConfiguration(
Resource resourceProperty, String passwordProperty) {
@@ -147,6 +158,15 @@ public class SpringVaultClientConfiguration extends AbstractVaultConfiguration
return SslConfiguration.KeyStoreConfiguration.of(resourceProperty);
}
private RestOperations applyNamespaceInterceptor(RestTemplate restTemplate) {
if (vaultProperties.getNamespace() != null) {
restTemplate.getInterceptors().add(VaultClients
.createNamespaceInterceptor(vaultProperties.getNamespace()));
}
return restTemplate;
}
/**
* @return a new {@link ClientAuthentication}.
*/

View File

@@ -16,6 +16,8 @@
package org.springframework.cloud.config.server.environment.vault.authentication;
import java.net.URI;
import org.springframework.cloud.config.server.environment.VaultEnvironmentProperties;
import org.springframework.cloud.config.server.environment.VaultEnvironmentProperties.AuthenticationMethod;
import org.springframework.cloud.config.server.environment.vault.SpringVaultClientAuthenticationProvider;
@@ -44,10 +46,22 @@ public class AzureMsiClientAuthenticationProvider
AuthenticationMethod.AZURE_MSI));
AzureMsiAuthenticationOptions options = AzureMsiAuthenticationOptions.builder()
.role(azureMsi.getRole()).build();
.role(azureMsi.getRole()).path(azureMsi.getAzurePath())
.instanceMetadataUri(getUri(azureMsi.getMetadataService(),
AzureMsiAuthenticationOptions.DEFAULT_INSTANCE_METADATA_SERVICE_URI))
.identityTokenServiceUri(getUri(azureMsi.getIdentityTokenService(),
AzureMsiAuthenticationOptions.DEFAULT_IDENTITY_TOKEN_SERVICE_URI))
.build();
return new AzureMsiAuthentication(options, vaultRestOperations,
externalRestOperations);
}
private URI getUri(String uriString, URI defaultUri) {
if (uriString == null || uriString.isEmpty()) {
return defaultUri;
}
return URI.create(uriString);
}
}

View File

@@ -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,11 +46,17 @@ 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.test.util.ReflectionTestUtils;
import org.springframework.util.ClassUtils;
import org.springframework.vault.authentication.AppRoleAuthentication;
import org.springframework.vault.authentication.AwsEc2Authentication;
import org.springframework.vault.authentication.AwsIamAuthentication;
import org.springframework.vault.authentication.AzureMsiAuthentication;
import org.springframework.vault.authentication.AzureMsiAuthenticationOptions;
import org.springframework.vault.authentication.ClientAuthentication;
import org.springframework.vault.authentication.ClientCertificateAuthentication;
import org.springframework.vault.authentication.CubbyholeAuthentication;
@@ -58,8 +65,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;
@@ -73,6 +83,8 @@ import static org.springframework.cloud.config.server.environment.VaultEnvironme
import static org.springframework.cloud.config.server.environment.VaultEnvironmentProperties.AuthenticationMethod.KUBERNETES;
import static org.springframework.cloud.config.server.environment.VaultEnvironmentProperties.AuthenticationMethod.PCF;
import static org.springframework.cloud.config.server.environment.VaultEnvironmentProperties.AuthenticationMethod.TOKEN;
import static org.springframework.vault.authentication.AzureMsiAuthenticationOptions.DEFAULT_IDENTITY_TOKEN_SERVICE_URI;
import static org.springframework.vault.authentication.AzureMsiAuthenticationOptions.DEFAULT_INSTANCE_METADATA_SERVICE_URI;
class SpringVaultClientConfigurationTests {
@@ -137,6 +149,16 @@ class SpringVaultClientConfigurationTests {
properties.getAzureMsi().setAzurePath("azure-msi");
assertClientAuthenticationOfType(properties, AzureMsiAuthentication.class);
AzureMsiAuthentication clientAuthentication = (AzureMsiAuthentication) getConfiguration(
properties).clientAuthentication();
AzureMsiAuthenticationOptions options = (AzureMsiAuthenticationOptions) ReflectionTestUtils
.getField(clientAuthentication, "options");
assertThat(options.getIdentityTokenServiceUri())
.isEqualTo(DEFAULT_IDENTITY_TOKEN_SERVICE_URI);
assertThat(options.getInstanceMetadataServiceUri())
.isEqualTo(DEFAULT_INSTANCE_METADATA_SERVICE_URI);
}
@Test
@@ -280,6 +302,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<? extends ClientAuthentication> type) {
ClientAuthentication clientAuthentication = getConfiguration(properties)