diff --git a/pom.xml b/pom.xml index a739e9ac..5b0a3f35 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,6 @@ spring-cloud-vault-dependencies - spring-cloud-vault-core spring-cloud-vault-config spring-cloud-vault-config-databases spring-cloud-vault-config-consul @@ -53,6 +52,14 @@ import pom + + + org.springframework.cloud + spring-cloud-vault-config + ${project.version} + test-jar + test + diff --git a/spring-cloud-vault-config-aws/pom.xml b/spring-cloud-vault-config-aws/pom.xml index 6d335a71..c90d2d9b 100644 --- a/spring-cloud-vault-config-aws/pom.xml +++ b/spring-cloud-vault-config-aws/pom.xml @@ -20,18 +20,13 @@ org.springframework.cloud - spring-cloud-vault-core - - - - org.springframework.cloud - spring-cloud-vault-core - test-jar + spring-cloud-vault-config org.springframework.cloud spring-cloud-vault-config + test-jar diff --git a/spring-cloud-vault-config-aws/src/main/java/org/springframework/cloud/vault/config/aws/VaultAwsProperties.java b/spring-cloud-vault-config-aws/src/main/java/org/springframework/cloud/vault/config/aws/VaultAwsProperties.java index d8395b2f..1c71dadd 100644 --- a/spring-cloud-vault-config-aws/src/main/java/org/springframework/cloud/vault/config/aws/VaultAwsProperties.java +++ b/spring-cloud-vault-config-aws/src/main/java/org/springframework/cloud/vault/config/aws/VaultAwsProperties.java @@ -17,7 +17,7 @@ package org.springframework.cloud.vault.config.aws; import org.hibernate.validator.constraints.NotEmpty; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.cloud.vault.VaultSecretBackend; +import org.springframework.cloud.vault.config.VaultSecretBackend; import lombok.Data; diff --git a/spring-cloud-vault-config-aws/src/main/java/org/springframework/cloud/vault/config/aws/VaultConfigAwsBootstrapConfiguration.java b/spring-cloud-vault-config-aws/src/main/java/org/springframework/cloud/vault/config/aws/VaultConfigAwsBootstrapConfiguration.java index fa513d44..715cb49a 100644 --- a/spring-cloud-vault-config-aws/src/main/java/org/springframework/cloud/vault/config/aws/VaultConfigAwsBootstrapConfiguration.java +++ b/spring-cloud-vault-config-aws/src/main/java/org/springframework/cloud/vault/config/aws/VaultConfigAwsBootstrapConfiguration.java @@ -20,8 +20,8 @@ import java.util.Map; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.vault.config.SecureBackendAccessor; -import org.springframework.cloud.vault.VaultSecretBackend; import org.springframework.cloud.vault.config.SecureBackendAccessorFactory; +import org.springframework.cloud.vault.config.VaultSecretBackend; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.Assert; @@ -59,16 +59,15 @@ public class VaultConfigAwsBootstrapConfiguration { /** * Creates a {@link SecureBackendAccessor} for a secure backend using - * {@link VaultAwsProperties}. This accessor transforms Vault's - * username/password property names to names provided with + * {@link VaultAwsProperties}. This accessor transforms Vault's username/password + * property names to names provided with * {@link VaultAwsProperties#getAccessKeyProperty()} and * {@link VaultAwsProperties#getSecretKeyProperty()}. * * @param properties must not be {@literal null}. * @return the {@link SecureBackendAccessor} */ - public static SecureBackendAccessor forAws( - final VaultAwsProperties properties) { + public static SecureBackendAccessor forAws(final VaultAwsProperties properties) { Assert.notNull(properties, "VaultAwsProperties must not be null"); return new SecureBackendAccessor() { @@ -93,8 +92,10 @@ public class VaultConfigAwsBootstrapConfiguration { Map input) { Map result = new HashMap(); - result.put(properties.getAccessKeyProperty(), input.get("access_key")); - result.put(properties.getSecretKeyProperty(), input.get("secret_key")); + result.put(properties.getAccessKeyProperty(), + input.get("access_key")); + result.put(properties.getSecretKeyProperty(), + input.get("secret_key")); return result; } diff --git a/spring-cloud-vault-config-aws/src/test/java/org/springframework/cloud/vault/config/aws/AwsSecretIntegrationTests.java b/spring-cloud-vault-config-aws/src/test/java/org/springframework/cloud/vault/config/aws/AwsSecretIntegrationTests.java index b09d52db..4207b299 100644 --- a/spring-cloud-vault-config-aws/src/test/java/org/springframework/cloud/vault/config/aws/AwsSecretIntegrationTests.java +++ b/spring-cloud-vault-config-aws/src/test/java/org/springframework/cloud/vault/config/aws/AwsSecretIntegrationTests.java @@ -15,34 +15,32 @@ */ package org.springframework.cloud.vault.config.aws; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.springframework.cloud.vault.AbstractIntegrationTests; -import org.springframework.cloud.vault.ClientAuthentication; -import org.springframework.cloud.vault.VaultClient; -import org.springframework.cloud.vault.VaultProperties; -import org.springframework.cloud.vault.config.VaultConfigOperations; -import org.springframework.cloud.vault.config.VaultTemplate; -import org.springframework.cloud.vault.util.Settings; -import org.springframework.util.StringUtils; - import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; import static org.springframework.cloud.vault.config.aws.VaultConfigAwsBootstrapConfiguration.AwsSecureBackendAccessorFactory.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + import org.junit.Before; import org.junit.Test; +import org.springframework.cloud.vault.config.VaultConfigOperations; +import org.springframework.cloud.vault.config.VaultConfigTemplate; +import org.springframework.cloud.vault.config.VaultProperties; +import org.springframework.cloud.vault.util.IntegrationTestSupport; +import org.springframework.cloud.vault.util.Settings; +import org.springframework.util.StringUtils; +import org.springframework.vault.core.VaultOperations; /** - * Integration tests for {@link VaultClient} using the aws secret backend. This test - * requires AWS credentials and a region, see {@link #AWS_ACCESS_KEY} and + * Integration tests for {@link VaultConfigTemplate} using the aws secret backend. This + * test requires AWS credentials and a region, see {@link #AWS_ACCESS_KEY} and * {@link #AWS_SECRET_KEY} to be provided externally. * * @author Mark Paluch */ -public class AwsSecretIntegrationTests extends AbstractIntegrationTests { +public class AwsSecretIntegrationTests extends IntegrationTestSupport { private final static String AWS_REGION = "eu-west-1"; private final static String AWS_ACCESS_KEY = System.getProperty("aws.access.key"); @@ -68,22 +66,25 @@ public class AwsSecretIntegrationTests extends AbstractIntegrationTests { aws.setEnabled(true); aws.setRole("readonly"); - if (!prepare().hasSecret(aws.getBackend())) { + if (!prepare().hasSecretBackend(aws.getBackend())) { prepare().mountSecret(aws.getBackend()); } + VaultOperations vaultOperations = prepare().getVaultOperations(); + Map connection = new HashMap<>(); connection.put("region", AWS_REGION); connection.put("access_key", AWS_ACCESS_KEY); connection.put("secret_key", AWS_SECRET_KEY); - prepare().write(String.format("%s/config/root", aws.getBackend()), connection); + vaultOperations.write(String.format("%s/config/root", aws.getBackend()), + connection); - prepare().write(String.format("%s/roles/%s", aws.getBackend(), aws.getRole()), + vaultOperations.write( + String.format("%s/roles/%s", aws.getBackend(), aws.getRole()), Collections.singletonMap("arn", ARN)); - configOperations = new VaultTemplate(vaultProperties, prepare().newVaultClient(), - ClientAuthentication.token(vaultProperties)).opsForConfig(); + configOperations = new VaultConfigTemplate(vaultOperations, vaultProperties); } @Test diff --git a/spring-cloud-vault-config-aws/src/test/java/org/springframework/cloud/vault/config/aws/VaultConfigAwsTests.java b/spring-cloud-vault-config-aws/src/test/java/org/springframework/cloud/vault/config/aws/VaultConfigAwsTests.java index b1e425c4..8f936d92 100644 --- a/spring-cloud-vault-config-aws/src/test/java/org/springframework/cloud/vault/config/aws/VaultConfigAwsTests.java +++ b/spring-cloud-vault-config-aws/src/test/java/org/springframework/cloud/vault/config/aws/VaultConfigAwsTests.java @@ -33,6 +33,7 @@ import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.cloud.vault.util.VaultRule; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.StringUtils; +import org.springframework.vault.core.VaultOperations; /** * Integration tests using the aws secret backend. In case this test should fail because @@ -73,18 +74,20 @@ public class VaultConfigAwsTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); - if (!vaultRule.prepare().hasSecret("aws")) { + if (!vaultRule.prepare().hasSecretBackend("aws")) { vaultRule.prepare().mountSecret("aws"); } + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + Map connection = new HashMap<>(); connection.put("region", AWS_REGION); connection.put("access_key", AWS_ACCESS_KEY); connection.put("secret_key", AWS_SECRET_KEY); - vaultRule.prepare().write("aws/config/root", connection); + vaultOperations.write("aws/config/root", connection); - vaultRule.prepare().write("aws/roles/readonly", + vaultOperations.write("aws/roles/readonly", Collections.singletonMap("arn", ARN)); } diff --git a/spring-cloud-vault-config-consul/pom.xml b/spring-cloud-vault-config-consul/pom.xml index 76800ef1..6841a3c4 100644 --- a/spring-cloud-vault-config-consul/pom.xml +++ b/spring-cloud-vault-config-consul/pom.xml @@ -18,18 +18,13 @@ org.springframework.cloud - spring-cloud-vault-core - - - - org.springframework.cloud - spring-cloud-vault-core - test-jar + spring-cloud-vault-config org.springframework.cloud spring-cloud-vault-config + test-jar 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 index c6b44b5d..8cc0a345 100644 --- 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 @@ -20,8 +20,8 @@ import java.util.Map; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.vault.config.SecureBackendAccessor; -import org.springframework.cloud.vault.VaultSecretBackend; import org.springframework.cloud.vault.config.SecureBackendAccessorFactory; +import org.springframework.cloud.vault.config.VaultSecretBackend; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.Assert; 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 index faa3ef46..fe5fdc2d 100644 --- 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 @@ -17,7 +17,7 @@ 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 org.springframework.cloud.vault.config.VaultSecretBackend; import lombok.Data; diff --git a/spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/ConsulSecretIntegrationTests.java b/spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/ConsulSecretIntegrationTests.java index d7c7d19f..b9bf2894 100644 --- a/spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/ConsulSecretIntegrationTests.java +++ b/spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/ConsulSecretIntegrationTests.java @@ -15,19 +15,23 @@ */ 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.config.consul.VaultConfigConsulBootstrapConfiguration.ConsulSecureBackendAccessorFactory.*; + import java.net.InetSocketAddress; import java.util.Collections; import java.util.HashMap; import java.util.Map; +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.ClientAuthentication; -import org.springframework.cloud.vault.VaultClient; -import org.springframework.cloud.vault.VaultProperties; import org.springframework.cloud.vault.config.VaultConfigOperations; -import org.springframework.cloud.vault.config.VaultTemplate; +import org.springframework.cloud.vault.config.VaultConfigTemplate; +import org.springframework.cloud.vault.config.VaultProperties; import org.springframework.cloud.vault.util.CanConnect; +import org.springframework.cloud.vault.util.IntegrationTestSupport; import org.springframework.cloud.vault.util.Settings; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpEntity; @@ -35,21 +39,15 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.util.Base64Utils; - -import static org.assertj.core.api.Assertions.*; -import static org.junit.Assume.*; -import static org.springframework.cloud.vault.config.consul.VaultConfigConsulBootstrapConfiguration.ConsulSecureBackendAccessorFactory.*; - -import org.junit.Before; -import org.junit.Test; +import org.springframework.vault.core.VaultOperations; /** - * Integration tests for {@link VaultClient} using the consul secret backend. This test - * requires a running Consul instance, see {@link #CONNECTION_URL}. + * Integration tests for {@link VaultConfigTemplate} using the consul secret backend. This + * test requires a running Consul instance, see {@link #CONNECTION_URL}. * * @author Mark Paluch */ -public class ConsulSecretIntegrationTests extends AbstractIntegrationTests { +public class ConsulSecretIntegrationTests extends IntegrationTestSupport { private final static String CONSUL_HOST = "localhost"; private final static int CONSUL_PORT = 8500; @@ -82,10 +80,12 @@ public class ConsulSecretIntegrationTests extends AbstractIntegrationTests { consul.setEnabled(true); consul.setRole("readonly"); - if (!prepare().hasSecret(consul.getBackend())) { + if (!prepare().hasSecretBackend(consul.getBackend())) { prepare().mountSecret(consul.getBackend()); } + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + HttpHeaders headers = new HttpHeaders(); headers.add("X-Consul-Token", CONSUL_ACL_MASTER_TOKEN); HttpEntity requestEntity = new HttpEntity<>( @@ -98,16 +98,15 @@ public class ConsulSecretIntegrationTests extends AbstractIntegrationTests { consulAccess.put("address", CONNECTION_URL); consulAccess.put("token", tokenResponse.getBody().get("ID")); - prepare().write(String.format("%s/config/access", consul.getBackend()), + vaultOperations.write(String.format("%s/config/access", consul.getBackend()), consulAccess); - prepare().write( + vaultOperations.write( String.format("%s/roles/%s", consul.getBackend(), consul.getRole()), Collections.singletonMap("policy", Base64Utils.encodeToString(POLICY.getBytes()))); - configOperations = new VaultTemplate(vaultProperties, prepare().newVaultClient(), - ClientAuthentication.token(vaultProperties)).opsForConfig(); + configOperations = new VaultConfigTemplate(vaultOperations, vaultProperties); } @Test diff --git a/spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/VaultConfigConsulTests.java b/spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/VaultConfigConsulTests.java index d871478b..6ed308bc 100644 --- a/spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/VaultConfigConsulTests.java +++ b/spring-cloud-vault-config-consul/src/test/java/org/springframework/cloud/vault/config/consul/VaultConfigConsulTests.java @@ -44,6 +44,8 @@ import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.security.crypto.codec.Base64; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.vault.core.VaultOperations; +import org.springframework.web.client.RestTemplate; /** * Integration tests using the consul secret backend. In case this test should fail @@ -72,7 +74,7 @@ public class VaultConfigConsulTests { }; /** - * Initialize the rabbitmq secret backend. + * Initialize the consul secret backend. * * @throws Exception */ @@ -84,27 +86,28 @@ public class VaultConfigConsulTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); - if (!vaultRule.prepare().hasSecret("consul")) { + if (!vaultRule.prepare().hasSecretBackend("consul")) { vaultRule.prepare().mountSecret("consul"); } - TestRestTemplate restTemplate = new TestRestTemplate(); + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.add("X-Consul-Token", CONSUL_ACL_MASTER_TOKEN); 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); consulAccess.put("token", tokenResponse.getBody().get("ID")); - vaultRule.prepare().write("consul/config/access", consulAccess); + vaultOperations.write("consul/config/access", consulAccess); - vaultRule.prepare().write("consul/roles/readonly", Collections + vaultOperations.write("consul/roles/readonly", Collections .singletonMap("policy", Base64.encode(POLICY.getBytes()))); } diff --git a/spring-cloud-vault-config-databases/pom.xml b/spring-cloud-vault-config-databases/pom.xml index 003fd29c..83820ae1 100644 --- a/spring-cloud-vault-config-databases/pom.xml +++ b/spring-cloud-vault-config-databases/pom.xml @@ -18,18 +18,13 @@ org.springframework.cloud - spring-cloud-vault-core - - - - org.springframework.cloud - spring-cloud-vault-core - test-jar + spring-cloud-vault-config org.springframework.cloud spring-cloud-vault-config + test-jar 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 index 8e494e35..d9fc5cb4 100644 --- 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 @@ -15,7 +15,7 @@ */ package org.springframework.cloud.vault.config.databases; -import org.springframework.cloud.vault.VaultSecretBackend; +import org.springframework.cloud.vault.config.VaultSecretBackend; /** * Configuration properties interface for database secrets. 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 index c269b10c..ad4dcdfd 100644 --- 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 @@ -20,8 +20,8 @@ import java.util.Map; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.vault.config.SecureBackendAccessor; -import org.springframework.cloud.vault.VaultSecretBackend; import org.springframework.cloud.vault.config.SecureBackendAccessorFactory; +import org.springframework.cloud.vault.config.VaultSecretBackend; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.Assert; 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 index a572902b..a579dc0c 100644 --- 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 @@ -2,9 +2,9 @@ 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; +import org.springframework.cloud.vault.config.VaultSecretBackend; /** * Configuration properties for Vault using the MySQL integration. diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CassandraSecretIntegrationTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CassandraSecretIntegrationTests.java index b0d410e0..e060fac8 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CassandraSecretIntegrationTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CassandraSecretIntegrationTests.java @@ -15,35 +15,33 @@ */ 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.config.databases.VaultConfigDatabaseBootstrapConfiguration.DatabaseSecureBackendAccessorFactory.*; + import java.net.InetSocketAddress; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import org.springframework.cloud.vault.AbstractIntegrationTests; -import org.springframework.cloud.vault.ClientAuthentication; -import org.springframework.cloud.vault.VaultClient; -import org.springframework.cloud.vault.VaultProperties; -import org.springframework.cloud.vault.config.VaultConfigOperations; -import org.springframework.cloud.vault.config.VaultTemplate; -import org.springframework.cloud.vault.util.CanConnect; -import org.springframework.cloud.vault.util.Settings; - -import static org.assertj.core.api.Assertions.*; -import static org.junit.Assume.*; -import static org.springframework.cloud.vault.config.databases.VaultConfigDatabaseBootstrapConfiguration.DatabaseSecureBackendAccessorFactory.*; - import org.junit.Before; import org.junit.Test; +import org.springframework.cloud.vault.config.VaultConfigOperations; +import org.springframework.cloud.vault.config.VaultConfigTemplate; +import org.springframework.cloud.vault.config.VaultProperties; +import org.springframework.cloud.vault.util.CanConnect; +import org.springframework.cloud.vault.util.IntegrationTestSupport; +import org.springframework.cloud.vault.util.Settings; +import org.springframework.vault.core.VaultOperations; /** - * Integration tests for {@link VaultClient} using the cassandra secret backend. This test - * requires a running Cassandra instance, see {@link #CASSANDRA_HOST} and other + * Integration tests for {@link VaultConfigTemplate} using the cassandra secret backend. + * This test requires a running Cassandra instance, see {@link #CASSANDRA_HOST} and other * {@code CASSANDRA_*} properties. * * @author Mark Paluch */ -public class CassandraSecretIntegrationTests extends AbstractIntegrationTests { +public class CassandraSecretIntegrationTests extends IntegrationTestSupport { private final static String CASSANDRA_HOST = "localhost"; private final static int CASSANDRA_PORT = 9042; @@ -71,26 +69,26 @@ public class CassandraSecretIntegrationTests extends AbstractIntegrationTests { cassandra.setEnabled(true); cassandra.setRole("readonly"); - if (!prepare().hasSecret(cassandra.getBackend())) { + if (!prepare().hasSecretBackend(cassandra.getBackend())) { prepare().mountSecret(cassandra.getBackend()); } + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + Map connection = new HashMap<>(); connection.put("hosts", CASSANDRA_HOST); connection.put("username", CASSANDRA_USERNAME); connection.put("password", CASSANDRA_PASSWORD); - prepare().write(String.format("%s/config/connection", cassandra.getBackend()), + vaultOperations.write( + String.format("%s/config/connection", cassandra.getBackend()), connection); - prepare() - .write(String.format("%s/roles/%s", cassandra.getBackend(), - cassandra.getRole()), - Collections.singletonMap("creation_cql", - CREATE_USER_AND_GRANT_CQL)); + vaultOperations.write( + String.format("%s/roles/%s", cassandra.getBackend(), cassandra.getRole()), + Collections.singletonMap("creation_cql", CREATE_USER_AND_GRANT_CQL)); - configOperations = new VaultTemplate(vaultProperties, prepare().newVaultClient(), - ClientAuthentication.token(vaultProperties)).opsForConfig(); + configOperations = new VaultConfigTemplate(vaultOperations, vaultProperties); } @Test diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/MySqlSecretIntegrationTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/MySqlSecretIntegrationTests.java index 67abefef..3e82fc3e 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/MySqlSecretIntegrationTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/MySqlSecretIntegrationTests.java @@ -15,38 +15,36 @@ */ package org.springframework.cloud.vault.config.databases; -import java.net.InetSocketAddress; -import java.util.Collections; -import java.util.Map; - -import org.springframework.cloud.vault.AbstractIntegrationTests; -import org.springframework.cloud.vault.ClientAuthentication; -import org.springframework.cloud.vault.VaultClient; -import org.springframework.cloud.vault.VaultProperties; -import org.springframework.cloud.vault.config.VaultConfigOperations; -import org.springframework.cloud.vault.config.VaultTemplate; -import org.springframework.cloud.vault.util.CanConnect; -import org.springframework.cloud.vault.util.Settings; - import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; import static org.springframework.cloud.vault.config.databases.VaultConfigDatabaseBootstrapConfiguration.DatabaseSecureBackendAccessorFactory.*; +import java.net.InetSocketAddress; +import java.util.Collections; +import java.util.Map; + import org.junit.Before; import org.junit.Test; +import org.springframework.cloud.vault.config.VaultConfigOperations; +import org.springframework.cloud.vault.config.VaultConfigTemplate; +import org.springframework.cloud.vault.config.VaultProperties; +import org.springframework.cloud.vault.util.CanConnect; +import org.springframework.cloud.vault.util.IntegrationTestSupport; +import org.springframework.cloud.vault.util.Settings; +import org.springframework.vault.core.VaultOperations; /** - * Integration tests for {@link VaultClient} using the mysql secret backend. This test - * requires a running MySQL instance, see {@link #ROOT_CREDENTIALS}. + * Integration tests for {@link VaultConfigTemplate} using the mysql secret backend. This + * test requires a running MySQL instance, see {@link #ROOT_CREDENTIALS}. * * @author Mark Paluch */ -public class MySqlSecretIntegrationTests extends AbstractIntegrationTests { +public class MySqlSecretIntegrationTests extends IntegrationTestSupport { private final static int MYSQL_PORT = 3306; private final static String MYSQL_HOST = "localhost"; - private final static String ROOT_CREDENTIALS = String.format( - "spring:vault@tcp(%s:%d)/", MYSQL_HOST, MYSQL_PORT); + private final static String ROOT_CREDENTIALS = String + .format("spring:vault@tcp(%s:%d)/", MYSQL_HOST, MYSQL_PORT); private final static String CREATE_USER_AND_GRANT_SQL = "CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';" + "GRANT SELECT ON *.* TO '{{name}}'@'%';"; @@ -67,19 +65,20 @@ public class MySqlSecretIntegrationTests extends AbstractIntegrationTests { mySql.setEnabled(true); mySql.setRole("readonly"); - if (!prepare().hasSecret(mySql.getBackend())) { + if (!prepare().hasSecretBackend(mySql.getBackend())) { prepare().mountSecret(mySql.getBackend()); } - prepare().write(String.format("%s/config/connection", mySql.getBackend()), + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + + vaultOperations.write(String.format("%s/config/connection", mySql.getBackend()), Collections.singletonMap("connection_url", ROOT_CREDENTIALS)); - prepare().write( + vaultOperations.write( String.format("%s/roles/%s", mySql.getBackend(), mySql.getRole()), Collections.singletonMap("sql", CREATE_USER_AND_GRANT_SQL)); - configOperations = new VaultTemplate(vaultProperties, prepare().newVaultClient(), - ClientAuthentication.token(vaultProperties)).opsForConfig(); + configOperations = new VaultConfigTemplate(vaultOperations, vaultProperties); } @Test diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/PostgreSqlSecretIntegrationTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/PostgreSqlSecretIntegrationTests.java index c9745663..d60ce6b9 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/PostgreSqlSecretIntegrationTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/PostgreSqlSecretIntegrationTests.java @@ -15,33 +15,33 @@ */ package org.springframework.cloud.vault.config.databases; -import java.net.InetSocketAddress; -import java.util.Collections; -import java.util.Map; - -import org.springframework.cloud.vault.AbstractIntegrationTests; -import org.springframework.cloud.vault.ClientAuthentication; -import org.springframework.cloud.vault.VaultClient; -import org.springframework.cloud.vault.VaultProperties; -import org.springframework.cloud.vault.config.VaultConfigOperations; -import org.springframework.cloud.vault.config.VaultTemplate; -import org.springframework.cloud.vault.util.CanConnect; -import org.springframework.cloud.vault.util.Settings; - import static org.assertj.core.api.Assertions.*; import static org.junit.Assume.*; import static org.springframework.cloud.vault.config.databases.VaultConfigDatabaseBootstrapConfiguration.DatabaseSecureBackendAccessorFactory.*; +import java.net.InetSocketAddress; +import java.util.Collections; +import java.util.Map; + import org.junit.Before; import org.junit.Test; +import org.springframework.cloud.vault.config.VaultConfigOperations; +import org.springframework.cloud.vault.config.VaultConfigTemplate; +import org.springframework.cloud.vault.config.VaultProperties; +import org.springframework.cloud.vault.util.CanConnect; +import org.springframework.cloud.vault.util.IntegrationTestSupport; +import org.springframework.cloud.vault.util.Settings; +import org.springframework.vault.core.VaultOperations; /** - * Integration tests for {@link VaultClient} using the postgresql secret backend. This - * test requires a running PostgreSQL instance, see {@link #CONNECTION_URL}. + * Integration tests for + * {@link org.springframework.cloud.vault.config.VaultConfigTemplate} using the postgresql + * secret backend. This test requires a running PostgreSQL instance, see + * {@link #CONNECTION_URL}. * * @author Mark Paluch */ -public class PostgreSqlSecretIntegrationTests extends AbstractIntegrationTests { +public class PostgreSqlSecretIntegrationTests extends IntegrationTestSupport { private final static String POSTGRES_HOST = "localhost"; private final static int POSTGRES_PORT = 5432; @@ -71,20 +71,23 @@ public class PostgreSqlSecretIntegrationTests extends AbstractIntegrationTests { postgreSql.setEnabled(true); postgreSql.setRole("readonly"); - if (!prepare().hasSecret(postgreSql.getBackend())) { + if (!prepare().hasSecretBackend(postgreSql.getBackend())) { prepare().mountSecret(postgreSql.getBackend()); } - prepare().write(String.format("%s/config/connection", postgreSql.getBackend()), + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + + vaultOperations.write( + String.format("%s/config/connection", postgreSql.getBackend()), Collections.singletonMap("connection_url", CONNECTION_URL)); - prepare().write( + vaultOperations.write( String.format("%s/roles/%s", postgreSql.getBackend(), postgreSql.getRole()), Collections.singletonMap("sql", CREATE_USER_AND_GRANT_SQL)); - configOperations = new VaultTemplate(vaultProperties, prepare().newVaultClient(), - ClientAuthentication.token(vaultProperties)).opsForConfig(); + configOperations = new VaultConfigTemplate(vaultOperations, vaultProperties); + } @Test diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCassandraTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCassandraTests.java index f0b3e83a..b08674af 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCassandraTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCassandraTests.java @@ -40,6 +40,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.datastax.driver.core.Cluster; import com.datastax.driver.core.PlainTextAuthProvider; import com.datastax.driver.core.Session; +import org.springframework.vault.core.VaultOperations; /** * Integration tests using the cassandra secret backend. In case this test should fail because of SSL make sure you run @@ -76,19 +77,21 @@ public class VaultConfigCassandraTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); - if (!vaultRule.prepare().hasSecret("cassandra")) { + if (!vaultRule.prepare().hasSecretBackend("cassandra")) { vaultRule.prepare().mountSecret("cassandra"); } + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + Map connection = new HashMap<>(); connection.put("hosts", CASSANDRA_HOST); connection.put("username", CASSANDRA_USERNAME); connection.put("password", CASSANDRA_PASSWORD); - vaultRule.prepare().write(String.format("%s/config/connection", "cassandra"), + vaultOperations.write(String.format("%s/config/connection", "cassandra"), connection); - vaultRule.prepare().write("cassandra/roles/readonly", + vaultOperations.write("cassandra/roles/readonly", Collections.singletonMap("creation_cql", CREATE_USER_AND_GRANT_CQL)); } diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigMySqlTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigMySqlTests.java index dd8303b2..4778adb4 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigMySqlTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigMySqlTests.java @@ -36,6 +36,7 @@ import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.cloud.vault.util.CanConnect; import org.springframework.cloud.vault.util.VaultRule; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.vault.core.VaultOperations; /** * Integration tests using the mysql secret backend. In case this test should fail because of SSL make sure you run the @@ -71,14 +72,16 @@ public class VaultConfigMySqlTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); - if (!vaultRule.prepare().hasSecret("mysql")) { + if (!vaultRule.prepare().hasSecretBackend("mysql")) { vaultRule.prepare().mountSecret("mysql"); } - vaultRule.prepare().write("mysql/config/connection", + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + + vaultOperations.write("mysql/config/connection", Collections.singletonMap("connection_url", ROOT_CREDENTIALS)); - vaultRule.prepare().write("mysql/roles/readonly", + vaultOperations.write("mysql/roles/readonly", Collections.singletonMap("sql", CREATE_USER_AND_GRANT_SQL)); } diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigPostgreSqlTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigPostgreSqlTests.java index efc86cb0..c102b302 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigPostgreSqlTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigPostgreSqlTests.java @@ -39,18 +39,21 @@ import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.cloud.vault.util.CanConnect; import org.springframework.cloud.vault.util.VaultRule; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.vault.core.VaultOperations; /** - * Integration tests using the postgresql secret backend. In case this test should fail because of SSL make sure you run - * the test within the spring-cloud-vault-config/spring-cloud-vault-config directory as the keystore is referenced with - * {@code ../work/keystore.jks}. + * Integration tests using the postgresql secret backend. In case this test should fail + * because of SSL make sure you run the test within the + * spring-cloud-vault-config/spring-cloud-vault-config directory as the keystore is + * referenced with {@code ../work/keystore.jks}. * * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.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" }) + "spring.cloud.vault.postgresql.role=readonly", + "spring.datasource.url=jdbc:postgresql://localhost:5432/postgres?ssl=false" }) public class VaultConfigPostgreSqlTests { private final static String POSTGRES_HOST = "localhost"; @@ -77,14 +80,16 @@ public class VaultConfigPostgreSqlTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); - if (!vaultRule.prepare().hasSecret("postgresql")) { + if (!vaultRule.prepare().hasSecretBackend("postgresql")) { vaultRule.prepare().mountSecret("postgresql"); } - vaultRule.prepare().write("postgresql/config/connection", + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + + vaultOperations.write("postgresql/config/connection", Collections.singletonMap("connection_url", CONNECTION_URL)); - vaultRule.prepare().write("postgresql/roles/readonly", + vaultOperations.write("postgresql/roles/readonly", Collections.singletonMap("sql", CREATE_USER_AND_GRANT_SQL)); } diff --git a/spring-cloud-vault-config-rabbitmq/pom.xml b/spring-cloud-vault-config-rabbitmq/pom.xml index 9b6b8e34..94fa0d11 100644 --- a/spring-cloud-vault-config-rabbitmq/pom.xml +++ b/spring-cloud-vault-config-rabbitmq/pom.xml @@ -20,18 +20,13 @@ org.springframework.cloud - spring-cloud-vault-core - - - - org.springframework.cloud - spring-cloud-vault-core - test-jar + spring-cloud-vault-config org.springframework.cloud spring-cloud-vault-config + test-jar 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 index 3d064e5a..d0015d1c 100644 --- 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 @@ -20,8 +20,8 @@ import java.util.Map; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.vault.config.SecureBackendAccessor; -import org.springframework.cloud.vault.VaultSecretBackend; import org.springframework.cloud.vault.config.SecureBackendAccessorFactory; +import org.springframework.cloud.vault.config.VaultSecretBackend; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.Assert; 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 index fc75a880..98788560 100644 --- 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 @@ -17,7 +17,7 @@ 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 org.springframework.cloud.vault.config.VaultSecretBackend; import lombok.Data; diff --git a/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/RabbitMqSecretIntegrationTests.java b/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/RabbitMqSecretIntegrationTests.java index 83e6edda..ebe69da6 100644 --- a/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/RabbitMqSecretIntegrationTests.java +++ b/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/RabbitMqSecretIntegrationTests.java @@ -15,34 +15,31 @@ */ 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.config.rabbitmq.VaultConfigRabbitMqBootstrapConfiguration.RabbitMqSecureBackendAccessorFactory.*; + import java.net.InetSocketAddress; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import org.springframework.cloud.vault.AbstractIntegrationTests; -import org.springframework.cloud.vault.ClientAuthentication; -import org.springframework.cloud.vault.VaultClient; -import org.springframework.cloud.vault.VaultProperties; -import org.springframework.cloud.vault.config.VaultConfigOperations; -import org.springframework.cloud.vault.config.VaultTemplate; -import org.springframework.cloud.vault.util.CanConnect; -import org.springframework.cloud.vault.util.Settings; - -import static org.assertj.core.api.Assertions.*; -import static org.junit.Assume.*; -import static org.springframework.cloud.vault.config.rabbitmq.VaultConfigRabbitMqBootstrapConfiguration.RabbitMqSecureBackendAccessorFactory.*; - import org.junit.Before; import org.junit.Test; +import org.springframework.cloud.vault.config.VaultConfigTemplate; +import org.springframework.cloud.vault.config.VaultProperties; +import org.springframework.cloud.vault.util.CanConnect; +import org.springframework.cloud.vault.util.IntegrationTestSupport; +import org.springframework.cloud.vault.util.Settings; +import org.springframework.vault.core.VaultOperations; /** - * Integration tests for {@link VaultClient} using the rabbitmq secret backend. This test - * requires a running RabbitMQ instance, see {@link #RABBITMQ_URI}. + * Integration tests for {@link VaultConfigTemplate} using the rabbitmq secret backend. + * This test requires a running RabbitMQ instance, see {@link #RABBITMQ_URI}. * * @author Mark Paluch */ -public class RabbitMqSecretIntegrationTests extends AbstractIntegrationTests { +public class RabbitMqSecretIntegrationTests extends IntegrationTestSupport { private final static int RABBITMQ_HTTP_MANAGEMENT_PORT = 15672; private final static String RABBITMQ_HOST = "localhost"; @@ -56,7 +53,7 @@ public class RabbitMqSecretIntegrationTests extends AbstractIntegrationTests { private final static String VHOSTS_ROLE = "{\"/\":{\"write\": \".*\", \"read\": \".*\"}}"; private VaultProperties vaultProperties = Settings.createVaultProperties(); - private VaultConfigOperations configOperations; + private VaultConfigTemplate configOperations; private VaultRabbitMqProperties rabbitmq = new VaultRabbitMqProperties(); /** @@ -67,13 +64,13 @@ 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"); - if (!prepare().hasSecret(rabbitmq.getBackend())) { + if (!prepare().hasSecretBackend(rabbitmq.getBackend())) { prepare().mountSecret(rabbitmq.getBackend()); } @@ -82,15 +79,16 @@ public class RabbitMqSecretIntegrationTests extends AbstractIntegrationTests { connection.put("username", RABBITMQ_USERNAME); connection.put("password", RABBITMQ_PASSWORD); - prepare().write(String.format("%s/config/connection", rabbitmq.getBackend()), - connection); + VaultOperations vaultOperations = prepare().getVaultOperations(); - prepare().write( + vaultOperations.write( + String.format("%s/config/connection", rabbitmq.getBackend()), connection); + + vaultOperations.write( String.format("%s/roles/%s", rabbitmq.getBackend(), rabbitmq.getRole()), Collections.singletonMap("vhosts", VHOSTS_ROLE)); - configOperations = new VaultTemplate(vaultProperties, prepare().newVaultClient(), - ClientAuthentication.token(vaultProperties)).opsForConfig(); + configOperations = new VaultConfigTemplate(vaultOperations, vaultProperties); } @Test diff --git a/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqTests.java b/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqTests.java index 00366d6e..aae78d9a 100644 --- a/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqTests.java +++ b/spring-cloud-vault-config-rabbitmq/src/test/java/org/springframework/cloud/vault/config/rabbitmq/VaultConfigRabbitMqTests.java @@ -39,6 +39,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; +import org.springframework.vault.core.VaultOperations; /** * Integration tests using the rabbitmq secret backend. In case this test should fail @@ -81,19 +82,21 @@ public class VaultConfigRabbitMqTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); - if (!vaultRule.prepare().hasSecret("rabbitmq")) { + if (!vaultRule.prepare().hasSecretBackend("rabbitmq")) { vaultRule.prepare().mountSecret("rabbitmq"); } + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + Map connection = new HashMap<>(); connection.put("connection_uri", RABBITMQ_URI); connection.put("username", RABBITMQ_USERNAME); connection.put("password", RABBITMQ_PASSWORD); - vaultRule.prepare().write(String.format("rabbitmq/config/connection"), + vaultOperations.write(String.format("rabbitmq/config/connection"), connection); - vaultRule.prepare().write(String.format("rabbitmq/roles/readonly"), + vaultOperations.write(String.format("rabbitmq/roles/readonly"), Collections.singletonMap("vhosts", VHOSTS_ROLE)); } diff --git a/spring-cloud-vault-config/pom.xml b/spring-cloud-vault-config/pom.xml index 752cf3a8..6ab97f31 100644 --- a/spring-cloud-vault-config/pom.xml +++ b/spring-cloud-vault-config/pom.xml @@ -17,8 +17,8 @@ - org.springframework.cloud - spring-cloud-vault-core + org.springframework.vault + spring-vault-core @@ -29,15 +29,59 @@ org.springframework.cloud - spring-cloud-vault-core - test-jar + spring-cloud-context + + + + org.springframework + spring-web + + + + org.slf4j + slf4j-api + + + + org.apache.httpcomponents + httpclient + true + + + + org.apache.httpcomponents + httpcore + true + + + + io.netty + netty-all + true com.squareup.okhttp okhttp - test + true + + + + + maven-jar-plugin + + + test-jar + + test-jar + + + + + + + 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 index c90818d7..cac68d6e 100644 --- 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 @@ -15,8 +15,6 @@ */ package org.springframework.cloud.vault.config; -import org.springframework.cloud.vault.VaultSecretBackend; - /** * Factory to convert {@link VaultSecretBackend} instance to a * {@link SecureBackendAccessor}. 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 index 24a98c6a..82b7e0f6 100644 --- 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 @@ -19,13 +19,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import lombok.extern.apachecommons.CommonsLog; -import org.springframework.cloud.vault.VaultSecretBackend; +import lombok.extern.slf4j.Slf4j; /** * @author Mark Paluch */ -@CommonsLog +@Slf4j public class SecureBackendFactories { public static Collection createBackendAcessors( diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultBootstrapConfiguration.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultBootstrapConfiguration.java new file mode 100644 index 00000000..8e110cd2 --- /dev/null +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultBootstrapConfiguration.java @@ -0,0 +1,281 @@ +/* + * 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.net.URI; +import java.util.Collection; + +import org.springframework.beans.BeanUtils; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; +import org.springframework.vault.authentication.AppIdAuthentication; +import org.springframework.vault.authentication.AppIdAuthenticationOptions; +import org.springframework.vault.authentication.AppIdUserIdMechanism; +import org.springframework.vault.authentication.AwsEc2Authentication; +import org.springframework.vault.authentication.AwsEc2AuthenticationOptions; +import org.springframework.vault.authentication.ClientAuthentication; +import org.springframework.vault.authentication.ClientCertificateAuthentication; +import org.springframework.vault.authentication.DefaultSessionManager; +import org.springframework.vault.authentication.IpAddressUserId; +import org.springframework.vault.authentication.MacAddressUserId; +import org.springframework.vault.authentication.SessionManager; +import org.springframework.vault.authentication.StaticUserId; +import org.springframework.vault.authentication.TokenAuthentication; +import org.springframework.vault.client.VaultClient; +import org.springframework.vault.client.VaultEndpoint; +import org.springframework.vault.config.AbstractVaultConfiguration.ClientFactoryWrapper; +import org.springframework.vault.config.ClientHttpRequestFactoryFactory; +import org.springframework.vault.core.DefaultVaultClientFactory; +import org.springframework.vault.core.VaultClientFactory; +import org.springframework.vault.core.VaultOperations; +import org.springframework.vault.core.VaultTemplate; +import org.springframework.vault.support.ClientOptions; +import org.springframework.vault.support.SslConfiguration; +import org.springframework.web.client.RestTemplate; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Vault support. + * + * @author Spencer Gibb + * @author Mark Paluch + */ +@Configuration +@ConditionalOnProperty(name = "spring.cloud.vault.enabled", matchIfMissing = true) +@EnableConfigurationProperties({ VaultProperties.class, + VaultGenericBackendProperties.class }) +public class VaultBootstrapConfiguration { + + private final ApplicationContext applicationContext; + private final VaultProperties vaultProperties; + private final Collection vaultSecretBackends; + private final Collection> factories; + + public VaultBootstrapConfiguration(ApplicationContext applicationContext, VaultProperties vaultProperties) { + + this.applicationContext = applicationContext; + this.vaultProperties = vaultProperties; + + this.vaultSecretBackends = applicationContext + .getBeansOfType(VaultSecretBackend.class).values(); + this.factories = (Collection) applicationContext + .getBeansOfType(SecureBackendAccessorFactory.class).values(); + } + + @Bean + public VaultPropertySourceLocator vaultPropertySourceLocator( + VaultOperations operations, VaultProperties vaultProperties, + VaultGenericBackendProperties vaultGenericBackendProperties) { + + Collection backendAccessors = SecureBackendFactories + .createBackendAcessors(vaultSecretBackends, factories); + VaultConfigTemplate vaultConfigTemplate = new VaultConfigTemplate(operations, + vaultProperties); + + return new VaultPropertySourceLocator(vaultConfigTemplate, vaultProperties, + vaultGenericBackendProperties, backendAccessors); + } + + + @Bean + @ConditionalOnMissingBean + public ClientAuthentication clientAuthentication() { + + VaultClient vaultClient = vaultClient(); + + switch (vaultProperties.getAuthentication()) { + + case TOKEN: + Assert.hasText("Token (spring.cloud.vault.token) must not be empty", + vaultProperties.getToken()); + return new TokenAuthentication(vaultProperties.getToken()); + + case APPID: + return appIdAuthentication(vaultProperties, vaultClient); + + case CERT: + return new ClientCertificateAuthentication(vaultClient); + + case AWS_EC2: + return awsEc2Authentication(vaultProperties, vaultClient); + + } + + throw new UnsupportedOperationException( + String.format("Client authentication %s not supported", + vaultProperties.getAuthentication())); + } + + private ClientAuthentication appIdAuthentication(VaultProperties vaultProperties, + VaultClient vaultClient) { + + VaultProperties.AppIdProperties appId = vaultProperties.getAppId(); + Assert.hasText(appId.getUserId(), + "UserId (spring.cloud.vault.app-id.user-id) must not be empty"); + + AppIdAuthenticationOptions authenticationOptions = AppIdAuthenticationOptions + .builder().appId(vaultProperties.getApplicationName()) // + .path(appId.getAppIdPath()) // + .userIdMechanism(getClientAuthentication(appId)).build(); + + return new AppIdAuthentication(authenticationOptions, vaultClient); + } + + private AppIdUserIdMechanism getClientAuthentication( + VaultProperties.AppIdProperties appId) { + + try { + Class userIdClass = ClassUtils.forName(appId.getUserId(), null); + return (AppIdUserIdMechanism) BeanUtils.instantiateClass(userIdClass); + } + catch (ClassNotFoundException ex) { + + switch (appId.getUserId().toUpperCase()) { + case VaultProperties.AppIdProperties.IP_ADDRESS: + return new IpAddressUserId(); + case VaultProperties.AppIdProperties.MAC_ADDRESS: + + if (StringUtils.hasText(appId.getNetworkInterface())) { + try { + return new MacAddressUserId( + Integer.parseInt(appId.getNetworkInterface())); + } + catch (NumberFormatException e) { + return new MacAddressUserId(appId.getNetworkInterface()); + } + } + + return new MacAddressUserId(); + default: + return new StaticUserId(appId.getUserId()); + } + } + } + + private ClientAuthentication awsEc2Authentication(VaultProperties vaultProperties, + VaultClient vaultClient) { + + VaultProperties.AwsEc2Properties awsEc2 = vaultProperties.getAwsEc2(); + + AwsEc2AuthenticationOptions authenticationOptions = AwsEc2AuthenticationOptions + .builder().role(awsEc2.getRole()) // + .path(awsEc2.getAwsEc2Path()) // + .identityDocumentUri(URI.create(awsEc2.getIdentityDocument())) // + .build(); + + return new AwsEc2Authentication(authenticationOptions, vaultClient, + vaultClient.getRestTemplate()); + } + + /** + * Creates a {@link ClientFactoryWrapper} containing a + * {@link ClientHttpRequestFactory}. {@link ClientHttpRequestFactory} is not exposed + * as root bean because {@link ClientHttpRequestFactory} is configured with + * {@link ClientOptions} and {@link SslConfiguration} which are not necessarily + * applicable for the whole application. + * + * @return the {@link ClientFactoryWrapper} to wrap a {@link ClientHttpRequestFactory} + * instance. + */ + @Bean + @ConditionalOnMissingBean + public ClientFactoryWrapper clientHttpRequestFactoryWrapper() { + + ClientOptions clientOptions = new ClientOptions( + vaultProperties.getConnectionTimeout(), vaultProperties.getReadTimeout()); + + VaultProperties.Ssl ssl = vaultProperties.getSsl(); + SslConfiguration sslConfiguration; + if (ssl != null) { + sslConfiguration = new SslConfiguration(ssl.getKeyStore(), + ssl.getKeyStorePassword(), ssl.getTrustStore(), + ssl.getTrustStorePassword()); + } + else { + sslConfiguration = SslConfiguration.NONE; + } + + return new ClientFactoryWrapper( + ClientHttpRequestFactoryFactory.create(clientOptions, sslConfiguration)); + } + + /** + * @return the {@link VaultClient} + * @see #clientHttpRequestFactoryWrapper() + */ + @Bean + @ConditionalOnMissingBean + public VaultClient vaultClient() { + + RestTemplate restTemplate = new RestTemplate( + clientHttpRequestFactoryWrapper().getClientHttpRequestFactory()); + + VaultEndpoint vaultEndpoint = new VaultEndpoint(); + vaultEndpoint.setHost(vaultProperties.getHost()); + vaultEndpoint.setPort(vaultProperties.getPort()); + vaultEndpoint.setScheme(vaultProperties.getScheme()); + + return new VaultClient(restTemplate, vaultEndpoint); + } + + /** + * Creates the {@link VaultClientFactory} to be used with {@link VaultTemplate}. Uses + * by default {@link DefaultVaultClientFactory} with the configured + * {@link #vaultClient()} instance. + * + * @return + */ + @Bean + @ConditionalOnMissingBean + public VaultClientFactory vaultClientFactory() { + return new DefaultVaultClientFactory(vaultClient()); + } + + /** + * Creates a {@link VaultTemplate}. + * + * @return + * @see #vaultClientFactory() + * @see #sessionManager(ClientAuthentication) + */ + @Bean + @ConditionalOnMissingBean + public VaultTemplate vaultTemplate(ClientAuthentication clientAuthentication) { + return new VaultTemplate(vaultClientFactory(), + sessionManager(clientAuthentication)); + } + + /** + * + * @return the {@link SessionManager} for Vault session management. + * @see SessionManager + * @see DefaultSessionManager + */ + @Bean + @ConditionalOnMissingBean + public SessionManager sessionManager(ClientAuthentication clientAuthentication) { + return new DefaultSessionManager(clientAuthentication); + } +} diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigBootstrapHealthIndicator.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultBootstrapHealthIndicatorConfiguration.java similarity index 90% rename from spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigBootstrapHealthIndicator.java rename to spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultBootstrapHealthIndicatorConfiguration.java index 9ddb517f..29006dd8 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigBootstrapHealthIndicator.java +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultBootstrapHealthIndicatorConfiguration.java @@ -25,7 +25,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.vault.VaultBootstrapConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -33,13 +32,12 @@ import org.springframework.context.annotation.Configuration; * @author Stuart Ingram */ @Configuration -@EnableConfigurationProperties @ConditionalOnBean(VaultBootstrapConfiguration.class) @ConditionalOnProperty(name = "spring.cloud.vault.enabled", matchIfMissing = true) @ConditionalOnExpression("${health.vault.enabled:true}") @AutoConfigureBefore({ EndpointAutoConfiguration.class }) -@AutoConfigureAfter({ HealthIndicatorAutoConfiguration.class }) -public class VaultConfigBootstrapHealthIndicator { +@AutoConfigureAfter({ VaultBootstrapConfiguration.class, HealthIndicatorAutoConfiguration.class }) +public class VaultBootstrapHealthIndicatorConfiguration { @Bean @ConditionalOnMissingBean(name = "vaultHealthIndicator") 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 deleted file mode 100644 index 8e0b8bff..00000000 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigBootstrapConfiguration.java +++ /dev/null @@ -1,123 +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.config; - -import java.util.Collection; -import java.util.Map; - -import javax.annotation.PostConstruct; - -import org.springframework.beans.BeansException; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.vault.AppIdUserIdMechanism; -import org.springframework.cloud.vault.ClientAuthentication; -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 VaultGenericBackendProperties vaultGenericBackendProperties() { - return new VaultGenericBackendProperties(); - } - - @Bean - @ConditionalOnMissingBean - public VaultOperations vaultOperations(VaultProperties properties, VaultClient client) { - - ClientAuthentication clientAuthentication = clientAuthentication( - applicationContext, properties, client); - - return new VaultTemplate(properties, client, clientAuthentication); - } - - @Bean - public VaultPropertySourceLocator vaultPropertySourceLocator( - VaultOperations operations, VaultProperties vaultProperties, - VaultGenericBackendProperties vaultGenericBackendProperties) { - - Collection backendAccessors = SecureBackendFactories - .createBackendAcessors(vaultSecretBackends, factories); - - return new VaultPropertySourceLocator(operations.opsForConfig(), vaultProperties, - vaultGenericBackendProperties, backendAccessors); - } - - private ClientAuthentication clientAuthentication( - ApplicationContext applicationContext, VaultProperties vaultProperties, - VaultClient client) { - - ClientAuthentication clientAuthentication; - - if (vaultProperties.getAuthentication() == VaultProperties.AuthenticationMethod.TOKEN) { - clientAuthentication = ClientAuthentication.token(vaultProperties); - } - else if (vaultProperties.getAuthentication() == VaultProperties.AuthenticationMethod.APPID) { - - Map appIdUserIdMechanisms = applicationContext - .getBeansOfType(AppIdUserIdMechanism.class); - if (!appIdUserIdMechanisms.isEmpty()) { - clientAuthentication = ClientAuthentication.appId(vaultProperties, - client, appIdUserIdMechanisms.values().iterator().next()); - } - else { - clientAuthentication = ClientAuthentication - .appId(vaultProperties, client); - } - } - else { - clientAuthentication = ClientAuthentication.create(vaultProperties, client); - } - - return clientAuthentication; - } - - @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/config/VaultConfigOperations.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigOperations.java index 3381f2fe..dcc91ca2 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigOperations.java +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigOperations.java @@ -15,13 +15,8 @@ */ package org.springframework.cloud.vault.config; -import java.net.URI; import java.util.Map; -import org.springframework.cloud.vault.VaultClientResponse; -import org.springframework.cloud.vault.VaultProperties; -import org.springframework.cloud.vault.VaultToken; - /** * Interface that specified a basic set of Vault operations, implemented by * {@link VaultConfigTemplate}. @@ -40,5 +35,4 @@ public interface VaultConfigOperations { * @throws IllegalStateException if {@link VaultProperties#isFailFast()} is enabled. */ Map read(SecureBackendAccessor secureBackendAccessor); - } diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigTemplate.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigTemplate.java index 232921c7..64fc05bb 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigTemplate.java +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultConfigTemplate.java @@ -15,36 +15,30 @@ */ package org.springframework.cloud.vault.config; -import java.net.URI; import java.util.Collections; +import java.util.HashMap; import java.util.Map; -import org.springframework.cloud.vault.ClientAuthentication; -import org.springframework.cloud.vault.VaultClient; -import org.springframework.cloud.vault.VaultClientResponse; -import org.springframework.cloud.vault.VaultProperties; -import org.springframework.cloud.vault.config.VaultOperations.SessionCallback; -import org.springframework.cloud.vault.config.VaultOperations.VaultSession; +import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.util.Assert; +import org.springframework.vault.client.VaultResponseEntity; +import org.springframework.vault.core.VaultOperations; +import org.springframework.vault.support.VaultResponse; -import lombok.extern.apachecommons.CommonsLog; - -import org.apache.commons.logging.Log; +import lombok.extern.slf4j.Slf4j; /** * Central class to retrieve configuration from Vault. * * @author Mark Paluch - * @see VaultClient - * @see ClientAuthentication + * @see VaultOperations */ -@CommonsLog +@Slf4j public class VaultConfigTemplate implements VaultConfigOperations { private final VaultOperations vaultOperations; private final VaultProperties properties; - private final VaultConfigSessionCallback callback; /** * Creates a new {@link VaultConfigTemplate}. @@ -52,38 +46,48 @@ public class VaultConfigTemplate implements VaultConfigOperations { * @param vaultOperations must not be {@literal null}. * @param properties must not be {@literal null}. */ - public VaultConfigTemplate(VaultOperations vaultOperations, VaultProperties properties) { + public VaultConfigTemplate(VaultOperations vaultOperations, + VaultProperties properties) { Assert.notNull(vaultOperations, "VaultOperations must not be null!"); Assert.notNull(properties, "VaultProperties must not be null!"); this.vaultOperations = vaultOperations; this.properties = properties; - this.callback = new VaultConfigSessionCallback(log); } - @Override - public Map read(SecureBackendAccessor secureBackendAccessor) { + public Map read(final SecureBackendAccessor secureBackendAccessor) { Assert.notNull(secureBackendAccessor, "SecureBackendAccessor must not be null!"); - VaultClientResponse response = vaultOperations.doWithVault("{backend}/{key}", - secureBackendAccessor.variables(), callback); + VaultResponseEntity response = vaultOperations.doWithVault( + new VaultOperations.SessionCallback>() { + @Override + public VaultResponseEntity doWithVault( + VaultOperations.VaultSession session) { + + return session.exchange("{backend}/{key}", HttpMethod.GET, null, + VaultResponse.class, secureBackendAccessor.variables()); + } + }); + + log.info(String.format("Fetching config from Vault at: %s", response.getUri())); if (response.getStatusCode() == HttpStatus.OK) { - return secureBackendAccessor - .transformProperties(response.getBody().getData()); + + Map stringMap = toStringMap(response.getBody().getData()); + + return secureBackendAccessor.transformProperties(stringMap); } if (response.getStatusCode() == HttpStatus.NOT_FOUND) { - log.info(String - .format("Could not locate PropertySource: %s", "key not found")); + log.info(String.format("Could not locate PropertySource: %s", + "key not found")); } else if (properties.isFailFast()) { - throw new IllegalStateException( - String.format( - "Could not locate PropertySource and the fail fast property is set, failing Status %d %s", - response.getStatusCode().value(), response.getMessage())); + throw new IllegalStateException(String.format( + "Could not locate PropertySource and the fail fast property is set, failing Status %d %s", + response.getStatusCode().value(), response.getMessage())); } else { log.warn(String.format("Could not locate PropertySource: Status %d %s", @@ -93,19 +97,17 @@ public class VaultConfigTemplate implements VaultConfigOperations { return Collections.emptyMap(); } - static class VaultConfigSessionCallback implements SessionCallback { + private Map toStringMap(Map data) { - private final Log log; + Map result = new HashMap<>(); + for (String key : data.keySet()) { + Object value = data.get(key); - public VaultConfigSessionCallback(Log log) { - this.log = log; + if (value != null) { + result.put(key, value.toString()); + } } - @Override - public VaultClientResponse doWithVault(URI uri, VaultSession session) { - log.info(String.format("Fetching config from Vault at: %s", uri)); - return session.read(uri); - } + return result; } - } diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultHealthIndicator.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultHealthIndicator.java index d9e03ea7..a1132990 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultHealthIndicator.java +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultHealthIndicator.java @@ -18,7 +18,8 @@ package org.springframework.cloud.vault.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.HealthIndicator; -import org.springframework.cloud.vault.VaultHealthResponse; +import org.springframework.vault.core.VaultOperations; +import org.springframework.vault.support.VaultHealth; /** * @author Stuart Ingram @@ -26,14 +27,14 @@ import org.springframework.cloud.vault.VaultHealthResponse; public class VaultHealthIndicator implements HealthIndicator { @Autowired - private VaultTemplate vaultTemplate; + private VaultOperations vaultOperations; @Override public Health health() { try { - VaultHealthResponse vaultHealthResponse = vaultTemplate.health(); + VaultHealth vaultHealthResponse = vaultOperations.opsForSys().health(); if (!vaultHealthResponse.isInitialized()) { return Health.down().withDetail("state", "Vault uninitialized").build(); @@ -44,14 +45,14 @@ public class VaultHealthIndicator implements HealthIndicator { } if (vaultHealthResponse.isStandby()) { - return Health.outOfService().withDetail("state", "Vault in standby").build(); + return Health.outOfService().withDetail("state", "Vault in standby") + .build(); } return Health.up().build(); } catch (Exception e) { - return Health.down().build(); + return Health.down(e).build(); } } - } diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultOperations.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultOperations.java deleted file mode 100644 index a4fa56bd..00000000 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultOperations.java +++ /dev/null @@ -1,109 +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.config; - -import java.net.URI; -import java.util.Map; - -import org.springframework.cloud.vault.VaultClientResponse; -import org.springframework.cloud.vault.VaultHealthResponse; - -/** - * Interface that specified a basic set of Vault operations, implemented by - * {@link VaultTemplate}. - * - * @author Mark Paluch - */ -public interface VaultOperations { - - /** - * @return the operations interface to interact with Vault configuration data. - */ - VaultConfigOperations opsForConfig(); - - /** - * Executes a Vault {@link SessionCallback}. Allows to interact with Vault in an - * authenticated session. - * - * @param path the path of the resource, e.g. {@code transit/encrypt/foo}, must not be - * empty or {@literal null}. - * @param sessionCallback the request. - * @return - */ - T doWithVault(String path, SessionCallback sessionCallback); - - /** - * Executes a Vault {@link SessionCallback}. Allows to interact with Vault in an - * authenticated session. - * - * @param pathTemplate the path of the resource, e.g. {@code transit/ key}/foo}, must - * not be empty or {@literal null}. * @param variables the variables for expansion of - * the {@code pathTemplate}, must not be {@literal null}. - * @param sessionCallback the request. - * @return - */ - T doWithVault(String pathTemplate, Map variables, - SessionCallback sessionCallback); - - /** - * Query the current Vault service for it's health status. - * - * @return A {@link VaultHealthResponse} containing the current service status. - */ - VaultHealthResponse health(); - - /** - * Callback to execute actions within an authenticated {@link VaultSession}. - * - * @author Mark Paluch - */ - public interface SessionCallback { - - /** - * Callback method. - * - * @param uri the URI that is used for the request, must not be {@literal null}. - * @param session session to use, must not be {@literal null}. - * @return - */ - T doWithVault(URI uri, VaultSession session); - } - - /** - * An authenticated Vault session. - * - * @author Mark Paluch - */ - public interface VaultSession { - - /** - * Read data from the given Vault {@code uri}. - * - * @param uri must not be {@literal null}. - * @return the {@link VaultClientResponse}. - */ - public VaultClientResponse read(URI uri); - - /** - * Write data to the given Vault {@code uri}. - * - * @param uri must not be {@literal null}. - * @param entity must not be {@literal null}. - * @return the {@link VaultClientResponse}. - */ - public VaultClientResponse write(URI uri, Object entity); - } -} diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultProperties.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultProperties.java similarity index 95% rename from spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultProperties.java rename to spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultProperties.java index 3e9e87ae..a8d8d650 100644 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultProperties.java +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultProperties.java @@ -13,7 +13,8 @@ * 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.hibernate.validator.constraints.NotEmpty; import org.hibernate.validator.constraints.Range; @@ -94,14 +95,14 @@ public class VaultProperties { /** * Property value for UserId generation using a Mac-Address. * - * @see MacAddressUserId + * @see org.springframework.vault.authentication.MacAddressUserId */ public final static String MAC_ADDRESS = "MAC_ADDRESS"; /** * Property value for UserId generation using an IP-Address. * - * @see IpAddressUserId + * @see org.springframework.vault.authentication.IpAddressUserId */ public final static String IP_ADDRESS = "IP_ADDRESS"; diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultPropertySource.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultPropertySource.java index 6fcbcea0..2fc431ad 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultPropertySource.java +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultPropertySource.java @@ -19,20 +19,19 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; -import org.springframework.cloud.vault.VaultProperties; import org.springframework.core.env.EnumerablePropertySource; import org.springframework.util.Assert; -import lombok.extern.apachecommons.CommonsLog; +import lombok.extern.slf4j.Slf4j; /** - * A {@link EnumerablePropertySource} backed by {@link VaultConfigOperations}. + * A {@link EnumerablePropertySource} backed by {@link VaultConfigTemplate}. * * @author Spencer Gibb * @author Mark Paluch */ -@CommonsLog -class VaultPropertySource extends EnumerablePropertySource { +@Slf4j +class VaultPropertySource extends EnumerablePropertySource { private final VaultProperties vaultProperties; private final SecureBackendAccessor secureBackendAccessor; @@ -45,12 +44,12 @@ class VaultPropertySource extends EnumerablePropertySource backendAccessors; @@ -57,7 +54,7 @@ class VaultPropertySourceLocator implements PropertySourceLocator, PriorityOrder * @param genericBackendProperties must not be {@literal null}. * @param backendAccessors must not be {@literal null}. */ - public VaultPropertySourceLocator(VaultConfigOperations operations, + public VaultPropertySourceLocator(VaultConfigTemplate operations, VaultProperties properties, VaultGenericBackendProperties genericBackendProperties, Collection backendAccessors) { @@ -79,7 +76,8 @@ class VaultPropertySourceLocator implements PropertySourceLocator, PriorityOrder if (environment instanceof ConfigurableEnvironment) { - CompositePropertySource propertySource = createCompositePropertySource((ConfigurableEnvironment) environment); + CompositePropertySource propertySource = createCompositePropertySource( + (ConfigurableEnvironment) environment); initialize(propertySource); return propertySource; @@ -130,8 +128,9 @@ class VaultPropertySourceLocator implements PropertySourceLocator, PriorityOrder if (StringUtils.hasText(propertySourceContext)) { - VaultPropertySource vaultPropertySource = createVaultPropertySource(generic( - genericBackendProperties.getBackend(), propertySourceContext)); + VaultPropertySource vaultPropertySource = createVaultPropertySource( + generic(genericBackendProperties.getBackend(), + propertySourceContext)); propertySource.addPropertySource(vaultPropertySource); } @@ -140,7 +139,8 @@ class VaultPropertySourceLocator implements PropertySourceLocator, PriorityOrder for (SecureBackendAccessor backendAccessor : backendAccessors) { - VaultPropertySource vaultPropertySource = createVaultPropertySource(backendAccessor); + VaultPropertySource vaultPropertySource = createVaultPropertySource( + backendAccessor); propertySource.addPropertySource(vaultPropertySource); } return propertySource; @@ -153,7 +153,8 @@ class VaultPropertySourceLocator implements PropertySourceLocator, PriorityOrder } } - private VaultPropertySource createVaultPropertySource(SecureBackendAccessor accessor) { + private VaultPropertySource createVaultPropertySource( + SecureBackendAccessor accessor) { return new VaultPropertySource(this.operations, this.properties, accessor); } diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultSecretBackend.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultSecretBackend.java similarity index 94% rename from spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultSecretBackend.java rename to spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultSecretBackend.java index b59e8459..1932ddf4 100644 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultSecretBackend.java +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultSecretBackend.java @@ -13,7 +13,8 @@ * 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; /** * A secret backend that can return secrets from Vault. diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultState.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultState.java deleted file mode 100644 index 52a92b7b..00000000 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultState.java +++ /dev/null @@ -1,30 +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.config; - -import lombok.Data; -import org.springframework.cloud.vault.VaultToken; - -/** - * State of the Vault client. - * - * @author Mark Paluch - */ -@Data -class VaultState { - private VaultToken token; -} diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultTemplate.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultTemplate.java deleted file mode 100644 index ca6b6230..00000000 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/VaultTemplate.java +++ /dev/null @@ -1,125 +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.config; - -import java.net.URI; -import java.util.Map; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.cloud.vault.ClientAuthentication; -import org.springframework.cloud.vault.VaultClient; -import org.springframework.cloud.vault.VaultClientResponse; -import org.springframework.cloud.vault.VaultHealthResponse; -import org.springframework.cloud.vault.VaultProperties; -import org.springframework.cloud.vault.VaultToken; -import org.springframework.util.Assert; - -/** - * This class encapsulates main Vault interaction. {@link VaultTemplate} will log into - * Vault on initialization and use the token throughout the whole lifetime. - * - * @author Mark Paluch - */ -public class VaultTemplate implements InitializingBean, VaultOperations { - - private final static String HEALTH_URL_TEMPLATE = "sys/health"; - - private final VaultProperties properties; - private final VaultClient client; - private final ClientAuthentication clientAuthentication; - private final transient VaultState vaultState = new VaultState(); - private final VaultSession vaultSession; - - /** - * Creates a new {@link VaultConfigTemplate} for the given {@link VaultProperties}, - * {@link VaultClient} and {@link ClientAuthentication}. - * - * @param properties must not be {@literal null}. - * @param client must not be {@literal null}. - * @param clientAuthentication must not be {@literal null}. - */ - public VaultTemplate(VaultProperties properties, VaultClient client, - ClientAuthentication clientAuthentication) { - - Assert.notNull(properties, "VaultProperties must not be null!"); - Assert.notNull(client, "VaultClient must not be null!"); - Assert.notNull(clientAuthentication, "ClientAuthentication must not be null!"); - - this.properties = properties; - this.client = client; - this.clientAuthentication = clientAuthentication; - this.vaultSession = new VaultSession() { - @Override - public VaultClientResponse read(URI uri) { - return VaultTemplate.this.client.read(uri, getToken()); - } - - @Override - public VaultClientResponse write(URI uri, Object entity) { - return VaultTemplate.this.client.write(uri, entity, getToken()); - } - }; - } - - @Override - public void afterPropertiesSet() { - login(); - } - - private void login() { - vaultState.setToken(clientAuthentication.login()); - } - - private VaultToken getToken() { - - if (vaultState.getToken() == null) { - login(); - } - - return vaultState.getToken(); - } - - @Override - public VaultConfigOperations opsForConfig() { - return new VaultConfigTemplate(this, properties); - } - - @Override - public T doWithVault(String path, SessionCallback sessionCallback) { - - Assert.notNull(sessionCallback, "SessionCallback must not be null!"); - - URI uri = VaultClient.buildUri(properties, path); - return sessionCallback.doWithVault(uri, vaultSession); - } - - @Override - public T doWithVault(String pathTemplate, Map variables, - SessionCallback sessionCallback) { - - Assert.notNull(sessionCallback, "SessionCallback must not be null!"); - - URI uri = client.buildUri(properties, pathTemplate, variables); - return sessionCallback.doWithVault(uri, vaultSession); - } - - @Override - public VaultHealthResponse health() { - - URI uri = VaultClient.buildUri(properties, HEALTH_URL_TEMPLATE); - return client.health(uri); - } -} 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 c042b3b4..d49d0c0f 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,4 +1,4 @@ # Bootstrap Configuration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ -org.springframework.cloud.vault.config.VaultConfigBootstrapConfiguration,\ -org.springframework.cloud.vault.config.VaultConfigBootstrapHealthIndicator \ No newline at end of file +org.springframework.cloud.vault.config.VaultBootstrapConfiguration,\ +org.springframework.cloud.vault.config.VaultBootstrapHealthIndicatorConfiguration \ No newline at end of file diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/AppIdAuthenticationIntegrationTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/AppIdAuthenticationIntegrationTests.java deleted file mode 100644 index 9c6ae995..00000000 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/AppIdAuthenticationIntegrationTests.java +++ /dev/null @@ -1,72 +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.config; - -import org.springframework.cloud.vault.ClientAuthentication; -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.util.Settings; - -import org.junit.Before; - -/** - * Integration tests for {@link VaultClient} using {@link AuthenticationMethod#APPID}. - * - * @author Mark Paluch - */ -public class AppIdAuthenticationIntegrationTests extends GenericSecretIntegrationTests { - - @Before - public void setUp() throws Exception { - - this.vaultProperties = Settings.createVaultProperties(); - - super.setUp(); - - AppIdProperties appId = configureAppIdProperties(); - vaultProperties.setApplicationName("myapp"); - vaultProperties.setAuthentication(AuthenticationMethod.APPID); - vaultProperties.setAppId(appId); - - if (!prepare().hasAuth(appId.getAppIdPath())) { - prepare().mountAuth(appId.getAppIdPath()); - } - - IpAddressUserId userIdMechanism = new IpAddressUserId(); - String userId = userIdMechanism.createUserId(); - prepare().mapAppId(vaultProperties.getApplicationName()); - prepare().mapUserId(vaultProperties.getApplicationName(), userId); - - VaultClient vaultClient = prepare().newVaultClient(); - - ClientAuthentication clientAuthentication = ClientAuthentication.appId( - vaultProperties, vaultClient, userIdMechanism); - - configOperations = new VaultTemplate(vaultProperties, - vaultClient, - clientAuthentication).opsForConfig(); - } - - private AppIdProperties configureAppIdProperties() { - - AppIdProperties appId = new AppIdProperties(); - appId.setUserId(AppIdProperties.IP_ADDRESS); - return appId; - } -} diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/GenericSecretIntegrationTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/GenericSecretIntegrationTests.java index 4fa141bc..8e97c0da 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/GenericSecretIntegrationTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/GenericSecretIntegrationTests.java @@ -15,46 +15,42 @@ */ package org.springframework.cloud.vault.config; -import java.util.HashMap; -import java.util.Map; - -import org.springframework.cloud.vault.AbstractIntegrationTests; -import org.springframework.cloud.vault.ClientAuthentication; -import org.springframework.cloud.vault.VaultClient; -import org.springframework.cloud.vault.VaultProperties; -import org.springframework.cloud.vault.util.Settings; - import static org.assertj.core.api.Assertions.*; 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.util.IntegrationTestSupport; +import org.springframework.cloud.vault.util.Settings; /** - * Integration tests for {@link VaultClient} using the generic secret backend. + * Integration tests for {@link VaultConfigTemplate} using the generic secret backend. * * @author Mark Paluch */ -public class GenericSecretIntegrationTests extends AbstractIntegrationTests { +public class GenericSecretIntegrationTests extends IntegrationTestSupport { - protected VaultProperties vaultProperties = Settings.createVaultProperties(); - protected VaultConfigOperations configOperations; + private VaultProperties vaultProperties = Settings.createVaultProperties(); + private VaultConfigOperations configOperations; @Before public void setUp() throws Exception { vaultProperties.setFailFast(false); - prepare().writeSecret("app-name", (Map) createData()); + prepare().getVaultOperations().write("secret/app-name", (Map) createData()); - configOperations = new VaultTemplate(vaultProperties, prepare().newVaultClient(), - ClientAuthentication.token(vaultProperties)).opsForConfig(); + configOperations = new VaultConfigTemplate(prepare().getVaultOperations(), + vaultProperties); } @Test public void shouldReturnSecretsCorrectly() throws Exception { - Map secretProperties = configOperations.read(generic("secret", - "app-name")); + Map secretProperties = configOperations + .read(generic("secret", "app-name")); assertThat(secretProperties).containsAllEntriesOf(createExpectedMap()); } @@ -62,8 +58,8 @@ public class GenericSecretIntegrationTests extends AbstractIntegrationTests { @Test public void shouldReturnNullIfNotFound() throws Exception { - Map secretProperties = configOperations.read(generic("secret", - "missing")); + Map secretProperties = configOperations + .read(generic("secret", "missing")); assertThat(secretProperties).isEmpty(); } 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 deleted file mode 100644 index 6e104783..00000000 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/PrepareVaultTests.java +++ /dev/null @@ -1,47 +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.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/config/VaultConfigAppIdCustomMechanismTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigAppIdCustomMechanismTests.java index 8dc3c433..37af9455 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigAppIdCustomMechanismTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigAppIdCustomMechanismTests.java @@ -19,6 +19,8 @@ package org.springframework.cloud.vault.config; import static org.assertj.core.api.Assertions.*; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import org.junit.BeforeClass; import org.junit.Test; @@ -29,14 +31,18 @@ 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.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; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.vault.authentication.AppIdAuthentication; +import org.springframework.vault.authentication.AppIdAuthenticationOptions; +import org.springframework.vault.authentication.AppIdUserIdMechanism; +import org.springframework.vault.authentication.ClientAuthentication; +import org.springframework.vault.client.VaultClient; +import org.springframework.vault.core.VaultOperations; /** * @author Mark Paluch @@ -54,10 +60,6 @@ public class VaultConfigAppIdCustomMechanismTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); - vaultRule.prepare().writeSecret( - VaultConfigAppIdCustomMechanismTests.class.getSimpleName(), - Collections.singletonMap("vault.value", "foo")); - VaultProperties vaultProperties = Settings.createVaultProperties(); vaultProperties.setAuthentication(VaultProperties.AuthenticationMethod.APPID); @@ -65,12 +67,29 @@ public class VaultConfigAppIdCustomMechanismTests { vaultRule.prepare().mountAuth(vaultProperties.getAppId().getAppIdPath()); } - vaultRule.prepare() - .mapAppId(VaultConfigAppIdCustomMechanismTests.class.getSimpleName()); - vaultRule.prepare().mapUserId( - VaultConfigAppIdCustomMechanismTests.class.getSimpleName(), - new StaticUserIdMechanism().createUserId()); + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + String appId = VaultConfigAppIdCustomMechanismTests.class.getSimpleName(); + + vaultOperations.write( + "secret/" + VaultConfigAppIdCustomMechanismTests.class.getSimpleName(), + Collections.singletonMap("vault.value", "foo")); + + Map appIdData = new HashMap(); + appIdData.put("value", "root"); // policy + appIdData.put("display_name", "this is my test application"); + + vaultOperations.write(String.format("auth/app-id/map/app-id/%s", appId), + appIdData); + + Map userIdData = new HashMap(); + userIdData.put("value", appId); // name of the app-id + userIdData.put("cidr_block", "0.0.0.0/0"); + + String userId = new StaticUserIdMechanism().createUserId(); + + vaultOperations.write(String.format("auth/app-id/map/user-id/%s", userId), + userIdData); } @Value("${vault.value}") @@ -78,7 +97,6 @@ public class VaultConfigAppIdCustomMechanismTests { @Test public void contextLoads() { - assertThat(configValue).isEqualTo("foo"); } @@ -93,10 +111,16 @@ public class VaultConfigAppIdCustomMechanismTests { @Configuration public static class BootstrapConfiguration { - @Bean @ConditionalOnProperty("use.custom.config") - AppIdUserIdMechanism appIdUserIdMechanism() { - return new StaticUserIdMechanism(); + @Bean + ClientAuthentication clientAuthentication(VaultClient vaultClient) { + return new AppIdAuthentication( + AppIdAuthenticationOptions + .builder() + .appId("VaultConfigAppIdCustomMechanismTests") + .userIdMechanism(new StaticUserIdMechanism()).build(), + vaultClient); + } } diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigAppIdTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigAppIdTests.java index 2824adfc..427310d8 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigAppIdTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigAppIdTests.java @@ -18,6 +18,8 @@ package org.springframework.cloud.vault.config; import static org.assertj.core.api.Assertions.*; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import org.junit.BeforeClass; import org.junit.Test; @@ -27,16 +29,17 @@ 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.cloud.vault.IpAddressUserId; -import org.springframework.cloud.vault.VaultProperties; import org.springframework.cloud.vault.util.Settings; import org.springframework.cloud.vault.util.VaultRule; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.vault.authentication.IpAddressUserId; +import org.springframework.vault.core.VaultOperations; /** - * Integration test using config infrastructure with AppId authentication. In case this test should fail because of SSL - * make sure you run the test within the spring-cloud-vault-config/spring-cloud-vault-config directory as the keystore - * is referenced with {@code ../work/keystore.jks}. + * Integration test using config infrastructure with AppId authentication. In case this + * test should fail because of SSL make sure you run the test within the + * spring-cloud-vault-config/spring-cloud-vault-config directory as the keystore is + * referenced with {@code ../work/keystore.jks}. * * @author Mark Paluch */ @@ -53,9 +56,6 @@ public class VaultConfigAppIdTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); - vaultRule.prepare().writeSecret(VaultConfigAppIdTests.class.getSimpleName(), - Collections.singletonMap("vault.value", "foo")); - VaultProperties vaultProperties = Settings.createVaultProperties(); vaultProperties.setAuthentication(VaultProperties.AuthenticationMethod.APPID); vaultProperties.getAppId().setUserId(VaultProperties.AppIdProperties.IP_ADDRESS); @@ -64,9 +64,29 @@ public class VaultConfigAppIdTests { vaultRule.prepare().mountAuth(vaultProperties.getAppId().getAppIdPath()); } - vaultRule.prepare().mapAppId(VaultConfigAppIdTests.class.getSimpleName()); - vaultRule.prepare().mapUserId(VaultConfigAppIdTests.class.getSimpleName(), - new IpAddressUserId().createUserId()); + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + + String appId = VaultConfigAppIdTests.class.getSimpleName(); + + vaultOperations.write( + "secret/" + VaultConfigAppIdTests.class.getSimpleName(), + Collections.singletonMap("vault.value", "foo")); + + Map appIdData = new HashMap(); + appIdData.put("value", "root"); // policy + appIdData.put("display_name", "this is my test application"); + + vaultOperations.write(String.format("auth/app-id/map/app-id/%s", appId), + appIdData); + + Map userIdData = new HashMap(); + userIdData.put("value", appId); // name of the app-id + userIdData.put("cidr_block", "0.0.0.0/0"); + + String userId = new IpAddressUserId().createUserId(); + + vaultOperations.write(String.format("auth/app-id/map/user-id/%s", userId), + userIdData); } @Value("${vault.value}") diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigDisabledTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigDisabledTests.java index d89e2e4c..21fb6cde 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigDisabledTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigDisabledTests.java @@ -27,11 +27,11 @@ 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.cloud.vault.VaultClient; import org.springframework.cloud.vault.util.VaultRule; import org.springframework.context.ApplicationContext; import org.springframework.core.env.Environment; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.vault.client.VaultClient; /** * Integration test using config infrastructure with token authentication. In case this @@ -52,7 +52,7 @@ public class VaultConfigDisabledTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); - vaultRule.prepare().writeSecret("testVaultApp", + vaultRule.prepare().getVaultOperations().write("secret/testVaultApp", Collections.singletonMap("vault.value", "foo")); } diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigGenericBackendDisabledTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigGenericBackendDisabledTests.java index ef8da5b2..b1e005cb 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigGenericBackendDisabledTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigGenericBackendDisabledTests.java @@ -50,7 +50,7 @@ public class VaultConfigGenericBackendDisabledTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); - vaultRule.prepare().writeSecret("testVaultApp", + vaultRule.prepare().getVaultOperations().write("secret/testVaultApp", Collections.singletonMap("vault.value", "foo")); } diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigTests.java index 5ef9ff70..dc242654 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigTests.java @@ -27,12 +27,12 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.SpringApplicationConfiguration; -import org.springframework.cloud.vault.VaultClient; import org.springframework.cloud.vault.util.VaultRule; import org.springframework.context.ApplicationContext; import org.springframework.core.env.Environment; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.vault.client.VaultClient; import org.springframework.web.client.RestTemplate; /** @@ -53,7 +53,7 @@ public class VaultConfigTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); - vaultRule.prepare().writeSecret("testVaultApp", + vaultRule.prepare().getVaultOperations().write("secret/testVaultApp", Collections.singletonMap("vault.value", "foo")); } diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigTlsCertAuthenticationTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigTlsCertAuthenticationTests.java index 62ed0656..55189795 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigTlsCertAuthenticationTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigTlsCertAuthenticationTests.java @@ -15,29 +15,28 @@ */ package org.springframework.cloud.vault.config; +import static org.assertj.core.api.Assertions.*; +import static org.springframework.cloud.vault.util.Settings.*; + import java.io.File; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import org.assertj.core.util.Files; +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.test.IntegrationTest; import org.springframework.boot.test.SpringApplicationConfiguration; -import org.springframework.cloud.vault.VaultProperties; import org.springframework.cloud.vault.util.Settings; import org.springframework.cloud.vault.util.VaultRule; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import static org.assertj.core.api.Assertions.*; -import static org.springframework.cloud.vault.util.Settings.*; - -import org.assertj.core.util.Files; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.springframework.vault.core.VaultOperations; /** * Integration test using config infrastructure with TLS certificate authentication. In @@ -61,16 +60,18 @@ public class VaultConfigTlsCertAuthenticationTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); - vaultRule.prepare().writeSecret( - VaultConfigTlsCertAuthenticationTests.class.getSimpleName(), - Collections.singletonMap("vault.value", "foo")); - VaultProperties vaultProperties = Settings.createVaultProperties(); if (!vaultRule.prepare().hasAuth(vaultProperties.getSsl().getCertAuthPath())) { vaultRule.prepare().mountAuth(vaultProperties.getSsl().getCertAuthPath()); } + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + + vaultOperations.write( + "secret/" + VaultConfigTlsCertAuthenticationTests.class.getSimpleName(), + Collections.singletonMap("vault.value", "foo")); + File workDir = findWorkDir(); String certificate = Files.contentOf( @@ -80,7 +81,7 @@ public class VaultConfigTlsCertAuthenticationTests { role.put("certificate", certificate); role.put("policies", "root"); - vaultRule.prepare().write("auth/cert/certs/my-role", role); + vaultOperations.write("auth/cert/certs/my-role", role); } @Value("${vault.value}") diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigWithContextTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigWithContextTests.java index a9ea8aa7..8956d86b 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigWithContextTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultConfigWithContextTests.java @@ -29,11 +29,13 @@ import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.cloud.vault.util.VaultRule; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.vault.core.VaultOperations; /** - * Integration test using config infrastructure with token authentication. In case this test should fail because of SSL - * make sure you run the test within the spring-cloud-vault-config/spring-cloud-vault-config directory as the keystore - * is referenced with {@code ../work/keystore.jks}. + * Integration test using config infrastructure with token authentication. In case this + * test should fail because of SSL make sure you run the test within the + * spring-cloud-vault-config/spring-cloud-vault-config directory as the keystore is + * referenced with {@code ../work/keystore.jks}. * * @author Mark Paluch */ @@ -48,11 +50,13 @@ public class VaultConfigWithContextTests { VaultRule vaultRule = new VaultRule(); vaultRule.before(); - vaultRule.prepare().writeSecret("testVaultApp/my-profile", + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + + vaultOperations.write("secret/testVaultApp/my-profile", Collections.singletonMap("vault.value", "hello")); - vaultRule.prepare().writeSecret("testVaultApp", - Collections.singletonMap("vault.value", "worls")); + vaultOperations.write("secret/testVaultApp", + Collections.singletonMap("vault.value", "world")); } @Value("${vault.value}") @@ -60,7 +64,6 @@ public class VaultConfigWithContextTests { @Test public void contextLoads() { - assertThat(configValue).isEqualTo("hello"); } diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultHealthIndicatorUnitTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultHealthIndicatorUnitTests.java index d2c463e9..259f8edc 100644 --- a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultHealthIndicatorUnitTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultHealthIndicatorUnitTests.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.cloud.vault.config; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; @@ -26,7 +26,9 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Status; -import org.springframework.cloud.vault.VaultHealthResponse; +import org.springframework.vault.core.VaultOperations; +import org.springframework.vault.core.VaultSysOperations; +import org.springframework.vault.support.VaultHealth; /** * @author Mark Paluch @@ -38,15 +40,26 @@ public class VaultHealthIndicatorUnitTests { VaultHealthIndicator healthIndicator = new VaultHealthIndicator(); @Mock - VaultTemplate vaultTemplate; + VaultOperations vaultOperations; + + @Mock + VaultSysOperations vaultSysOperations; + + @Mock + VaultHealth healthResponse; + + @Before + public void before() throws Exception { + + when(vaultOperations.opsForSys()).thenReturn(vaultSysOperations); + when(vaultSysOperations.health()).thenReturn(healthResponse); + } @Test public void shouldReportHealthyService() throws Exception { - VaultHealthResponse healthResponse = new VaultHealthResponse(); - healthResponse.setInitialized(true); - - when(vaultTemplate.health()).thenReturn(healthResponse); + when(healthResponse.isInitialized()).thenReturn(true); + when(vaultOperations.opsForSys()).thenReturn(vaultSysOperations); Health health = healthIndicator.health(); assertThat(health.getStatus()).isEqualTo(Status.UP); @@ -56,11 +69,8 @@ public class VaultHealthIndicatorUnitTests { @Test public void shouldReportSealedService() throws Exception { - VaultHealthResponse healthResponse = new VaultHealthResponse(); - healthResponse.setInitialized(true); - healthResponse.setSealed(true); - - when(vaultTemplate.health()).thenReturn(healthResponse); + when(healthResponse.isInitialized()).thenReturn(true); + when(healthResponse.isSealed()).thenReturn(true); Health health = healthIndicator.health(); @@ -71,10 +81,6 @@ public class VaultHealthIndicatorUnitTests { @Test public void shouldReportUninitializedService() throws Exception { - VaultHealthResponse healthResponse = new VaultHealthResponse(); - - when(vaultTemplate.health()).thenReturn(healthResponse); - Health health = healthIndicator.health(); assertThat(health.getStatus()).isEqualTo(Status.DOWN); @@ -84,11 +90,8 @@ public class VaultHealthIndicatorUnitTests { @Test public void shouldReportStandbyService() throws Exception { - VaultHealthResponse healthResponse = new VaultHealthResponse(); - healthResponse.setInitialized(true); - healthResponse.setStandby(true); - - when(vaultTemplate.health()).thenReturn(healthResponse); + when(healthResponse.isInitialized()).thenReturn(true); + when(healthResponse.isStandby()).thenReturn(true); Health health = healthIndicator.health(); @@ -99,10 +102,11 @@ public class VaultHealthIndicatorUnitTests { @Test public void exceptionsShouldReportDownStatus() throws Exception { - when(vaultTemplate.health()).thenThrow(new IllegalStateException()); + reset(vaultSysOperations); + when(vaultSysOperations.health()).thenThrow(new IllegalStateException()); Health health = healthIndicator.health(); assertThat(health.getStatus()).isEqualTo(Status.DOWN); - assertThat(health.getDetails()).isEmpty(); + assertThat(health.getDetails()).containsKey("error"); } } \ No newline at end of file diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultPropertySourceIntegrationTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultPropertySourceIntegrationTests.java new file mode 100644 index 00000000..e116fabd --- /dev/null +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/config/VaultPropertySourceIntegrationTests.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; + +import static org.assertj.core.api.Assertions.*; + +import java.util.Collections; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.cloud.vault.util.IntegrationTestSupport; +import org.springframework.cloud.vault.util.Settings; + +/** + * Integration tests for {@link VaultPropertySource}. + * + * @author Mark Paluch + */ +public class VaultPropertySourceIntegrationTests extends IntegrationTestSupport { + + @Before + public void before() throws Exception { + prepare().getVaultOperations().write("secret/myapp", + Collections.singletonMap("key", "value")); + } + + @Test + public void shouldReadValue() throws Exception { + + VaultProperties vaultProperties = Settings.createVaultProperties(); + + VaultPropertySource propertySource = new VaultPropertySource( + new VaultConfigTemplate(prepare().getVaultOperations(), vaultProperties), + vaultProperties, SecureBackendAccessors.generic("secret", "myapp")); + + propertySource.init(); + + assertThat(propertySource.getPropertyNames()).contains("key"); + assertThat(propertySource.getProperty("key")).isEqualTo("value"); + } +} \ No newline at end of file diff --git a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/CanConnect.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/CanConnect.java similarity index 100% rename from spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/CanConnect.java rename to spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/CanConnect.java diff --git a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/AbstractIntegrationTests.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/IntegrationTestSupport.java similarity index 91% rename from spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/AbstractIntegrationTests.java rename to spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/IntegrationTestSupport.java index 901c84da..9e004fe3 100644 --- a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/AbstractIntegrationTests.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/IntegrationTestSupport.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.cloud.vault; +package org.springframework.cloud.vault.util; import org.junit.Rule; import org.springframework.cloud.vault.util.PrepareVault; @@ -25,7 +25,7 @@ import org.springframework.cloud.vault.util.VaultRule; * * @author Mark Paluch */ -public abstract class AbstractIntegrationTests { +public abstract class IntegrationTestSupport { @Rule public final VaultRule vaultRule = new VaultRule(); diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/PrepareVault.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/PrepareVault.java new file mode 100644 index 00000000..a4e605a5 --- /dev/null +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/PrepareVault.java @@ -0,0 +1,156 @@ +/* + * 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.util; + +import java.util.Collections; +import java.util.Map; + +import org.springframework.util.Assert; +import org.springframework.vault.core.VaultOperations; +import org.springframework.vault.core.VaultSysOperations; +import org.springframework.vault.support.VaultInitializationRequest; +import org.springframework.vault.support.VaultInitializationResponse; +import org.springframework.vault.support.VaultMount; +import org.springframework.vault.support.VaultToken; +import org.springframework.vault.support.VaultTokenRequest; +import org.springframework.vault.support.VaultTokenResponse; +import org.springframework.vault.support.VaultUnsealStatus; + +/** + * @author Mark Paluch + */ +public class PrepareVault { + + private final VaultOperations vaultOperations; + private final VaultSysOperations adminOperations; + + public PrepareVault(VaultOperations vaultOperations) { + + this.vaultOperations = vaultOperations; + this.adminOperations = vaultOperations.opsForSys(); + } + + /** + * Initialize Vault and unseal the vault. + * + * @return the root token. + */ + public VaultToken initializeVault() { + + int createKeys = 2; + int requiredKeys = 2; + + VaultInitializationResponse initialized = vaultOperations.opsForSys() + .initialize(new VaultInitializationRequest(createKeys, requiredKeys)); + + for (int i = 0; i < requiredKeys; i++) { + + VaultUnsealStatus unsealStatus = vaultOperations.opsForSys() + .unseal(initialized.getKeys().get(i)); + + if (!unsealStatus.isSealed()) { + break; + } + } + + return VaultToken.of(initialized.getRootToken()); + } + + /** + * Create a token for the given {@code tokenId} and {@code policy}. + * + * @param tokenId + * @param policy + * @return + */ + public VaultToken createToken(String tokenId, String policy) { + + VaultTokenRequest tokenRequest = new VaultTokenRequest(); + + tokenRequest.setId(tokenId); + if (policy != null) { + tokenRequest.setPolicies(Collections.singletonList(policy)); + } + + VaultTokenResponse vaultTokenResponse = vaultOperations.opsForToken() + .create(tokenRequest); + return vaultTokenResponse.getToken(); + } + + /** + * Check whether Vault is available (vault created and unsealed). + * + * @return + */ + public boolean isAvailable() { + return adminOperations.isInitialized() && !adminOperations.health().isSealed(); + } + + /** + * Mount an auth backend. + * + * @param authBackend + */ + public void mountAuth(String authBackend) { + + Assert.hasText(authBackend, "AuthBackend must not be empty"); + + adminOperations.authMount(authBackend, VaultMount.create(authBackend)); + } + + /** + * Check whether a auth-backend is enabled. + * + * @param authBackend + * @return + */ + public boolean hasAuth(String authBackend) { + + Assert.hasText(authBackend, "AuthBackend must not be empty"); + + return adminOperations.getAuthMounts().containsKey(authBackend + "/"); + } + + /** + * Mount an secret backend. + * + * @param secretBackend + */ + public void mountSecret(String secretBackend) { + + Assert.hasText(secretBackend, "SecretBackend must not be empty"); + + adminOperations.mount(secretBackend, VaultMount.create(secretBackend)); + } + + /** + * Check whether a auth-backend is enabled. + * + * @param secretBackend + * @return + */ + public boolean hasSecretBackend(String secretBackend) { + + Assert.hasText(secretBackend, "SecretBackend must not be empty"); + Map mounts = adminOperations.getMounts(); + return mounts.containsKey(secretBackend) + || mounts.containsKey(secretBackend + "/"); + } + + public VaultOperations getVaultOperations() { + return vaultOperations; + } +} diff --git a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/Settings.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/Settings.java similarity index 80% rename from spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/Settings.java rename to spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/Settings.java index aa4a8a51..9abda5e5 100644 --- a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/Settings.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/Settings.java @@ -13,13 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cloud.vault.util; import java.io.File; -import org.springframework.cloud.vault.VaultProperties; -import org.springframework.cloud.vault.VaultToken; +import org.springframework.cloud.vault.config.VaultProperties; import org.springframework.core.io.FileSystemResource; +import org.springframework.vault.support.SslConfiguration; +import org.springframework.vault.support.VaultToken; /** * Utility to retrieve settings during test. @@ -37,13 +39,24 @@ public class Settings { VaultProperties vaultProperties = new VaultProperties(); vaultProperties.getSsl().setTrustStorePassword("changeit"); - vaultProperties.getSsl().setTrustStore( - new FileSystemResource(new File(workDir, "keystore.jks"))); + vaultProperties.getSsl() + .setTrustStore(new FileSystemResource(new File(workDir, "keystore.jks"))); vaultProperties.setToken(token().getToken()); return vaultProperties; } + /** + * @return the vault properties. + */ + public static SslConfiguration createSslConfiguration() { + + File workDir = findWorkDir(); + + return SslConfiguration.forTrustStore( + new FileSystemResource(new File(workDir, "keystore.jks")), "changeit"); + } + /** * Find the {@code work} directory, starting at the {@code user.dir} directory. Search * is performed by walking the parent directories. @@ -55,8 +68,8 @@ public class Settings { } /** - * Find the {@code work} directory, starting at the given {@code directory}. Search - * is performed by walking the parent directories. + * Find the {@code work} directory, starting at the given {@code directory}. Search is + * performed by walking the parent directories. * @return the {@link File} pointing to the {@code work} directory * @throws IllegalStateException If the {@code work} directory cannot be found. */ diff --git a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/TestRestTemplateFactory.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/TestRestTemplateFactory.java similarity index 59% rename from spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/TestRestTemplateFactory.java rename to spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/TestRestTemplateFactory.java index bb291187..23bcc17e 100644 --- a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/TestRestTemplateFactory.java +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/TestRestTemplateFactory.java @@ -13,79 +13,84 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.cloud.vault; + +package org.springframework.cloud.vault.util; import java.util.concurrent.atomic.AtomicReference; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; -import org.springframework.boot.test.TestRestTemplate; import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.util.Assert; +import org.springframework.vault.config.ClientHttpRequestFactoryFactory; +import org.springframework.vault.support.ClientOptions; +import org.springframework.vault.support.SslConfiguration; import org.springframework.web.client.DefaultResponseErrorHandler; - -import lombok.SneakyThrows; +import org.springframework.web.client.RestTemplate; /** - * Factory for {@link TestRestTemplate}. The template caches the + * Factory for {@link RestTemplate}. The template caches the * {@link ClientHttpRequestFactory} once it was initialized. Changes to timeouts or the * SSL configuration won't be applied once a {@link ClientHttpRequestFactory} was created * for the first time. + * * @author Mark Paluch */ public class TestRestTemplateFactory { - private final static AtomicReference factoryCache = new AtomicReference<>(); + private static final AtomicReference factoryCache = new AtomicReference(); /** - * Create a new {@link TestRestTemplate} using the {@link VaultProperties}. The + * Create a new {@link RestTemplate} using the {@link SslConfiguration}. The * underlying {@link ClientHttpRequestFactory} is cached. See - * {@link #create(ClientHttpRequestFactory)} to create {@link TestRestTemplate} for a + * {@link #create(ClientHttpRequestFactory)} to create {@link RestTemplate} for a * given {@link ClientHttpRequestFactory}. * - * @param vaultProperties must not be {@literal null}. + * @param sslConfiguration must not be {@literal null}. * @return */ - @SneakyThrows - public static TestRestTemplate create(VaultProperties vaultProperties) { + public static RestTemplate create(SslConfiguration sslConfiguration) { - Assert.notNull(vaultProperties, "VaultProperties must not be null!"); + Assert.notNull(sslConfiguration, "SslConfiguration must not be null!"); - initializeClientHttpRequestFactory(vaultProperties); - return create(factoryCache.get()); + try { + initializeClientHttpRequestFactory(sslConfiguration); + return create(factoryCache.get()); + } + catch (Exception e) { + throw new IllegalStateException(e); + } } /** - * Create a new {@link TestRestTemplate} using the {@link ClientHttpRequestFactory}. - * The {@link TestRestTemplate} will throw + * Create a new {@link RestTemplate} using the {@link ClientHttpRequestFactory}. The + * {@link RestTemplate} will throw * {@link org.springframework.web.client.HttpStatusCodeException exceptions} in error - * cases and behave in that aspect like the regular - * {@link org.springframework.web.client.RestTemplate}. + * cases and behave in that aspect like the regular {@link RestTemplate}. * * @param requestFactory must not be {@literal null}. * @return */ - @SneakyThrows - public static TestRestTemplate create(ClientHttpRequestFactory requestFactory) { + public static RestTemplate create(ClientHttpRequestFactory requestFactory) { Assert.notNull(requestFactory, "ClientHttpRequestFactory must not be null!"); - TestRestTemplate testRestTemplate = new TestRestTemplate(); - testRestTemplate.setErrorHandler(new DefaultResponseErrorHandler()); - testRestTemplate.setRequestFactory(requestFactory); + RestTemplate RestTemplate = new RestTemplate(); + RestTemplate.setErrorHandler(new DefaultResponseErrorHandler()); + RestTemplate.setRequestFactory(requestFactory); - return testRestTemplate; + return RestTemplate; } - private static void initializeClientHttpRequestFactory(VaultProperties vaultProperties) - throws Exception { + private static void initializeClientHttpRequestFactory( + SslConfiguration sslConfiguration) throws Exception { if (factoryCache.get() != null) { return; } final ClientHttpRequestFactory clientHttpRequestFactory = ClientHttpRequestFactoryFactory - .create(vaultProperties); + .create(new ClientOptions(), sslConfiguration); if (factoryCache.compareAndSet(null, clientHttpRequestFactory)) { diff --git a/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/VaultRule.java b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/VaultRule.java new file mode 100644 index 00000000..db455157 --- /dev/null +++ b/spring-cloud-vault-config/src/test/java/org/springframework/cloud/vault/util/VaultRule.java @@ -0,0 +1,127 @@ +/* + * 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.util; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; + +import org.junit.rules.ExternalResource; +import org.springframework.util.Assert; +import org.springframework.vault.authentication.SessionManager; +import org.springframework.vault.client.VaultClient; +import org.springframework.vault.client.VaultEndpoint; +import org.springframework.vault.core.DefaultVaultClientFactory; +import org.springframework.vault.core.VaultTemplate; +import org.springframework.vault.support.SslConfiguration; +import org.springframework.vault.support.VaultToken; + +/** + * Vault rule to ensure a running and prepared Vault. + * + * @author Mark Paluch + */ +public class VaultRule extends ExternalResource { + + private final VaultEndpoint vaultEndpoint; + private final PrepareVault prepareVault; + + private VaultToken token; + + /** + * Create a new {@link VaultRule} with default SSL configuration and endpoint. + * + * @see Settings#createSslConfiguration() + * @see VaultEndpoint + */ + public VaultRule() { + this(Settings.createSslConfiguration(), new VaultEndpoint()); + } + + /** + * Create a new {@link VaultRule} with the given {@link SslConfiguration} and + * {@link VaultEndpoint}. + * + * @param sslConfiguration must not be {@literal null}. + * @param vaultEndpoint must not be {@literal null}. + */ + public VaultRule(SslConfiguration sslConfiguration, VaultEndpoint vaultEndpoint) { + + Assert.notNull(sslConfiguration, "SslConfiguration must not be null"); + Assert.notNull(vaultEndpoint, "VaultEndpoint must not be null"); + + VaultClient vaultClient = new VaultClient( + TestRestTemplateFactory.create(sslConfiguration), vaultEndpoint); + DefaultVaultClientFactory clientFactory = new DefaultVaultClientFactory( + vaultClient); + + VaultTemplate vaultTemplate = new VaultTemplate(clientFactory, + new PreparingSessionManager()); + + this.token = Settings.token(); + this.prepareVault = new PrepareVault(vaultTemplate); + this.vaultEndpoint = vaultEndpoint; + } + + @Override + public void before() { + + Socket socket = null; + try { + + socket = new Socket(); + + socket.connect(new InetSocketAddress(InetAddress.getByName("localhost"), + vaultEndpoint.getPort())); + socket.close(); + + } + catch (Exception ex) { + throw new IllegalStateException(String.format( + "Vault is not running on localhost:%d which is required to run a test using @Rule %s", + vaultEndpoint.getPort(), getClass().getSimpleName())); + } + finally { + if (socket != null) { + try { + socket.close(); + } + catch (IOException e) { + } + } + } + + if (!this.prepareVault.isAvailable()) { + this.token = prepareVault.initializeVault(); + this.prepareVault.createToken(Settings.token().getToken(), "root"); + this.token = Settings.token(); + } + } + + public PrepareVault prepare() { + return prepareVault; + } + + private class PreparingSessionManager implements SessionManager { + + @Override + public VaultToken getSessionToken() { + return token; + } + } +} diff --git a/spring-cloud-vault-core/pom.xml b/spring-cloud-vault-core/pom.xml deleted file mode 100644 index 46e5fbc6..00000000 --- a/spring-cloud-vault-core/pom.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - 4.0.0 - - - org.springframework.cloud - spring-cloud-vault-parent - 1.0.0.BUILD-SNAPSHOT - .. - - - org.springframework.cloud - spring-cloud-vault-core - Spring Cloud Vault Core - Spring Cloud Vault Core - - - - - org.springframework.cloud - spring-cloud-context - - - - com.fasterxml.jackson.core - jackson-databind - - - - org.springframework - spring-web - - - - org.apache.httpcomponents - httpclient - true - - - - org.apache.httpcomponents - httpcore - true - - - - io.netty - netty-all - true - - - - com.squareup.okhttp - okhttp - true - - - - - - - maven-jar-plugin - - - test-jar - - test-jar - - - - - - - - diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/AppIdUserIdMechanism.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/AppIdUserIdMechanism.java deleted file mode 100644 index 4a2089ab..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/AppIdUserIdMechanism.java +++ /dev/null @@ -1,32 +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; - -/** - * Interface to obtain a UserId for AppId authentication. - * - * @author Mark Paluch - */ -public interface AppIdUserIdMechanism { - - /** - * Creates a UserId for AppId authentication. - * - * @return the UserId. - */ - String createUserId(); -} diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/ClientAuthentication.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/ClientAuthentication.java deleted file mode 100644 index 8904e193..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/ClientAuthentication.java +++ /dev/null @@ -1,78 +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 org.springframework.web.client.RestTemplate; - -/** - * @author Mark Paluch - */ -public abstract class ClientAuthentication { - - /** - * Perform a login to Vault and return a {@link VaultToken}. - * - * @return a {@link VaultToken}. - */ - public abstract VaultToken login(); - - /** - * Creates a Token-based authentication adapter. - * - * @param vaultProperties must not be {@literal null}. - * @return the {@link ClientAuthentication} adapter. - */ - public static ClientAuthentication token(VaultProperties vaultProperties) { - return new TokenClientAuthentication(vaultProperties); - } - - /** - * Creates a generic authentication adapter. - * - * @param vaultProperties must not be {@literal null}. - * @param vaultClient must not be {@literal null}. - * @return the {@link ClientAuthentication} adapter. - */ - public static ClientAuthentication create(VaultProperties vaultProperties, - VaultClient vaultClient) { - return new DefaultClientAuthentication(vaultProperties, vaultClient); - } - - /** - * Creates an AppId-based authentication adapter. - * - * @param vaultProperties must not be {@literal null}. - * @return the {@link ClientAuthentication} adapter. - */ - public static ClientAuthentication appId(VaultProperties vaultProperties, - VaultClient vaultClient) { - return new DefaultClientAuthentication(vaultProperties, vaultClient); - } - - /** - * Creates an AppId-based authentication adapter. - * - * @param vaultProperties must not be {@literal null}. - * @param vaultClient must not be {@literal null}. - * @param userIdMechanism must not be {@literal null}. - * @return the {@link ClientAuthentication} adapter. - */ - public static ClientAuthentication appId(VaultProperties vaultProperties, - VaultClient vaultClient, AppIdUserIdMechanism userIdMechanism) { - return new DefaultClientAuthentication(vaultProperties, vaultClient, - userIdMechanism); - } -} diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactory.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactory.java deleted file mode 100644 index 2ecd347c..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactory.java +++ /dev/null @@ -1,284 +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.io.IOException; -import java.io.InputStream; -import java.security.GeneralSecurityException; -import java.security.KeyStore; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; - -import org.springframework.cloud.vault.VaultProperties.Ssl; -import org.springframework.core.io.Resource; -import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.http.client.Netty4ClientHttpRequestFactory; -import org.springframework.http.client.OkHttpClientHttpRequestFactory; -import org.springframework.http.client.SimpleClientHttpRequestFactory; -import org.springframework.util.ClassUtils; -import org.springframework.util.StringUtils; - -import com.squareup.okhttp.OkHttpClient; - -import io.netty.handler.ssl.SslContextBuilder; -import io.netty.handler.ssl.SslProvider; -import lombok.extern.apachecommons.CommonsLog; - -import org.apache.http.client.config.RequestConfig; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; - -/** - * Factory for {@link ClientHttpRequestFactory} that supports Apache HTTP Components, - * OkHttp, Netty and the JDK HTTP client (in that order). This factory configures a - * {@link ClientHttpRequestFactory} depending on the available dependencies. - * - * @author Mark Paluch - */ -@CommonsLog -class ClientHttpRequestFactoryFactory { - - private final static boolean HTTP_COMPONENTS_PRESENT = ClassUtils.isPresent( - "org.apache.http.client.HttpClient", - ClientHttpRequestFactoryFactory.class.getClassLoader()); - - private final static boolean OKHTTP_PRESENT = ClassUtils.isPresent( - "com.squareup.okhttp.OkHttpClient", - ClientHttpRequestFactoryFactory.class.getClassLoader()); - - private final static boolean NETTY_PRESENT = ClassUtils.isPresent( - "io.netty.channel.nio.NioEventLoopGroup", - ClientHttpRequestFactoryFactory.class.getClassLoader()); - - /** - * Creates a {@link ClientHttpRequestFactory} for the given {@link VaultProperties}. - * - * @param vaultProperties must not be {@literal null} - * @return a new {@link ClientHttpRequestFactory}. Lifecycle beans must be initialized - * after obtaining. - */ - public static ClientHttpRequestFactory create(VaultProperties vaultProperties) { - - try { - - if (HTTP_COMPONENTS_PRESENT) { - return HttpComponents.usingHttpComponents(vaultProperties); - } - - if (OKHTTP_PRESENT) { - return OkHttp.usingOkHttp(vaultProperties); - } - - if (NETTY_PRESENT) { - return Netty.usingNetty(vaultProperties); - } - - } - catch (IOException | GeneralSecurityException e) { - throw new IllegalStateException(e); - } - - if (hasSslConfiguration(vaultProperties)) { - log.warn("VaultProperties has SSL configured but the SSL configuration " - + "must be applied outside the Vault Client to use the JDK HTTP client"); - } - - return new SimpleClientHttpRequestFactory(); - } - - private static SSLContext getSSLContext(VaultProperties.Ssl ssl) - throws GeneralSecurityException, IOException { - - KeyManager[] keyManagers = ssl.getKeyStore() != null ? createKeyManagerFactory( - ssl.getKeyStore(), ssl.getKeyStorePassword()).getKeyManagers() : null; - - TrustManager[] trustManagers = ssl.getTrustStore() != null ? createTrustManagerFactory( - ssl.getTrustStore(), ssl.getTrustStorePassword()).getTrustManagers() - : null; - - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(keyManagers, trustManagers, null); - - return sslContext; - } - - private static KeyManagerFactory createKeyManagerFactory(Resource keystoreFile, - String storePassword) throws GeneralSecurityException, IOException { - - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - - try (InputStream inputStream = keystoreFile.getInputStream()) { - keyStore.load(inputStream, - StringUtils.hasText(storePassword) ? storePassword.toCharArray() - : null); - } - - KeyManagerFactory keyManagerFactory = KeyManagerFactory - .getInstance(KeyManagerFactory.getDefaultAlgorithm()); - keyManagerFactory.init(keyStore, - StringUtils.hasText(storePassword) ? storePassword.toCharArray() - : new char[0]); - - return keyManagerFactory; - } - - private static TrustManagerFactory createTrustManagerFactory(Resource trustFile, - String storePassword) throws GeneralSecurityException, IOException { - - KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); - - try (InputStream inputStream = trustFile.getInputStream()) { - trustStore.load(inputStream, - StringUtils.hasText(storePassword) ? storePassword.toCharArray() - : null); - } - - TrustManagerFactory trustManagerFactory = TrustManagerFactory - .getInstance(TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init(trustStore); - - return trustManagerFactory; - } - - private static boolean hasSslConfiguration(VaultProperties vaultProperties) { - - Ssl ssl = vaultProperties.getSsl(); - - if (ssl == null) { - return false; - } - - return ssl.getTrustStore() != null || ssl.getKeyStore() != null; - } - - /** - * {@link ClientHttpRequestFactory} for Apache Http Components. - * - * @author Mark Paluch - */ - static class HttpComponents { - - static ClientHttpRequestFactory usingHttpComponents( - VaultProperties vaultProperties) throws GeneralSecurityException, - IOException { - - HttpClientBuilder httpClientBuilder = HttpClients.custom(); - - if (hasSslConfiguration(vaultProperties)) { - - SSLContext sslContext = getSSLContext(vaultProperties.getSsl()); - SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory( - sslContext); - httpClientBuilder.setSSLSocketFactory(sslSocketFactory); - httpClientBuilder.setSSLContext(sslContext); - } - - RequestConfig requestConfig = RequestConfig.custom() // - .setConnectTimeout(vaultProperties.getConnectionTimeout()) // - .setSocketTimeout(vaultProperties.getReadTimeout()) // - .setAuthenticationEnabled(true) // - .build(); - - httpClientBuilder.setDefaultRequestConfig(requestConfig); - - return new HttpComponentsClientHttpRequestFactory(httpClientBuilder.build()); - } - } - - /** - * {@link ClientHttpRequestFactory} for the {@link OkHttpClient}. - * - * @author Mark Paluch - */ - static class OkHttp { - - static ClientHttpRequestFactory usingOkHttp(VaultProperties vaultProperties) - throws GeneralSecurityException, IOException { - - final OkHttpClient okHttpClient = new OkHttpClient(); - - OkHttpClientHttpRequestFactory requestFactory = new OkHttpClientHttpRequestFactory( - okHttpClient) { - - @Override - public void destroy() throws IOException { - - 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 { - - static ClientHttpRequestFactory usingNetty(VaultProperties vaultProperties) - throws GeneralSecurityException, IOException { - - VaultProperties.Ssl ssl = vaultProperties.getSsl(); - - final Netty4ClientHttpRequestFactory requestFactory = new Netty4ClientHttpRequestFactory(); - - if (hasSslConfiguration(vaultProperties)) { - - SslContextBuilder sslContextBuilder = SslContextBuilder // - .forClient(); - - if (ssl.getTrustStore() != null) { - sslContextBuilder.trustManager(createTrustManagerFactory( - ssl.getTrustStore(), ssl.getTrustStorePassword())); - } - - if (ssl.getKeyStore() != null) { - sslContextBuilder.keyManager(createKeyManagerFactory( - ssl.getKeyStore(), ssl.getKeyStorePassword())); - } - - requestFactory.setSslContext(sslContextBuilder.sslProvider( - SslProvider.JDK).build()); - } - - requestFactory.setConnectTimeout(vaultProperties.getConnectionTimeout()); - requestFactory.setReadTimeout(vaultProperties.getReadTimeout()); - - return requestFactory; - } - } -} diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/DefaultClientAuthentication.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/DefaultClientAuthentication.java deleted file mode 100644 index b6955c81..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/DefaultClientAuthentication.java +++ /dev/null @@ -1,234 +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.net.URI; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import org.springframework.cloud.vault.VaultProperties.AuthenticationMethod; -import org.springframework.cloud.vault.VaultProperties.Ssl; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; -import org.springframework.web.client.RestTemplate; - -import lombok.Value; -import lombok.extern.apachecommons.CommonsLog; - -/** - * Default implementation of {@link ClientAuthentication}. - * - * @author Mark Paluch - */ -@CommonsLog -class DefaultClientAuthentication extends ClientAuthentication { - - private final VaultProperties properties; - private final VaultClient vaultClient; - private final AppIdUserIdMechanism appIdUserIdMechanism; - private char[] nonce; - - /** - * Creates a {@link DefaultClientAuthentication} using {@link VaultProperties} and - * {@link RestTemplate}. - * - * @param properties must not be {@literal null}. - * @param vaultClient must not be {@literal null}. - */ - DefaultClientAuthentication(VaultProperties properties, VaultClient vaultClient) { - - Assert.notNull(properties, "VaultProperties must not be null"); - Assert.notNull(vaultClient, "RestTemplate must not be null"); - - this.properties = properties; - this.vaultClient = vaultClient; - this.appIdUserIdMechanism = null; - } - - /** - * Creates a {@link DefaultClientAuthentication} using {@link VaultProperties} and - * {@link RestTemplate} for AppId authentication. - * - * @param properties must not be {@literal null}. - * @param vaultClient must not be {@literal null}. - * @param appIdUserIdMechanism must not be {@literal null}. - */ - DefaultClientAuthentication(VaultProperties properties, VaultClient vaultClient, - AppIdUserIdMechanism appIdUserIdMechanism) { - - Assert.notNull(properties, "VaultProperties must not be null"); - Assert.notNull(vaultClient, "VaultClient must not be null"); - Assert.notNull(appIdUserIdMechanism, "AppIdUserIdMechanism must not be null"); - - this.properties = properties; - this.vaultClient = vaultClient; - this.appIdUserIdMechanism = appIdUserIdMechanism; - } - - @Override - public VaultToken login() { - - if (properties.getAuthentication() == VaultProperties.AuthenticationMethod.APPID - && appIdUserIdMechanism != null) { - log.info("Using AppId authentication to log into Vault"); - - VaultProperties.AppIdProperties appId = properties.getAppId(); - return createTokenUsingAppId(new AppIdTuple(properties.getApplicationName(), - appIdUserIdMechanism.createUserId()), appId); - } - - if (properties.getAuthentication() == AuthenticationMethod.CERT - && properties.getSsl() != null) { - log.info("Using TLS Certificate authentication to log into Vault"); - - return createTokenUsingTlsCertAuthentication(properties.getSsl()); - } - - if (properties.getAuthentication() == VaultProperties.AuthenticationMethod.AWS_EC2) { - log.info("Using AWS-EC2 authentication to log into Vault"); - - return createTokenUsingAwsEc2(); - } - - throw new UnsupportedOperationException(String.format( - "Cannot create a token for auth method %s", - properties.getAuthentication())); - } - - private VaultToken createTokenUsingAppId(AppIdTuple appIdTuple, - VaultProperties.AppIdProperties appId) { - - URI uri = VaultClient.buildUri(properties, - String.format("auth/%s/login", appId.getAppIdPath())); - - Map login = getAppIdLogin(appIdTuple); - - VaultClientResponse response = vaultClient.write(uri, login); - - if (!response.isSuccessful()) { - throw new IllegalStateException(String.format( - "Cannot login using app-id: %s", response.getMessage())); - } - - VaultResponse body = response.getBody(); - String token = (String) body.getAuth().get("client_token"); - - log.debug("Login successful using AppId authentication"); - - return VaultToken.of(token, body.getLeaseDuration()); - } - - private VaultToken createTokenUsingTlsCertAuthentication(Ssl ssl) { - - URI uri = VaultClient.buildUri(properties, - String.format("auth/%s/login", ssl.getCertAuthPath())); - - VaultClientResponse response = vaultClient.write(uri, Collections.emptyMap()); - - if (!response.isSuccessful()) { - throw new IllegalStateException(String.format( - "Cannot login using TLS certificates: %s", response.getMessage())); - } - - VaultResponse body = response.getBody(); - String token = (String) body.getAuth().get("client_token"); - - log.debug("Login successful using TLS certificates"); - - return VaultToken.of(token, body.getLeaseDuration()); - } - - private Map getAppIdLogin(AppIdTuple appIdTuple) { - - Map login = new HashMap<>(); - login.put("app_id", appIdTuple.getAppId()); - login.put("user_id", appIdTuple.getUserId()); - return login; - } - - @SuppressWarnings("unchecked") - private VaultToken createTokenUsingAwsEc2() { - - VaultProperties.AwsEc2Properties awsEc2 = this.properties.getAwsEc2(); - - URI uri = VaultClient.buildUri(this.properties, - String.format("auth/%s/login", awsEc2.getAwsEc2Path())); - - Map login = getEc2Login(awsEc2); - - VaultClientResponse response = vaultClient.write(uri, login); - - if (!response.isSuccessful()) { - throw new IllegalStateException(String.format( - "Cannot login using AWS-EC2: %s", response.getMessage())); - } - - VaultResponse body = response.getBody(); - String token = (String) body.getAuth().get("client_token"); - - if (log.isDebugEnabled()) { - - if (body.getAuth().get("metadata") instanceof Map) { - Map metadata = (Map) body.getAuth().get( - "metadata"); - log.debug(String - .format("Login successful using AWS-EC2 authentication for instance %s, AMI %s", - metadata.get("instance_id"), metadata.get("instance_id"))); - } - else { - log.debug("Login successful using AWS-EC2 authentication"); - } - } - - return VaultToken.of(token, body.getLeaseDuration()); - } - - private Map getEc2Login(VaultProperties.AwsEc2Properties properties) { - - Map login = new HashMap<>(); - - if (StringUtils.hasText(properties.getRole())) { - login.put("role", properties.getRole()); - } - - if (properties.isUseNonce()) { - if (this.nonce == null) { - this.nonce = createNonce(); - } - - login.put("nonce", new String(this.nonce)); - } - - String pkcs7 = vaultClient.getRestTemplate().getForObject( - properties.getIdentityDocument(), String.class); - if (StringUtils.hasText(pkcs7)) { - login.put("pkcs7", pkcs7.replaceAll("\\r", "").replace("\\n", "")); - } - return login; - } - - private char[] createNonce() { - return UUID.randomUUID().toString().toCharArray(); - } - - @Value - private static class AppIdTuple { - private String appId; - private String userId; - } -} diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/IpAddressUserId.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/IpAddressUserId.java deleted file mode 100644 index 5b30edda..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/IpAddressUserId.java +++ /dev/null @@ -1,38 +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.io.IOException; -import java.net.InetAddress; - -/** - * Mechanism to generate a SHA-256 hashed and hex-encoded representation of the IP address. Can be calculated with - * {@code echo -n 192.168.99.1 | sha256sum}. - * - * @author Mark Paluch - */ -public class IpAddressUserId implements AppIdUserIdMechanism { - - @Override - public String createUserId() { - try { - return Sha256.toSha256(InetAddress.getLocalHost().getHostAddress()); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } -} diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/MacAddressUserId.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/MacAddressUserId.java deleted file mode 100644 index 5130294a..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/MacAddressUserId.java +++ /dev/null @@ -1,110 +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.io.IOException; -import java.net.InetAddress; -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; - -/** - * 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 VaultProperties.AppIdProperties#networkInterface} can be - * specified optionally to select a network interface (index/name). - * - * @author Mark Paluch - */ -@Value -@RequiredArgsConstructor -@CommonsLog -public class MacAddressUserId implements AppIdUserIdMechanism { - - private final VaultProperties vaultProperties; - - @Override - public String createUserId() { - try { - - NetworkInterface networkInterface = null; - List interfaces = Collections.list(NetworkInterface.getNetworkInterfaces()); - - VaultProperties.AppIdProperties appId = vaultProperties.getAppId(); - if (StringUtils.hasText(appId.getNetworkInterface())) { - try { - networkInterface = getNetworkInterface(Integer.parseInt(appId.getNetworkInterface()), interfaces); - } catch (NumberFormatException e) { - networkInterface = getNetworkInterface((appId.getNetworkInterface()), interfaces); - } - } - - if (networkInterface == null) { - if (StringUtils.hasText(appId.getNetworkInterface())) { - log.warn( - String.format("Did not find a NetworkInterface applying hint %s", appId.getNetworkInterface())); - } - - InetAddress localHost = InetAddress.getLocalHost(); - networkInterface = NetworkInterface.getByInetAddress(localHost); - - if (networkInterface == null) { - throw new IllegalStateException(String.format("Cannot determine NetworkInterface for %s", localHost)); - } - } - - byte[] mac = networkInterface.getHardwareAddress(); - if (mac == null) { - throw new IllegalStateException(String.format("Network interface %s has no hardware address", networkInterface.getName())); - } - - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < mac.length; i++) { - sb.append(String.format("%02X", mac[i])); - } - return Sha256.toSha256(sb.toString()); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - private NetworkInterface getNetworkInterface(Number hint, List interfaces) { - - if (interfaces.size() > hint.intValue() && hint.intValue() >= 0) { - return interfaces.get(hint.intValue()); - } - - return null; - } - - private NetworkInterface getNetworkInterface(String hint, List interfaces) { - - for (NetworkInterface anInterface : interfaces) { - if (hint.equals(anInterface.getDisplayName()) || hint.equals(anInterface.getName())) { - return anInterface; - } - } - - return null; - } -} diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/Sha256.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/Sha256.java deleted file mode 100644 index 54072f1d..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/Sha256.java +++ /dev/null @@ -1,64 +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.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import org.springframework.security.crypto.codec.Hex; -import org.springframework.util.Assert; - -/** - * Utility to generate a SHA 256 checksum. - * - * @author Mark Paluch - */ -class Sha256 { - - /** - * Generates a hex-encoded SHA256 checksum from the supplied {@code content}. - * - * @param content must not be {@literal null} and not empty. - * @return hex-encoded SHA256 checksum - */ - public static String toSha256(String content) { - - Assert.hasText(content, "Content must not be empty"); - - MessageDigest messageDigest = getMessageDigest("SHA-256"); - byte[] digest = messageDigest.digest(content.getBytes(StandardCharsets.US_ASCII)); - return new String(Hex.encode(digest)); - } - - /** - * Get a MessageDigest instance for the given algorithm. Throws an - * IllegalArgumentException if algorithm is unknown - * - * @return MessageDigest instance - * @throws IllegalArgumentException if NoSuchAlgorithmException is thrown - */ - private static MessageDigest getMessageDigest(String algorithm) - throws IllegalArgumentException { - try { - return MessageDigest.getInstance(algorithm); - } - catch (NoSuchAlgorithmException e) { - throw new IllegalArgumentException("No such algorithm [" + algorithm + "]"); - } - } -} diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/StaticUserId.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/StaticUserId.java deleted file mode 100644 index 8b375252..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/StaticUserId.java +++ /dev/null @@ -1,38 +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 lombok.RequiredArgsConstructor; -import lombok.Value; -import lombok.extern.apachecommons.CommonsLog; - -/** - * A static UserId. - * @author Mark Paluch - */ -@Value -@RequiredArgsConstructor -@CommonsLog -public class StaticUserId implements AppIdUserIdMechanism { - - private final VaultProperties vaultProperties; - - @Override - public String createUserId() { - return vaultProperties.getAppId().getUserId(); - } -} diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/TokenClientAuthentication.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/TokenClientAuthentication.java deleted file mode 100644 index b89a4db7..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/TokenClientAuthentication.java +++ /dev/null @@ -1,46 +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 org.springframework.util.Assert; - -/** - * Static Token-based client authentication method. - * - * @author Mark Paluch - */ -class TokenClientAuthentication extends ClientAuthentication { - - private final VaultProperties vaultProperties; - - TokenClientAuthentication(VaultProperties vaultProperties) { - - Assert.notNull(vaultProperties); - Assert.isTrue( - vaultProperties - .getAuthentication() == VaultProperties.AuthenticationMethod.TOKEN, - String.format("Authentication must be Token but is %s", - vaultProperties.getAuthentication())); - Assert.hasText(vaultProperties.getToken(), "Token must not be empty"); - - this.vaultProperties = vaultProperties; - } - - @Override - public VaultToken login() { - return VaultToken.of(vaultProperties.getToken()); - } -} diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultBootstrapConfiguration.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultBootstrapConfiguration.java deleted file mode 100644 index 0536227b..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultBootstrapConfiguration.java +++ /dev/null @@ -1,121 +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 org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; -import org.springframework.web.client.RestTemplate; - -/** - * @author Spencer Gibb - * @author Mark Paluch - */ -@Configuration -@EnableConfigurationProperties -@ConditionalOnProperty(name = "spring.cloud.vault.enabled", matchIfMissing = true) -public class VaultBootstrapConfiguration { - - @Bean - public ClientFactoryWrapper clientHttpRequestFactoryWrapper() { - return new ClientFactoryWrapper( - ClientHttpRequestFactoryFactory.create(vaultProperties())); - } - - @Bean - public VaultClient vaultClient(ApplicationContext applicationContext) { - - RestTemplate restTemplate = new RestTemplate( - clientHttpRequestFactoryWrapper().getClientHttpRequestFactory()); - - VaultClient vaultClient = new VaultClient(); - vaultClient.setRestTemplate(restTemplate); - - return vaultClient; - } - - @Bean - public VaultProperties vaultProperties() { - return new VaultProperties(); - } - - @Bean - @ConditionalOnMissingBean - @ConditionalOnProperty(prefix = "spring.cloud.vault", name = "authentication", havingValue = "APPID") - public AppIdUserIdMechanism appIdUserIdMechanism(VaultProperties vaultProperties) { - - String userId = vaultProperties.getAppId().getUserId(); - Assert.hasText(userId, - "UserId (spring.cloud.vault.app-id.user-id) must not be empty."); - - try { - Class userIdClass = ClassUtils.forName(userId, null); - return (AppIdUserIdMechanism) BeanUtils.instantiateClass(userIdClass); - } - catch (ClassNotFoundException ex) { - - switch (userId.toUpperCase()) { - case VaultProperties.AppIdProperties.IP_ADDRESS: - return new IpAddressUserId(); - case VaultProperties.AppIdProperties.MAC_ADDRESS: - return new MacAddressUserId(vaultProperties); - default: - return new StaticUserId(vaultProperties); - } - } - } - - /** - * Wrapper for {@link ClientHttpRequestFactory} to not expose the bean globally. - */ - public 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-core/src/main/java/org/springframework/cloud/vault/VaultClient.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultClient.java deleted file mode 100644 index e1b799de..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultClient.java +++ /dev/null @@ -1,208 +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 com.fasterxml.jackson.databind.ObjectMapper; - -import java.net.URI; -import java.util.Map; - -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.util.Assert; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.HttpStatusCodeException; -import org.springframework.web.client.RestTemplate; - -import lombok.Getter; -import lombok.Setter; - -/** - * Vault client. This client reads data from Vault. - * - * @author Spencer Gibb - * @author Mark Paluch - */ -public class VaultClient { - - public static final String API_VERSION = "v1"; - public static final String VAULT_TOKEN = "X-Vault-Token"; - - @Setter - @Getter - private RestTemplate restTemplate; - - public VaultClient() { - this(new RestTemplate()); - } - - public VaultClient(RestTemplate restTemplate) { - this.restTemplate = restTemplate; - } - - /** - * Read data from the given Vault {@code uri} using the {@link VaultToken}. - * - * @param uri must not be {@literal null}. - * @param vaultToken must not be {@literal null}. - * @return A {@link Map} containing properties. - */ - public VaultClientResponse read(URI uri, VaultToken vaultToken) { - - Assert.notNull(uri, "URI must not be empty!"); - Assert.notNull(vaultToken, "Vault Token must not be null!"); - - return exchange(uri, HttpMethod.GET, new HttpEntity<>(createHeaders(vaultToken))); - } - - /** - * Write data to the given Vault {@code uri} using the {@link VaultToken}. - * - * @param uri must not be {@literal null}. - * @param entity must not be {@literal null}. - * @return A {@link Map} containing properties. - */ - public VaultClientResponse write(URI uri, Object entity) { - - Assert.notNull(uri, "URI must not be empty!"); - Assert.notNull(entity, "Entity must not be null!"); - - return exchange(uri, HttpMethod.POST, new HttpEntity<>(entity)); - } - - /** - * Write data to the given Vault {@code uri} using the {@link VaultToken}. - * - * @param uri must not be {@literal null}. - * @param entity must not be {@literal null}. - * @param vaultToken must not be {@literal null}. - * @return A {@link Map} containing properties. - */ - public VaultClientResponse write(URI uri, Object entity, VaultToken vaultToken) { - - Assert.notNull(uri, "URI must not be empty!"); - Assert.notNull(entity, "Vault Token must not be null!"); - Assert.notNull(vaultToken, "Vault Token must not be null!"); - - return exchange(uri, HttpMethod.POST, new HttpEntity<>(entity, - createHeaders(vaultToken))); - } - - /** - * Query the current Vault service for it's health status - * - * @param uri must not be {@literal null}. - * @return A {@link VaultHealthResponse} containing the current service status. - */ - public VaultHealthResponse health(URI uri) { - try { - ResponseEntity healthResponse = this.restTemplate.exchange( - uri, HttpMethod.GET, null, - VaultHealthResponse.class); - return healthResponse.getBody(); - } catch (HttpStatusCodeException responseError) { - try { - ObjectMapper mapper = new ObjectMapper(); - return mapper.readValue(responseError.getResponseBodyAsString(), VaultHealthResponse.class); - } - catch (Exception jsonError) { - throw responseError; - } - } - } - - private VaultClientResponse exchange(URI uri, HttpMethod httpMethod, - HttpEntity httpEntity) { - - Assert.notNull(uri, "URI must not be empty!"); - - try { - ResponseEntity response = this.restTemplate.exchange(uri, - httpMethod, httpEntity, VaultResponse.class); - - return VaultClientResponse.of(response.getBody(), response.getStatusCode(), - uri, response.getStatusCode().getReasonPhrase()); - } - catch (HttpServerErrorException | HttpClientErrorException e) { - - String message = e.getResponseBodyAsString(); - - if (MediaType.APPLICATION_JSON.includes(e.getResponseHeaders() - .getContentType())) { - message = VaultErrorMessage.getError(message); - } - - return VaultClientResponse.of(null, e.getStatusCode(), uri, message); - } - } - - /** - * Build the Vault {@link URI} based on the given {@link VaultProperties} and - * {@code path}. - * - * @param properties must not be {@literal null}. - * @param path must not be empty or {@literal null}. - * @return - */ - public static URI buildUri(VaultProperties properties, String path) { - return URI.create(createBaseUrlWithPath(properties, path)); - } - - /** - * Build the Vault {@link URI} based on the given {@link VaultProperties} and - * {@code pathTemplate}. URI template variables will be expanded using - * {@code uriVariables}. - * - * @param properties must not be {@literal null}. - * @param pathTemplate must not be empty or {@literal null}. - * @param uriVariables must not be {@literal null}. - * @see org.springframework.web.util.UriComponentsBuilder - * @return - */ - public URI buildUri(VaultProperties properties, String pathTemplate, - Map uriVariables) { - - Assert.notNull(properties, "VaultProperties must not be null!"); - Assert.hasText(pathTemplate, "Path must not be empty!"); - Assert.notNull(properties, "Vault Token must not be null!"); - - return restTemplate.getUriTemplateHandler().expand( - createBaseUrlWithPath(properties, pathTemplate), uriVariables); - } - - private HttpHeaders createHeaders(VaultToken vaultToken) { - - Assert.notNull(vaultToken, "Vault Token must not be null!"); - - HttpHeaders headers = new HttpHeaders(); - headers.add(VAULT_TOKEN, vaultToken.getToken()); - return headers; - } - - private static String createBaseUrlWithPath(VaultProperties properties, String path) { - - Assert.notNull(properties, "VaultProperties must not be null!"); - Assert.hasText(path, "Path must not be empty!"); - - return String.format("%s://%s:%s/%s/%s", properties.getScheme(), - properties.getHost(), properties.getPort(), API_VERSION, path); - } - -} diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultClientResponse.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultClientResponse.java deleted file mode 100644 index e29065fe..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultClientResponse.java +++ /dev/null @@ -1,48 +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.net.URI; - -import org.springframework.http.HttpStatus; - -import lombok.Value; - -/** - * Encapsulates the client response used in {@link VaultClient}. Consists of the body, - * status code the location and a message. The {@code body} is empty for all - * non-successful results. - * - * This class is immutable. - * - * @author Mark Paluch - */ -@Value(staticConstructor = "of") -public class VaultClientResponse { - - private VaultResponse body; - private HttpStatus statusCode; - private URI uri; - private String message; - - /** - * - * @return {@literal true} if the request was completed successfully. - */ - public boolean isSuccessful() { - return body != null && statusCode.is2xxSuccessful(); - } -} diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultErrorMessage.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultErrorMessage.java deleted file mode 100644 index fe2ce115..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultErrorMessage.java +++ /dev/null @@ -1,63 +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.io.IOException; -import java.util.Collection; -import java.util.Map; - -import com.fasterxml.jackson.databind.ObjectMapper; - -/** - * Utility to obtain a Vault error message. - * - * @author Mark Paluch - */ -class VaultErrorMessage { - - private final static ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - - /** - * Obtain the error message from a JSON response. - * - * @param json - * @return - */ - static String getError(String json) { - - if (json.contains("\"errors\":")) { - - try { - Map map = OBJECT_MAPPER.readValue(json.getBytes(), - Map.class); - if (map.containsKey("errors")) { - - Collection errors = (Collection) map.get("errors"); - if (errors.size() == 1) { - return errors.iterator().next(); - } - return errors.toString(); - } - - } - catch (IOException o_O) { - // ignore - } - } - return json; - } -} diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultHealthResponse.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultHealthResponse.java deleted file mode 100644 index 50bfb1a4..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultHealthResponse.java +++ /dev/null @@ -1,38 +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 lombok.Data; - -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * Value object to bind HTTP API responses for sys/health. - * - * @author Stuart Ingram - * @author Bill Koch - */ -@Data -public class VaultHealthResponse { - - private boolean initialized; - private boolean sealed; - private boolean standby; - - @JsonProperty("server_time_utc") - private int serverTimeUtc; -} diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultResponse.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultResponse.java deleted file mode 100644 index d6fb745a..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultResponse.java +++ /dev/null @@ -1,44 +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.Map; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import lombok.Data; - -/** - * Value object to bind HTTP API responses. - * - * @author Spencer Gibb - * @author Mark Paluch - */ -@Data -public class VaultResponse { - - private Map auth; - private Map data; - private Map metadata; - - @JsonProperty("lease_duration") - private long leaseDuration; - - @JsonProperty("lease_id") - private String leaseId; - private boolean renewable; -} \ No newline at end of file diff --git a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultToken.java b/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultToken.java deleted file mode 100644 index 693a248c..00000000 --- a/spring-cloud-vault-core/src/main/java/org/springframework/cloud/vault/VaultToken.java +++ /dev/null @@ -1,56 +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 org.springframework.util.Assert; - -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Value; - -/** - * Value object for a Vault token. - * - * @author Mark Paluch - */ -@Value -@AllArgsConstructor(access = AccessLevel.PRIVATE) -public class VaultToken { - - private String token; - private long leaseDuration; - - /** - * Creates a new {@link VaultToken}. - * @param token must not be {@literal null}. - * @return the created {@link VaultToken} - */ - public static VaultToken of(String token) { - return of(token, 0); - } - - /** - * Creates a new {@link VaultToken} with a {@code leaseDuration}. - * @param token must not be {@literal null}. - * @return the created {@link VaultToken} - */ - public static VaultToken of(String token, long leaseDuration) { - - Assert.hasText(token, "Token must not be empty"); - return new VaultToken(token, leaseDuration); - } -} 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 deleted file mode 100644 index ec4d51a7..00000000 --- a/spring-cloud-vault-core/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,3 +0,0 @@ -# Bootstrap Configuration -org.springframework.cloud.bootstrap.BootstrapConfiguration=\ -org.springframework.cloud.vault.VaultBootstrapConfiguration \ No newline at end of file diff --git a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/AppIdAuthenticationMethodsIntegrationTests.java b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/AppIdAuthenticationMethodsIntegrationTests.java deleted file mode 100644 index 4101693e..00000000 --- a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/AppIdAuthenticationMethodsIntegrationTests.java +++ /dev/null @@ -1,151 +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.net.NetworkInterface; -import java.net.SocketException; -import java.util.Enumeration; - -import org.springframework.cloud.vault.VaultProperties.AppIdProperties; -import org.springframework.cloud.vault.VaultProperties.AuthenticationMethod; -import org.springframework.cloud.vault.util.Settings; - -import static org.assertj.core.api.Assertions.*; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -/** - * Integration tests for {@link VaultClient} using various UserIds. - * - * @author Mark Paluch - */ -public class AppIdAuthenticationMethodsIntegrationTests extends AbstractIntegrationTests { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Before - public void setUp() throws Exception { - - if (!prepare().hasAuth("app-id")) { - prepare().mountAuth("app-id"); - } - - prepare().mapAppId("myapp"); - } - - @Test - public void loginUsingIpAddressShouldCreateAToken() throws Exception { - - VaultProperties vaultProperties = prepareAppIdAuthenticationMethod( - AppIdProperties.IP_ADDRESS, "myapp"); - - ClientAuthentication clientAuthentication = new DefaultClientAuthentication( - vaultProperties, prepare().newVaultClient(), new IpAddressUserId()); - - assertThat(clientAuthentication.login()).isNotNull(); - } - - @Test - public void loginUsingStaticUserIdShouldCreateAToken() throws Exception { - - VaultProperties vaultProperties = prepareAppIdAuthenticationMethod("my-user-id", - "myapp"); - - ClientAuthentication clientAuthentication = new DefaultClientAuthentication( - vaultProperties, prepare().newVaultClient(), new StaticUserId( - vaultProperties)); - - assertThat(clientAuthentication.login()).isNotNull(); - } - - @Test - public void loginUsingMacAddressShouldCreateAToken() throws Exception { - - VaultProperties vaultProperties = prepareAppIdAuthenticationMethod( - AppIdProperties.MAC_ADDRESS, "myapp"); - - ClientAuthentication clientAuthentication = new DefaultClientAuthentication( - vaultProperties, prepare().newVaultClient(), new MacAddressUserId( - vaultProperties)); - - assertThat(clientAuthentication.login()).isNotNull(); - } - - @Test - public void invalidLogin() throws Exception { - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Cannot login using app-id"); - - VaultProperties vaultProperties = prepareAppIdAuthenticationMethod( - AppIdProperties.IP_ADDRESS, "myapp"); - vaultProperties.setApplicationName("foobar"); - - ClientAuthentication clientAuthentication = new DefaultClientAuthentication( - vaultProperties, prepare().newVaultClient(), new MacAddressUserId( - vaultProperties)); - - clientAuthentication.login(); - - fail("Missing IllegalStateException"); - } - - private VaultProperties prepareAppIdAuthenticationMethod(String userId, String appId) - throws SocketException { - - VaultProperties vaultProperties = Settings.createVaultProperties(); - - AppIdProperties appIdProperties = new AppIdProperties(); - vaultProperties.setApplicationName(appId); - appIdProperties.setUserId(userId); - - Enumeration networkInterfaces = NetworkInterface - .getNetworkInterfaces(); - NetworkInterface networkInterface = null; - while (networkInterfaces.hasMoreElements()) { - networkInterface = networkInterfaces.nextElement(); - if (networkInterface.getHardwareAddress() != null) { - break; - } - } - - // make sure we have always a network interface even if the localhost reverse - // lookup maps to an IP address that is not handled by this host. - appIdProperties.setNetworkInterface(networkInterface.getName()); - - vaultProperties.setAuthentication(AuthenticationMethod.APPID); - vaultProperties.setAppId(appIdProperties); - - String userIdValue; - if (userId.equals(AppIdProperties.IP_ADDRESS)) { - userIdValue = new IpAddressUserId().createUserId(); - } - else if (userId.equals(AppIdProperties.MAC_ADDRESS)) { - userIdValue = new MacAddressUserId(vaultProperties).createUserId(); - } - else { - userIdValue = userId; - } - - prepare().mapUserId(vaultProperties.getApplicationName(), userIdValue); - - return vaultProperties; - } -} diff --git a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/AwsEc2AuthenticationMethodsIntegrationTests.java b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/AwsEc2AuthenticationMethodsIntegrationTests.java deleted file mode 100644 index d3934122..00000000 --- a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/AwsEc2AuthenticationMethodsIntegrationTests.java +++ /dev/null @@ -1,93 +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.Collections; -import java.util.HashMap; -import java.util.Map; - -import org.springframework.boot.test.IntegrationTest; -import org.springframework.cloud.vault.VaultProperties.AuthenticationMethod; -import org.springframework.cloud.vault.util.Settings; -import org.springframework.util.StringUtils; - -import static org.assertj.core.api.Assertions.*; -import static org.junit.Assume.*; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -/** - * Integration tests for {@link VaultClient} using AWS-EC2 login. This test requires AWS - * credentials, a region and an AMI, see {@link #AWS_ACCESS_KEY}, {@link #AWS_SECRET_KEY} - * and the {@link IntegrationTest} properties to be provided externally. It needs to be - * run on a AWS-EC2 instance to be able to obtain instance metadata. - * - * @author Mark Paluch - */ -public class AwsEc2AuthenticationMethodsIntegrationTests extends AbstractIntegrationTests { - - private final static String AWS_REGION = "eu-west-1"; - private final static String AWS_AMI = "ami-f95ef58a"; - private final static String AWS_ACCESS_KEY = System.getProperty("aws.access.key"); - private final static String AWS_SECRET_KEY = System.getProperty("aws.secret.key"); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Before - public void setUp() throws Exception { - - assumeTrue(StringUtils.hasText(AWS_ACCESS_KEY) - && StringUtils.hasText(AWS_SECRET_KEY)); - - if (!prepare().hasAuth("aws-ec2")) { - prepare().mountAuth("aws-ec2"); - } - - Map config = new HashMap<>(); - config.put("access_key", AWS_ACCESS_KEY); - config.put("secret_key", AWS_SECRET_KEY); - config.put("endpoint", String.format("https://ec2.%s.amazonaws.com", AWS_REGION)); - - prepare().write("auth/aws-ec2/config/client", config); - - prepare().write(String.format("auth/aws-ec2/role/%s", AWS_AMI), - Collections.singletonMap("bound_ami_id", AWS_AMI)); - } - - @Test - public void loginShouldCreateAToken() throws Exception { - - VaultProperties vaultProperties = prepareAwsEc2Authentication(); - - ClientAuthentication clientAuthentication = new DefaultClientAuthentication( - vaultProperties, prepare().newVaultClient()); - - assertThat(clientAuthentication.login()).isNotNull(); - } - - private VaultProperties prepareAwsEc2Authentication() { - - VaultProperties vaultProperties = Settings.createVaultProperties(); - vaultProperties.setAuthentication(AuthenticationMethod.AWS_EC2); - - return vaultProperties; - } -} diff --git a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/CertAuthenticationMethodsIntegrationTests.java b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/CertAuthenticationMethodsIntegrationTests.java deleted file mode 100644 index 03b3278d..00000000 --- a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/CertAuthenticationMethodsIntegrationTests.java +++ /dev/null @@ -1,127 +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.io.File; -import java.nio.charset.StandardCharsets; -import java.util.Collections; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.cloud.vault.ClientHttpRequestFactoryFactory.Netty; -import org.springframework.cloud.vault.ClientHttpRequestFactoryFactory.OkHttp; -import org.springframework.cloud.vault.VaultProperties.AuthenticationMethod; -import org.springframework.cloud.vault.util.Settings; -import org.springframework.core.io.FileSystemResource; -import org.springframework.http.client.ClientHttpRequestFactory; - -import static org.assertj.core.api.Assertions.*; -import static org.springframework.cloud.vault.util.Settings.*; - -import org.assertj.core.util.Files; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -/** - * Integration tests for {@link VaultClient} using TLS certificate authentication using - * various HTTP clients. - * - * @author Mark Paluch - */ -public class CertAuthenticationMethodsIntegrationTests extends AbstractIntegrationTests { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - VaultProperties vaultProperties = prepareCertAuthenticationMethod(); - - @Before - public void setUp() throws Exception { - - if (!prepare().hasAuth("cert")) { - prepare().mountAuth("cert"); - } - - File workDir = findWorkDir(); - - String certificate = Files.contentOf( - new File(workDir, "ca/certs/client.cert.pem"), StandardCharsets.US_ASCII); - - prepare().write("auth/cert/certs/my-role", - Collections.singletonMap("certificate", certificate)); - } - - @Test - public void shouldAuthenticateUsingCertificateAuthenticationUsingHttpComponents() - throws Exception { - - VaultClient client = new VaultClient( - TestRestTemplateFactory - .create(ClientHttpRequestFactoryFactory.HttpComponents - .usingHttpComponents(vaultProperties))); - - ClientAuthentication clientAuthentication = new DefaultClientAuthentication( - vaultProperties, client); - - assertThat(clientAuthentication.login()).isNotNull(); - } - - @Test - public void shouldAuthenticateUsingCertificateAuthenticationUsingOkHttp() - throws Exception { - - ClientHttpRequestFactory factory = OkHttp.usingOkHttp(vaultProperties); - - VaultClient client = new VaultClient(TestRestTemplateFactory.create(factory)); - - ClientAuthentication clientAuthentication = new DefaultClientAuthentication( - vaultProperties, client); - - assertThat(clientAuthentication.login()).isNotNull(); - - ((DisposableBean) factory).destroy(); - } - - @Test - public void shouldAuthenticateUsingCertificateAuthenticationUsingNetty() - throws Exception { - - ClientHttpRequestFactory factory = Netty.usingNetty(vaultProperties); - - VaultClient client = new VaultClient(TestRestTemplateFactory.create(factory)); - - ClientAuthentication clientAuthentication = new DefaultClientAuthentication( - vaultProperties, client); - - assertThat(clientAuthentication.login()).isNotNull(); - - ((DisposableBean) factory).destroy(); - } - - private VaultProperties prepareCertAuthenticationMethod() { - - VaultProperties vaultProperties = Settings.createVaultProperties(); - - vaultProperties.setAuthentication(AuthenticationMethod.CERT); - - vaultProperties.getSsl().setKeyStorePassword("changeit"); - vaultProperties.getSsl().setKeyStore( - new FileSystemResource(new File(findWorkDir(), "client-cert.jks"))); - - return vaultProperties; - } -} diff --git a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactoryIntegrationTests.java b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactoryIntegrationTests.java deleted file mode 100644 index 780ea77a..00000000 --- a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/ClientHttpRequestFactoryFactoryIntegrationTests.java +++ /dev/null @@ -1,98 +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 static org.assertj.core.api.AssertionsForClassTypes.*; -import static org.springframework.cloud.vault.ClientHttpRequestFactoryFactory.*; - -import org.junit.Test; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.cloud.vault.util.Settings; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.http.client.ClientHttpRequestFactory; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.http.client.Netty4ClientHttpRequestFactory; -import org.springframework.http.client.OkHttpClientHttpRequestFactory; -import org.springframework.web.client.HttpStatusCodeException; -import org.springframework.web.client.RestTemplate; - -/** - * Integration tests for {@link ClientHttpRequestFactory}. - * - * @author Mark Paluch - */ -public class ClientHttpRequestFactoryFactoryIntegrationTests { - - private VaultProperties vaultProperties = Settings.createVaultProperties(); - private String url = String.format("%s://%s:%d/v1/sys/health", vaultProperties.getScheme(), vaultProperties.getHost(), - vaultProperties.getPort()); - - @Test - public void httpComponentsClientShouldWork() throws Exception { - - ClientHttpRequestFactory factory = HttpComponents.usingHttpComponents(vaultProperties); - RestTemplate template = new RestTemplate(factory); - - String response = request(template); - - assertThat(factory).isInstanceOf(HttpComponentsClientHttpRequestFactory.class); - assertThat(response).isNotNull().contains("initialized"); - - ((DisposableBean) factory).destroy(); - } - - private String request(RestTemplate template) { - - // Uninitialized and sealed can cause status 500 - try { - ResponseEntity responseEntity = template.exchange(url, HttpMethod.GET, null, String.class); - return responseEntity.getBody(); - } catch (HttpStatusCodeException e) { - return e.getResponseBodyAsString(); - } - } - - @Test - public void nettyClientShouldWork() throws Exception { - - ClientHttpRequestFactory factory = Netty.usingNetty(vaultProperties); - ((InitializingBean) factory).afterPropertiesSet(); - RestTemplate template = new RestTemplate(factory); - - String response = request(template); - - assertThat(factory).isInstanceOf(Netty4ClientHttpRequestFactory.class); - assertThat(response).isNotNull().contains("initialized"); - - ((DisposableBean) factory).destroy(); - } - - @Test - public void okHttpClientShouldWork() throws Exception { - - ClientHttpRequestFactory factory = OkHttp.usingOkHttp(vaultProperties); - RestTemplate template = new RestTemplate(factory); - - String response = request(template); - - assertThat(factory).isInstanceOf(OkHttpClientHttpRequestFactory.class); - assertThat(response).isNotNull().contains("initialized"); - - ((DisposableBean) factory).destroy(); - } -} diff --git a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/PrepareVaultTests.java b/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/PrepareVaultTests.java deleted file mode 100644 index 51d8aed1..00000000 --- a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/PrepareVaultTests.java +++ /dev/null @@ -1,44 +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 org.junit.Test; -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-core/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 deleted file mode 100644 index fb444d00..00000000 --- a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/PrepareVault.java +++ /dev/null @@ -1,514 +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.util; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.springframework.cloud.vault.VaultClient; -import org.springframework.cloud.vault.VaultProperties; -import org.springframework.cloud.vault.VaultToken; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.util.Assert; -import org.springframework.web.client.HttpStatusCodeException; -import org.springframework.web.client.RestTemplate; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import lombok.Data; -import lombok.NonNull; -import lombok.Setter; -import lombok.Value; - -/** - * Test helper to prepare various settings within Vault. - * - * @author Mark Paluch - */ -public class PrepareVault { - - public final static String INITIALIZE_URL_TEMPLATE = "{baseuri}/sys/init"; - public final static String MOUNT_AUTH_URL_TEMPLATE = "{baseuri}/sys/auth/{authBackend}"; - public final static String SYS_AUTH_URL_TEMPLATE = "{baseuri}/sys/auth"; - public final static String MOUNT_SECRET_URL_TEMPLATE = "{baseuri}/sys/mounts/{type}"; - public final static String SYS_MOUNTS_URL_TEMPLATE = "{baseuri}/sys/mounts"; - public final static String SEAL_STATUS_URL_TEMPLATE = "{baseuri}/sys/seal-status"; - public final static String UNSEAL_URL_TEMPLATE = "{baseuri}/sys/unseal"; - public final static String CREATE_TOKEN_URL_TEMPLATE = "{baseuri}/auth/token/create-orphan"; - public final static String WRITE_URL_TEMPLATE = "{baseuri}/{path}"; - public static final ParameterizedTypeReference> MAP_OF_MAPS_TYPE = new ParameterizedTypeReference>() { - - }; - - private final RestTemplate restTemplate; - - @Setter - @NonNull - private VaultProperties vaultProperties; - - @Setter - @NonNull - private VaultToken rootToken; - - public PrepareVault(RestTemplate restTemplate) { - - Assert.notNull(restTemplate, "RestTemplate must not be null"); - this.restTemplate = restTemplate; - } - - /** - * Creates a new {@link VaultClient}. - * - * @return - */ - public VaultClient newVaultClient() { - return new VaultClient(restTemplate); - } - - /** - * Initialize Vault and unseal the vault. - * - * @return the root token. - */ - public VaultToken initializeVault() { - - Assert.notNull(vaultProperties, "VaultProperties must not be null"); - - Map parameters = parameters(vaultProperties); - - int createKeys = 2; - int requiredKeys = 2; - - InitializeVault initializeVault = InitializeVault.of(createKeys, requiredKeys); - - ResponseEntity initResponse = restTemplate.exchange( - INITIALIZE_URL_TEMPLATE, HttpMethod.PUT, - new HttpEntity<>(initializeVault), VaultInitialized.class, parameters); - - if (!initResponse.getStatusCode().is2xxSuccessful()) { - throw new IllegalStateException("Cannot initialize vault: " - + initResponse.toString()); - } - VaultInitialized initialized = initResponse.getBody(); - - for (int i = 0; i < requiredKeys; i++) { - - UnsealKey unsealKey = UnsealKey.of(initialized.getKeys().get(i)); - ResponseEntity unsealResponse = restTemplate.exchange( - UNSEAL_URL_TEMPLATE, HttpMethod.PUT, new HttpEntity<>(unsealKey), - UnsealProgress.class, parameters); - - UnsealProgress unsealProgress = unsealResponse.getBody(); - if (!unsealProgress.isSealed()) { - break; - } - } - - return VaultToken.of(initialized.getRootToken()); - } - - /** - * Create a token for the given {@code tokenId} and {@code policy}. - * - * @param tokenId - * @param policy - * @return - */ - public VaultToken createToken(String tokenId, String policy) { - - Map parameters = parameters(vaultProperties); - - CreateToken createToken = new CreateToken(); - createToken.setId(tokenId); - if (policy != null) { - createToken.setPolicies(Collections.singletonList(policy)); - } - - HttpHeaders headers = authenticatedHeaders(); - - HttpEntity entity = new HttpEntity<>(createToken, headers); - - ResponseEntity createTokenResponse = restTemplate.exchange( - CREATE_TOKEN_URL_TEMPLATE, HttpMethod.POST, entity, TokenCreated.class, - parameters); - - if (!createTokenResponse.getStatusCode().is2xxSuccessful()) { - throw new IllegalStateException("Cannot create token: " - + createTokenResponse.toString()); - } - - AuthToken authToken = createTokenResponse.getBody().getAuth(); - - return VaultToken.of(authToken.getClientToken()); - } - - /** - * Check whether Vault is available (vault created and unsealed). - * - * @return - */ - public boolean isAvailable() { - - Map parameters = parameters(vaultProperties); - - ResponseEntity exchange = null; - try { - exchange = restTemplate.getForEntity(SEAL_STATUS_URL_TEMPLATE, String.class, - parameters); - - if (exchange.getStatusCode().is2xxSuccessful()) { - return true; - } - } - catch (HttpStatusCodeException e) { - if (e.getStatusCode().is4xxClientError()) { - return false; - } - } - - if (exchange.getStatusCode().is4xxClientError()) { - return false; - } - throw new IllegalStateException("Vault error: " + exchange.toString()); - } - - /** - * Mount an auth backend. - * - * @param authBackend - */ - public void mountAuth(String authBackend) { - - Assert.hasText(authBackend, "AuthBackend must not be empty"); - - Map parameters = parameters(vaultProperties); - parameters.put("authBackend", authBackend); - - Map requestEntity = Collections.singletonMap("type", authBackend); - - HttpEntity> entity = new HttpEntity<>(requestEntity, - authenticatedHeaders()); - - ResponseEntity responseEntity = restTemplate.exchange( - MOUNT_AUTH_URL_TEMPLATE, HttpMethod.POST, entity, String.class, - parameters); - - if (!responseEntity.getStatusCode().is2xxSuccessful()) { - throw new IllegalStateException("Cannot create mount auth backend: " - + responseEntity.toString()); - } - - responseEntity.getBody(); - } - - /** - * Check whether a auth-backend is enabled. - * - * @param authBackend - * @return - */ - public boolean hasAuth(String authBackend) { - - Assert.hasText(authBackend, "AuthBackend must not be empty"); - return hasMount(SYS_AUTH_URL_TEMPLATE, authBackend); - } - - /** - * Mount an secret backend. - * - * @param secretBackend - */ - public void mountSecret(String secretBackend) { - - Assert.hasText(secretBackend, "SecretBackend must not be empty"); - - Map parameters = parameters(vaultProperties); - parameters.put("type", secretBackend); - - Map requestEntity = Collections.singletonMap("type", - secretBackend); - - HttpEntity> entity = new HttpEntity<>(requestEntity, - authenticatedHeaders()); - - ResponseEntity responseEntity = restTemplate.exchange( - MOUNT_SECRET_URL_TEMPLATE, HttpMethod.POST, entity, String.class, - parameters); - - if (!responseEntity.getStatusCode().is2xxSuccessful()) { - throw new IllegalStateException("Cannot create mount secret backend: " - + responseEntity.toString()); - } - - responseEntity.getBody(); - } - - /** - * Check whether a auth-backend is enabled. - * - * @param secretBackend - * @return - */ - public boolean hasSecret(String secretBackend) { - - Assert.hasText(secretBackend, "SecretBackend must not be empty"); - return hasMount(SYS_MOUNTS_URL_TEMPLATE, secretBackend); - } - - private boolean hasMount(String urlTemplate, String type) { - Map parameters = parameters(vaultProperties); - - HttpEntity> entity = new HttpEntity<>(authenticatedHeaders()); - - ResponseEntity> responseEntity = restTemplate.exchange( - urlTemplate, HttpMethod.GET, entity, MAP_OF_MAPS_TYPE, parameters); - - if (!responseEntity.getStatusCode().is2xxSuccessful()) { - throw new IllegalStateException("Cannot enumerate mounts: " - + responseEntity.toString()); - } - - Map body = responseEntity.getBody(); - for (Entry entry : body.entrySet()) { - - if (entry.getValue() instanceof Map) { - Map nested = (Map) entry.getValue(); - - if (entry.getKey().contains(type) && type.equals(nested.get("type"))) { - return true; - } - } - - } - - return false; - } - - /** - * Write key-value data to the Vault secret backend. - * - * @param path - * @param data - */ - public void writeSecret(String path, Map data) { - - Assert.hasText(path, "Path must not be empty"); - write("secret/" + path, data); - } - - /** - * Write key-value data to a path in Vault. - * - * @param path - * @param data - */ - public void write(String path, Map data) { - write(HttpMethod.POST, path, data); - } - - /** - * Write key-value data to a path in Vault. - * - * @param httpMethod - * @param path - * @param data - */ - public void write(HttpMethod httpMethod, String path, Map data) { - - Assert.notNull(httpMethod, "HttpMethod must not be null"); - Assert.hasText(path, "Path must not be empty"); - Assert.notNull(data, "Data must not be null"); - - HttpHeaders headers = authenticatedHeaders(); - - Map parameters = parameters(vaultProperties); - parameters.put("path", path); - - ResponseEntity exchange = restTemplate.exchange(WRITE_URL_TEMPLATE, - HttpMethod.PUT, new HttpEntity(data, headers), String.class, - parameters); - - if (!exchange.getStatusCode().is2xxSuccessful()) { - throw new IllegalStateException(String.format("Cannot write to %s: %s", path, - exchange.getBody())); - } - } - - /** - * Create an userId to appId mapping. - * - * @param appId - * @param userId - */ - public void mapUserId(String appId, String userId) { - - Map userIdData = new HashMap<>(); - userIdData.put("value", appId); // name of the app-id - userIdData.put("cidr_block", "0.0.0.0/0"); - - String appIdPath = vaultProperties.getAppId().getAppIdPath(); - if (!hasAuth(appIdPath)) { - mountAuth(appIdPath); - } - - write(String.format("auth/%s/map/user-id/%s", appIdPath, userId), userIdData); - } - - /** - * Create an appId mapping. - * - * @param appId - */ - public void mapAppId(String appId) { - - Map appIdData = new HashMap<>(); - appIdData.put("value", "root"); // policy - appIdData.put("display_name", "this is my test application"); - - write(String.format("auth/%s/map/app-id/%s", vaultProperties.getAppId() - .getAppIdPath(), appId), appIdData); - } - - private HttpHeaders authenticatedHeaders() { - HttpHeaders headers = new HttpHeaders(); - headers.add(VaultClient.VAULT_TOKEN, rootToken.getToken()); - return headers; - } - - private Map parameters(VaultProperties vaultProperties) { - - Map parameters = new HashMap<>(); - - String baseUri = String.format("%s://%s:%s/%s", vaultProperties.getScheme(), - vaultProperties.getHost(), vaultProperties.getPort(), - VaultClient.API_VERSION); - parameters.put("baseuri", baseUri); - - return parameters; - } - - /** - * @author Mark Paluch - */ - @Data - static class TokenCreated { - - @JsonProperty("lease_duration") - private long leaseDuration; - @JsonProperty("renewable") - private boolean renewable; - @JsonProperty("auth") - private AuthToken auth; - - } - - /** - * @author Mark Paluch - */ - @Value(staticConstructor = "of") - static class InitializeVault { - - @JsonProperty("secret_shares") - private int secretShares; - - @JsonProperty("secret_threshold") - private int secretThreshold; - } - - /** - * @author Mark Paluch - */ - @Data - static class CreateToken { - - @JsonProperty("id") - private String id; - - @JsonProperty("policies") - private List policies; - - @JsonProperty("ttl") - private String ttl; - } - - /** - * @author Mark Paluch - */ - @Value(staticConstructor = "of") - static class UnsealKey { - @JsonProperty - @NonNull - private String key; - } - - /** - * @author Mark Paluch - */ - @Data - static class UnsealProgress { - - @JsonProperty("sealed") - private boolean sealed; - @JsonProperty("t") - private int t; - @JsonProperty("n") - private int n; - @JsonProperty("progress") - private int progress; - } - - /** - * @author Mark Paluch - */ - @Data - static class VaultInitialized { - - @JsonProperty("keys") - private List keys; - @JsonProperty("root_token") - private String rootToken; - } - - /** - * @author Mark Paluch - */ - @Data - public static class AuthToken { - - @JsonProperty("client_token") - private String clientToken; - - @JsonProperty("policies") - private List policies; - - @JsonProperty("metadata") - private Map metadata; - - @JsonProperty("lease_duration") - private long leaseDuration; - - @JsonProperty("renewable") - private boolean renewable; - } -} diff --git a/spring-cloud-vault-core/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 deleted file mode 100644 index 7e719c68..00000000 --- a/spring-cloud-vault-core/src/test/java/org/springframework/cloud/vault/util/VaultRule.java +++ /dev/null @@ -1,79 +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.util; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; - -import org.junit.rules.ExternalResource; -import org.springframework.cloud.vault.TestRestTemplateFactory; -import org.springframework.cloud.vault.VaultProperties; -import org.springframework.cloud.vault.VaultToken; - -/** - * Vault rule to ensure a running and prepared Vault. - * - * @author Mark Paluch - */ -public class VaultRule extends ExternalResource { - - private final VaultProperties vaultProperties; - private final PrepareVault prepareVault; - - public VaultRule() { - this(Settings.createVaultProperties()); - } - - public VaultRule(VaultProperties vaultProperties) { - - this.vaultProperties = vaultProperties; - this.prepareVault = new PrepareVault(TestRestTemplateFactory.create(vaultProperties)); - } - - @Override - public void before() { - - try (Socket socket = new Socket()) { - - socket.connect(new InetSocketAddress(InetAddress.getByName("localhost"), - vaultProperties.getPort())); - socket.close(); - - } - catch (Exception ex) { - throw new IllegalStateException(String.format( - "Vault is not running on localhost:%d which is required to run a test using @Rule %s", - vaultProperties.getPort(), getClass().getSimpleName())); - } - - prepareVault.setVaultProperties(vaultProperties); - - if (!prepareVault.isAvailable()) { - VaultToken rootToken = prepareVault.initializeVault(); - prepareVault.setRootToken(rootToken); - prepareVault.createToken(vaultProperties.getToken(), "root"); - } - else { - prepareVault.setRootToken(Settings.token()); - } - } - - public PrepareVault prepare() { - return prepareVault; - } - -} diff --git a/spring-cloud-vault-dependencies/pom.xml b/spring-cloud-vault-dependencies/pom.xml index f7716dbf..ef64f2ab 100644 --- a/spring-cloud-vault-dependencies/pom.xml +++ b/spring-cloud-vault-dependencies/pom.xml @@ -22,15 +22,24 @@ 1.1.2.BUILD-SNAPSHOT 1.4.0.RELEASE + 1.0.0.BUILD-SNAPSHOT 4.5.2 4.4.4 4.1.0.Final 2.7.5 + 1.7.21 + + + org.springframework.vault + spring-vault-core + ${spring-vault.version} + + org.springframework.cloud @@ -38,14 +47,6 @@ ${project.version} - - org.springframework.cloud - spring-cloud-vault-core - ${project.version} - test-jar - test - - org.springframework.cloud spring-cloud-vault-config @@ -119,6 +120,13 @@ true + + + org.slf4j + slf4j-api + ${slf4j.version} + + org.assertj diff --git a/spring-cloud-vault-starter-config/pom.xml b/spring-cloud-vault-starter-config/pom.xml index 89c3dd60..fe2ad46a 100644 --- a/spring-cloud-vault-starter-config/pom.xml +++ b/spring-cloud-vault-starter-config/pom.xml @@ -24,8 +24,8 @@ - org.springframework.cloud - spring-cloud-vault-core + org.springframework.vault + spring-vault-core diff --git a/spring-cloud-vault-core/src/test/resources/consul.json b/src/test/bash/consul.json similarity index 100% rename from spring-cloud-vault-core/src/test/resources/consul.json rename to src/test/bash/consul.json diff --git a/src/test/bash/local_run_consul.sh b/src/test/bash/local_run_consul.sh index f3761281..278a15c9 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-core/src/test/resources/consul.json + -config-file=${BASEDIR}/src/test/bash/consul.json exit $? diff --git a/src/test/bash/local_run_vault.sh b/src/test/bash/local_run_vault.sh index 38381c8f..140522b9 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-core/src/test/resources/vault.conf +./vault/vault server -config=${BASEDIR}/src/test/bash/vault.conf exit $? diff --git a/spring-cloud-vault-core/src/test/resources/vault.conf b/src/test/bash/vault.conf similarity index 100% rename from spring-cloud-vault-core/src/test/resources/vault.conf rename to src/test/bash/vault.conf