From f8a4e3a4fd22c0101e5711dfe2b93702d1e50bdf Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 2 Mar 2017 11:58:44 +0100 Subject: [PATCH] Add EnvironmentVaultConfiguration. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide a EnvironmentVaultConfiguration for common configuration scenarios to obtain configuration from Spring's Environment. EnvironmentVaultConfiguration supports various authentication mechanisms: Token, AppId, AppRole, AWS EC2, Client-Certificates, and Cubbyhole. Java-based configuration class: @PropertySource("vault.properties") @Import(EnvironmentVaultConfiguration.class) public class MyConfiguration{ } vault.properties vault.uri=https://localhost:8200 vault.token=… Closes gh-30. --- .../ClientHttpRequestFactoryFactory.java | 2 +- .../config/EnvironmentVaultConfiguration.java | 326 ++++++++++++++++++ ...igurationAppIdAuthenticationUnitTests.java | 57 +++ ...urationAppRoleAuthenticationUnitTests.java | 57 +++ ...gurationAwsEc2AuthenticationUnitTests.java | 56 +++ ...tionClientCertAuthenticationUnitTests.java | 57 +++ ...ationCubbyholeAuthenticationUnitTests.java | 56 +++ ...nvironmentVaultConfigurationUnitTests.java | 100 ++++++ .../asciidoc/reference/getting-started.adoc | 74 ++++ 9 files changed, 784 insertions(+), 1 deletion(-) create mode 100644 spring-vault-core/src/main/java/org/springframework/vault/config/EnvironmentVaultConfiguration.java create mode 100644 spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationAppIdAuthenticationUnitTests.java create mode 100644 spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationAppRoleAuthenticationUnitTests.java create mode 100644 spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationAwsEc2AuthenticationUnitTests.java create mode 100644 spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationClientCertAuthenticationUnitTests.java create mode 100644 spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationCubbyholeAuthenticationUnitTests.java create mode 100644 spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationUnitTests.java diff --git a/spring-vault-core/src/main/java/org/springframework/vault/config/ClientHttpRequestFactoryFactory.java b/spring-vault-core/src/main/java/org/springframework/vault/config/ClientHttpRequestFactoryFactory.java index ee007e1b..0cf8e22b 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/config/ClientHttpRequestFactoryFactory.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/config/ClientHttpRequestFactoryFactory.java @@ -132,7 +132,7 @@ public class ClientHttpRequestFactoryFactory { return new SimpleClientHttpRequestFactory(); } - private static SSLContext getSSLContext(SslConfiguration sslConfiguration) + static SSLContext getSSLContext(SslConfiguration sslConfiguration) throws GeneralSecurityException, IOException { KeyManager[] keyManagers = sslConfiguration.getKeyStore() != null ? createKeyManagerFactory( diff --git a/spring-vault-core/src/main/java/org/springframework/vault/config/EnvironmentVaultConfiguration.java b/spring-vault-core/src/main/java/org/springframework/vault/config/EnvironmentVaultConfiguration.java new file mode 100644 index 00000000..a21c70b6 --- /dev/null +++ b/spring-vault-core/src/main/java/org/springframework/vault/config/EnvironmentVaultConfiguration.java @@ -0,0 +1,326 @@ +/* + * Copyright 2017 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.vault.config; + +import java.net.URI; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.vault.authentication.AppIdAuthentication; +import org.springframework.vault.authentication.AppIdAuthenticationOptions; +import org.springframework.vault.authentication.AppIdUserIdMechanism; +import org.springframework.vault.authentication.AppRoleAuthentication; +import org.springframework.vault.authentication.AppRoleAuthenticationOptions; +import org.springframework.vault.authentication.AwsEc2Authentication; +import org.springframework.vault.authentication.AwsEc2AuthenticationOptions; +import org.springframework.vault.authentication.AwsEc2AuthenticationOptions.AwsEc2AuthenticationOptionsBuilder; +import org.springframework.vault.authentication.ClientAuthentication; +import org.springframework.vault.authentication.ClientCertificateAuthentication; +import org.springframework.vault.authentication.CubbyholeAuthentication; +import org.springframework.vault.authentication.CubbyholeAuthenticationOptions; +import org.springframework.vault.authentication.IpAddressUserId; +import org.springframework.vault.authentication.MacAddressUserId; +import org.springframework.vault.authentication.StaticUserId; +import org.springframework.vault.authentication.TokenAuthentication; +import org.springframework.vault.client.VaultEndpoint; +import org.springframework.vault.support.SslConfiguration; +import org.springframework.vault.support.VaultToken; +import org.springframework.web.client.RestOperations; + +/** + * Configuration using Spring's {@link org.springframework.core.env.Environment} to + * configure Spring Vault endpoint, SSL options and authentication options. This + * configuration class uses predefined property keys and is usually imported as part of an + * existing Java-based configuration. Configuration is obtained from other, existing + * property sources. + *

