BAEL-1784 Spring Vault - Bhargava.Kotharu@gmail.com (#5094)
* BAEL-1784 Spring Vault Initial Commit * Added Vault Process initalizer and integration tests * Added comments and code clean up * Skip IntegrationTest in pom file * Fixed failing integration test * Code indentation
This commit is contained in:
parent
5a09cee678
commit
a575f7b763
1
pom.xml
1
pom.xml
|
@ -1106,6 +1106,7 @@
|
||||||
<module>spring-remoting</module>
|
<module>spring-remoting</module>
|
||||||
<module>spring-reactor</module>
|
<module>spring-reactor</module>
|
||||||
<module>spring-vertx</module>
|
<module>spring-vertx</module>
|
||||||
|
<module>spring-vault</module>
|
||||||
<module>spring-jinq</module>
|
<module>spring-jinq</module>
|
||||||
<module>spring-rest-embedded-tomcat</module>
|
<module>spring-rest-embedded-tomcat</module>
|
||||||
<module>testing-modules/testing</module>
|
<module>testing-modules/testing</module>
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<project
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||||
|
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>spring-vault</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<name>spring-vault</name>
|
||||||
|
<description>Spring Vault sample project</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>parent-boot-2</artifactId>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../parent-boot-2</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.vault</groupId>
|
||||||
|
<artifactId>spring-vault-core</artifactId>
|
||||||
|
<version>${spring.vault.core.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>${maven-surefire-plugin.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/*IntegrationTest.java</exclude>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<spring.vault.core.version>2.0.1.RELEASE</spring.vault.core.version>
|
||||||
|
</properties>
|
||||||
|
</project>
|
|
@ -0,0 +1,30 @@
|
||||||
|
package org.baeldung.springvault;
|
||||||
|
|
||||||
|
public class Credentials {
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public Credentials() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Credentials(String username, String password) {
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Credential [username=" + username + ", password=" + password + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package org.baeldung.springvault;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.vault.authentication.TokenAuthentication;
|
||||||
|
import org.springframework.vault.client.VaultEndpoint;
|
||||||
|
import org.springframework.vault.core.VaultTemplate;
|
||||||
|
import org.springframework.vault.core.env.VaultPropertySource;
|
||||||
|
import org.springframework.vault.support.VaultResponse;
|
||||||
|
import org.springframework.vault.support.VaultResponseSupport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sample service to demonstrate storing and retrieval of secrets.
|
||||||
|
*
|
||||||
|
* NOTE: We need to configure Vault and provide the Vault uri in the properties file.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class CredentialsService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private VaultTemplate vaultTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To Secure Credentials
|
||||||
|
* @param credentials
|
||||||
|
* @return VaultResponse
|
||||||
|
* @throws URISyntaxException
|
||||||
|
*/
|
||||||
|
public void secureCredentials(Credentials credentials) throws URISyntaxException {
|
||||||
|
|
||||||
|
vaultTemplate.write("credentials/myapp", credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To Retrieve Credentials
|
||||||
|
* @return Credentials
|
||||||
|
* @throws URISyntaxException
|
||||||
|
*/
|
||||||
|
public Credentials accessCredentials() throws URISyntaxException {
|
||||||
|
|
||||||
|
VaultResponseSupport<Credentials> response = vaultTemplate.read("credentials/myapp", Credentials.class);
|
||||||
|
return response.getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package org.baeldung.springvault;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sample application to demonstrate basics of Spring Vault
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SpringBootApplication
|
||||||
|
public class SpringVaultApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(SpringVaultApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package org.baeldung.springvault;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.vault.authentication.ClientAuthentication;
|
||||||
|
import org.springframework.vault.authentication.TokenAuthentication;
|
||||||
|
import org.springframework.vault.client.VaultEndpoint;
|
||||||
|
import org.springframework.vault.config.AbstractVaultConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example class to configure Vault beans using AbstractVaultConfiguration
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class VaultConfig extends AbstractVaultConfiguration {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientAuthentication clientAuthentication() {
|
||||||
|
return new TokenAuthentication("00000000-0000-0000-0000-000000000000");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VaultEndpoint vaultEndpoint() {
|
||||||
|
return VaultEndpoint.create("host", 8020);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.baeldung.springvault;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
import org.springframework.vault.authentication.ClientAuthentication;
|
||||||
|
import org.springframework.vault.authentication.TokenAuthentication;
|
||||||
|
import org.springframework.vault.client.VaultEndpoint;
|
||||||
|
import org.springframework.vault.config.AbstractVaultConfiguration;
|
||||||
|
import org.springframework.vault.config.EnvironmentVaultConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example class to configure Vault beans using EnvironmentVaultConfiguration
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@PropertySource(value = { "vault-config.properties" })
|
||||||
|
@Import(value = EnvironmentVaultConfiguration.class)
|
||||||
|
public class VaultEnvironmentConfig {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
vault.uri=https://localhost:8200
|
||||||
|
vault.token=00000000-0000-0000-0000-000000000000
|
|
@ -0,0 +1,113 @@
|
||||||
|
package org.baeldung.springvault;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This is a test class to initialize Vault.
|
||||||
|
*/
|
||||||
|
public class VaultInitializer implements Closeable {
|
||||||
|
|
||||||
|
private static final String UNSEAL_KEY = "Unseal Key:";
|
||||||
|
private static final String ROOT_TOKEN = "Root Token:";
|
||||||
|
|
||||||
|
private Process vaultProcess;
|
||||||
|
private String unSealKey;
|
||||||
|
private String rootToken;
|
||||||
|
|
||||||
|
public String getRootToken() {
|
||||||
|
return rootToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUnSealKey() {
|
||||||
|
return unSealKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final VaultInitializer initializeValut() {
|
||||||
|
VaultInitializer vaultProcess = new VaultInitializer();
|
||||||
|
vaultProcess.start();
|
||||||
|
// Secrets is by default enabled.
|
||||||
|
vaultProcess.enableSecrets();
|
||||||
|
return vaultProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private void enableSecrets() {
|
||||||
|
System.out.println("Enabling Secrets at path credentials/myapp...");
|
||||||
|
ProcessBuilder pb = new ProcessBuilder("vault", "secrets", "enable", "-path=credentials/myapp", "kv");
|
||||||
|
Map<String, String> map = pb.environment();
|
||||||
|
map.put("VAULT_ADDR", "http://127.0.0.1:8200");
|
||||||
|
try {
|
||||||
|
Process p = pb.inheritIO()
|
||||||
|
.start();
|
||||||
|
p.waitFor();
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("unable to enableSecrets" + e);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
System.out.println("starting vault");
|
||||||
|
// This starts the vault server.
|
||||||
|
ProcessBuilder pb = new ProcessBuilder("vault", "server", "-dev");
|
||||||
|
|
||||||
|
try {
|
||||||
|
vaultProcess = pb.start();
|
||||||
|
// wait for initialization to complete.
|
||||||
|
Thread.sleep(5000);
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("unable to start vault in new process" + e);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
System.out.println("Thread interrupted " + e);
|
||||||
|
}
|
||||||
|
extractUnsealKeyAndToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To get the root token which is generated every time server is initialized.
|
||||||
|
*/
|
||||||
|
private void extractUnsealKeyAndToken() {
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(vaultProcess.getInputStream()));
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
String line = null;
|
||||||
|
boolean tokenExtracted = false;
|
||||||
|
try {
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
builder.append(line);
|
||||||
|
builder.append(System.getProperty("line.separator"));
|
||||||
|
if (line.contains(UNSEAL_KEY)) {
|
||||||
|
String tmp = line.replace(UNSEAL_KEY, "");
|
||||||
|
unSealKey = tmp.trim();
|
||||||
|
} else if (line.contains(ROOT_TOKEN)) {
|
||||||
|
String tmp = line.replace(ROOT_TOKEN, "");
|
||||||
|
rootToken = tmp.trim();
|
||||||
|
tokenExtracted = true;
|
||||||
|
}
|
||||||
|
if (tokenExtracted)
|
||||||
|
break;
|
||||||
|
System.out.println(line);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("unable to read vault output" + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
String result = builder.toString();
|
||||||
|
|
||||||
|
System.out.println("Unseal Key {}" + unSealKey);
|
||||||
|
System.out.println("Root Token {}" + rootToken);
|
||||||
|
System.out.println(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
|
||||||
|
System.out.println("stoping vault");
|
||||||
|
vaultProcess.destroy();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package org.baeldung.springvault;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.FixMethodOrder;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.MethodSorters;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext.ClassMode;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.TestPropertySource;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
||||||
|
import org.springframework.vault.authentication.TokenAuthentication;
|
||||||
|
import org.springframework.vault.client.VaultEndpoint;
|
||||||
|
import org.springframework.vault.core.VaultTemplate;
|
||||||
|
import org.springframework.vault.support.VaultResponse;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest(classes = CredentialsService.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||||
|
@ContextConfiguration(classes = VaultTestConfiguration.class, loader = AnnotationConfigContextLoader.class)
|
||||||
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
|
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
|
||||||
|
public class VaultIntegrationTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CredentialsService credentialsService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test to secure credentials.
|
||||||
|
*
|
||||||
|
* @throws URISyntaxException
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void givenCredentials_whenSecureCredentials_thenCredentialsSecured() throws URISyntaxException {
|
||||||
|
try {
|
||||||
|
// Given
|
||||||
|
Credentials credentials = new Credentials("username", "password");
|
||||||
|
|
||||||
|
// When
|
||||||
|
credentialsService.secureCredentials(credentials);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test to access credentials
|
||||||
|
* @throws URISyntaxException
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void whenAccessCredentials_thenCredentialsRetrieved() throws URISyntaxException {
|
||||||
|
|
||||||
|
// Given
|
||||||
|
Credentials credentials = credentialsService.accessCredentials();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertNotNull(credentials);
|
||||||
|
assertEquals("username", credentials.getUsername());
|
||||||
|
assertEquals("password", credentials.getPassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package org.baeldung.springvault;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.vault.authentication.TokenAuthentication;
|
||||||
|
import org.springframework.vault.client.VaultEndpoint;
|
||||||
|
import org.springframework.vault.core.VaultTemplate;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class VaultTestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public VaultInitializer vaultInitializer() {
|
||||||
|
VaultInitializer vaultInitializer = VaultInitializer.initializeValut();
|
||||||
|
return vaultInitializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public VaultTemplate vaultTemplate() throws URISyntaxException {
|
||||||
|
|
||||||
|
VaultInitializer vaultInitializer = vaultInitializer();
|
||||||
|
VaultTemplate vaultTemplate = new VaultTemplate(VaultEndpoint.from(new URI("http://localhost:8200")), new TokenAuthentication(vaultInitializer.getRootToken()));
|
||||||
|
return vaultTemplate;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue