Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
3794f4aac6 | |||
f805a9c751 | |||
767c2cce91 | |||
ed703f6e53 | |||
e767c07a61 | |||
c1f6ee891b | |||
5d46e75068 | |||
7a67080aa0 | |||
81c28f10c1 | |||
b99edb86ac |
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/target/
|
||||
/*.iml
|
||||
/.idea/
|
||||
/*.project
|
||||
*~
|
@ -4,9 +4,10 @@ branches:
|
||||
language: java
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
dist: trusty
|
||||
env:
|
||||
- PATH=$PATH:.
|
||||
before_script:
|
||||
- wget https://releases.hashicorp.com/vault/0.7.0/vault_0.7.0_linux_amd64.zip
|
||||
- unzip vault_0.7.0_linux_amd64.zip
|
||||
- rm vault_0.7.0_linux_amd64.zip
|
||||
- wget https://releases.hashicorp.com/vault/0.7.2/vault_0.7.2_linux_amd64.zip
|
||||
- unzip vault_0.7.2_linux_amd64.zip
|
||||
- rm vault_0.7.2_linux_amd64.zip
|
||||
|
@ -1,3 +1,11 @@
|
||||
## 0.6.0 [2017-05-12]
|
||||
* [feature] Initialization from environment variables using `fromEnv()` in factory (#8)
|
||||
* [feature] Automatic authentication with `buildAndAuth()`
|
||||
* [feature] Custom timeout and number of retries (#9)
|
||||
* [feature] Connector implements `AutoCloseable`
|
||||
* [fix] `SecretResponse` does not throw NPE on `get(key)` and `getData()`
|
||||
* [test] Tested against Vault 0.7.2
|
||||
|
||||
## 0.5.0 [2017-03-18]
|
||||
* [feature] Convenience methods for DB credentials (#7)
|
||||
* [fix] Minor bugfix in TokenBuilder
|
||||
|
11
README.md
11
README.md
@ -12,6 +12,7 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
|
||||
|
||||
* HTTP(S) backend connector
|
||||
* Ability to provide or enforce custom CA certificate
|
||||
* Optional initialization from environment variables
|
||||
* Authorization methods
|
||||
* Token
|
||||
* Username/Password
|
||||
@ -27,8 +28,9 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
|
||||
* Delete secrets
|
||||
* Renew/revoke leases
|
||||
* Raw secret content or JSON decoding
|
||||
* SQL secret handling
|
||||
* Connector Factory with builder pattern
|
||||
* Tested against Vault 0.7.0
|
||||
* Tested against Vault 0.7.2
|
||||
|
||||
|
||||
## Maven Artifact
|
||||
@ -36,7 +38,7 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
|
||||
<dependency>
|
||||
<groupId>de.stklcode.jvault</groupId>
|
||||
<artifactId>connector</artifactId>
|
||||
<version>0.5.0</version>
|
||||
<version>0.6.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
@ -58,6 +60,11 @@ VaultConnector vault = VaultConnectorFactory.httpFactory()
|
||||
.withPort(8200)
|
||||
.withTrustedCA(Paths.get("/path/to/CA.pem"))
|
||||
.build();
|
||||
|
||||
// Initialization from environment variables
|
||||
VaultConnector vault = VaultConnectorFactory.httpFactory()
|
||||
.fromEnv()
|
||||
.build();
|
||||
```
|
||||
|
||||
### Authentication
|
||||
|
12
pom.xml
12
pom.xml
@ -4,7 +4,7 @@
|
||||
|
||||
<groupId>de.stklcode.jvault</groupId>
|
||||
<artifactId>connector</artifactId>
|
||||
<version>0.5.0</version>
|
||||
<version>0.6.0</version>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@ -52,12 +52,12 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.8.7</version>
|
||||
<version>2.8.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.8.7</version>
|
||||
<version>2.8.8.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@ -72,5 +72,11 @@
|
||||
<version>2.0.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.stefanbirkner</groupId>
|
||||
<artifactId>system-rules</artifactId>
|
||||
<version>1.16.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -23,11 +23,13 @@ import de.stklcode.jvault.connector.model.*;
|
||||
import de.stklcode.jvault.connector.model.response.*;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.AuthMethod;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.*;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.params.HttpConnectionParams;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
@ -64,6 +66,8 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
|
||||
private final String baseURL; /* Base URL of Vault */
|
||||
private final SSLContext sslContext; /* Custom SSLSocketFactory */
|
||||
private final int retries; /* Number of retries on 5xx errors */
|
||||
private final Integer timeout; /* Timeout in milliseconds */
|
||||
|
||||
private boolean authorized = false; /* authorization status */
|
||||
private String token; /* current token */
|
||||
@ -115,11 +119,26 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
* @param sslContext Custom SSL Context
|
||||
*/
|
||||
public HTTPVaultConnector(String hostname, boolean useTLS, Integer port, String prefix, SSLContext sslContext) {
|
||||
this(hostname, useTLS, port, prefix, sslContext, 0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create connector using hostname, schema, port, path and trusted certificate.
|
||||
*
|
||||
* @param hostname The hostname
|
||||
* @param useTLS If TRUE, use HTTPS, otherwise HTTP
|
||||
* @param port The port
|
||||
* @param prefix HTTP API prefix (default: /v1/)
|
||||
* @param sslContext Custom SSL Context
|
||||
*/
|
||||
public HTTPVaultConnector(String hostname, boolean useTLS, Integer port, String prefix, SSLContext sslContext, int numberOfRetries, Integer timeout) {
|
||||
this(((useTLS) ? "https" : "http") +
|
||||
"://" + hostname +
|
||||
((port != null) ? ":" + port : "") +
|
||||
prefix,
|
||||
sslContext);
|
||||
sslContext,
|
||||
numberOfRetries,
|
||||
timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,8 +157,32 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
* @param sslContext Custom SSL Context
|
||||
*/
|
||||
public HTTPVaultConnector(String baseURL, SSLContext sslContext) {
|
||||
this(baseURL, sslContext, 0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create connector using full URL and trusted certificate.
|
||||
*
|
||||
* @param baseURL The URL
|
||||
* @param sslContext Custom SSL Context
|
||||
* @param numberOfRetries number of retries on 5xx errors
|
||||
*/
|
||||
public HTTPVaultConnector(String baseURL, SSLContext sslContext, int numberOfRetries) {
|
||||
this(baseURL, sslContext, numberOfRetries, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create connector using full URL and trusted certificate.
|
||||
*
|
||||
* @param baseURL The URL
|
||||
* @param sslContext Custom SSL Context
|
||||
* @param numberOfRetries number of retries on 5xx errors
|
||||
*/
|
||||
public HTTPVaultConnector(String baseURL, SSLContext sslContext, int numberOfRetries, Integer timeout) {
|
||||
this.baseURL = baseURL;
|
||||
this.sslContext = sslContext;
|
||||
this.retries = numberOfRetries;
|
||||
this.timeout = timeout;
|
||||
this.jsonMapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
@ -567,6 +610,13 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
return createTokenInternal(token, PATH_TOKEN + PATH_CREATE + "/" + role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
authorized = false;
|
||||
token = null;
|
||||
tokenTTL = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create token.
|
||||
* Centralized method to handle different token creation requests.
|
||||
@ -634,7 +684,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
if (token != null)
|
||||
post.addHeader("X-Vault-Token", token);
|
||||
|
||||
return request(post);
|
||||
return request(post, retries);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -661,7 +711,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
if (token != null)
|
||||
put.addHeader("X-Vault-Token", token);
|
||||
|
||||
return request(put);
|
||||
return request(put, retries);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -678,7 +728,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
if (token != null)
|
||||
delete.addHeader("X-Vault-Token", token);
|
||||
|
||||
return request(delete);
|
||||
return request(delete, retries);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -701,22 +751,27 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
if (token != null)
|
||||
get.addHeader("X-Vault-Token", token);
|
||||
|
||||
return request(get);
|
||||
return request(get, retries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute prepared HTTP request and return result.
|
||||
*
|
||||
* @param base Prepares Request
|
||||
* @param base Prepares Request
|
||||
* @param retries number of retries
|
||||
* @return HTTP response
|
||||
* @throws VaultConnectorException on connection error
|
||||
*/
|
||||
private String request(HttpRequestBase base) throws VaultConnectorException {
|
||||
private String request(HttpRequestBase base, int retries) throws VaultConnectorException {
|
||||
/* Set JSON Header */
|
||||
base.addHeader("accept", "application/json");
|
||||
|
||||
HttpResponse response = null;
|
||||
try (CloseableHttpClient httpClient = HttpClientBuilder.create().setSSLContext(sslContext).build()) {
|
||||
/* Set custom timeout, if defined */
|
||||
if (this.timeout != null)
|
||||
base.setConfig(RequestConfig.copy(RequestConfig.DEFAULT).setConnectTimeout(timeout).build());
|
||||
/* Execute request */
|
||||
response = httpClient.execute(base);
|
||||
/* Check if response is valid */
|
||||
if (response == null)
|
||||
@ -733,20 +788,26 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
case 403:
|
||||
throw new PermissionDeniedException();
|
||||
default:
|
||||
InvalidResponseException ex = new InvalidResponseException("Invalid response code")
|
||||
.withStatusCode(response.getStatusLine().getStatusCode());
|
||||
if (response.getEntity() != null) {
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) {
|
||||
String responseString = br.lines().collect(Collectors.joining("\n"));
|
||||
ErrorResponse er = jsonMapper.readValue(responseString, ErrorResponse.class);
|
||||
/* Check for "permission denied" response */
|
||||
if (er.getErrors().size() > 0 && er.getErrors().get(0).equals("permission denied"))
|
||||
throw new PermissionDeniedException();
|
||||
throw ex.withResponse(er.toString());
|
||||
} catch (IOException ignored) {
|
||||
if (response.getStatusLine().getStatusCode() >= 500 && response.getStatusLine().getStatusCode() < 600 && retries > 0) {
|
||||
/* Retry on 5xx errors */
|
||||
return request(base, retries - 1);
|
||||
} else {
|
||||
/* Fail on different error code and/or no retries left */
|
||||
InvalidResponseException ex = new InvalidResponseException("Invalid response code")
|
||||
.withStatusCode(response.getStatusLine().getStatusCode());
|
||||
if (response.getEntity() != null) {
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) {
|
||||
String responseString = br.lines().collect(Collectors.joining("\n"));
|
||||
ErrorResponse er = jsonMapper.readValue(responseString, ErrorResponse.class);
|
||||
/* Check for "permission denied" response */
|
||||
if (er.getErrors().size() > 0 && er.getErrors().get(0).equals("permission denied"))
|
||||
throw new PermissionDeniedException();
|
||||
throw ex.withResponse(er.toString());
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new InvalidResponseException("Unable to read response", e);
|
||||
|
@ -30,7 +30,7 @@ import java.util.*;
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
*/
|
||||
public interface VaultConnector {
|
||||
public interface VaultConnector extends AutoCloseable {
|
||||
String PATH_SECRET = "secret";
|
||||
|
||||
/**
|
||||
|
@ -23,9 +23,6 @@ package de.stklcode.jvault.connector.exception;
|
||||
* @since 0.4.0
|
||||
*/
|
||||
public class TlsException extends VaultConnectorException {
|
||||
private Integer statusCode;
|
||||
private String response;
|
||||
|
||||
public TlsException() {
|
||||
}
|
||||
|
||||
@ -40,12 +37,4 @@ public class TlsException extends VaultConnectorException {
|
||||
public TlsException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public Integer getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
public String getResponse() {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
package de.stklcode.jvault.connector.factory;
|
||||
|
||||
import de.stklcode.jvault.connector.HTTPVaultConnector;
|
||||
import de.stklcode.jvault.connector.VaultConnector;
|
||||
import de.stklcode.jvault.connector.exception.ConnectionException;
|
||||
import de.stklcode.jvault.connector.exception.TlsException;
|
||||
import de.stklcode.jvault.connector.exception.VaultConnectorException;
|
||||
|
||||
@ -25,8 +27,11 @@ import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.*;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
@ -39,16 +44,25 @@ import java.security.cert.X509Certificate;
|
||||
* @since 0.1
|
||||
*/
|
||||
public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
||||
private static final String ENV_VAULT_ADDR = "VAULT_ADDR";
|
||||
private static final String ENV_VAULT_CACERT = "VAULT_CACERT";
|
||||
private static final String ENV_VAULT_TOKEN = "VAULT_TOKEN";
|
||||
private static final String ENV_VAULT_MAX_RETRIES = "VAULT_MAX_RETRIES";
|
||||
|
||||
public static final String DEFAULT_HOST = "127.0.0.1";
|
||||
public static final Integer DEFAULT_PORT = 8200;
|
||||
public static final boolean DEFAULT_TLS = true;
|
||||
public static final String DEFAULT_PREFIX = "/v1/";
|
||||
public static final int DEFAULT_NUMBER_OF_RETRIES = 0;
|
||||
|
||||
private String host;
|
||||
private Integer port;
|
||||
private boolean tls;
|
||||
private String prefix;
|
||||
private SSLContext sslContext;
|
||||
private int numberOfRetries;
|
||||
private Integer timeout;
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* Default empty constructor.
|
||||
@ -59,6 +73,7 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
||||
port = DEFAULT_PORT;
|
||||
tls = DEFAULT_TLS;
|
||||
prefix = DEFAULT_PREFIX;
|
||||
numberOfRetries = DEFAULT_NUMBER_OF_RETRIES;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -150,9 +165,91 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set token for automatic authentication, using {@link #buildAndAuth()}.
|
||||
*
|
||||
* @param token Vault token
|
||||
* @return self
|
||||
* @since 0.6.0
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withToken(String token) throws VaultConnectorException {
|
||||
this.token = token;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build connector based on the {@code }VAULT_ADDR} and {@code VAULT_CACERT} (optional) environment variables.
|
||||
*
|
||||
* @return self
|
||||
* @since 0.6.0
|
||||
*/
|
||||
public HTTPVaultConnectorFactory fromEnv() throws VaultConnectorException {
|
||||
/* Parse URL from environment variable */
|
||||
if (System.getenv(ENV_VAULT_ADDR) != null && !System.getenv(ENV_VAULT_ADDR).trim().isEmpty()) {
|
||||
try {
|
||||
URL url = new URL(System.getenv(ENV_VAULT_ADDR));
|
||||
this.host = url.getHost();
|
||||
this.port = url.getPort();
|
||||
this.tls = url.getProtocol().equals("https");
|
||||
} catch (MalformedURLException e) {
|
||||
throw new ConnectionException("URL provided in environment variable malformed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read number of retries */
|
||||
if (System.getenv(ENV_VAULT_MAX_RETRIES) != null) {
|
||||
try {
|
||||
numberOfRetries = Integer.parseInt(System.getenv(ENV_VAULT_MAX_RETRIES));
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Read token */
|
||||
token = System.getenv(ENV_VAULT_TOKEN);
|
||||
|
||||
/* Parse certificate, if set */
|
||||
if (System.getenv(ENV_VAULT_CACERT) != null && !System.getenv(ENV_VAULT_CACERT).trim().isEmpty()) {
|
||||
return withTrustedCA(Paths.get(System.getenv(ENV_VAULT_CACERT)));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the number of retries to attempt on 5xx errors.
|
||||
*
|
||||
* @param numberOfRetries The number of retries to attempt on 5xx errors (default: 0)
|
||||
* @return self
|
||||
* @since 0.6.0
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withNumberOfRetries(int numberOfRetries) {
|
||||
this.numberOfRetries = numberOfRetries;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a custom timeout for the HTTP connection.
|
||||
*
|
||||
* @param milliseconds Timeout value in milliseconds.
|
||||
* @return self
|
||||
* @since 0.6.0
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withTimeout(int milliseconds) {
|
||||
this.timeout = milliseconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HTTPVaultConnector build() {
|
||||
return new HTTPVaultConnector(host, tls, port, prefix, sslContext);
|
||||
return new HTTPVaultConnector(host, tls, port, prefix, sslContext, numberOfRetries, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HTTPVaultConnector buildAndAuth() throws VaultConnectorException {
|
||||
if (token == null)
|
||||
throw new ConnectionException("No vault token provided, unable to authenticate.");
|
||||
HTTPVaultConnector con = new HTTPVaultConnector(host, tls, port, prefix, sslContext, numberOfRetries, timeout);
|
||||
con.authToken(token);
|
||||
return con;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,13 +23,14 @@ import de.stklcode.jvault.connector.exception.VaultConnectorException;
|
||||
* Abstract Vault Connector Factory interface.
|
||||
* Provides builder pattern style factory for Vault connectors.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
*/
|
||||
public abstract class VaultConnectorFactory {
|
||||
/**
|
||||
* Get Factory implementation for HTTP Vault Connector
|
||||
* @return HTTP Connector Factory
|
||||
*
|
||||
* @return HTTP Connector Factory
|
||||
*/
|
||||
public static HTTPVaultConnectorFactory httpFactory() {
|
||||
return new HTTPVaultConnectorFactory();
|
||||
@ -37,7 +38,16 @@ public abstract class VaultConnectorFactory {
|
||||
|
||||
/**
|
||||
* Build command, produces connector after initialization.
|
||||
* @return Vault Connector instance.
|
||||
*
|
||||
* @return Vault Connector instance.
|
||||
*/
|
||||
public abstract VaultConnector build();
|
||||
|
||||
/**
|
||||
* Build connector and authenticate with token set in factory or from environment.
|
||||
*
|
||||
* @return Authenticated Vault connector instance.
|
||||
* @since 0.6.0
|
||||
*/
|
||||
public abstract VaultConnector buildAndAuth() throws VaultConnectorException;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -45,6 +46,8 @@ public class SecretResponse extends VaultDataResponse {
|
||||
* @since 0.4.0
|
||||
*/
|
||||
public Map<String, Object> getData() {
|
||||
if (data == null)
|
||||
return new HashMap<>();
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -56,7 +59,9 @@ public class SecretResponse extends VaultDataResponse {
|
||||
* @since 0.4.0
|
||||
*/
|
||||
public Object get(String key) {
|
||||
return data.get(key);
|
||||
if (data == null)
|
||||
return null;
|
||||
return getData().get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,9 +73,9 @@ public class SecretResponse extends VaultDataResponse {
|
||||
*/
|
||||
@Deprecated
|
||||
public String getValue() {
|
||||
if (data.get("value") == null)
|
||||
if (get("value") == null)
|
||||
return null;
|
||||
return data.get("value").toString();
|
||||
return get("value").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2016-2017 Stefan Kalscheuer
|
||||
*
|
||||
* 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 de.stklcode.jvault.connector.factory;
|
||||
|
||||
import de.stklcode.jvault.connector.HTTPVaultConnector;
|
||||
import de.stklcode.jvault.connector.exception.TlsException;
|
||||
import de.stklcode.jvault.connector.exception.VaultConnectorException;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.contrib.java.lang.system.EnvironmentVariables;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* JUnit test for HTTP Vault connector factory
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.6.0
|
||||
*/
|
||||
public class HTTPVaultConnectorFactoryTest {
|
||||
private static String VAULT_ADDR = "https://localhost:8201";
|
||||
private static Integer VAULT_MAX_RETRIES = 13;
|
||||
private static String VAULT_TOKEN = "00001111-2222-3333-4444-555566667777";
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder tmpDir = new TemporaryFolder();
|
||||
|
||||
@Rule
|
||||
public final EnvironmentVariables environment = new EnvironmentVariables();
|
||||
|
||||
/**
|
||||
* Test building from environment variables
|
||||
*/
|
||||
@Test
|
||||
public void testFromEnv() throws NoSuchFieldException, IllegalAccessException, IOException {
|
||||
/* Provide address only should be enough */
|
||||
setenv(VAULT_ADDR, null, null, null);
|
||||
|
||||
HTTPVaultConnectorFactory factory = null;
|
||||
HTTPVaultConnector connector;
|
||||
try {
|
||||
factory = VaultConnectorFactory.httpFactory().fromEnv();
|
||||
} catch (VaultConnectorException e) {
|
||||
fail("Factory creation from minimal environment failed");
|
||||
}
|
||||
connector = factory.build();
|
||||
|
||||
assertThat("URL nor set correctly", getPrivate(connector, "baseURL"), is(equalTo(VAULT_ADDR + "/v1/")));
|
||||
assertThat("SSL context set when no cert provided", getPrivate(connector, "sslContext"), is(nullValue()));
|
||||
assertThat("Non-default number of retries, when none set", getPrivate(connector, "retries"), is(0));
|
||||
|
||||
/* Provide address and number of retries */
|
||||
setenv(VAULT_ADDR, null, VAULT_MAX_RETRIES.toString(), null);
|
||||
|
||||
try {
|
||||
factory = VaultConnectorFactory.httpFactory().fromEnv();
|
||||
} catch (VaultConnectorException e) {
|
||||
fail("Factory creation from environment failed");
|
||||
}
|
||||
connector = factory.build();
|
||||
|
||||
assertThat("URL nor set correctly", getPrivate(connector, "baseURL"), is(equalTo(VAULT_ADDR + "/v1/")));
|
||||
assertThat("SSL context set when no cert provided", getPrivate(connector, "sslContext"), is(nullValue()));
|
||||
assertThat("Number of retries not set correctly", getPrivate(connector, "retries"), is(VAULT_MAX_RETRIES));
|
||||
|
||||
/* Provide CA certificate */
|
||||
String VAULT_CACERT = tmpDir.newFolder().toString() + "/doesnotexist";
|
||||
setenv(VAULT_ADDR, VAULT_CACERT, VAULT_MAX_RETRIES.toString(), null);
|
||||
|
||||
try {
|
||||
VaultConnectorFactory.httpFactory().fromEnv();
|
||||
fail("Creation with unknown cert path failed.");
|
||||
} catch (VaultConnectorException e) {
|
||||
assertThat(e, is(instanceOf(TlsException.class)));
|
||||
assertThat(e.getCause(), is(instanceOf(NoSuchFileException.class)));
|
||||
assertThat(((NoSuchFileException)e.getCause()).getFile(), is(VAULT_CACERT));
|
||||
}
|
||||
|
||||
/* Automatic authentication */
|
||||
setenv(VAULT_ADDR, null, VAULT_MAX_RETRIES.toString(), VAULT_TOKEN);
|
||||
|
||||
try {
|
||||
factory = VaultConnectorFactory.httpFactory().fromEnv();
|
||||
} catch (VaultConnectorException e) {
|
||||
fail("Factory creation from minimal environment failed");
|
||||
}
|
||||
assertThat("Token nor set correctly", getPrivate(factory, "token"), is(equalTo(VAULT_TOKEN)));
|
||||
}
|
||||
|
||||
private void setenv(String vault_addr, String vault_cacert, String vault_max_retries, String vault_token) {
|
||||
environment.set("VAULT_ADDR", vault_addr);
|
||||
environment.set("VAULT_CACERT", vault_cacert);
|
||||
environment.set("VAULT_MAX_RETRIES", vault_max_retries);
|
||||
environment.set("VAULT_TOKEN", vault_token);
|
||||
}
|
||||
|
||||
private Object getPrivate(Object target, String fieldName) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = target.getClass().getDeclaredField(fieldName);
|
||||
if (field.isAccessible())
|
||||
return field.get(target);
|
||||
field.setAccessible(true);
|
||||
Object value = field.get(target);
|
||||
field.setAccessible(false);
|
||||
return value;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user