+ * Usage: + * + * Java-based configuration part: + * + *

+ *     
+ * @Configuration
+ * @Import(EnvironmentVaultConfiguration.class)
+ * public class MyConfiguration {
+ * }
+ *     
+ * 
+ * + * Supplied properties: + * + *
+ *     
+ * vault.uri=https://localhost:8200
+ * vault.token=00000000-0000-0000-0000-000000000000
+ *     
+ * 
+ * + *

Property keys

+ * + * Authentication-specific properties must be provided depending on the authentication + * method. + * + * + * @author Mark Paluch + * @see org.springframework.core.env.Environment + * @see org.springframework.core.env.PropertySource + * @see VaultEndpoint + * @see AppIdAuthentication + * @see AppRoleAuthentication + * @see AwsEc2Authentication + * @see ClientCertificateAuthentication + * @see CubbyholeAuthentication + */ +@Configuration +public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration + implements ApplicationContextAware { + + private RestOperations cachedRestOperations; + private ApplicationContext applicationContext; + + @Override + public RestOperations restOperations() { + + if (this.cachedRestOperations != null) { + return this.cachedRestOperations; + } + + this.cachedRestOperations = super.restOperations(); + return this.cachedRestOperations; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + + this.applicationContext = applicationContext; + super.setApplicationContext(applicationContext); + } + + @Override + public VaultEndpoint vaultEndpoint() { + + String uri = getProperty("vault.uri"); + if (uri != null) { + return VaultEndpoint.from(URI.create(uri)); + } + + throw new IllegalStateException("Vault URI (vault.uri) is null"); + } + + @Override + public SslConfiguration sslConfiguration() { + + Resource keyStore = getResource("vault.ssl.key-store"); + String keyStorePassword = getProperty("vault.ssl.key-store-password"); + Resource trustStore = getResource("vault.ssl.trust-store"); + String trustStorePassword = getProperty("vault.ssl.trust-store-password"); + + return new SslConfiguration(keyStore, keyStorePassword, trustStore, + trustStorePassword); + } + + @Override + public ClientAuthentication clientAuthentication() { + + String authentication = getEnvironment() + .getProperty("vault.authentication", AuthenticationMethod.TOKEN.name()) + .toUpperCase().replace('-', '_'); + + AuthenticationMethod authenticationMethod = AuthenticationMethod + .valueOf(authentication); + + switch (authenticationMethod) { + + case TOKEN: + return tokenAuthentication(); + case APPID: + return appIdAuthentication(); + case APPROLE: + return appRoleAuthentication(); + case AWS_EC2: + return awsEc2Authentication(); + case CERT: + return new ClientCertificateAuthentication(restOperations()); + case CUBBYHOLE: + return cubbyholeAuthentication(); + + default: + throw new IllegalStateException(String.format( + "Vault authentication method %s is not supported with %s", + authenticationMethod, getClass().getSimpleName())); + } + } + + // ------------------------------------------------------------------------- + // Implementation hooks and helper methods + // ------------------------------------------------------------------------- + + protected ClientAuthentication tokenAuthentication() { + + String token = getProperty("vault.token"); + Assert.hasText(token, + "Vault Token authentication: Token (vault.token) must not be empty"); + + return new TokenAuthentication(token); + } + + protected ClientAuthentication appIdAuthentication() { + + String appId = getEnvironment().getProperty("vault.app-id.app-id", + getProperty("spring.application.name")); + String userId = getProperty("vault.app-id.user-id"); + + Assert.hasText(appId, + "Vault AppId authentication: AppId (vault.app-id.app-id) must not be empty"); + Assert.hasText(userId, + "Vault AppId authentication: UserId (vault.app-id.user-id) must not be empty"); + + AppIdAuthenticationOptions authenticationOptions = AppIdAuthenticationOptions + .builder().appId(appId) // + .userIdMechanism(getAppIdUserIdMechanism(userId)).build(); + + return new AppIdAuthentication(authenticationOptions, restOperations()); + } + + protected ClientAuthentication appRoleAuthentication() { + + String roleId = getProperty("vault.app-role.role-id"); + String secretId = getProperty("vault.app-role.secret-id"); + Assert.hasText(roleId, + "Vault AppRole authentication: RoleId (vault.app-role.role-id) must not be empty"); + + AppRoleAuthenticationOptions.AppRoleAuthenticationOptionsBuilder builder = AppRoleAuthenticationOptions + .builder().roleId(roleId); + + if (StringUtils.hasText(secretId)) { + builder = builder.secretId(secretId); + } + + return new AppRoleAuthentication(builder.build(), restOperations()); + } + + protected AppIdUserIdMechanism getAppIdUserIdMechanism(String userId) { + + if (userId.equalsIgnoreCase(AppIdUserId.IP_ADDRESS.name())) { + return new IpAddressUserId(); + } + + if (userId.equalsIgnoreCase(AppIdUserId.MAC_ADDRESS.name())) { + return new MacAddressUserId(); + } + + return new StaticUserId(userId); + } + + protected ClientAuthentication awsEc2Authentication() { + + String roleId = getProperty("vault.aws-ec2.role-id"); + String identityDocument = getProperty("vault.aws-ec2.identity-document"); + Assert.hasText(roleId, + "Vault AWS EC2 authentication: RoleId (vault.aws-ec2.role-id) must not be empty"); + + AwsEc2AuthenticationOptionsBuilder builder = AwsEc2AuthenticationOptions.builder() + .role(roleId); + + if (StringUtils.hasText(identityDocument)) { + builder.identityDocumentUri(URI.create(identityDocument)); + } + + return new AwsEc2Authentication(builder.build(), restOperations(), + restOperations()); + } + + protected ClientAuthentication cubbyholeAuthentication() { + + String token = getProperty("vault.token"); + Assert.hasText(token, + "Vault Cubbyhole authentication: Initial token (vault.token) must not be empty"); + + CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions.builder() // + .wrapped() // + .initialToken(VaultToken.of(token)) // + .build(); + + return new CubbyholeAuthentication(options, restOperations()); + } + + private String getProperty(String key) { + return getEnvironment().getProperty(key); + } + + private Resource getResource(String key) { + + String value = getProperty(key); + return value != null ? applicationContext.getResource(value) : null; + } + + enum AppIdUserId { + IP_ADDRESS, MAC_ADDRESS; + } + + enum AuthenticationMethod { + TOKEN, APPID, APPROLE, AWS_EC2, CERT, CUBBYHOLE; + } +} diff --git a/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationAppIdAuthenticationUnitTests.java b/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationAppIdAuthenticationUnitTests.java new file mode 100644 index 00000000..ee3f7c32 --- /dev/null +++ b/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationAppIdAuthenticationUnitTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2017 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.vault.config; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.vault.authentication.AppIdAuthentication; +import org.springframework.vault.authentication.ClientAuthentication; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for {@link EnvironmentVaultConfiguration} with AppId authentication. + * + * @author Mark Paluch + */ +@RunWith(SpringRunner.class) +@TestPropertySource(properties = { "vault.uri=https://localhost:8123", + "vault.authentication=appid", "vault.app-id.user-id=IP_ADDRESS", + "vault.app-id.app-id=foo" }) +public class EnvironmentVaultConfigurationAppIdAuthenticationUnitTests { + + @Configuration + @Import(EnvironmentVaultConfiguration.class) + static class ApplicationConfiguration { + } + + @Autowired + private EnvironmentVaultConfiguration configuration; + + @Test + public void shouldConfigureAuthentication() { + + ClientAuthentication clientAuthentication = configuration.clientAuthentication(); + + assertThat(clientAuthentication).isInstanceOf(AppIdAuthentication.class); + } +} diff --git a/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationAppRoleAuthenticationUnitTests.java b/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationAppRoleAuthenticationUnitTests.java new file mode 100644 index 00000000..efb5c667 --- /dev/null +++ b/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationAppRoleAuthenticationUnitTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2017 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.vault.config; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.vault.authentication.AppRoleAuthentication; +import org.springframework.vault.authentication.ClientAuthentication; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for {@link EnvironmentVaultConfiguration} with AppRole authentication. + * + * @author Mark Paluch + */ +@RunWith(SpringRunner.class) +@TestPropertySource(properties = { "vault.uri=https://localhost:8123", + "vault.authentication=approle", "vault.app-role.role-id=role", + "vault.app-role.secret-id=foo" }) +public class EnvironmentVaultConfigurationAppRoleAuthenticationUnitTests { + + @Configuration + @Import(EnvironmentVaultConfiguration.class) + static class ApplicationConfiguration { + } + + @Autowired + private EnvironmentVaultConfiguration configuration; + + @Test + public void shouldConfigureAuthentication() { + + ClientAuthentication clientAuthentication = configuration.clientAuthentication(); + + assertThat(clientAuthentication).isInstanceOf(AppRoleAuthentication.class); + } +} diff --git a/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationAwsEc2AuthenticationUnitTests.java b/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationAwsEc2AuthenticationUnitTests.java new file mode 100644 index 00000000..efa11456 --- /dev/null +++ b/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationAwsEc2AuthenticationUnitTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2017 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.vault.config; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.vault.authentication.AwsEc2Authentication; +import org.springframework.vault.authentication.ClientAuthentication; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for {@link EnvironmentVaultConfiguration} with AppRole authentication. + * + * @author Mark Paluch + */ +@RunWith(SpringRunner.class) +@TestPropertySource(properties = { "vault.uri=https://localhost:8123", + "vault.authentication=aws-ec2", "vault.aws-ec2.role-id=role" }) +public class EnvironmentVaultConfigurationAwsEc2AuthenticationUnitTests { + + @Configuration + @Import(EnvironmentVaultConfiguration.class) + static class ApplicationConfiguration { + } + + @Autowired + private EnvironmentVaultConfiguration configuration; + + @Test + public void shouldConfigureAuthentication() { + + ClientAuthentication clientAuthentication = configuration.clientAuthentication(); + + assertThat(clientAuthentication).isInstanceOf(AwsEc2Authentication.class); + } +} diff --git a/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationClientCertAuthenticationUnitTests.java b/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationClientCertAuthenticationUnitTests.java new file mode 100644 index 00000000..683dca9a --- /dev/null +++ b/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationClientCertAuthenticationUnitTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2017 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.vault.config; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.vault.authentication.ClientAuthentication; +import org.springframework.vault.authentication.ClientCertificateAuthentication; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for {@link EnvironmentVaultConfiguration} with AppRole authentication. + * + * @author Mark Paluch + */ +@RunWith(SpringRunner.class) +@TestPropertySource(properties = { "vault.uri=https://localhost:8123", + "vault.authentication=cert", "vault.aws-ec2.role-id=role" }) +public class EnvironmentVaultConfigurationClientCertAuthenticationUnitTests { + + @Configuration + @Import(EnvironmentVaultConfiguration.class) + static class ApplicationConfiguration { + } + + @Autowired + private EnvironmentVaultConfiguration configuration; + + @Test + public void shouldConfigureAuthentication() { + + ClientAuthentication clientAuthentication = configuration.clientAuthentication(); + + assertThat(clientAuthentication) + .isInstanceOf(ClientCertificateAuthentication.class); + } +} diff --git a/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationCubbyholeAuthenticationUnitTests.java b/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationCubbyholeAuthenticationUnitTests.java new file mode 100644 index 00000000..e9ebf473 --- /dev/null +++ b/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationCubbyholeAuthenticationUnitTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2017 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.vault.config; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.vault.authentication.ClientAuthentication; +import org.springframework.vault.authentication.CubbyholeAuthentication; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for {@link EnvironmentVaultConfiguration} with AppRole authentication. + * + * @author Mark Paluch + */ +@RunWith(SpringRunner.class) +@TestPropertySource(properties = { "vault.uri=https://localhost:8123", + "vault.authentication=cubbyhole", "vault.token=my-token" }) +public class EnvironmentVaultConfigurationCubbyholeAuthenticationUnitTests { + + @Configuration + @Import(EnvironmentVaultConfiguration.class) + static class ApplicationConfiguration { + } + + @Autowired + private EnvironmentVaultConfiguration configuration; + + @Test + public void shouldConfigureAuthentication() { + + ClientAuthentication clientAuthentication = configuration.clientAuthentication(); + + assertThat(clientAuthentication).isInstanceOf(CubbyholeAuthentication.class); + } +} diff --git a/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationUnitTests.java b/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationUnitTests.java new file mode 100644 index 00000000..eef1db6b --- /dev/null +++ b/spring-vault-core/src/test/java/org/springframework/vault/config/EnvironmentVaultConfigurationUnitTests.java @@ -0,0 +1,100 @@ +/* + * Copyright 2017 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.vault.config; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.UrlResource; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.vault.authentication.ClientAuthentication; +import org.springframework.vault.authentication.TokenAuthentication; +import org.springframework.vault.support.SslConfiguration; +import org.springframework.vault.support.VaultToken; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for {@link EnvironmentVaultConfiguration}. + * + * @author Mark Paluch + */ +@RunWith(SpringRunner.class) +@TestPropertySource(properties = { "vault.uri=https://localhost:8123", + "vault.token=my-token", "vault.ssl.key-store-password=key store password", + "vault.ssl.trust-store-password=trust store password" }) +public class EnvironmentVaultConfigurationUnitTests { + + @Configuration + @Import(EnvironmentVaultConfiguration.class) + static class ApplicationConfiguration { + } + + @Autowired + private EnvironmentVaultConfiguration configuration; + + @Autowired + private ConfigurableEnvironment configurableEnvironment; + + @Test + public void shouldConfigureEndpoint() { + assertThat(configuration.vaultEndpoint().getPort()).isEqualTo(8123); + } + + @Test + public void shouldConfigureTokenAuthentication() { + + ClientAuthentication clientAuthentication = configuration.clientAuthentication(); + + assertThat(clientAuthentication).isInstanceOf(TokenAuthentication.class); + assertThat(clientAuthentication.login()).isEqualTo(VaultToken.of("my-token")); + } + + @Test + public void shouldConfigureSsl() { + + Map map = new HashMap(); + map.put("vault.ssl.key-store", "http://foo.bar"); + map.put("vault.ssl.trust-store", "classpath:certificate.json"); + + MapPropertySource propertySource = new MapPropertySource("shouldConfigureSsl", + map); + configurableEnvironment.getPropertySources().addFirst(propertySource); + + SslConfiguration sslConfiguration = configuration.sslConfiguration(); + + assertThat(sslConfiguration.getKeyStore()).isInstanceOf(UrlResource.class); + assertThat(sslConfiguration.getKeyStorePassword()) + .isEqualTo("key store password"); + + assertThat(sslConfiguration.getTrustStore()) + .isInstanceOf(ClassPathResource.class); + assertThat(sslConfiguration.getTrustStorePassword()) + .isEqualTo("trust store password"); + + configurableEnvironment.getPropertySources().remove(propertySource.getName()); + } +} diff --git a/src/main/asciidoc/reference/getting-started.adoc b/src/main/asciidoc/reference/getting-started.adoc index 23b30efd..e9d36897 100644 --- a/src/main/asciidoc/reference/getting-started.adoc +++ b/src/main/asciidoc/reference/getting-started.adoc @@ -261,6 +261,11 @@ public class AppConfig extends AbstractVaultConfiguration { `AbstractVaultConfiguration` or provided by your configuration. ==== +NOTE: Creating a custom configuration class might be cumbersome in some cases. +Take a look at `EnvironmentVaultConfiguration` that allows configuration by using +properties from existing property sources and Spring's `Environment`. Read more +in <>. + [[vault.core.template.sessionmanagement]] === Session Management @@ -309,6 +314,75 @@ Please note that providing `SslConfiguration` can be only applied when either Apache Http Components or the OkHttp client is on your class-path. + +[[vault.core.environment-vault-configuration]] +== Using `EnvironmentVaultConfiguration` + +Spring Vault includes `EnvironmentVaultConfiguration` configure the Vault client from Spring's `Environment` and a set of predefined +property keys. `EnvironmentVaultConfiguration` supports frequently applied configurations. Other configurations are supported by deriving from the most appropriate configuration class. Include `EnvironmentVaultConfiguration` with `@Import(EnvironmentVaultConfiguration.class)` to existing +Java-based configuration classes and supply configuration properties through any of Spring's ``PropertySource``s. + +.Using EnvironmentVaultConfiguration with a property file +==== + +.Java-based configuration class +[source,java] +---- +@PropertySource("vault.properties") +@Import(EnvironmentVaultConfiguration.class) +public class MyConfiguration{ +} +---- + +.vault.properties +[source,properties] +---- +vault.uri=https://localhost:8200 +vault.token=00000000-0000-0000-0000-000000000000 +---- +==== + +**Property keys** + +* Vault URI: `vault.uri` +* SSL Configuration + ** Keystore resource: `vault.ssl.key-store` (optional) + ** Keystore password: `vault.ssl.key-store-password` (optional) + ** Truststore resource: `vault.ssl.trust-store` (optional) + ** Truststore password: `vault.ssl.trust-store-password` (optional) +* Authentication method: `vault.authentication` (defaults to `TOKEN`, supported authentication methods are: `TOKEN`, `APPID`, `APPROLE`, `AWS_EC2`, `CERT`, `CUBBYHOLE`) + + +**Authentication-specific property keys** + +**<>** + +* Vault Token: `vault.token` + +**<>** + +* AppId: `vault.app-id.app-id` +* UserId: `vault.app-id.user-id`. `MAC_ADDRESS` and `IP_ADDRESS` use `MacAddressUserId`, respective `IpAddressUserId` user id mechanisms. Any other value is used with `StaticUserId`. + +**<>** + +* RoleId: `vault.app-role.role-id` +* SecretId: `vault.app-role.secret-id` (optional) + +**<>** + +* RoleId: `vault.aws-ec2.role-id` +* Identity Document URL: `vault.aws-ec2.identity-document` (optional) + +**<>** + +No configuration options. + +**<>** + +* Initial Vault Token: `vault.token` + + [[vault.core.propertysupport]] == Vault Property Source Support