From c0da914b00804f3ca255eb4f3ff3587055c731a2 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 21 Jun 2016 00:12:43 +0200 Subject: [PATCH] Split into modules #11 Split Spring Cloud Vault Config into multiple modules: Core, Config, Database/Consul/RabbitMQ integrations. --- .travis.yml | 2 +- pom.xml | 72 +++- spring-cloud-vault-config-consul/pom.xml | 83 +++++ ...ultConfigConsulBootstrapConfiguration.java | 96 +++++ .../config/consul/VaultConsulProperties.java | 54 +++ .../vault/config/consul/package-info.java | 5 + .../main/resources/META-INF/spring.factories | 3 + .../consul}/ConsulSecretIntegrationTests.java | 20 +- .../config/consul/VaultConfigConsulTests.java | 11 +- .../src/test/resources/bootstrap.yml | 5 + spring-cloud-vault-config-databases/pom.xml | 97 +++++ .../databases/DatabaseSecretProperties.java | 49 +++ .../databases/VaultCassandraProperties.java | 59 +++ ...tConfigDatabaseBootstrapConfiguration.java | 108 ++++++ .../databases/VaultMySqlProperties.java | 45 +++ .../databases/VaultPostgreSqlProperties.java | 59 +++ .../vault/config/databases/package-info.java | 5 + .../main/resources/META-INF/spring.factories | 3 + .../CassandraSecretIntegrationTests.java | 13 +- .../MySqlSecretIntegrationTests.java | 13 +- .../PostgreSqlSecretIntegrationTests.java | 12 +- .../databases/VaultConfigCassandraTests.java | 6 +- .../databases/VaultConfigMySqlTests.java | 6 +- .../databases/VaultConfigPostgreSqlTests.java | 13 +- .../src/test/resources/bootstrap.yml | 5 + .../src/test/resources/cassandra.yaml | 0 spring-cloud-vault-config-rabbitmq/pom.xml | 72 ++++ ...tConfigRabbitMqBootstrapConfiguration.java | 98 +++++ .../rabbitmq/VaultRabbitMqProperties.java | 60 +++ .../vault/config/rabbitmq/package-info.java | 5 + .../main/resources/META-INF/spring.factories | 3 + .../RabbitMqSecretIntegrationTests.java | 24 +- .../rabbitmq/VaultConfigRabbitMqTests.java | 8 +- .../src/test/resources/bootstrap.yml | 5 + spring-cloud-vault-config/pom.xml | 114 +----- .../cloud/vault/SecureBackendAccessors.java | 149 -------- .../cloud/vault/VaultProperties.java | 349 ------------------ .../config/SecureBackendAccessorFactory.java | 43 +++ .../vault/config/SecureBackendAccessors.java | 77 ++++ .../vault/config/SecureBackendFactories.java | 72 ++++ .../VaultConfigBootstrapConfiguration.java | 76 ++++ .../{ => config}/VaultPropertySource.java | 49 +-- .../VaultPropertySourceLocator.java | 47 ++- .../cloud/vault/{ => config}/VaultState.java | 3 +- .../main/resources/META-INF/spring.factories | 2 +- .../AppIdAuthenticationIntegrationTests.java | 6 +- .../ApplicationFailFastTests.java | 2 +- .../GenericSecretIntegrationTests.java | 9 +- .../cloud/vault/config/PrepareVaultTests.java | 47 +++ ...VaultConfigAppIdCustomMechanismTests.java} | 18 +- .../VaultConfigAppIdTests.java} | 14 +- .../VaultConfigTests.java} | 6 +- .../test/resources/META-INF/spring.factories | 2 +- spring-cloud-vault-core/pom.xml | 92 +++++ .../cloud/vault/AppIdUserIdMechanism.java | 0 .../ClientHttpRequestFactoryFactory.java | 192 +++++----- .../cloud/vault/IpAddressUserId.java | 0 .../cloud/vault/MacAddressUserId.java | 6 +- .../cloud/vault/SecureBackendAccessor.java | 0 .../springframework/cloud/vault/Sha256.java | 0 .../cloud/vault/StaticUserId.java | 0 .../vault/VaultBootstrapConfiguration.java | 49 ++- .../cloud/vault/VaultClient.java | 3 +- .../cloud/vault/VaultProperties.java | 155 ++++++++ .../cloud/vault/VaultResponse.java | 6 +- .../cloud/vault/VaultSecretBackend.java | 22 +- .../cloud/vault/VaultToken.java | 0 .../main/resources/META-INF/spring.factories | 3 + .../cloud/vault/AbstractIntegrationTests.java | 0 ...AuthenticationMethodsIntegrationTests.java | 8 +- ...RequestFactoryFactoryIntegrationTests.java | 7 +- .../cloud/vault/PrepareVaultTests.java | 0 .../cloud/vault/TestRestTemplateFactory.java | 0 .../cloud/vault/util/CanConnect.java | 0 .../cloud/vault/util/PrepareVault.java | 0 .../cloud/vault/util/Settings.java | 0 .../cloud/vault/util/VaultRule.java | 0 .../src/test/resources/consul.json | 0 .../src/test/resources/vault.conf | 0 src/test/bash/local_run_consul.sh | 2 +- src/test/bash/local_run_vault.sh | 2 +- 81 files changed, 1912 insertions(+), 839 deletions(-) create mode 100644 spring-cloud-vault-config-consul/pom.xml create mode 100644 spring-cloud-vault-config-consul/src/main/java/org/springframework/cloud/vault/config/consul/VaultConfigConsulBootstrapConfiguration.java create mode 100644 spring-cloud-vault-config-consul/src/main/java/org/springframework/cloud/vault/config/consul/VaultConsulProperties.java create mode 100644 spring-cloud-vault-config-consul/src/main/java/org/springframework/cloud/vault/config/consul/package-info.java create mode 100644 spring-cloud-vault-config-consul/src/main/resources/META-INF/spring.factories rename {spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault => spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul}/ConsulSecretIntegrationTests.java (81%) rename spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultConsulTests.java => spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/VaultConfigConsulTests.java (91%) create mode 100644 spring-cloud-vault-config-consul/src/test/resources/bootstrap.yml create mode 100644 spring-cloud-vault-config-databases/pom.xml create mode 100644 spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/DatabaseSecretProperties.java create mode 100644 spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCassandraProperties.java create mode 100644 spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultConfigDatabaseBootstrapConfiguration.java create mode 100644 spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultMySqlProperties.java create mode 100644 spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultPostgreSqlProperties.java create mode 100644 spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/package-info.java create mode 100644 spring-cloud-vault-config-databases/src/main/resources/META-INF/spring.factories rename {spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault => spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases}/CassandraSecretIntegrationTests.java (83%) rename {spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault => spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases}/MySqlSecretIntegrationTests.java (81%) rename {spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault => spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases}/PostgreSqlSecretIntegrationTests.java (82%) rename spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultCassandraTests.java => spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCassandraTests.java (95%) rename spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultMySqlTests.java => spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigMySqlTests.java (95%) rename spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultPostgreSqlTests.java => spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigPostgreSqlTests.java (92%) create mode 100644 spring-cloud-vault-config-databases/src/test/resources/bootstrap.yml rename {spring-cloud-vault-config => spring-cloud-vault-config-databases}/src/test/resources/cassandra.yaml (100%) create mode 100644 spring-cloud-vault-config-rabbitmq/pom.xml create mode 100644 spring-cloud-vault-config-rabbitmq/src/main/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqBootstrapConfiguration.java create mode 100644 spring-cloud-vault-config-rabbitmq/src/main/java/org/springframework/cloud/vault/config/rabbitmq/VaultRabbitMqProperties.java create mode 100644 spring-cloud-vault-config-rabbitmq/src/main/java/org/springframework/cloud/vault/config/rabbitmq/package-info.java create mode 100644 spring-cloud-vault-config-rabbitmq/src/main/resources/META-INF/spring.factories rename spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/RabbitMQSecretIntegrationTests.java => spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/RabbitMqSecretIntegrationTests.java (72%) rename spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultRabbitMQTests.java => spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqTests.java (95%) create mode 100644 spring-cloud-vault-config-rabbitmq/src/test/resources/bootstrap.yml delete mode 100644 spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/SecureBackendAccessors.java delete mode 100644 spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultProperties.java create mode 100644 spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/SecureBackendAccessorFactory.java create mode 100644 spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/SecureBackendAccessors.java create mode 100644 spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/SecureBackendFactories.java create mode 100644 spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigBootstrapConfiguration.java rename spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/{ => config}/VaultPropertySource.java (77%) rename spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/{ => config}/VaultPropertySourceLocator.java (61%) rename spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/{ => config}/VaultState.java (88%) rename spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/{ => config}/AppIdAuthenticationIntegrationTests.java (88%) rename spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/{configclient => config}/ApplicationFailFastTests.java (96%) rename spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/{ => config}/GenericSecretIntegrationTests.java (86%) create mode 100644 spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/PrepareVaultTests.java rename spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/{VaultAppIdCustomMechanismTests.java => config/VaultConfigAppIdCustomMechanismTests.java} (82%) rename spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/{configclient/VaultAppIdTests.java => config/VaultConfigAppIdTests.java} (85%) rename spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/{configclient/VaultTests.java => config/VaultConfigTests.java} (92%) create mode 100644 spring-cloud-vault-core/pom.xml rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/main/java/org/springframework/cloud/vault/AppIdUserIdMechanism.java (100%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/main/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactory.java (60%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/main/java/org/springframework/cloud/vault/IpAddressUserId.java (100%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/main/java/org/springframework/cloud/vault/MacAddressUserId.java (97%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/main/java/org/springframework/cloud/vault/SecureBackendAccessor.java (100%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/main/java/org/springframework/cloud/vault/Sha256.java (100%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/main/java/org/springframework/cloud/vault/StaticUserId.java (100%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/main/java/org/springframework/cloud/vault/VaultBootstrapConfiguration.java (69%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/main/java/org/springframework/cloud/vault/VaultClient.java (98%) create mode 100644 spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultProperties.java rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/main/java/org/springframework/cloud/vault/VaultResponse.java (95%) rename spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/MyUserIdMechanism.java => spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultSecretBackend.java (71%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/main/java/org/springframework/cloud/vault/VaultToken.java (100%) create mode 100644 spring-cloud-vault-core/src/main/resources/META-INF/spring.factories rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/test/java/org/springframework/cloud/vault/AbstractIntegrationTests.java (100%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/test/java/org/springframework/cloud/vault/AppIdAuthenticationMethodsIntegrationTests.java (96%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/test/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactoryIntegrationTests.java (92%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/test/java/org/springframework/cloud/vault/PrepareVaultTests.java (100%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/test/java/org/springframework/cloud/vault/TestRestTemplateFactory.java (100%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/test/java/org/springframework/cloud/vault/util/CanConnect.java (100%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/test/java/org/springframework/cloud/vault/util/PrepareVault.java (100%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/test/java/org/springframework/cloud/vault/util/Settings.java (100%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/test/java/org/springframework/cloud/vault/util/VaultRule.java (100%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/test/resources/consul.json (100%) rename {spring-cloud-vault-config => spring-cloud-vault-core}/src/test/resources/vault.conf (100%) diff --git a/.travis.yml b/.travis.yml index 13d8e01d..066a0f68 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ install: - mkdir -p download - test -f download/apache-cassandra-2.2.6-bin.tar.gz || wget http://www-eu.apache.org/dist/cassandra/2.2.6/apache-cassandra-2.2.6-bin.tar.gz -O download/apache-cassandra-2.2.6-bin.tar.gz - tar xzf download/apache-cassandra-2.2.6-bin.tar.gz - - cp -f spring-cloud-vault-config/src/test/resources/cassandra.yaml apache-cassandra-2.2.6/conf + - cp -f spring-cloud-vault-config-databases/src/test/resources/cassandra.yaml apache-cassandra-2.2.6/conf - apache-cassandra-2.2.6/bin/cassandra - src/test/bash/create_certificates.sh - src/test/bash/install_vault.sh diff --git a/pom.xml b/pom.xml index 1075742b..4acc28da 100644 --- a/pom.xml +++ b/pom.xml @@ -1,8 +1,8 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - + org.springframework.cloud spring-cloud-build @@ -20,10 +20,74 @@ Configuration Integration with Hashicorp Vault - spring-cloud-vault-config - docs + spring-cloud-vault-core + spring-cloud-vault-config + spring-cloud-vault-config-databases + spring-cloud-vault-config-consul + spring-cloud-vault-config-rabbitmq + docs + + UTF-8 + 1.7 + 4.5.2 + 4.4.4 + 4.1.0.Final + 2.7.5 + + + + + + org.springframework.cloud + spring-cloud-context + 1.1.0.BUILD-SNAPSHOT + + + + org.assertj + assertj-core + 3.3.0 + test + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + true + + + commons-logging + commons-logging + + + + + + org.apache.httpcomponents + httpcore + ${httpcore.version} + true + + + + io.netty + netty-all + ${netty.version} + true + + + + com.squareup.okhttp + okhttp + ${okhttp.version} + true + + + + spring-snapshots diff --git a/spring-cloud-vault-config-consul/pom.xml b/spring-cloud-vault-config-consul/pom.xml new file mode 100644 index 00000000..49b02f74 --- /dev/null +++ b/spring-cloud-vault-config-consul/pom.xml @@ -0,0 +1,83 @@ + + + 4.0.0 + + + org.springframework.cloud + spring-cloud-vault-config-parent + 1.0.0.BUILD-SNAPSHOT + .. + + + org.springframework.cloud + spring-cloud-vault-config-consul + 1.0.0.BUILD-SNAPSHOT + jar + + Spring Cloud Vault Config Consul support + Spring Cloud Vault Config Consul support + + + + org.springframework.cloud + spring-cloud-vault-core + ${project.version} + + + org.springframework.cloud + spring-cloud-vault-core + ${project.version} + test-jar + test + + + org.springframework.cloud + spring-cloud-vault-config + ${project.version} + + + org.projectlombok + lombok + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.projectlombok + lombok + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.apache.httpcomponents + httpclient + test + + + + org.apache.httpcomponents + httpcore + test + + + + org.assertj + assertj-core + + + + diff --git a/spring-cloud-vault-config-consul/src/main/java/org/springframework/cloud/vault/config/consul/VaultConfigConsulBootstrapConfiguration.java b/spring-cloud-vault-config-consul/src/main/java/org/springframework/cloud/vault/config/consul/VaultConfigConsulBootstrapConfiguration.java new file mode 100644 index 00000000..c01289d1 --- /dev/null +++ b/spring-cloud-vault-config-consul/src/main/java/org/springframework/cloud/vault/config/consul/VaultConfigConsulBootstrapConfiguration.java @@ -0,0 +1,96 @@ +/* + * Copyright 2016 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.cloud.vault.config.consul; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.vault.SecureBackendAccessor; +import org.springframework.cloud.vault.config.SecureBackendAccessorFactory; +import org.springframework.cloud.vault.VaultSecretBackend; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.Assert; + +/** + * @author Mark Paluch + */ +@Configuration +@EnableConfigurationProperties +public class VaultConfigConsulBootstrapConfiguration { + + @Bean + public SecureBackendAccessorFactory secureBackendAccessorFactory() { + return new ConsulSecureBackendAccessorFactory(); + } + + @Bean + public VaultConsulProperties vaultConsulProperties() { + return new VaultConsulProperties(); + } + + static class ConsulSecureBackendAccessorFactory + implements SecureBackendAccessorFactory { + + @Override + public SecureBackendAccessor createSecureBackendAccessor( + VaultConsulProperties properties) { + return forConsul(properties); + } + + @Override + public boolean supports(VaultSecretBackend secretBackend) { + return secretBackend instanceof VaultConsulProperties; + } + + /** + * Creates a {@link SecureBackendAccessor} for a secure backend using + * {@link VaultConsulProperties}. This accessor transforms Vault's token property + * names to names provided with {@link VaultConsulProperties#getTokenProperty()}. + * + * @param properties must not be {@literal null}. + * @return the {@link SecureBackendAccessor} + */ + public static SecureBackendAccessor forConsul( + final VaultConsulProperties properties) { + + Assert.notNull(properties, "VaultConsulProperties must not be null"); + + return new SecureBackendAccessor() { + + @Override + public Map variables() { + + Map variables = new HashMap<>(); + variables.put("backend", properties.getBackend()); + variables.put("key", String.format("creds/%s", properties.getRole())); + return variables; + } + + @Override + public Map transformProperties( + Map input) { + + Map result = new HashMap(); + result.put(properties.getTokenProperty(), input.get("token")); + + return result; + } + }; + } + } +} diff --git a/spring-cloud-vault-config-consul/src/main/java/org/springframework/cloud/vault/config/consul/VaultConsulProperties.java b/spring-cloud-vault-config-consul/src/main/java/org/springframework/cloud/vault/config/consul/VaultConsulProperties.java new file mode 100644 index 00000000..faa3ef46 --- /dev/null +++ b/spring-cloud-vault-config-consul/src/main/java/org/springframework/cloud/vault/config/consul/VaultConsulProperties.java @@ -0,0 +1,54 @@ +/* + * Copyright 2016 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.cloud.vault.config.consul; + +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.vault.VaultSecretBackend; + +import lombok.Data; + +/** + * Configuration properties for Hashicorp Consul. + * + * @author Mark Paluch + */ +@ConfigurationProperties("spring.cloud.vault.consul") +@Data +public class VaultConsulProperties implements VaultSecretBackend { + + /** + * Enable consul backend usage. + */ + private boolean enabled = false; + + /** + * Role name for credentials. + */ + private String role; + + /** + * Consul backend path. + */ + @NotEmpty + private String backend = "consul"; + + /** + * Target property for the obtained token. + */ + @NotEmpty + private String tokenProperty = "spring.cloud.consul.token"; +} \ No newline at end of file diff --git a/spring-cloud-vault-config-consul/src/main/java/org/springframework/cloud/vault/config/consul/package-info.java b/spring-cloud-vault-config-consul/src/main/java/org/springframework/cloud/vault/config/consul/package-info.java new file mode 100644 index 00000000..0e3fba3b --- /dev/null +++ b/spring-cloud-vault-config-consul/src/main/java/org/springframework/cloud/vault/config/consul/package-info.java @@ -0,0 +1,5 @@ +/** + * Consul integration with Vault. + * @author Mark Paluch + */ +package org.springframework.cloud.vault.config.consul; \ No newline at end of file diff --git a/spring-cloud-vault-config-consul/src/main/resources/META-INF/spring.factories b/spring-cloud-vault-config-consul/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..eaef6195 --- /dev/null +++ b/spring-cloud-vault-config-consul/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Bootstrap Configuration +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ +org.springframework.cloud.vault.config.consul.VaultConfigConsulBootstrapConfiguration \ No newline at end of file diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/ConsulSecretIntegrationTests.java b/spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/ConsulSecretIntegrationTests.java similarity index 81% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/ConsulSecretIntegrationTests.java rename to spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/ConsulSecretIntegrationTests.java index e7355b07..c97a84d4 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/ConsulSecretIntegrationTests.java +++ b/spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/ConsulSecretIntegrationTests.java @@ -13,21 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.vault; +package org.springframework.cloud.vault.config.consul; import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; -import static org.springframework.cloud.vault.SecureBackendAccessors.*; +import static org.springframework.cloud.vault.config.consul.VaultConfigConsulBootstrapConfiguration.ConsulSecureBackendAccessorFactory.*; import java.net.InetSocketAddress; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import org.apache.commons.codec.binary.Base64; import org.junit.Before; import org.junit.Test; import org.springframework.boot.test.TestRestTemplate; +import org.springframework.cloud.vault.AbstractIntegrationTests; +import org.springframework.cloud.vault.TestRestTemplateFactory; +import org.springframework.cloud.vault.VaultClient; +import org.springframework.cloud.vault.VaultProperties; import org.springframework.cloud.vault.util.CanConnect; import org.springframework.cloud.vault.util.Settings; import org.springframework.core.ParameterizedTypeReference; @@ -35,6 +38,7 @@ import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; +import org.springframework.util.Base64Utils; /** * Integration tests for {@link VaultClient} using the consul secret backend. This test @@ -58,7 +62,7 @@ public class ConsulSecretIntegrationTests extends AbstractIntegrationTests { private VaultProperties vaultProperties = Settings.createVaultProperties(); private VaultClient vaultClient = new VaultClient(vaultProperties); - private VaultProperties.Consul consul = vaultProperties.getConsul(); + private VaultConsulProperties consul = new VaultConsulProperties(); private TestRestTemplate restTemplate = new TestRestTemplate(); @@ -84,8 +88,8 @@ public class ConsulSecretIntegrationTests extends AbstractIntegrationTests { HttpEntity requestEntity = new HttpEntity<>( "{\"Name\": \"sample\", \"Type\": \"management\"}", headers); ResponseEntity> tokenResponse = restTemplate.exchange( - "http://{address}/v1/acl/create", HttpMethod.PUT, requestEntity, - STRING_MAP, CONNECTION_URL); + "http://{host}:{port}/v1/acl/create", HttpMethod.PUT, requestEntity, + STRING_MAP, CONSUL_HOST, CONSUL_PORT); Map consulAccess = new HashMap<>(); consulAccess.put("address", CONNECTION_URL); @@ -97,7 +101,7 @@ public class ConsulSecretIntegrationTests extends AbstractIntegrationTests { prepare().write( String.format("%s/roles/%s", consul.getBackend(), consul.getRole()), Collections.singletonMap("policy", - Base64.encodeBase64String(POLICY.getBytes()))); + Base64Utils.encodeToString(POLICY.getBytes()))); vaultClient.setRest(TestRestTemplateFactory.create(vaultProperties)); } @@ -105,7 +109,7 @@ public class ConsulSecretIntegrationTests extends AbstractIntegrationTests { @Test public void shouldCreateCredentialsCorrectly() throws Exception { - Map secretProperties = vaultClient.read(consul(consul), + Map secretProperties = vaultClient.read(forConsul(consul), Settings.token()); assertThat(secretProperties).containsKeys("spring.cloud.consul.token"); diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultConsulTests.java b/spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/VaultConfigConsulTests.java similarity index 91% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultConsulTests.java rename to spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/VaultConfigConsulTests.java index 8516d333..d871478b 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultConsulTests.java +++ b/spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/VaultConfigConsulTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.vault.configclient; +package org.springframework.cloud.vault.config.consul; import static org.assertj.core.api.Java6Assertions.*; import static org.junit.Assume.*; @@ -25,13 +25,13 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -import org.apache.commons.codec.binary.Base64; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.IntegrationTest; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.boot.test.TestRestTemplate; @@ -42,6 +42,7 @@ import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; +import org.springframework.security.crypto.codec.Base64; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** @@ -53,10 +54,10 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes = VaultConsulTests.TestApplication.class) +@SpringApplicationConfiguration(classes = VaultConfigConsulTests.TestApplication.class) @IntegrationTest({ "spring.cloud.vault.consul.enabled=true", "spring.cloud.vault.consul.role=readonly" }) -public class VaultConsulTests { +public class VaultConfigConsulTests { private final static String CONSUL_HOST = "localhost"; private final static int CONSUL_PORT = 8500; @@ -104,7 +105,7 @@ public class VaultConsulTests { vaultRule.prepare().write("consul/config/access", consulAccess); vaultRule.prepare().write("consul/roles/readonly", Collections - .singletonMap("policy", Base64.encodeBase64String(POLICY.getBytes()))); + .singletonMap("policy", Base64.encode(POLICY.getBytes()))); } @Value("${spring.cloud.consul.token}") diff --git a/spring-cloud-vault-config-consul/src/test/resources/bootstrap.yml b/spring-cloud-vault-config-consul/src/test/resources/bootstrap.yml new file mode 100644 index 00000000..c598d962 --- /dev/null +++ b/spring-cloud-vault-config-consul/src/test/resources/bootstrap.yml @@ -0,0 +1,5 @@ +spring: + application.name: testVaultApp + cloud.vault.token: 00000000-0000-0000-0000-000000000000 + cloud.vault.ssl.trust-store: file:../work/keystore.jks + cloud.vault.ssl.trust-store-password: changeit diff --git a/spring-cloud-vault-config-databases/pom.xml b/spring-cloud-vault-config-databases/pom.xml new file mode 100644 index 00000000..4789e703 --- /dev/null +++ b/spring-cloud-vault-config-databases/pom.xml @@ -0,0 +1,97 @@ + + + 4.0.0 + + + org.springframework.cloud + spring-cloud-vault-config-parent + 1.0.0.BUILD-SNAPSHOT + .. + + + org.springframework.cloud + spring-cloud-vault-config-databases + 1.0.0.BUILD-SNAPSHOT + jar + + Spring Cloud Vault Config Database support + Spring Cloud Vault Config Database support + + + + org.springframework.cloud + spring-cloud-vault-core + ${project.version} + + + org.springframework.cloud + spring-cloud-vault-core + ${project.version} + test-jar + test + + + org.springframework.cloud + spring-cloud-vault-config + ${project.version} + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.projectlombok + lombok + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-jdbc + test + + + + com.squareup.okhttp + okhttp + test + + + + com.h2database + h2 + test + + + org.assertj + assertj-core + 3.3.0 + test + + + mysql + mysql-connector-java + 5.1.38 + test + + + org.postgresql + postgresql + 9.4.1208.jre7 + test + + + com.datastax.cassandra + cassandra-driver-core + 2.1.10 + test + + + + diff --git a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/DatabaseSecretProperties.java b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/DatabaseSecretProperties.java new file mode 100644 index 00000000..639eb736 --- /dev/null +++ b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/DatabaseSecretProperties.java @@ -0,0 +1,49 @@ +/* + * Copyright 2016 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.cloud.vault.config.databases; + +import org.springframework.cloud.vault.VaultSecretBackend; + +/** + * Configuration properties interface for database secrets. + */ +public interface DatabaseSecretProperties extends VaultSecretBackend { + + /** + * Role name. + * + * @return the role name + */ + String getRole(); + + /** + * Backend path. + * + * @return the backend path. + */ + String getBackend(); + + /** + * Name of the target property for the obtained username. + */ + String getUsernameProperty(); + + /** + * Name of the target property for the obtained password. + */ + String getPasswordProperty(); + +} \ No newline at end of file diff --git a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCassandraProperties.java b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCassandraProperties.java new file mode 100644 index 00000000..549aa68c --- /dev/null +++ b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCassandraProperties.java @@ -0,0 +1,59 @@ +/* + * Copyright 2016 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.cloud.vault.config.databases; + +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import lombok.Data; + +/** + * Configuration properties for Vault using the Apache Cassandra integration. + * + * @author Mark Paluch + */ +@ConfigurationProperties("spring.cloud.vault.cassandra") +@Data +public class VaultCassandraProperties implements DatabaseSecretProperties { + + /** + * Enable cassandra backend usage. + */ + private boolean enabled = false; + + /** + * Role name for credentials. + */ + private String role; + + /** + * Cassandra backend path. + */ + @NotEmpty + private String backend = "cassandra"; + + /** + * Target property for the obtained username. + */ + @NotEmpty + private String usernameProperty = "spring.data.cassandra.username"; + + /** + * Target property for the obtained password. + */ + @NotEmpty + private String passwordProperty = "spring.data.cassandra.password"; +} diff --git a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultConfigDatabaseBootstrapConfiguration.java b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultConfigDatabaseBootstrapConfiguration.java new file mode 100644 index 00000000..ecbd809f --- /dev/null +++ b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultConfigDatabaseBootstrapConfiguration.java @@ -0,0 +1,108 @@ +/* + * Copyright 2016 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.cloud.vault.config.databases; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.vault.SecureBackendAccessor; +import org.springframework.cloud.vault.config.SecureBackendAccessorFactory; +import org.springframework.cloud.vault.VaultSecretBackend; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.Assert; + +/** + * @author Mark Paluch + */ +@Configuration +@EnableConfigurationProperties +public class VaultConfigDatabaseBootstrapConfiguration { + + @Bean + public SecureBackendAccessorFactory secureBackendAccessorFactory() { + return new DatabaseSecureBackendAccessorFactory(); + } + + @Bean + public VaultMySqlProperties mySqlProperties() { + return new VaultMySqlProperties(); + } + + @Bean + public VaultPostgreSqlProperties postgreSqlProperties() { + return new VaultPostgreSqlProperties(); + } + + @Bean + public VaultCassandraProperties cassandraProperties() { + return new VaultCassandraProperties(); + } + + static class DatabaseSecureBackendAccessorFactory + implements SecureBackendAccessorFactory { + + @Override + public SecureBackendAccessor createSecureBackendAccessor( + DatabaseSecretProperties properties) { + return forDatabase(properties); + } + + @Override + public boolean supports(VaultSecretBackend secretBackend) { + return secretBackend instanceof DatabaseSecretProperties; + } + + /** + * Creates a {@link SecureBackendAccessor} for a secure backend using + * {@link DatabaseSecretProperties}. This accessor transforms Vault's + * username/password property names to names provided with + * {@link DatabaseSecretProperties#getUsernameProperty()} and + * {@link DatabaseSecretProperties#getPasswordProperty()}. + * + * @param properties must not be {@literal null}. + * @return the {@link SecureBackendAccessor} + */ + public static SecureBackendAccessor forDatabase( + final DatabaseSecretProperties properties) { + Assert.notNull(properties, "DatabaseSecretProperties must not be null"); + + return new SecureBackendAccessor() { + + @Override + public Map variables() { + + Map variables = new HashMap<>(); + variables.put("backend", properties.getBackend()); + variables.put("key", String.format("creds/%s", properties.getRole())); + return variables; + } + + @Override + public Map transformProperties( + Map input) { + + Map result = new HashMap(); + result.put(properties.getUsernameProperty(), input.get("username")); + result.put(properties.getPasswordProperty(), input.get("password")); + + return result; + } + }; + } + } +} diff --git a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultMySqlProperties.java b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultMySqlProperties.java new file mode 100644 index 00000000..a572902b --- /dev/null +++ b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultMySqlProperties.java @@ -0,0 +1,45 @@ +package org.springframework.cloud.vault.config.databases; + +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.vault.VaultSecretBackend; + +import lombok.Data; + +/** + * Configuration properties for Vault using the MySQL integration. + * + * @author Mark Paluch + */ +@ConfigurationProperties("spring.cloud.vault.mysql") +@Data +public class VaultMySqlProperties implements DatabaseSecretProperties, VaultSecretBackend { + + /** + * Enable mysql backend usage. + */ + private boolean enabled = false; + + /** + * Role name for credentials. + */ + private String role; + + /** + * mysql backend path. + */ + @NotEmpty + private String backend = "mysql"; + + /** + * Target property for the obtained username. + */ + @NotEmpty + private String usernameProperty = "spring.datasource.username"; + + /** + * Target property for the obtained username. + */ + @NotEmpty + private String passwordProperty = "spring.datasource.password"; +} diff --git a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultPostgreSqlProperties.java b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultPostgreSqlProperties.java new file mode 100644 index 00000000..49a51a82 --- /dev/null +++ b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultPostgreSqlProperties.java @@ -0,0 +1,59 @@ +/* + * Copyright 2016 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.cloud.vault.config.databases; + +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import lombok.Data; + +/** + * Configuration properties for Vault using the PostgreSQL integration. + * + * @author Mark Paluch + */ +@ConfigurationProperties("spring.cloud.vault.postgresql") +@Data +public class VaultPostgreSqlProperties implements DatabaseSecretProperties { + + /** + * Enable postgresql backend usage. + */ + private boolean enabled = false; + + /** + * Role name for credentials. + */ + private String role; + + /** + * postgresql backend path. + */ + @NotEmpty + private String backend = "postgresql"; + + /** + * Target property for the obtained username. + */ + @NotEmpty + private String usernameProperty = "spring.datasource.username"; + + /** + * Target property for the obtained username. + */ + @NotEmpty + private String passwordProperty = "spring.datasource.password"; +} diff --git a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/package-info.java b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/package-info.java new file mode 100644 index 00000000..2d0d4c9e --- /dev/null +++ b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/package-info.java @@ -0,0 +1,5 @@ +/** + * Database integration with Vault. + * @author Mark Paluch + */ +package org.springframework.cloud.vault.config.databases; \ No newline at end of file diff --git a/spring-cloud-vault-config-databases/src/main/resources/META-INF/spring.factories b/spring-cloud-vault-config-databases/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..b8f5c321 --- /dev/null +++ b/spring-cloud-vault-config-databases/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Bootstrap Configuration +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ +org.springframework.cloud.vault.config.databases.VaultConfigDatabaseBootstrapConfiguration \ No newline at end of file diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/CassandraSecretIntegrationTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CassandraSecretIntegrationTests.java similarity index 83% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/CassandraSecretIntegrationTests.java rename to spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CassandraSecretIntegrationTests.java index 4fc872d2..028e10f6 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/CassandraSecretIntegrationTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CassandraSecretIntegrationTests.java @@ -13,20 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.vault; +package org.springframework.cloud.vault.config.databases; import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; -import static org.springframework.cloud.vault.SecureBackendAccessors.*; +import static org.springframework.cloud.vault.config.databases.VaultConfigDatabaseBootstrapConfiguration.DatabaseSecureBackendAccessorFactory.*; import java.net.InetSocketAddress; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.springframework.cloud.vault.AbstractIntegrationTests; +import org.springframework.cloud.vault.TestRestTemplateFactory; +import org.springframework.cloud.vault.VaultClient; +import org.springframework.cloud.vault.VaultProperties; import org.springframework.cloud.vault.util.CanConnect; import org.springframework.cloud.vault.util.Settings; @@ -50,7 +53,7 @@ public class CassandraSecretIntegrationTests extends AbstractIntegrationTests { private VaultProperties vaultProperties = Settings.createVaultProperties(); private VaultClient vaultClient = new VaultClient(vaultProperties); - private VaultProperties.Cassandra cassandra = vaultProperties.getCassandra(); + private VaultCassandraProperties cassandra = new VaultCassandraProperties(); /** * Initialize cassandra secret backend. @@ -87,7 +90,7 @@ public class CassandraSecretIntegrationTests extends AbstractIntegrationTests { @Test public void shouldCreateCredentialsCorrectly() throws Exception { - Map secretProperties = vaultClient.read(database(cassandra), + Map secretProperties = vaultClient.read(forDatabase(cassandra), Settings.token()); assertThat(secretProperties).containsKeys("spring.data.cassandra.username", diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/MySqlSecretIntegrationTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/MySqlSecretIntegrationTests.java similarity index 81% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/MySqlSecretIntegrationTests.java rename to spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/MySqlSecretIntegrationTests.java index 6f5d7117..5b34971a 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/MySqlSecretIntegrationTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/MySqlSecretIntegrationTests.java @@ -13,19 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.vault; +package org.springframework.cloud.vault.config.databases; import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; -import static org.springframework.cloud.vault.SecureBackendAccessors.*; +import static org.springframework.cloud.vault.config.databases.VaultConfigDatabaseBootstrapConfiguration.DatabaseSecureBackendAccessorFactory.forDatabase; import java.net.InetSocketAddress; import java.util.Collections; import java.util.Map; -import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.springframework.cloud.vault.AbstractIntegrationTests; +import org.springframework.cloud.vault.TestRestTemplateFactory; +import org.springframework.cloud.vault.VaultClient; +import org.springframework.cloud.vault.VaultProperties; import org.springframework.cloud.vault.util.CanConnect; import org.springframework.cloud.vault.util.Settings; @@ -46,7 +49,7 @@ public class MySqlSecretIntegrationTests extends AbstractIntegrationTests { private VaultProperties vaultProperties = Settings.createVaultProperties(); private VaultClient vaultClient = new VaultClient(vaultProperties); - private VaultProperties.MySql mySql = vaultProperties.getMysql(); + private VaultMySqlProperties mySql = new VaultMySqlProperties(); /** * Initialize the mysql secret backend. @@ -77,7 +80,7 @@ public class MySqlSecretIntegrationTests extends AbstractIntegrationTests { @Test public void shouldCreateCredentialsCorrectly() throws Exception { - Map secretProperties = vaultClient.read(database(mySql), + Map secretProperties = vaultClient.read(forDatabase(mySql), Settings.token()); assertThat(secretProperties).containsKeys("spring.datasource.username", diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/PostgreSqlSecretIntegrationTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/PostgreSqlSecretIntegrationTests.java similarity index 82% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/PostgreSqlSecretIntegrationTests.java rename to spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/PostgreSqlSecretIntegrationTests.java index 58eddb99..084a0df7 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/PostgreSqlSecretIntegrationTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/PostgreSqlSecretIntegrationTests.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.vault; +package org.springframework.cloud.vault.config.databases; import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; -import static org.springframework.cloud.vault.SecureBackendAccessors.*; +import static org.springframework.cloud.vault.config.databases.VaultConfigDatabaseBootstrapConfiguration.DatabaseSecureBackendAccessorFactory.*; import java.net.InetSocketAddress; import java.util.Collections; @@ -25,6 +25,10 @@ import java.util.Map; import org.junit.Before; import org.junit.Test; +import org.springframework.cloud.vault.AbstractIntegrationTests; +import org.springframework.cloud.vault.TestRestTemplateFactory; +import org.springframework.cloud.vault.VaultClient; +import org.springframework.cloud.vault.VaultProperties; import org.springframework.cloud.vault.util.CanConnect; import org.springframework.cloud.vault.util.Settings; @@ -49,7 +53,7 @@ public class PostgreSqlSecretIntegrationTests extends AbstractIntegrationTests { private VaultProperties vaultProperties = Settings.createVaultProperties(); private VaultClient vaultClient = new VaultClient(vaultProperties); - private VaultProperties.PostgreSql postgreSql = vaultProperties.getPostgresql(); + private VaultPostgreSqlProperties postgreSql = new VaultPostgreSqlProperties(); /** * Initialize the postgresql secret backend. @@ -82,7 +86,7 @@ public class PostgreSqlSecretIntegrationTests extends AbstractIntegrationTests { @Test public void shouldCreateCredentialsCorrectly() throws Exception { - Map secretProperties = vaultClient.read(database(postgreSql), + Map secretProperties = vaultClient.read(forDatabase(postgreSql), Settings.token()); assertThat(secretProperties).containsKeys("spring.datasource.username", diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultCassandraTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCassandraTests.java similarity index 95% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultCassandraTests.java rename to spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCassandraTests.java index 74725aa8..f0b3e83a 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultCassandraTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCassandraTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.vault.configclient; +package org.springframework.cloud.vault.config.databases; import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; @@ -49,10 +49,10 @@ import com.datastax.driver.core.Session; * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes = VaultCassandraTests.TestApplication.class) +@SpringApplicationConfiguration(classes = VaultConfigCassandraTests.TestApplication.class) @IntegrationTest({ "spring.cloud.vault.cassandra.enabled=true", "spring.cloud.vault.cassandra.role=readonly" }) -public class VaultCassandraTests { +public class VaultConfigCassandraTests { private final static String CASSANDRA_HOST = "localhost"; private final static int CASSANDRA_PORT = 9042; diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultMySqlTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigMySqlTests.java similarity index 95% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultMySqlTests.java rename to spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigMySqlTests.java index c3eebfa6..dd8303b2 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultMySqlTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigMySqlTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.vault.configclient; +package org.springframework.cloud.vault.config.databases; import static org.junit.Assume.*; @@ -45,11 +45,11 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes = VaultMySqlTests.TestApplication.class) +@SpringApplicationConfiguration(classes = VaultConfigMySqlTests.TestApplication.class) @IntegrationTest({ "spring.cloud.vault.mysql.enabled=true", "spring.cloud.vault.mysql.role=readonly", "spring.datasource.url=jdbc:mysql://localhost:3306/mysql?useSSL=false" }) -public class VaultMySqlTests { +public class VaultConfigMySqlTests { private final static int MYSQL_PORT = 3306; private final static String MYSQL_HOST = "localhost"; diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultPostgreSqlTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigPostgreSqlTests.java similarity index 92% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultPostgreSqlTests.java rename to spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigPostgreSqlTests.java index 42104f8e..efc86cb0 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultPostgreSqlTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigPostgreSqlTests.java @@ -14,29 +14,28 @@ * limitations under the License. */ -package org.springframework.cloud.vault.configclient; +package org.springframework.cloud.vault.config.databases; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; -import javax.sql.DataSource; import java.net.InetSocketAddress; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Collections; +import javax.sql.DataSource; + import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; -import org.postgresql.jdbc.PgConnection; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.IntegrationTest; import org.springframework.boot.test.SpringApplicationConfiguration; -import org.springframework.cglib.proxy.Proxy; import org.springframework.cloud.vault.util.CanConnect; import org.springframework.cloud.vault.util.VaultRule; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -49,10 +48,10 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes = VaultPostgreSqlTests.TestApplication.class) +@SpringApplicationConfiguration(classes = VaultConfigPostgreSqlTests.TestApplication.class) @IntegrationTest({ "spring.cloud.vault.postgresql.enabled=true", "spring.cloud.vault.postgresql.role=readonly", "spring.datasource.url=jdbc:postgresql://localhost:5432/postgres?ssl=false" }) -public class VaultPostgreSqlTests { +public class VaultConfigPostgreSqlTests { private final static String POSTGRES_HOST = "localhost"; private final static int POSTGRES_PORT = 5432; diff --git a/spring-cloud-vault-config-databases/src/test/resources/bootstrap.yml b/spring-cloud-vault-config-databases/src/test/resources/bootstrap.yml new file mode 100644 index 00000000..c598d962 --- /dev/null +++ b/spring-cloud-vault-config-databases/src/test/resources/bootstrap.yml @@ -0,0 +1,5 @@ +spring: + application.name: testVaultApp + cloud.vault.token: 00000000-0000-0000-0000-000000000000 + cloud.vault.ssl.trust-store: file:../work/keystore.jks + cloud.vault.ssl.trust-store-password: changeit diff --git a/spring-cloud-vault-config/src/test/resources/cassandra.yaml b/spring-cloud-vault-config-databases/src/test/resources/cassandra.yaml similarity index 100% rename from spring-cloud-vault-config/src/test/resources/cassandra.yaml rename to spring-cloud-vault-config-databases/src/test/resources/cassandra.yaml diff --git a/spring-cloud-vault-config-rabbitmq/pom.xml b/spring-cloud-vault-config-rabbitmq/pom.xml new file mode 100644 index 00000000..b39dcb24 --- /dev/null +++ b/spring-cloud-vault-config-rabbitmq/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + + org.springframework.cloud + spring-cloud-vault-config-parent + 1.0.0.BUILD-SNAPSHOT + .. + + + org.springframework.cloud + spring-cloud-vault-config-rabbitmq + 1.0.0.BUILD-SNAPSHOT + jar + + Spring Cloud Vault Config RabbitMQ support + Spring Cloud Vault Config RabbitMQ support + + + + org.springframework.cloud + spring-cloud-vault-core + ${project.version} + + + org.springframework.cloud + spring-cloud-vault-core + ${project.version} + test-jar + test + + + org.springframework.cloud + spring-cloud-vault-config + ${project.version} + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.projectlombok + lombok + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-amqp + test + + + + com.squareup.okhttp + okhttp + test + + + + org.assertj + assertj-core + + + + diff --git a/spring-cloud-vault-config-rabbitmq/src/main/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqBootstrapConfiguration.java b/spring-cloud-vault-config-rabbitmq/src/main/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqBootstrapConfiguration.java new file mode 100644 index 00000000..82c28e75 --- /dev/null +++ b/spring-cloud-vault-config-rabbitmq/src/main/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqBootstrapConfiguration.java @@ -0,0 +1,98 @@ +/* + * Copyright 2016 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.cloud.vault.config.rabbitmq; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.vault.SecureBackendAccessor; +import org.springframework.cloud.vault.config.SecureBackendAccessorFactory; +import org.springframework.cloud.vault.VaultSecretBackend; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.Assert; + +/** + * @author Mark Paluch + */ +@Configuration +@EnableConfigurationProperties +public class VaultConfigRabbitMqBootstrapConfiguration { + + @Bean + public SecureBackendAccessorFactory secureBackendAccessorFactory() { + return new RabbitMqSecureBackendAccessorFactory(); + } + + @Bean + public VaultRabbitMqProperties rabbitMqProperties() { + return new VaultRabbitMqProperties(); + } + + static class RabbitMqSecureBackendAccessorFactory + implements SecureBackendAccessorFactory { + + @Override + public SecureBackendAccessor createSecureBackendAccessor( + VaultRabbitMqProperties properties) { + return forRabbitMq(properties); + } + + @Override + public boolean supports(VaultSecretBackend secretBackend) { + return secretBackend instanceof VaultRabbitMqProperties; + } + + /** + * Creates a {@link SecureBackendAccessor} for a secure backend using + * {@link VaultRabbitMqProperties}. This accessor transforms Vault's + * username/password property names to names provided with + * {@link VaultRabbitMqProperties#getUsernameProperty()} and + * {@link VaultRabbitMqProperties#getPasswordProperty()}. + * + * @param properties must not be {@literal null}. + * @return the {@link SecureBackendAccessor} + */ + public static SecureBackendAccessor forRabbitMq( + final VaultRabbitMqProperties properties) { + Assert.notNull(properties, "DatabaseSecretProperties must not be null"); + + return new SecureBackendAccessor() { + + @Override + public Map variables() { + + Map variables = new HashMap<>(); + variables.put("backend", properties.getBackend()); + variables.put("key", String.format("creds/%s", properties.getRole())); + return variables; + } + + @Override + public Map transformProperties( + Map input) { + + Map result = new HashMap(); + result.put(properties.getUsernameProperty(), input.get("username")); + result.put(properties.getPasswordProperty(), input.get("password")); + + return result; + } + }; + } + } +} diff --git a/spring-cloud-vault-config-rabbitmq/src/main/java/org/springframework/cloud/vault/config/rabbitmq/VaultRabbitMqProperties.java b/spring-cloud-vault-config-rabbitmq/src/main/java/org/springframework/cloud/vault/config/rabbitmq/VaultRabbitMqProperties.java new file mode 100644 index 00000000..91e74bec --- /dev/null +++ b/spring-cloud-vault-config-rabbitmq/src/main/java/org/springframework/cloud/vault/config/rabbitmq/VaultRabbitMqProperties.java @@ -0,0 +1,60 @@ +/* + * Copyright 2016 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.cloud.vault.config.rabbitmq; + +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.vault.VaultSecretBackend; + +import lombok.Data; + +/** + * Configuration properties for Vault using the RabbitMQ integration. + * + * @author Mark Paluch + */ +@ConfigurationProperties("spring.cloud.vault.rabbitmq") +@Data +public class VaultRabbitMqProperties implements VaultSecretBackend { + + /** + * Enable rabbitmq backend usage. + */ + private boolean enabled = false; + + /** + * Role name for credentials. + */ + private String role; + + /** + * RabbitMQ backend path. + */ + @NotEmpty + private String backend = "rabbitmq"; + + /** + * Target property for the obtained username. + */ + @NotEmpty + private String usernameProperty = "spring.rabbitmq.username"; + + /** + * Target property for the obtained password. + */ + @NotEmpty + private String passwordProperty = "spring.rabbitmq.password"; +} \ No newline at end of file diff --git a/spring-cloud-vault-config-rabbitmq/src/main/java/org/springframework/cloud/vault/config/rabbitmq/package-info.java b/spring-cloud-vault-config-rabbitmq/src/main/java/org/springframework/cloud/vault/config/rabbitmq/package-info.java new file mode 100644 index 00000000..ef58b572 --- /dev/null +++ b/spring-cloud-vault-config-rabbitmq/src/main/java/org/springframework/cloud/vault/config/rabbitmq/package-info.java @@ -0,0 +1,5 @@ +/** + * RabbitMQ integration with Vault. + * @author Mark Paluch + */ +package org.springframework.cloud.vault.config.rabbitmq; \ No newline at end of file diff --git a/spring-cloud-vault-config-rabbitmq/src/main/resources/META-INF/spring.factories b/spring-cloud-vault-config-rabbitmq/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..f74510a6 --- /dev/null +++ b/spring-cloud-vault-config-rabbitmq/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Bootstrap Configuration +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ +org.springframework.cloud.vault.config.rabbitmq.VaultConfigRabbitMqBootstrapConfiguration \ No newline at end of file diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/RabbitMQSecretIntegrationTests.java b/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/RabbitMqSecretIntegrationTests.java similarity index 72% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/RabbitMQSecretIntegrationTests.java rename to spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/RabbitMqSecretIntegrationTests.java index b66f2aa2..34917958 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/RabbitMQSecretIntegrationTests.java +++ b/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/RabbitMqSecretIntegrationTests.java @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.vault; +package org.springframework.cloud.vault.config.rabbitmq; import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; -import static org.springframework.cloud.vault.SecureBackendAccessors.*; +import static org.springframework.cloud.vault.config.rabbitmq.VaultConfigRabbitMqBootstrapConfiguration.RabbitMqSecureBackendAccessorFactory.*; import java.net.InetSocketAddress; import java.util.Collections; @@ -26,6 +26,10 @@ import java.util.Map; import org.junit.Before; import org.junit.Test; +import org.springframework.cloud.vault.AbstractIntegrationTests; +import org.springframework.cloud.vault.TestRestTemplateFactory; +import org.springframework.cloud.vault.VaultClient; +import org.springframework.cloud.vault.VaultProperties; import org.springframework.cloud.vault.util.CanConnect; import org.springframework.cloud.vault.util.Settings; @@ -35,7 +39,7 @@ import org.springframework.cloud.vault.util.Settings; * * @author Mark Paluch */ -public class RabbitMQSecretIntegrationTests extends AbstractIntegrationTests { +public class RabbitMqSecretIntegrationTests extends AbstractIntegrationTests { private final static int RABBITMQ_HTTP_MANAGEMENT_PORT = 15672; private final static String RABBITMQ_HOST = "localhost"; @@ -43,14 +47,14 @@ public class RabbitMQSecretIntegrationTests extends AbstractIntegrationTests { private final static String RABBITMQ_USERNAME = "guest"; private final static String RABBITMQ_PASSWORD = "guest"; - private final static String RABBITMQ_URI = String - .format("http://%s:%d", RABBITMQ_HOST, RABBITMQ_HTTP_MANAGEMENT_PORT); + private final static String RABBITMQ_URI = String.format("http://%s:%d", + RABBITMQ_HOST, RABBITMQ_HTTP_MANAGEMENT_PORT); private final static String VHOSTS_ROLE = "{\"/\":{\"write\": \".*\", \"read\": \".*\"}}"; private VaultProperties vaultProperties = Settings.createVaultProperties(); private VaultClient vaultClient = new VaultClient(vaultProperties); - private VaultProperties.Rabbitmq rabbitmq = vaultProperties.getRabbitmq(); + private VaultRabbitMqProperties rabbitmq = new VaultRabbitMqProperties(); /** * Initialize the mysql secret backend. @@ -60,7 +64,8 @@ public class RabbitMQSecretIntegrationTests extends AbstractIntegrationTests { @Before public void setUp() throws Exception { - assumeTrue(CanConnect.to(new InetSocketAddress(RABBITMQ_HOST, RABBITMQ_HTTP_MANAGEMENT_PORT))); + assumeTrue(CanConnect + .to(new InetSocketAddress(RABBITMQ_HOST, RABBITMQ_HTTP_MANAGEMENT_PORT))); rabbitmq.setEnabled(true); rabbitmq.setRole("readonly"); @@ -77,7 +82,8 @@ public class RabbitMQSecretIntegrationTests extends AbstractIntegrationTests { prepare().write(String.format("%s/config/connection", rabbitmq.getBackend()), connection); - prepare().write(String.format("%s/roles/%s", rabbitmq.getBackend(), rabbitmq.getRole()), + prepare().write( + String.format("%s/roles/%s", rabbitmq.getBackend(), rabbitmq.getRole()), Collections.singletonMap("vhosts", VHOSTS_ROLE)); vaultClient.setRest(TestRestTemplateFactory.create(vaultProperties)); @@ -86,7 +92,7 @@ public class RabbitMQSecretIntegrationTests extends AbstractIntegrationTests { @Test public void shouldCreateCredentialsCorrectly() throws Exception { - Map secretProperties = vaultClient.read(database(rabbitmq), + Map secretProperties = vaultClient.read(forRabbitMq(rabbitmq), Settings.token()); assertThat(secretProperties).containsKeys("spring.rabbitmq.username", diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultRabbitMQTests.java b/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqTests.java similarity index 95% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultRabbitMQTests.java rename to spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqTests.java index 357ce7c7..00366d6e 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultRabbitMQTests.java +++ b/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.vault.configclient; +package org.springframework.cloud.vault.config.rabbitmq; import static org.junit.Assume.*; @@ -49,11 +49,11 @@ import com.rabbitmq.client.ConnectionFactory; * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes = VaultRabbitMQTests.TestApplication.class) +@SpringApplicationConfiguration(classes = VaultConfigRabbitMqTests.TestApplication.class) @IntegrationTest({ "spring.cloud.vault.rabbitmq.enabled=true", "spring.cloud.vault.rabbitmq.role=readonly", "spring.rabbitmq.address=localhost" }) -public class VaultRabbitMQTests { +public class VaultConfigRabbitMqTests { private final static int RABBITMQ_HTTP_MANAGEMENT_PORT = 15672; private final static int RABBITMQ_PORT = 5672; @@ -133,4 +133,4 @@ public class VaultRabbitMQTests { SpringApplication.run(TestApplication.class, args); } } -} +} \ No newline at end of file diff --git a/spring-cloud-vault-config-rabbitmq/src/test/resources/bootstrap.yml b/spring-cloud-vault-config-rabbitmq/src/test/resources/bootstrap.yml new file mode 100644 index 00000000..c598d962 --- /dev/null +++ b/spring-cloud-vault-config-rabbitmq/src/test/resources/bootstrap.yml @@ -0,0 +1,5 @@ +spring: + application.name: testVaultApp + cloud.vault.token: 00000000-0000-0000-0000-000000000000 + cloud.vault.ssl.trust-store: file:../work/keystore.jks + cloud.vault.ssl.trust-store-password: changeit diff --git a/spring-cloud-vault-config/pom.xml b/spring-cloud-vault-config/pom.xml index 7ecaf34e..9388abd8 100644 --- a/spring-cloud-vault-config/pom.xml +++ b/spring-cloud-vault-config/pom.xml @@ -1,8 +1,8 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - + org.springframework.cloud spring-cloud-vault-config-parent @@ -15,32 +15,22 @@ 1.0.0.BUILD-SNAPSHOT jar - spring-cloud-vault-config + Spring Cloud Vault Configuration Integration Configuration Integration with Hashicorp Vault - - UTF-8 - 1.7 - 4.5.2 - 4.4.4 - 4.1.0.Final - 2.7.5 - - org.springframework.boot - spring-boot-starter-actuator - true - - - org.springframework.boot - spring-boot-starter-web + org.springframework.cloud + spring-cloud-vault-core + ${project.version} org.springframework.cloud - spring-cloud-context - 1.1.0.BUILD-SNAPSHOT + spring-cloud-vault-core + ${project.version} + test-jar + test org.projectlombok @@ -52,99 +42,17 @@ spring-boot-starter-test test - - org.springframework.boot - spring-boot-starter-jdbc - test - - - org.springframework.boot - spring-boot-starter-amqp - test - - - - org.apache.httpcomponents - httpclient - ${httpclient.version} - true - - - commons-logging - commons-logging - - - - - - org.apache.httpcomponents - httpcore - ${httpcore.version} - true - - - - io.netty - netty-all - ${netty.version} - true - com.squareup.okhttp okhttp - ${okhttp.version} - true - - - - com.h2database - h2 test + org.assertj assertj-core - 3.3.0 - test - - - mysql - mysql-connector-java - 5.1.38 - test - - - org.postgresql - postgresql - 9.4.1208.jre7 - test - - - com.datastax.cassandra - cassandra-driver-core - 2.1.10 - test - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/SecureBackendAccessors.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/SecureBackendAccessors.java deleted file mode 100644 index 2c81337a..00000000 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/SecureBackendAccessors.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2016 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.cloud.vault; - -import java.util.HashMap; -import java.util.Map; - -import org.springframework.util.Assert; - -/** - * Collection of common used {@link SecureBackendAccessor accessors} to access secure - * backends. - * - * @author Mark Paluch - */ -public class SecureBackendAccessors { - - /** - * Creates a {@link SecureBackendAccessor} for the {@code generic} secure backend. - * - * @param vaultProperties must not be {@literal null}. - * @param key must not be {@literal null} and not empty. - * @return the {@link SecureBackendAccessor} - */ - public static SecureBackendAccessor generic(VaultProperties vaultProperties, - String key) { - - Assert.notNull(vaultProperties, "VaultProperties must not be null"); - return generic(vaultProperties.getBackend(), key); - } - - /** - * Creates a {@link SecureBackendAccessor} for the {@code generic} secure backend. - * - * @param secretBackendPath must not be {@literal null} and not empty. - * @param key must not be {@literal null} and not empty. - * @return the {@link SecureBackendAccessor} - */ - public static SecureBackendAccessor generic(final String secretBackendPath, - final String key) { - - Assert.hasText(secretBackendPath, "Secret Backend Path must not be empty"); - Assert.hasText(key, "Key must not be empty"); - - return new SecureBackendAccessor() { - - @Override - public Map variables() { - Map variables = new HashMap<>(); - variables.put("backend", secretBackendPath); - variables.put("key", key); - return variables; - } - - @Override - public Map transformProperties(Map input) { - return input; - } - }; - } - - /** - * Creates a {@link SecureBackendAccessor} for a secure backend using - * {@link org.springframework.cloud.vault.VaultProperties.DatabaseSecretProperties}. - * This accessor transforms Vault's username/password property names to names provided - * with {@link VaultProperties.DatabaseSecretProperties#getUsernameProperty()} and - * {@link VaultProperties.DatabaseSecretProperties#getUsernameProperty()}. - * - * @param properties must not be {@literal null}. - * @return the {@link SecureBackendAccessor} - */ - public static SecureBackendAccessor database( - final VaultProperties.DatabaseSecretProperties properties) { - - Assert.notNull(properties, "DatabaseSecretProperties must not be null"); - - return new SecureBackendAccessor() { - - @Override - public Map variables() { - - Map variables = new HashMap<>(); - variables.put("backend", properties.getBackend()); - variables.put("key", String.format("creds/%s", properties.getRole())); - return variables; - } - - @Override - public Map transformProperties(Map input) { - - Map result = new HashMap(); - result.put(properties.getUsernameProperty(), input.get("username")); - result.put(properties.getPasswordProperty(), input.get("password")); - - return result; - } - }; - } - - /** - * Creates a {@link SecureBackendAccessor} for a secure backend using - * {@link org.springframework.cloud.vault.VaultProperties.Consul}. - * This accessor transforms Vault's token property names to names provided - * with {@link VaultProperties.Consul#getTokenProperty()}. - * - * @param properties must not be {@literal null}. - * @return the {@link SecureBackendAccessor} - */ - public static SecureBackendAccessor consul( - final VaultProperties.Consul properties) { - - Assert.notNull(properties, "Consul properties must not be null"); - - return new SecureBackendAccessor() { - - @Override - public Map variables() { - - Map variables = new HashMap<>(); - variables.put("backend", properties.getBackend()); - variables.put("key", String.format("creds/%s", properties.getRole())); - return variables; - } - - @Override - public Map transformProperties(Map input) { - - Map result = new HashMap(); - result.put(properties.getTokenProperty(), input.get("token")); - - return result; - } - }; - } -} diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultProperties.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultProperties.java deleted file mode 100644 index f26bf1e2..00000000 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultProperties.java +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright 2013-2015 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.cloud.vault; - -import org.hibernate.validator.constraints.NotEmpty; -import org.hibernate.validator.constraints.Range; -import org.springframework.boot.context.properties.ConfigurationProperties; - -import lombok.Data; -import org.springframework.core.io.Resource; - -/** - * @author Spencer Gibb - * @author Mark Paluch - */ -@ConfigurationProperties("spring.cloud.vault") -@Data -public class VaultProperties { - - /** - * Enable Vault config server. - */ - private boolean enabled = true; - - /** - * Vault server host. - */ - @NotEmpty - private String host = "localhost"; - - /** - * Vault server port. - */ - @Range(min = 1, max = 65535) - private int port = 8200; - - /** - * Protocol scheme. Can be either "http" or "https". - */ - private String scheme = "https"; - - /** - * Name of the default backend. - */ - @NotEmpty - private String backend = "secret"; - - /** - * Name of the default context. - */ - @NotEmpty - private String defaultContext = "application"; - - /** - * Profile-separator to combine application name and profile. - */ - @NotEmpty - private String profileSeparator = ","; - - /** - * Connection timeout; - */ - private int connectionTimeout = 5000; - - /** - * Read timeout; - */ - private int readTimeout = 15000; - - /** - * Fail fast if data cannot be obtained from Vault. - */ - private boolean failFast = false; - - /** - * Static vault token. Required if {@link #authentication} is {@code TOKEN}. - */ - private String token; - - private AppIdProperties appId = new AppIdProperties(); - - private Ssl ssl = new Ssl(); - - private MySql mysql = new MySql(); - - private PostgreSql postgresql = new PostgreSql(); - - private Cassandra cassandra = new Cassandra(); - - private Consul consul = new Consul(); - - private Rabbitmq rabbitmq = new Rabbitmq(); - - /** - * Application name for AppId authentication. - */ - @org.springframework.beans.factory.annotation.Value("${spring.application.name:application}") - private String applicationName; - - private AuthenticationMethod authentication = AuthenticationMethod.TOKEN; - - @Data - public static class AppIdProperties { - - /** - * Property value for UserId generation using a Mac-Address. - * @see MacAddressUserId - */ - public final static String MAC_ADDRESS = "MAC_ADDRESS"; - - /** - * Property value for UserId generation using an IP-Address. - * @see IpAddressUserId - */ - public final static String IP_ADDRESS = "IP_ADDRESS"; - - /** - * Mount path of the AppId authentication backend. - */ - private String appIdPath = "app-id"; - - /** - * Network interface hint for the "MAC_ADDRESS" UserId mechanism. - */ - private String networkInterface = null; - - /** - * UserId mechanism. Can be either "MAC_ADDRESS", "IP_ADDRESS", a string or a - * class name. - */ - @NotEmpty - private String userId = MAC_ADDRESS; - } - - @Data - public static class Ssl { - - /** - * Trust store that holds SSL certificates. - */ - private Resource trustStore; - - /** - * Password used to access the trust store. - */ - private String trustStorePassword; - } - - @Data - public static class MySql implements DatabaseSecretProperties { - - /** - * Enable mysql backend usage. - */ - private boolean enabled = false; - - /** - * Role name for credentials. - */ - private String role; - - /** - * mysql backend path. - */ - @NotEmpty - private String backend = "mysql"; - - /** - * Target property for the obtained username. - */ - @NotEmpty - private String usernameProperty = "spring.datasource.username"; - - /** - * Target property for the obtained username. - */ - @NotEmpty - private String passwordProperty = "spring.datasource.password"; - } - - @Data - public static class PostgreSql implements DatabaseSecretProperties { - - /** - * Enable postgresql backend usage. - */ - private boolean enabled = false; - - /** - * Role name for credentials. - */ - private String role; - - /** - * postgresql backend path. - */ - @NotEmpty - private String backend = "postgresql"; - - /** - * Target property for the obtained username. - */ - @NotEmpty - private String usernameProperty = "spring.datasource.username"; - - /** - * Target property for the obtained username. - */ - @NotEmpty - private String passwordProperty = "spring.datasource.password"; - } - - @Data - public static class Cassandra implements DatabaseSecretProperties { - - /** - * Enable cassandra backend usage. - */ - private boolean enabled = false; - - /** - * Role name for credentials. - */ - private String role; - - /** - * Cassandra backend path. - */ - @NotEmpty - private String backend = "cassandra"; - - /** - * Target property for the obtained username. - */ - @NotEmpty - private String usernameProperty = "spring.data.cassandra.username"; - - /** - * Target property for the obtained password. - */ - @NotEmpty - private String passwordProperty = "spring.data.cassandra.password"; - } - - @Data - public static class Consul { - - /** - * Enable consul backend usage. - */ - private boolean enabled = false; - - /** - * Role name for credentials. - */ - private String role; - - /** - * Consul backend path. - */ - @NotEmpty - private String backend = "consul"; - - /** - * Target property for the obtained token. - */ - @NotEmpty - private String tokenProperty = "spring.cloud.consul.token"; - } - - @Data - public static class Rabbitmq implements DatabaseSecretProperties { - - /** - * Enable rabbitmq backend usage. - */ - private boolean enabled = false; - - /** - * Role name for credentials. - */ - private String role; - - /** - * RabbitMQ backend path. - */ - @NotEmpty - private String backend = "rabbitmq"; - - /** - * Target property for the obtained username. - */ - @NotEmpty - private String usernameProperty = "spring.rabbitmq.username"; - - /** - * Target property for the obtained password. - */ - @NotEmpty - private String passwordProperty = "spring.rabbitmq.password"; - } - - /** - * Configuration properties interface for database secrets. - */ - public interface DatabaseSecretProperties { - - /** - * Role name. - * - * @return the role name - */ - String getRole(); - - /** - * Backend path. - * - * @return the backend path. - */ - String getBackend(); - - /** - * Name of the target property for the obtained username. - */ - String getUsernameProperty(); - - /** - * Name of the target property for the obtained password. - */ - String getPasswordProperty(); - } - - public enum AuthenticationMethod { - TOKEN, APPID, - } -} diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/SecureBackendAccessorFactory.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/SecureBackendAccessorFactory.java new file mode 100644 index 00000000..bc73b26a --- /dev/null +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/SecureBackendAccessorFactory.java @@ -0,0 +1,43 @@ +/* + * Copyright 2016 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.cloud.vault.config; + +import org.springframework.cloud.vault.SecureBackendAccessor; +import org.springframework.cloud.vault.VaultSecretBackend; + +/** + * Factory to convert {@link VaultSecretBackend} instance to a + * {@link SecureBackendAccessor}. + * + * @author Mark Paluch + */ +public interface SecureBackendAccessorFactory { + + /** + * Converts a {@link VaultSecretBackend} into a {@link SecureBackendAccessor}. + * @param configurationProperties + * @return the {@link SecureBackendAccessor}. + */ + SecureBackendAccessor createSecureBackendAccessor(T configurationProperties); + + /** + * Checks whether the {@link VaultSecretBackend} is supported by this + * {@link SecureBackendAccessorFactory}. + * @param secretBackend must not be {@literal null}. + * @return {@literal true} if the given {@link VaultSecretBackend} is supported + */ + boolean supports(VaultSecretBackend secretBackend); +} diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/SecureBackendAccessors.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/SecureBackendAccessors.java new file mode 100644 index 00000000..8d0b05db --- /dev/null +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/SecureBackendAccessors.java @@ -0,0 +1,77 @@ +/* + * Copyright 2016 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.cloud.vault.config; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.cloud.vault.SecureBackendAccessor; +import org.springframework.cloud.vault.VaultProperties; +import org.springframework.util.Assert; + +/** + * Collection of common used {@link SecureBackendAccessor accessors} to access secure + * backends. + * + * @author Mark Paluch + */ +class SecureBackendAccessors { + + /** + * Creates a {@link SecureBackendAccessor} for the {@code generic} secure backend. + * + * @param vaultProperties must not be {@literal null}. + * @param key must not be {@literal null} and not empty. + * @return the {@link SecureBackendAccessor} + */ + public static SecureBackendAccessor generic(VaultProperties vaultProperties, + String key) { + + Assert.notNull(vaultProperties, "VaultProperties must not be null"); + return generic(vaultProperties.getBackend(), key); + } + + /** + * Creates a {@link SecureBackendAccessor} for the {@code generic} secure backend. + * + * @param secretBackendPath must not be {@literal null} and not empty. + * @param key must not be {@literal null} and not empty. + * @return the {@link SecureBackendAccessor} + */ + public static SecureBackendAccessor generic(final String secretBackendPath, + final String key) { + + Assert.hasText(secretBackendPath, "Secret Backend Path must not be empty"); + Assert.hasText(key, "Key must not be empty"); + + return new SecureBackendAccessor() { + + @Override + public Map variables() { + Map variables = new HashMap<>(); + variables.put("backend", secretBackendPath); + variables.put("key", key); + return variables; + } + + @Override + public Map transformProperties(Map input) { + return input; + } + }; + } +} diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/SecureBackendFactories.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/SecureBackendFactories.java new file mode 100644 index 00000000..1d67485f --- /dev/null +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/SecureBackendFactories.java @@ -0,0 +1,72 @@ +/* + * Copyright 2016 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.cloud.vault.config; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.springframework.cloud.vault.SecureBackendAccessor; + +import lombok.extern.apachecommons.CommonsLog; +import org.springframework.cloud.vault.VaultSecretBackend; + +/** + * @author Mark Paluch + */ +@CommonsLog +public class SecureBackendFactories { + + public static Collection createBackendAcessors( + Collection vaultSecretBackends, + Collection> factories) { + + List accessors = new ArrayList<>(); + + for (VaultSecretBackend vaultSecretBackend : vaultSecretBackends) { + + if (!vaultSecretBackend.isEnabled()) { + continue; + } + + SecureBackendAccessor accessor = createSecureBackendAccessor(factories, + vaultSecretBackend); + if (accessor == null) { + log.warn(String.format("Cannot create SecureBackendAccessor for %s", + vaultSecretBackend)); + continue; + } + + accessors.add(accessor); + } + + return accessors; + } + + private static SecureBackendAccessor createSecureBackendAccessor( + Collection> factories, + VaultSecretBackend vaultSecretBackend) { + SecureBackendAccessor accessor = null; + for (SecureBackendAccessorFactory factory : factories) { + + if (factory.supports(vaultSecretBackend)) { + accessor = factory.createSecureBackendAccessor(vaultSecretBackend); + break; + } + } + return accessor; + } +} diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigBootstrapConfiguration.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigBootstrapConfiguration.java new file mode 100644 index 00000000..0f90e21c --- /dev/null +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigBootstrapConfiguration.java @@ -0,0 +1,76 @@ +/* + * Copyright 2016 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.cloud.vault.config; + +import java.util.Collection; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.BeansException; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.vault.SecureBackendAccessor; +import org.springframework.cloud.vault.VaultBootstrapConfiguration; +import org.springframework.cloud.vault.VaultClient; +import org.springframework.cloud.vault.VaultProperties; +import org.springframework.cloud.vault.VaultSecretBackend; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author Mark Paluch + */ +@Configuration +@EnableConfigurationProperties +@ConditionalOnProperty(name = "spring.cloud.vault.enabled", matchIfMissing = true) +@ConditionalOnBean(VaultBootstrapConfiguration.class) +public class VaultConfigBootstrapConfiguration implements ApplicationContextAware { + + private ApplicationContext applicationContext; + + private Collection vaultSecretBackends; + private Collection> factories; + + @Bean + public VaultPropertySourceLocator vaultPropertySourceLocator(VaultClient vaultClient, + VaultProperties vaultProperties) { + + Collection backendAccessors = SecureBackendFactories + .createBackendAcessors(vaultSecretBackends, factories); + + return new VaultPropertySourceLocator(vaultClient, vaultProperties, + backendAccessors); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + this.applicationContext = applicationContext; + } + + @PostConstruct + private void postConstruct() { + + this.vaultSecretBackends = applicationContext + .getBeansOfType(VaultSecretBackend.class).values(); + this.factories = (Collection) applicationContext + .getBeansOfType(SecureBackendAccessorFactory.class).values(); + + } +} diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultPropertySource.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultPropertySource.java similarity index 77% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultPropertySource.java rename to spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultPropertySource.java index a22761d8..8d8caf6e 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultPropertySource.java +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultPropertySource.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2016 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. @@ -14,18 +14,29 @@ * limitations under the License. */ -package org.springframework.cloud.vault; +package org.springframework.cloud.vault.config; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.springframework.cloud.vault.SecureBackendAccessor; +import org.springframework.cloud.vault.VaultClient; +import org.springframework.cloud.vault.VaultProperties; import org.springframework.cloud.vault.VaultProperties.AppIdProperties; import org.springframework.cloud.vault.VaultProperties.AuthenticationMethod; +import org.springframework.cloud.vault.VaultToken; import org.springframework.core.env.EnumerablePropertySource; import org.springframework.util.Assert; import lombok.extern.apachecommons.CommonsLog; /** + * A {@link EnumerablePropertySource} backed by {@link VaultClient}. + * * @author Spencer Gibb * @author Mark Paluch */ @@ -47,12 +58,13 @@ public class VaultPropertySource extends EnumerablePropertySource { this.vaultState = state; } - public void init() { + public void init(Collection externalBackendAccessors) { Assert.hasText(vaultProperties.getBackend(), "No generic secret backend configured (spring.cloud.vault.backend)"); - List accessors = getSecureBackendAccessors(); + List accessors = getSecureBackendAccessors( + externalBackendAccessors); for (SecureBackendAccessor accessor : accessors) { try { @@ -80,37 +92,16 @@ public class VaultPropertySource extends EnumerablePropertySource { } } - private List getSecureBackendAccessors() { + private List getSecureBackendAccessors( + Collection externalBackendAccessors) { List accessors = new ArrayList<>(); accessors.add(SecureBackendAccessors.generic(vaultProperties.getBackend(), this.context)); - VaultProperties.MySql mySql = vaultProperties.getMysql(); - if (mySql.isEnabled()) { - accessors.add(SecureBackendAccessors.database(mySql)); - } + accessors.addAll(externalBackendAccessors); - VaultProperties.PostgreSql postgreSql = vaultProperties.getPostgresql(); - if (postgreSql.isEnabled()) { - accessors.add(SecureBackendAccessors.database(postgreSql)); - } - - VaultProperties.Cassandra cassandra = vaultProperties.getCassandra(); - if (cassandra.isEnabled()) { - accessors.add(SecureBackendAccessors.database(cassandra)); - } - - VaultProperties.Consul consul = vaultProperties.getConsul(); - if (consul.isEnabled()) { - accessors.add(SecureBackendAccessors.consul(consul)); - } - - VaultProperties.Rabbitmq rabbitmq = vaultProperties.getRabbitmq(); - if (rabbitmq.isEnabled()) { - accessors.add(SecureBackendAccessors.database(rabbitmq)); - } return accessors; } diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultPropertySourceLocator.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultPropertySourceLocator.java similarity index 61% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultPropertySourceLocator.java rename to spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultPropertySourceLocator.java index 29d77285..771d4f94 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultPropertySourceLocator.java +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultPropertySourceLocator.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2016 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. @@ -14,38 +14,61 @@ * limitations under the License. */ -package org.springframework.cloud.vault; +package org.springframework.cloud.vault.config; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import org.springframework.cloud.bootstrap.config.PropertySourceLocator; +import org.springframework.cloud.vault.SecureBackendAccessor; +import org.springframework.cloud.vault.VaultClient; +import org.springframework.cloud.vault.VaultProperties; import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.PropertySource; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * {@link PropertySourceLocator} using {@link VaultClient}. * * @author Spencer Gibb + * @author Mark Paluch */ public class VaultPropertySourceLocator implements PropertySourceLocator { - private VaultClient vault; + private VaultClient vaultClient; private VaultProperties properties; + private final Collection backendAcessors; + private transient final VaultState vaultState = new VaultState(); - public VaultPropertySourceLocator(VaultClient vault, VaultProperties properties) { - this.vault = vault; + /** + * Creates a new {@link VaultPropertySourceLocator}. + * @param vaultClient must not be {@literal null}. + * @param properties must not be {@literal null}. + * @param backendAccessors must not be {@literal null}. + */ + public VaultPropertySourceLocator(VaultClient vaultClient, VaultProperties properties, + Collection backendAccessors) { + + Assert.notNull(vaultClient, "VaultClient must not be null"); + Assert.notNull(properties, "VaultProperties must not be null"); + Assert.notNull(backendAccessors, "BackendAccessors must not be null"); + + this.vaultClient = vaultClient; this.properties = properties; + this.backendAcessors = backendAccessors; } @Override public PropertySource locate(Environment environment) { + if (environment instanceof ConfigurableEnvironment) { ConfigurableEnvironment env = (ConfigurableEnvironment) environment; String appName = env.getProperty("spring.application.name"); @@ -66,9 +89,12 @@ public class VaultPropertySourceLocator implements PropertySourceLocator { CompositePropertySource composite = new CompositePropertySource("vault"); for (String propertySourceContext : contexts) { - VaultPropertySource propertySource = create(propertySourceContext); - propertySource.init(); - composite.addPropertySource(propertySource); + + if(StringUtils.hasText(propertySourceContext)) { + VaultPropertySource propertySource = create(propertySourceContext); + propertySource.init(backendAcessors); + composite.addPropertySource(propertySource); + } } return composite; @@ -77,11 +103,12 @@ public class VaultPropertySourceLocator implements PropertySourceLocator { } private VaultPropertySource create(String context) { - return new VaultPropertySource(context, this.vault, this.properties, this.vaultState); + return new VaultPropertySource(context, this.vaultClient, this.properties, + this.vaultState); } private void addProfiles(List contexts, String baseContext, - List profiles) { + List profiles) { for (String profile : profiles) { contexts.add(baseContext + this.properties.getProfileSeparator() + profile); } diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultState.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultState.java similarity index 88% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultState.java rename to spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultState.java index 96207534..52a92b7b 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultState.java +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultState.java @@ -14,9 +14,10 @@ * limitations under the License. */ -package org.springframework.cloud.vault; +package org.springframework.cloud.vault.config; import lombok.Data; +import org.springframework.cloud.vault.VaultToken; /** * State of the Vault client. diff --git a/spring-cloud-vault-config/src/main/resources/META-INF/spring.factories b/spring-cloud-vault-config/src/main/resources/META-INF/spring.factories index ec4d51a7..64084bbb 100644 --- a/spring-cloud-vault-config/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-vault-config/src/main/resources/META-INF/spring.factories @@ -1,3 +1,3 @@ # Bootstrap Configuration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ -org.springframework.cloud.vault.VaultBootstrapConfiguration \ No newline at end of file +org.springframework.cloud.vault.config.VaultConfigBootstrapConfiguration \ No newline at end of file diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/AppIdAuthenticationIntegrationTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/AppIdAuthenticationIntegrationTests.java similarity index 88% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/AppIdAuthenticationIntegrationTests.java rename to spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/AppIdAuthenticationIntegrationTests.java index 6804f536..6f65889e 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/AppIdAuthenticationIntegrationTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/AppIdAuthenticationIntegrationTests.java @@ -13,11 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.vault; +package org.springframework.cloud.vault.config; import org.junit.Before; +import org.springframework.cloud.vault.IpAddressUserId; +import org.springframework.cloud.vault.TestRestTemplateFactory; +import org.springframework.cloud.vault.VaultClient; import org.springframework.cloud.vault.VaultProperties.AppIdProperties; import org.springframework.cloud.vault.VaultProperties.AuthenticationMethod; +import org.springframework.cloud.vault.VaultToken; import org.springframework.cloud.vault.util.Settings; /** diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/ApplicationFailFastTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/ApplicationFailFastTests.java similarity index 96% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/ApplicationFailFastTests.java rename to spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/ApplicationFailFastTests.java index 4da1eaa4..8dda78f6 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/ApplicationFailFastTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/ApplicationFailFastTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.vault.configclient; +package org.springframework.cloud.vault.config; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/GenericSecretIntegrationTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/GenericSecretIntegrationTests.java similarity index 86% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/GenericSecretIntegrationTests.java rename to spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/GenericSecretIntegrationTests.java index a49effcb..cd016549 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/GenericSecretIntegrationTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/GenericSecretIntegrationTests.java @@ -13,16 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.vault; +package org.springframework.cloud.vault.config; import static org.assertj.core.api.Assertions.*; -import static org.springframework.cloud.vault.SecureBackendAccessors.*; +import static org.springframework.cloud.vault.config.SecureBackendAccessors.*; import java.util.HashMap; import java.util.Map; import org.junit.Before; import org.junit.Test; +import org.springframework.cloud.vault.AbstractIntegrationTests; +import org.springframework.cloud.vault.TestRestTemplateFactory; +import org.springframework.cloud.vault.VaultClient; +import org.springframework.cloud.vault.VaultProperties; +import org.springframework.cloud.vault.VaultToken; import org.springframework.cloud.vault.util.Settings; /** diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/PrepareVaultTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/PrepareVaultTests.java new file mode 100644 index 00000000..6e104783 --- /dev/null +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/PrepareVaultTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 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.cloud.vault.config; + +import org.junit.Test; +import org.springframework.cloud.vault.TestRestTemplateFactory; +import org.springframework.cloud.vault.VaultProperties; +import org.springframework.cloud.vault.VaultToken; +import org.springframework.cloud.vault.util.PrepareVault; +import org.springframework.cloud.vault.util.Settings; + +/** + * Integration tests for {@link PrepareVault}. + * + * @author Mark Paluch + */ +public class PrepareVaultTests { + + private VaultProperties vaultProperties = Settings.createVaultProperties(); + private PrepareVault prepareVault = new PrepareVault(TestRestTemplateFactory.create(vaultProperties)); + + @Test + public void initializeShouldCreateANewVault() throws Exception { + + prepareVault.setRootToken(Settings.token()); + prepareVault.setVaultProperties(vaultProperties); + + if (!prepareVault.isAvailable()) { + VaultToken rootToken = prepareVault.initializeVault(); + prepareVault.setRootToken(rootToken); + prepareVault.createToken(vaultProperties.getToken(), "root"); + } + } +} diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/VaultAppIdCustomMechanismTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigAppIdCustomMechanismTests.java similarity index 82% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/VaultAppIdCustomMechanismTests.java rename to spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigAppIdCustomMechanismTests.java index 0b9db8a2..8dc3c433 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/VaultAppIdCustomMechanismTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigAppIdCustomMechanismTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.vault; +package org.springframework.cloud.vault.config; import static org.assertj.core.api.Assertions.*; @@ -29,7 +29,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.test.IntegrationTest; import org.springframework.boot.test.SpringApplicationConfiguration; -import org.springframework.cloud.vault.VaultAppIdCustomMechanismTests.BootstrapConfiguration; +import org.springframework.cloud.vault.AppIdUserIdMechanism; +import org.springframework.cloud.vault.config.VaultConfigAppIdCustomMechanismTests.BootstrapConfiguration; +import org.springframework.cloud.vault.VaultProperties; import org.springframework.cloud.vault.util.Settings; import org.springframework.cloud.vault.util.VaultRule; import org.springframework.context.annotation.Bean; @@ -41,10 +43,10 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; */ @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = { BootstrapConfiguration.class, - VaultAppIdCustomMechanismTests.TestApplication.class }) + VaultConfigAppIdCustomMechanismTests.TestApplication.class }) @IntegrationTest({ "spring.cloud.vault.authentication=appid", "use.custom.config=true", - "spring.application.name=VaultAppIdCustomMechanismTests" }) -public class VaultAppIdCustomMechanismTests { + "spring.application.name=VaultConfigAppIdCustomMechanismTests" }) +public class VaultConfigAppIdCustomMechanismTests { @BeforeClass public static void beforeClass() throws Exception { @@ -53,7 +55,7 @@ public class VaultAppIdCustomMechanismTests { vaultRule.before(); vaultRule.prepare().writeSecret( - VaultAppIdCustomMechanismTests.class.getSimpleName(), + VaultConfigAppIdCustomMechanismTests.class.getSimpleName(), Collections.singletonMap("vault.value", "foo")); VaultProperties vaultProperties = Settings.createVaultProperties(); @@ -64,9 +66,9 @@ public class VaultAppIdCustomMechanismTests { } vaultRule.prepare() - .mapAppId(VaultAppIdCustomMechanismTests.class.getSimpleName()); + .mapAppId(VaultConfigAppIdCustomMechanismTests.class.getSimpleName()); vaultRule.prepare().mapUserId( - VaultAppIdCustomMechanismTests.class.getSimpleName(), + VaultConfigAppIdCustomMechanismTests.class.getSimpleName(), new StaticUserIdMechanism().createUserId()); } diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultAppIdTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigAppIdTests.java similarity index 85% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultAppIdTests.java rename to spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigAppIdTests.java index 0fb33b1f..2824adfc 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultAppIdTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigAppIdTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.vault.configclient; +package org.springframework.cloud.vault.config; import static org.assertj.core.api.Assertions.*; @@ -41,11 +41,11 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes = VaultAppIdTests.TestApplication.class) +@SpringApplicationConfiguration(classes = VaultConfigAppIdTests.TestApplication.class) @IntegrationTest({ "spring.cloud.vault.authentication=appid", "spring.cloud.vault.app-id.user-id=IP_ADDRESS", - "spring.application.name=VaultAppIdTests" }) -public class VaultAppIdTests { + "spring.application.name=VaultConfigAppIdTests" }) +public class VaultConfigAppIdTests { @BeforeClass public static void beforeClass() throws Exception { @@ -53,7 +53,7 @@ public class VaultAppIdTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); - vaultRule.prepare().writeSecret(VaultAppIdTests.class.getSimpleName(), + vaultRule.prepare().writeSecret(VaultConfigAppIdTests.class.getSimpleName(), Collections.singletonMap("vault.value", "foo")); VaultProperties vaultProperties = Settings.createVaultProperties(); @@ -64,8 +64,8 @@ public class VaultAppIdTests { vaultRule.prepare().mountAuth(vaultProperties.getAppId().getAppIdPath()); } - vaultRule.prepare().mapAppId(VaultAppIdTests.class.getSimpleName()); - vaultRule.prepare().mapUserId(VaultAppIdTests.class.getSimpleName(), + vaultRule.prepare().mapAppId(VaultConfigAppIdTests.class.getSimpleName()); + vaultRule.prepare().mapUserId(VaultConfigAppIdTests.class.getSimpleName(), new IpAddressUserId().createUserId()); } diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigTests.java similarity index 92% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultTests.java rename to spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigTests.java index 6e3689ca..76806bfb 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/configclient/VaultTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.vault.configclient; +package org.springframework.cloud.vault.config; import static org.assertj.core.api.Assertions.*; @@ -37,8 +37,8 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes = VaultTests.TestApplication.class) -public class VaultTests { +@SpringApplicationConfiguration(classes = VaultConfigTests.TestApplication.class) +public class VaultConfigTests { @BeforeClass public static void beforeClass() throws Exception { diff --git a/spring-cloud-vault-config/src/test/resources/META-INF/spring.factories b/spring-cloud-vault-config/src/test/resources/META-INF/spring.factories index 852326b6..cc4abbfb 100644 --- a/spring-cloud-vault-config/src/test/resources/META-INF/spring.factories +++ b/spring-cloud-vault-config/src/test/resources/META-INF/spring.factories @@ -1,3 +1,3 @@ # Bootstrap Configuration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ -org.springframework.cloud.vault.VaultAppIdCustomMechanismTests.BootstrapConfiguration +org.springframework.cloud.vault.config.VaultConfigAppIdCustomMechanismTests.BootstrapConfiguration diff --git a/spring-cloud-vault-core/pom.xml b/spring-cloud-vault-core/pom.xml new file mode 100644 index 00000000..84ba994f --- /dev/null +++ b/spring-cloud-vault-core/pom.xml @@ -0,0 +1,92 @@ + + + 4.0.0 + + + org.springframework.cloud + spring-cloud-vault-config-parent + 1.0.0.BUILD-SNAPSHOT + .. + + + org.springframework.cloud + spring-cloud-vault-core + 1.0.0.BUILD-SNAPSHOT + jar + + Spring Cloud Vault Core + Spring Cloud Vault Core + + + + org.springframework.cloud + spring-cloud-context + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.projectlombok + lombok + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.apache.httpcomponents + httpclient + true + + + + org.apache.httpcomponents + httpcore + true + + + + io.netty + netty-all + true + + + + com.squareup.okhttp + okhttp + true + + + + org.assertj + assertj-core + + + + + + + maven-jar-plugin + + + test-jar + + test-jar + + + + + + + + diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/AppIdUserIdMechanism.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/AppIdUserIdMechanism.java similarity index 100% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/AppIdUserIdMechanism.java rename to spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/AppIdUserIdMechanism.java diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactory.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactory.java similarity index 60% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactory.java rename to spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactory.java index 1d6f183e..2d89c5e7 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactory.java +++ b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactory.java @@ -77,15 +77,15 @@ class ClientHttpRequestFactoryFactory { try { if (HTTP_COMPONENTS_PRESENT) { - return usingHttpComponents(vaultProperties); + return HttpComponents.usingHttpComponents(vaultProperties); } if (OKHTTP_PRESENT) { - return usingOkHttp(vaultProperties); + return OkHttp.usingOkHttp(vaultProperties); } if (NETTY_PRESENT) { - return usingNetty(vaultProperties); + return Netty.usingNetty(vaultProperties); } } @@ -101,87 +101,6 @@ class ClientHttpRequestFactoryFactory { return new SimpleClientHttpRequestFactory(); } - protected static ClientHttpRequestFactory usingHttpComponents( - VaultProperties vaultProperties) - throws GeneralSecurityException, IOException { - - HttpClientBuilder httpClientBuilder = HttpClients.custom(); - - if (hasSslConfiguration(vaultProperties)) { - - SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory( - getSSLContext(vaultProperties.getSsl())); - httpClientBuilder.setSSLSocketFactory(sslSocketFactory); - } - - RequestConfig requestConfig = RequestConfig.custom() // - .setConnectTimeout(vaultProperties.getConnectionTimeout()) // - .setSocketTimeout(vaultProperties.getReadTimeout()) // - .build(); - - httpClientBuilder.setDefaultRequestConfig(requestConfig); - - HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory( - httpClientBuilder.build()); - - return factory; - } - - protected static ClientHttpRequestFactory usingNetty(VaultProperties vaultProperties) - throws GeneralSecurityException, IOException { - - VaultProperties.Ssl ssl = vaultProperties.getSsl(); - - final Netty4ClientHttpRequestFactory requestFactory = new Netty4ClientHttpRequestFactory(); - - if (hasSslConfiguration(vaultProperties)) { - - SslContext sslContext = SslContextBuilder // - .forClient() // - .trustManager(createTrustManagerFactory(ssl.getTrustStore(), - ssl.getTrustStorePassword())) // - .sslProvider(SslProvider.JDK) // - .build(); - - requestFactory.setSslContext(sslContext); - } - - requestFactory.setConnectTimeout(vaultProperties.getConnectionTimeout()); - requestFactory.setReadTimeout(vaultProperties.getReadTimeout()); - - return requestFactory; - } - - protected static ClientHttpRequestFactory usingOkHttp(VaultProperties vaultProperties) - throws GeneralSecurityException, IOException { - - final OkHttpClient okHttpClient = new OkHttpClient(); - - OkHttpClientHttpRequestFactory requestFactory = new OkHttpClientHttpRequestFactory( - okHttpClient) { - - @Override - public void destroy() throws Exception { - - if (okHttpClient.getCache() != null) { - okHttpClient.getCache().close(); - } - - okHttpClient.getDispatcher().getExecutorService().shutdown(); - } - }; - - if (hasSslConfiguration(vaultProperties)) { - okHttpClient.setSslSocketFactory( - getSSLContext(vaultProperties.getSsl()).getSocketFactory()); - } - - requestFactory.setConnectTimeout(vaultProperties.getConnectionTimeout()); - requestFactory.setReadTimeout(vaultProperties.getReadTimeout()); - - return requestFactory; - } - private static SSLContext getSSLContext(VaultProperties.Ssl ssl) throws GeneralSecurityException, IOException { @@ -217,4 +136,109 @@ class ClientHttpRequestFactoryFactory { return vaultProperties.getSsl() != null && vaultProperties.getSsl().getTrustStore() != null; } + + /** + * {@link ClientHttpRequestFactory} for Apache Http Components. + * + * @author Mark Paluch + */ + static class HttpComponents { + protected static ClientHttpRequestFactory usingHttpComponents( + VaultProperties vaultProperties) + throws GeneralSecurityException, IOException { + + HttpClientBuilder httpClientBuilder = HttpClients.custom(); + + if (hasSslConfiguration(vaultProperties)) { + + SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory( + getSSLContext(vaultProperties.getSsl())); + httpClientBuilder.setSSLSocketFactory(sslSocketFactory); + } + + RequestConfig requestConfig = RequestConfig.custom() // + .setConnectTimeout(vaultProperties.getConnectionTimeout()) // + .setSocketTimeout(vaultProperties.getReadTimeout()) // + .build(); + + httpClientBuilder.setDefaultRequestConfig(requestConfig); + + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory( + httpClientBuilder.build()); + + return factory; + } + } + + /** + * {@link ClientHttpRequestFactory} for the {@link OkHttpClient}. + * + * @author Mark Paluch + */ + static class OkHttp { + + protected static ClientHttpRequestFactory usingOkHttp( + VaultProperties vaultProperties) + throws GeneralSecurityException, IOException { + + final OkHttpClient okHttpClient = new OkHttpClient(); + + OkHttpClientHttpRequestFactory requestFactory = new OkHttpClientHttpRequestFactory( + okHttpClient) { + + @Override + public void destroy() throws Exception { + + if (okHttpClient.getCache() != null) { + okHttpClient.getCache().close(); + } + + okHttpClient.getDispatcher().getExecutorService().shutdown(); + } + }; + + if (hasSslConfiguration(vaultProperties)) { + okHttpClient.setSslSocketFactory( + getSSLContext(vaultProperties.getSsl()).getSocketFactory()); + } + + requestFactory.setConnectTimeout(vaultProperties.getConnectionTimeout()); + requestFactory.setReadTimeout(vaultProperties.getReadTimeout()); + + return requestFactory; + } + } + + /** + * {@link ClientHttpRequestFactory} for Netty. + * + * @author Mark Paluch + */ + static class Netty { + protected static ClientHttpRequestFactory usingNetty( + VaultProperties vaultProperties) + throws GeneralSecurityException, IOException { + + VaultProperties.Ssl ssl = vaultProperties.getSsl(); + + final Netty4ClientHttpRequestFactory requestFactory = new Netty4ClientHttpRequestFactory(); + + if (hasSslConfiguration(vaultProperties)) { + + SslContext sslContext = SslContextBuilder // + .forClient() // + .trustManager(createTrustManagerFactory(ssl.getTrustStore(), + ssl.getTrustStorePassword())) // + .sslProvider(SslProvider.JDK) // + .build(); + + requestFactory.setSslContext(sslContext); + } + + requestFactory.setConnectTimeout(vaultProperties.getConnectionTimeout()); + requestFactory.setReadTimeout(vaultProperties.getReadTimeout()); + + return requestFactory; + } + } } diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/IpAddressUserId.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/IpAddressUserId.java similarity index 100% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/IpAddressUserId.java rename to spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/IpAddressUserId.java diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/MacAddressUserId.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/MacAddressUserId.java similarity index 97% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/MacAddressUserId.java rename to spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/MacAddressUserId.java index 238d052d..5130294a 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/MacAddressUserId.java +++ b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/MacAddressUserId.java @@ -22,16 +22,16 @@ import java.net.NetworkInterface; import java.util.Collections; import java.util.List; +import org.springframework.util.StringUtils; + import lombok.RequiredArgsConstructor; import lombok.Value; import lombok.extern.apachecommons.CommonsLog; -import org.springframework.util.StringUtils; - /** * Mechanism to generate a UserId based on the Mac address. {@link MacAddressUserId} creates a hex-encoded * representation of the Mac address without any separators (0123456789AB). A - * {@link org.springframework.cloud.vault.VaultProperties.AppIdProperties#networkInterface} can be + * {@link VaultProperties.AppIdProperties#networkInterface} can be * specified optionally to select a network interface (index/name). * * @author Mark Paluch diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/SecureBackendAccessor.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/SecureBackendAccessor.java similarity index 100% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/SecureBackendAccessor.java rename to spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/SecureBackendAccessor.java diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/Sha256.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/Sha256.java similarity index 100% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/Sha256.java rename to spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/Sha256.java diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/StaticUserId.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/StaticUserId.java similarity index 100% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/StaticUserId.java rename to spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/StaticUserId.java diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultBootstrapConfiguration.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultBootstrapConfiguration.java similarity index 69% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultBootstrapConfiguration.java rename to spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultBootstrapConfiguration.java index f0a94927..4f2d765a 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultBootstrapConfiguration.java +++ b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultBootstrapConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2016 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. @@ -19,6 +19,8 @@ package org.springframework.cloud.vault; import java.util.Map; import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -41,15 +43,16 @@ import org.springframework.web.client.RestTemplate; public class VaultBootstrapConfiguration { @Bean - @Qualifier("vault-ClientHttpRequestFactory") - public ClientHttpRequestFactory clientHttpRequestFactory(){ - return ClientHttpRequestFactoryFactory.create(vaultProperties()); + public ClientFactoryWrapper clientHttpRequestFactoryWrapper() { + return new ClientFactoryWrapper( + ClientHttpRequestFactoryFactory.create(vaultProperties())); } @Bean @Qualifier("vault-RestTemplate") - public RestTemplate restTemplate(){ - return new RestTemplate(clientHttpRequestFactory()); + public RestTemplate restTemplate() { + return new RestTemplate( + clientHttpRequestFactoryWrapper().getClientHttpRequestFactory()); } @Bean @@ -99,10 +102,34 @@ public class VaultBootstrapConfiguration { } } - @Bean - public VaultPropertySourceLocator vaultPropertySourceLocator( - ApplicationContext applicationContext) { - return new VaultPropertySourceLocator(vaultClient(applicationContext), - vaultProperties()); + /** + * Wrapper for {@link ClientHttpRequestFactory} to not expose the bean globally. + */ + static class ClientFactoryWrapper implements InitializingBean, DisposableBean { + + private final ClientHttpRequestFactory clientHttpRequestFactory; + + public ClientFactoryWrapper(ClientHttpRequestFactory clientHttpRequestFactory) { + this.clientHttpRequestFactory = clientHttpRequestFactory; + } + + @Override + public void destroy() throws Exception { + if (clientHttpRequestFactory instanceof DisposableBean) { + ((DisposableBean) clientHttpRequestFactory).destroy(); + } + } + + @Override + public void afterPropertiesSet() throws Exception { + + if (clientHttpRequestFactory instanceof InitializingBean) { + ((InitializingBean) clientHttpRequestFactory).afterPropertiesSet(); + } + } + + public ClientHttpRequestFactory getClientHttpRequestFactory() { + return clientHttpRequestFactory; + } } } diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultClient.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultClient.java similarity index 98% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultClient.java rename to spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultClient.java index 37b60968..921aeef5 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultClient.java +++ b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2016 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. @@ -57,7 +57,6 @@ public class VaultClient { @Setter private AppIdUserIdMechanism appIdUserIdMechanism; - private ClientHttpRequestFactory clientHttpRequestFactory; private final VaultProperties properties; public VaultClient(VaultProperties properties) { diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultProperties.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultProperties.java new file mode 100644 index 00000000..4ad24a4c --- /dev/null +++ b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultProperties.java @@ -0,0 +1,155 @@ +/* + * Copyright 2016 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.cloud.vault; + +import org.hibernate.validator.constraints.NotEmpty; +import org.hibernate.validator.constraints.Range; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.core.io.Resource; + +import lombok.Data; + +/** + * @author Spencer Gibb + * @author Mark Paluch + */ +@ConfigurationProperties("spring.cloud.vault") +@Data +public class VaultProperties { + + /** + * Enable Vault config server. + */ + private boolean enabled = true; + + /** + * Vault server host. + */ + @NotEmpty + private String host = "localhost"; + + /** + * Vault server port. + */ + @Range(min = 1, max = 65535) + private int port = 8200; + + /** + * Protocol scheme. Can be either "http" or "https". + */ + private String scheme = "https"; + + /** + * Name of the default backend. + */ + @NotEmpty + private String backend = "secret"; + + /** + * Name of the default context. + */ + @NotEmpty + private String defaultContext = "application"; + + /** + * Profile-separator to combine application name and profile. + */ + @NotEmpty + private String profileSeparator = ","; + + /** + * Connection timeout; + */ + private int connectionTimeout = 5000; + + /** + * Read timeout; + */ + private int readTimeout = 15000; + + /** + * Fail fast if data cannot be obtained from Vault. + */ + private boolean failFast = false; + + /** + * Static vault token. Required if {@link #authentication} is {@code TOKEN}. + */ + private String token; + + private AppIdProperties appId = new AppIdProperties(); + + private Ssl ssl = new Ssl(); + + /** + * Application name for AppId authentication. + */ + @org.springframework.beans.factory.annotation.Value("${spring.application.name:application}") + private String applicationName; + + private AuthenticationMethod authentication = AuthenticationMethod.TOKEN; + + @Data + public static class AppIdProperties { + + /** + * Property value for UserId generation using a Mac-Address. + * @see MacAddressUserId + */ + public final static String MAC_ADDRESS = "MAC_ADDRESS"; + + /** + * Property value for UserId generation using an IP-Address. + * @see IpAddressUserId + */ + public final static String IP_ADDRESS = "IP_ADDRESS"; + + /** + * Mount path of the AppId authentication backend. + */ + private String appIdPath = "app-id"; + + /** + * Network interface hint for the "MAC_ADDRESS" UserId mechanism. + */ + private String networkInterface = null; + + /** + * UserId mechanism. Can be either "MAC_ADDRESS", "IP_ADDRESS", a string or a + * class name. + */ + @NotEmpty + private String userId = MAC_ADDRESS; + } + + @Data + public static class Ssl { + + /** + * Trust store that holds SSL certificates. + */ + private Resource trustStore; + + /** + * Password used to access the trust store. + */ + private String trustStorePassword; + } + + public enum AuthenticationMethod { + TOKEN, APPID, + } +} diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultResponse.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultResponse.java similarity index 95% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultResponse.java rename to spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultResponse.java index e8b1d433..d6fb745a 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultResponse.java +++ b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2016 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. @@ -18,10 +18,10 @@ package org.springframework.cloud.vault; import java.util.Map; -import lombok.Data; - import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + /** * Value object to bind HTTP API responses. * diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/MyUserIdMechanism.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultSecretBackend.java similarity index 71% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/MyUserIdMechanism.java rename to spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultSecretBackend.java index 5d287cb2..b59e8459 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/MyUserIdMechanism.java +++ b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultSecretBackend.java @@ -13,17 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.cloud.vault; /** + * A secret backend that can return secrets from Vault. + * * @author Mark Paluch */ -public class MyUserIdMechanism implements AppIdUserIdMechanism { +public interface VaultSecretBackend { - @Override - public String createUserId() { - String userId = ""; - return userId; - } + /** + * Backend path. + * + * @return the backend path. + */ + String getBackend(); + + /** + * + * @return {@literal true} if the backend is enabled. + */ + boolean isEnabled(); } diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultToken.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultToken.java similarity index 100% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/VaultToken.java rename to spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultToken.java diff --git a/spring-cloud-vault-core/src/main/resources/META-INF/spring.factories b/spring-cloud-vault-core/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..ec4d51a7 --- /dev/null +++ b/spring-cloud-vault-core/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Bootstrap Configuration +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ +org.springframework.cloud.vault.VaultBootstrapConfiguration \ No newline at end of file diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/AbstractIntegrationTests.java b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/AbstractIntegrationTests.java similarity index 100% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/AbstractIntegrationTests.java rename to spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/AbstractIntegrationTests.java diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/AppIdAuthenticationMethodsIntegrationTests.java b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/AppIdAuthenticationMethodsIntegrationTests.java similarity index 96% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/AppIdAuthenticationMethodsIntegrationTests.java rename to spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/AppIdAuthenticationMethodsIntegrationTests.java index 1248e475..f5d3e7d3 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/AppIdAuthenticationMethodsIntegrationTests.java +++ b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/AppIdAuthenticationMethodsIntegrationTests.java @@ -41,6 +41,11 @@ public class AppIdAuthenticationMethodsIntegrationTests extends AbstractIntegrat @Before public void setUp() throws Exception { + + if (!prepare().hasAuth("app-id")) { + prepare().mountAuth("app-id"); + } + prepare().mapAppId("myapp"); } @@ -50,7 +55,8 @@ public class AppIdAuthenticationMethodsIntegrationTests extends AbstractIntegrat VaultClient vaultClient = new VaultClient( prepareAppIdAuthenticationMethod(AppIdProperties.IP_ADDRESS, "myapp")); - vaultClient.setRest(TestRestTemplateFactory.create(Settings.createVaultProperties())); + vaultClient.setRest( + TestRestTemplateFactory.create(Settings.createVaultProperties())); vaultClient.setAppIdUserIdMechanism(new IpAddressUserId()); assertThat(vaultClient.createToken()).isNotNull(); diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactoryIntegrationTests.java b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactoryIntegrationTests.java similarity index 92% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactoryIntegrationTests.java rename to spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactoryIntegrationTests.java index 5a985b9c..dc9b4d1e 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactoryIntegrationTests.java +++ b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactoryIntegrationTests.java @@ -16,6 +16,7 @@ package org.springframework.cloud.vault; import static org.assertj.core.api.AssertionsForClassTypes.*; +import static org.springframework.cloud.vault.ClientHttpRequestFactoryFactory.*; import org.junit.Test; import org.springframework.beans.factory.DisposableBean; @@ -42,7 +43,7 @@ public class ClientHttpRequestFactoryFactoryIntegrationTests { @Test public void httpComponentsClientShouldWork() throws Exception { - ClientHttpRequestFactory factory = ClientHttpRequestFactoryFactory + ClientHttpRequestFactory factory = HttpComponents .usingHttpComponents(vaultProperties); RestTemplate template = new RestTemplate(factory); @@ -57,7 +58,7 @@ public class ClientHttpRequestFactoryFactoryIntegrationTests { @Test public void nettyClientShouldWork() throws Exception { - ClientHttpRequestFactory factory = ClientHttpRequestFactoryFactory + ClientHttpRequestFactory factory = Netty .usingNetty(vaultProperties); ((InitializingBean) factory).afterPropertiesSet(); RestTemplate template = new RestTemplate(factory); @@ -73,7 +74,7 @@ public class ClientHttpRequestFactoryFactoryIntegrationTests { @Test public void okHttpClientShouldWork() throws Exception { - ClientHttpRequestFactory factory = ClientHttpRequestFactoryFactory + ClientHttpRequestFactory factory = OkHttp .usingOkHttp(vaultProperties); RestTemplate template = new RestTemplate(factory); diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/PrepareVaultTests.java b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/PrepareVaultTests.java similarity index 100% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/PrepareVaultTests.java rename to spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/PrepareVaultTests.java diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/TestRestTemplateFactory.java b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/TestRestTemplateFactory.java similarity index 100% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/TestRestTemplateFactory.java rename to spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/TestRestTemplateFactory.java diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/CanConnect.java b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/CanConnect.java similarity index 100% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/CanConnect.java rename to spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/CanConnect.java diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/PrepareVault.java b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/PrepareVault.java similarity index 100% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/PrepareVault.java rename to spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/PrepareVault.java diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/Settings.java b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/Settings.java similarity index 100% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/Settings.java rename to spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/Settings.java diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/VaultRule.java b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/VaultRule.java similarity index 100% rename from spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/VaultRule.java rename to spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/VaultRule.java diff --git a/spring-cloud-vault-config/src/test/resources/consul.json b/spring-cloud-vault-core/src/test/resources/consul.json similarity index 100% rename from spring-cloud-vault-config/src/test/resources/consul.json rename to spring-cloud-vault-core/src/test/resources/consul.json diff --git a/spring-cloud-vault-config/src/test/resources/vault.conf b/spring-cloud-vault-core/src/test/resources/vault.conf similarity index 100% rename from spring-cloud-vault-config/src/test/resources/vault.conf rename to spring-cloud-vault-core/src/test/resources/vault.conf diff --git a/src/test/bash/local_run_consul.sh b/src/test/bash/local_run_consul.sh index 0ae7660d..f3761281 100755 --- a/src/test/bash/local_run_consul.sh +++ b/src/test/bash/local_run_consul.sh @@ -12,6 +12,6 @@ mkdir -p ${BASEDIR}/consul/data ./consul/consul agent -server \ -bootstrap-expect 1 \ -data-dir ${BASEDIR}/consul/data \ - -config-file=${BASEDIR}/spring-cloud-vault-config/src/test/resources/consul.json + -config-file=${BASEDIR}/spring-cloud-vault-core/src/test/resources/consul.json exit $? diff --git a/src/test/bash/local_run_vault.sh b/src/test/bash/local_run_vault.sh index fc00213c..38381c8f 100755 --- a/src/test/bash/local_run_vault.sh +++ b/src/test/bash/local_run_vault.sh @@ -6,6 +6,6 @@ BASEDIR=`dirname $0`/../../.. -./vault/vault server -config=${BASEDIR}/spring-cloud-vault-config/src/test/resources/vault.conf +./vault/vault server -config=${BASEDIR}/spring-cloud-vault-core/src/test/resources/vault.conf exit $?