Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
23419e94f1 | |||
5b34cfcc27 | |||
b1c78b50d2 | |||
238ac8bd10 | |||
c8a2e0784f | |||
23f98f190b | |||
745ab7a24c | |||
71f68f088f | |||
52a1abfb87 | |||
4bf9df5f73 | |||
8ae4dccdd6 | |||
7ac550230f | |||
c1d519826c | |||
a727ed960b | |||
c685ec82a0 | |||
934628f382 | |||
ce90f9fba2 | |||
6b25113b9f | |||
63dc329857 | |||
42094101a3 | |||
259747afae | |||
d7365dcaf1 | |||
c24d1cae0b | |||
af7b99587f | |||
13c2cce162 | |||
e9663ef794 | |||
3fd74a7fd2 | |||
21943896c7 | |||
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
|
||||
*~
|
19
.travis.yml
19
.travis.yml
@ -4,9 +4,22 @@ branches:
|
||||
language: java
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
dist: trusty
|
||||
install: true
|
||||
addons:
|
||||
sonarcloud:
|
||||
organization: "stklcode-github"
|
||||
token:
|
||||
secure: "sM9OfX5jW764pn9cb2LSXArnXucKMws+eGeg5NnZxHRcGYt4hpBKLSregBSsBNzUoWVj0zNzPCpnh+UQvgxQzUerOqwEdjTBpy3SNPaxSn7UpoSg+Wz3aUmL9ugmx01b51/wMG4UCHEwTZt2tpgTPVtw8K6uSO78e0dSICCBHDnRcdQwOjMEQHIJJ/qHVRwuy/MzLCAP3W1JPZlsphZg9QsFyhB4hW97dE90joZezfocQIv2xI/r6k+BLz0pY6MxYCul0RiDumaiaej0CPvEJI/uSu//BAQjUdHw+mQgnKUYIbrn2ONOviwNfwdr94JyoZEN2B6zASUmNLjPf4AbIojDeyS+CrpQpm17EVm/Qk/Ds+Xra4PPPIcsZhiWzV0KoDUz9xLfXuRJ526VT5tDPiaeI7oETf0+8l+JIS1b399FyqHi7smzjpvC6GuKflQrbuHK4MuKzDh7WTHiqokGG4SS0wOQIaaHB3dfdwwQzPh6IM24e8CETxh3DjMeqUTU4DWmv5po55jZ934TtxVQvVN78bTG9O0zS9u+JmRY04OZ+OaXuFam6MfMUFQi0EPZzdGul/oWSibGUu3bNfVEBp60CnJwYNM/dKG6U7pJthLHvSwiQFOdKzHZ+l1jZJ4gPaXaIGqpwqVGr28ntqA/El1rytPixr2driE6bYMt5jw="
|
||||
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.8.1/vault_0.8.1_linux_amd64.zip
|
||||
- unzip vault_0.8.1_linux_amd64.zip
|
||||
- rm vault_0.8.1_linux_amd64.zip
|
||||
cache:
|
||||
directories:
|
||||
- '$HOME/.m2/repository'
|
||||
- '$HOME/.sonar/cache'
|
||||
script:
|
||||
- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar
|
23
CHANGELOG.md
23
CHANGELOG.md
@ -1,3 +1,24 @@
|
||||
## 0.6.2 [2017-08-19]
|
||||
* [fix] Prevent potential NPE on SecretResponse getter
|
||||
* [fix] Removed stack traces on PUT request and response deserialization (#13)
|
||||
* [improvement] Fields of InvalidResposneException made final
|
||||
* [deprecation] `listAppRoleSecretss()` in favor of `listAppRoleSecrets()` (#14)
|
||||
* [test] Tested against Vault 0.8.1, increased coverage
|
||||
|
||||
## 0.6.1 [2017-08-02]
|
||||
* [fix] `TokenModel.getPassword()` returned username instead of password
|
||||
* [fix] `TokenModel.getUsername()` and `getPassword()` could produce NPE in multithreaded environments
|
||||
* [fix] `TokenData.getCreatinTtl()` renamed to `getCreationTtl()` (typo fix)
|
||||
* [test] Tested against Vault 0.7.3
|
||||
|
||||
## 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
|
||||
@ -31,4 +52,4 @@
|
||||
* [test] Tested against Vault 0.6.0
|
||||
|
||||
## 0.1.0 [2016-03-29]
|
||||
* First release
|
||||
* First release
|
||||
|
12
README.md
12
README.md
@ -1,6 +1,7 @@
|
||||
# Java Vault Connector
|
||||
|
||||
[](https://travis-ci.org/stklcode/jvaultconnector)
|
||||
[](https://sonarcloud.io/dashboard?id=de.stklcode.jvault%3Aconnector)
|
||||
[](https://github.com/stklcode/jvaultconnector/blob/master/LICENSE.txt)
|
||||
[](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.stklcode.jvault%22%20AND%20a%3A%22connector%22)
|
||||
|
||||
@ -12,6 +13,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 +29,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.8.1
|
||||
|
||||
|
||||
## Maven Artifact
|
||||
@ -36,7 +39,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.2</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
@ -58,6 +61,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.2</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.9.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.8.7</version>
|
||||
<version>2.9.0</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.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -23,6 +23,7 @@ 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;
|
||||
@ -37,7 +38,6 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
/**
|
||||
* Vault Connector implementatin using Vault's HTTP API.
|
||||
*
|
||||
@ -60,10 +60,14 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
private static final String PATH_AUTH_APPROLE = "auth/approle/";
|
||||
private static final String PATH_REVOKE = "sys/revoke/";
|
||||
|
||||
private static final String HEADER_VAULT_TOKEN = "X-Vault-Token";
|
||||
|
||||
private final ObjectMapper jsonMapper;
|
||||
|
||||
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 */
|
||||
@ -75,7 +79,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
* @param hostname The hostname
|
||||
* @param useTLS If TRUE, use HTTPS, otherwise HTTP
|
||||
*/
|
||||
public HTTPVaultConnector(String hostname, boolean useTLS) {
|
||||
public HTTPVaultConnector(final String hostname, final boolean useTLS) {
|
||||
this(hostname, useTLS, null);
|
||||
}
|
||||
|
||||
@ -86,7 +90,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
* @param useTLS If TRUE, use HTTPS, otherwise HTTP
|
||||
* @param port The port
|
||||
*/
|
||||
public HTTPVaultConnector(String hostname, boolean useTLS, Integer port) {
|
||||
public HTTPVaultConnector(final String hostname, final boolean useTLS, final Integer port) {
|
||||
this(hostname, useTLS, port, PATH_PREFIX);
|
||||
}
|
||||
|
||||
@ -98,11 +102,11 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
* @param port The port
|
||||
* @param prefix HTTP API prefix (default: /v1/)
|
||||
*/
|
||||
public HTTPVaultConnector(String hostname, boolean useTLS, Integer port, String prefix) {
|
||||
this(((useTLS) ? "https" : "http") +
|
||||
"://" + hostname +
|
||||
((port != null) ? ":" + port : "") +
|
||||
prefix);
|
||||
public HTTPVaultConnector(final String hostname, final boolean useTLS, final Integer port, final String prefix) {
|
||||
this(((useTLS) ? "https" : "http")
|
||||
+ "://" + hostname
|
||||
+ ((port != null) ? ":" + port : "")
|
||||
+ prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,12 +118,39 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
* @param prefix HTTP API prefix (default: /v1/)
|
||||
* @param sslContext Custom SSL Context
|
||||
*/
|
||||
public HTTPVaultConnector(String hostname, boolean useTLS, Integer port, String prefix, SSLContext sslContext) {
|
||||
this(((useTLS) ? "https" : "http") +
|
||||
"://" + hostname +
|
||||
((port != null) ? ":" + port : "") +
|
||||
prefix,
|
||||
sslContext);
|
||||
public HTTPVaultConnector(final String hostname,
|
||||
final boolean useTLS,
|
||||
final Integer port,
|
||||
final String prefix,
|
||||
final 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
|
||||
* @param numberOfRetries Number of retries on 5xx errors
|
||||
* @param timeout Timeout for HTTP requests (milliseconds)
|
||||
*/
|
||||
public HTTPVaultConnector(final String hostname,
|
||||
final boolean useTLS,
|
||||
final Integer port,
|
||||
final String prefix,
|
||||
final SSLContext sslContext,
|
||||
final int numberOfRetries,
|
||||
final Integer timeout) {
|
||||
this(((useTLS) ? "https" : "http")
|
||||
+ "://" + hostname
|
||||
+ ((port != null) ? ":" + port : "")
|
||||
+ prefix,
|
||||
sslContext,
|
||||
numberOfRetries,
|
||||
timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -127,7 +158,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
*
|
||||
* @param baseURL The URL
|
||||
*/
|
||||
public HTTPVaultConnector(String baseURL) {
|
||||
public HTTPVaultConnector(final String baseURL) {
|
||||
this(baseURL, null);
|
||||
}
|
||||
|
||||
@ -137,21 +168,49 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
* @param baseURL The URL
|
||||
* @param sslContext Custom SSL Context
|
||||
*/
|
||||
public HTTPVaultConnector(String baseURL, SSLContext sslContext) {
|
||||
public HTTPVaultConnector(final String baseURL, final 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(final String baseURL, final SSLContext sslContext, final 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
|
||||
* @param timeout Timeout for HTTP requests (milliseconds)
|
||||
*/
|
||||
public HTTPVaultConnector(final String baseURL,
|
||||
final SSLContext sslContext,
|
||||
final int numberOfRetries,
|
||||
final Integer timeout) {
|
||||
this.baseURL = baseURL;
|
||||
this.sslContext = sslContext;
|
||||
this.retries = numberOfRetries;
|
||||
this.timeout = timeout;
|
||||
this.jsonMapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetAuth() {
|
||||
public final void resetAuth() {
|
||||
token = null;
|
||||
tokenTTL = 0;
|
||||
authorized = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SealResponse sealStatus() {
|
||||
public final SealResponse sealStatus() {
|
||||
try {
|
||||
String response = requestGet(PATH_SEAL_STATUS, new HashMap<>());
|
||||
return jsonMapper.readValue(response, SealResponse.class);
|
||||
@ -165,7 +224,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean seal() {
|
||||
public final boolean seal() {
|
||||
try {
|
||||
requestPut(PATH_SEAL, new HashMap<>());
|
||||
return true;
|
||||
@ -176,7 +235,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SealResponse unseal(final String key, final Boolean reset) {
|
||||
public final SealResponse unseal(final String key, final Boolean reset) {
|
||||
Map<String, String> param = new HashMap<>();
|
||||
param.put("key", key);
|
||||
if (reset != null)
|
||||
@ -191,12 +250,12 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized() {
|
||||
public final boolean isAuthorized() {
|
||||
return authorized && (tokenTTL == 0 || tokenTTL >= System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AuthBackend> getAuthBackends() throws VaultConnectorException {
|
||||
public final List<AuthBackend> getAuthBackends() throws VaultConnectorException {
|
||||
try {
|
||||
String response = requestGet(PATH_AUTH, new HashMap<>());
|
||||
/* Parse response */
|
||||
@ -211,7 +270,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse authToken(final String token) throws VaultConnectorException {
|
||||
public final TokenResponse authToken(final String token) throws VaultConnectorException {
|
||||
/* set token */
|
||||
this.token = token;
|
||||
this.tokenTTL = 0;
|
||||
@ -226,7 +285,8 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse authUserPass(final String username, final String password) throws VaultConnectorException {
|
||||
public final AuthResponse authUserPass(final String username, final String password)
|
||||
throws VaultConnectorException {
|
||||
final Map<String, String> payload = new HashMap<>();
|
||||
payload.put("password", password);
|
||||
return queryAuth(PATH_AUTH_USERPASS + username, payload);
|
||||
@ -234,7 +294,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public AuthResponse authAppId(final String appID, final String userID) throws VaultConnectorException {
|
||||
public final AuthResponse authAppId(final String appID, final String userID) throws VaultConnectorException {
|
||||
final Map<String, String> payload = new HashMap<>();
|
||||
payload.put("app_id", appID);
|
||||
payload.put("user_id", userID);
|
||||
@ -242,7 +302,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse authAppRole(final String roleID, final String secretID) throws VaultConnectorException {
|
||||
public final AuthResponse authAppRole(final String roleID, final String secretID) throws VaultConnectorException {
|
||||
final Map<String, String> payload = new HashMap<>();
|
||||
payload.put("role_id", roleID);
|
||||
if (secretID != null)
|
||||
@ -251,14 +311,15 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
/**
|
||||
* Query authorization request to given backend
|
||||
* Query authorization request to given backend.
|
||||
*
|
||||
* @param path The path to request
|
||||
* @param payload Payload (credentials)
|
||||
* @return The AuthResponse
|
||||
* @throws VaultConnectorException on errors
|
||||
*/
|
||||
private AuthResponse queryAuth(final String path, final Map<String, String> payload) throws VaultConnectorException {
|
||||
private AuthResponse queryAuth(final String path, final Map<String, String> payload)
|
||||
throws VaultConnectorException {
|
||||
try {
|
||||
/* Get response */
|
||||
String response = requestPost(path, payload);
|
||||
@ -276,7 +337,8 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean registerAppId(final String appID, final String policy, final String displayName) throws VaultConnectorException {
|
||||
public final boolean registerAppId(final String appID, final String policy, final String displayName)
|
||||
throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
Map<String, String> payload = new HashMap<>();
|
||||
@ -292,7 +354,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean registerUserId(final String appID, final String userID) throws VaultConnectorException {
|
||||
public final boolean registerUserId(final String appID, final String userID) throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
Map<String, String> payload = new HashMap<>();
|
||||
@ -306,7 +368,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createAppRole(final AppRole role) throws VaultConnectorException {
|
||||
public final boolean createAppRole(final AppRole role) throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
/* Get response */
|
||||
@ -320,7 +382,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppRoleResponse lookupAppRole(final String roleName) throws VaultConnectorException {
|
||||
public final AppRoleResponse lookupAppRole(final String roleName) throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
/* Request HTTP response and parse Secret */
|
||||
@ -336,7 +398,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteAppRole(String roleName) throws VaultConnectorException {
|
||||
public final boolean deleteAppRole(final String roleName) throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
|
||||
@ -351,7 +413,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAppRoleID(final String roleName) throws VaultConnectorException {
|
||||
public final String getAppRoleID(final String roleName) throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
/* Request HTTP response and parse Secret */
|
||||
@ -367,7 +429,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setAppRoleID(final String roleName, final String roleID) throws VaultConnectorException {
|
||||
public final boolean setAppRoleID(final String roleName, final String roleID) throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
/* Request HTTP response and parse Secret */
|
||||
@ -381,7 +443,8 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppRoleSecretResponse createAppRoleSecret(final String roleName, final AppRoleSecret secret) throws VaultConnectorException {
|
||||
public final AppRoleSecretResponse createAppRoleSecret(final String roleName, final AppRoleSecret secret)
|
||||
throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
/* Get response */
|
||||
@ -400,12 +463,15 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppRoleSecretResponse lookupAppRoleSecret(final String roleName, final String secretID) throws VaultConnectorException {
|
||||
public final AppRoleSecretResponse lookupAppRoleSecret(final String roleName, final String secretID)
|
||||
throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
/* Request HTTP response and parse Secret */
|
||||
try {
|
||||
String response = requestPost(PATH_AUTH_APPROLE + "role/" + roleName + "/secret-id/lookup", new AppRoleSecret(secretID));
|
||||
String response = requestPost(
|
||||
PATH_AUTH_APPROLE + "role/" + roleName + "/secret-id/lookup",
|
||||
new AppRoleSecret(secretID));
|
||||
return jsonMapper.readValue(response, AppRoleSecretResponse.class);
|
||||
} catch (IOException e) {
|
||||
throw new InvalidResponseException("Unable to parse response", e);
|
||||
@ -413,12 +479,15 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean destroyAppRoleSecret(final String roleName, final String secretID) throws VaultConnectorException {
|
||||
public final boolean destroyAppRoleSecret(final String roleName, final String secretID)
|
||||
throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
|
||||
/* Request HTTP response and expect empty result */
|
||||
String response = requestPost(PATH_AUTH_APPROLE + "role/" + roleName + "/secret-id/destroy", new AppRoleSecret(secretID));
|
||||
String response = requestPost(
|
||||
PATH_AUTH_APPROLE + "role/" + roleName + "/secret-id/destroy",
|
||||
new AppRoleSecret(secretID));
|
||||
|
||||
/* Response should be code 204 without content */
|
||||
if (!response.equals(""))
|
||||
@ -428,7 +497,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listAppRoles() throws VaultConnectorException {
|
||||
public final List<String> listAppRoles() throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
|
||||
@ -445,12 +514,14 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listAppRoleSecretss(final String roleName) throws VaultConnectorException {
|
||||
public final List<String> listAppRoleSecrets(final String roleName) throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
|
||||
try {
|
||||
String response = requestGet(PATH_AUTH_APPROLE + "role/" + roleName + "/secret-id?list=true", new HashMap<>());
|
||||
String response = requestGet(
|
||||
PATH_AUTH_APPROLE + "role/" + roleName + "/secret-id?list=true",
|
||||
new HashMap<>());
|
||||
SecretListResponse secrets = jsonMapper.readValue(response, SecretListResponse.class);
|
||||
return secrets.getKeys();
|
||||
} catch (IOException e) {
|
||||
@ -462,7 +533,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretResponse read(final String key) throws VaultConnectorException {
|
||||
public final SecretResponse read(final String key) throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
/* Request HTTP response and parse Secret */
|
||||
@ -478,7 +549,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> list(final String path) throws VaultConnectorException {
|
||||
public final List<String> list(final String path) throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
|
||||
@ -494,7 +565,8 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
}
|
||||
|
||||
public void write(final String key, final Map<String, Object> data) throws VaultConnectorException {
|
||||
@Override
|
||||
public final void write(final String key, final Map<String, Object> data) throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
|
||||
@ -506,7 +578,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String key) throws VaultConnectorException {
|
||||
public final void delete(final String key) throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
|
||||
@ -519,7 +591,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revoke(String leaseID) throws VaultConnectorException {
|
||||
public final void revoke(final String leaseID) throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
|
||||
@ -532,7 +604,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecretResponse renew(String leaseID, Integer increment) throws VaultConnectorException {
|
||||
public final SecretResponse renew(final String leaseID, final Integer increment) throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
|
||||
@ -551,22 +623,29 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse createToken(final Token token) throws VaultConnectorException {
|
||||
public final AuthResponse createToken(final Token token) throws VaultConnectorException {
|
||||
return createTokenInternal(token, PATH_TOKEN + PATH_CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse createToken(final Token token, boolean orphan) throws VaultConnectorException {
|
||||
public final AuthResponse createToken(final Token token, final boolean orphan) throws VaultConnectorException {
|
||||
return createTokenInternal(token, PATH_TOKEN + PATH_CREATE_ORPHAN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthResponse createToken(final Token token, final String role) throws VaultConnectorException {
|
||||
public final AuthResponse createToken(final Token token, final String role) throws VaultConnectorException {
|
||||
if (role == null || role.isEmpty())
|
||||
throw new InvalidRequestException("No role name specified.");
|
||||
return createTokenInternal(token, PATH_TOKEN + PATH_CREATE + "/" + role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void close() {
|
||||
authorized = false;
|
||||
token = null;
|
||||
tokenTTL = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create token.
|
||||
* Centralized method to handle different token creation requests.
|
||||
@ -592,7 +671,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TokenResponse lookupToken(final String token) throws VaultConnectorException {
|
||||
public final TokenResponse lookupToken(final String token) throws VaultConnectorException {
|
||||
if (!isAuthorized())
|
||||
throw new AuthorizationRequiredException();
|
||||
/* Request HTTP response and parse Secret */
|
||||
@ -632,9 +711,9 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
post.setEntity(input);
|
||||
/* Set X-Vault-Token header */
|
||||
if (token != null)
|
||||
post.addHeader("X-Vault-Token", token);
|
||||
post.addHeader(HEADER_VAULT_TOKEN, token);
|
||||
|
||||
return request(post);
|
||||
return request(post, retries);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -653,15 +732,15 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
try {
|
||||
entity = new StringEntity(jsonMapper.writeValueAsString(payload));
|
||||
} catch (UnsupportedEncodingException | JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
throw new InvalidRequestException("Payload serialization failed", e);
|
||||
}
|
||||
/* Parse parameters */
|
||||
put.setEntity(entity);
|
||||
/* Set X-Vault-Token header */
|
||||
if (token != null)
|
||||
put.addHeader("X-Vault-Token", token);
|
||||
put.addHeader(HEADER_VAULT_TOKEN, token);
|
||||
|
||||
return request(put);
|
||||
return request(put, retries);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -676,9 +755,9 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
HttpDelete delete = new HttpDelete(baseURL + path);
|
||||
/* Set X-Vault-Token header */
|
||||
if (token != null)
|
||||
delete.addHeader("X-Vault-Token", token);
|
||||
delete.addHeader(HEADER_VAULT_TOKEN, token);
|
||||
|
||||
return request(delete);
|
||||
return request(delete, retries);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -688,8 +767,10 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
* @param payload Map of payload values (will be converted to JSON)
|
||||
* @return HTTP response
|
||||
* @throws VaultConnectorException on connection error
|
||||
* @throws URISyntaxException on invalid URI syntax
|
||||
*/
|
||||
private String requestGet(final String path, final Map<String, String> payload) throws VaultConnectorException, URISyntaxException {
|
||||
private String requestGet(final String path, final Map<String, String> payload)
|
||||
throws VaultConnectorException, URISyntaxException {
|
||||
/* Add parameters to URI */
|
||||
URIBuilder uriBuilder = new URIBuilder(baseURL + path);
|
||||
payload.forEach(uriBuilder::addParameter);
|
||||
@ -699,24 +780,29 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
|
||||
/* Set X-Vault-Token header */
|
||||
if (token != null)
|
||||
get.addHeader("X-Vault-Token", token);
|
||||
get.addHeader(HEADER_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(final HttpRequestBase base, final 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)
|
||||
@ -724,29 +810,40 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
|
||||
switch (response.getStatusLine().getStatusCode()) {
|
||||
case 200:
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) {
|
||||
try (BufferedReader br = new BufferedReader(
|
||||
new InputStreamReader(response.getEntity().getContent()))) {
|
||||
return br.lines().collect(Collectors.joining("\n"));
|
||||
} catch (IOException ignored) {
|
||||
throw new InvalidResponseException("Could not parse response body", 200);
|
||||
}
|
||||
case 204:
|
||||
return "";
|
||||
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 */
|
||||
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().isEmpty() && er.getErrors().get(0).equals("permission denied"))
|
||||
throw new PermissionDeniedException();
|
||||
throw new InvalidResponseException("Invalid response code",
|
||||
response.getStatusLine().getStatusCode(), er.toString());
|
||||
} catch (IOException ignored) {
|
||||
// Exception ignored.
|
||||
}
|
||||
}
|
||||
throw new InvalidResponseException("Invalid response code",
|
||||
response.getStatusLine().getStatusCode());
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new InvalidResponseException("Unable to read response", e);
|
||||
@ -755,6 +852,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
||||
try {
|
||||
EntityUtils.consume(response.getEntity());
|
||||
} catch (IOException ignored) {
|
||||
// Exception ignored.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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";
|
||||
|
||||
/**
|
||||
@ -144,7 +144,8 @@ public interface VaultConnector {
|
||||
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. Consider using {@link #createAppRole} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
boolean registerAppId(final String appID, final String policy, final String displayName) throws VaultConnectorException;
|
||||
boolean registerAppId(final String appID, final String policy, final String displayName)
|
||||
throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Register a new AppRole role from given metamodel.
|
||||
@ -204,7 +205,8 @@ public interface VaultConnector {
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.4.0
|
||||
*/
|
||||
default boolean createAppRole(final String roleName, final List<String> policies, final String roleID) throws VaultConnectorException {
|
||||
default boolean createAppRole(final String roleName, final List<String> policies, final String roleID)
|
||||
throws VaultConnectorException {
|
||||
return createAppRole(new AppRoleBuilder(roleName).withPolicies(policies).withId(roleID).build());
|
||||
}
|
||||
|
||||
@ -269,7 +271,8 @@ public interface VaultConnector {
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.4.0
|
||||
*/
|
||||
default AppRoleSecretResponse createAppRoleSecret(final String roleName, final String secretID) throws VaultConnectorException {
|
||||
default AppRoleSecretResponse createAppRoleSecret(final String roleName, final String secretID)
|
||||
throws VaultConnectorException {
|
||||
return createAppRoleSecret(roleName, new AppRoleSecret(secretID));
|
||||
}
|
||||
|
||||
@ -282,7 +285,8 @@ public interface VaultConnector {
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.4.0
|
||||
*/
|
||||
AppRoleSecretResponse createAppRoleSecret(final String roleName, final AppRoleSecret secret) throws VaultConnectorException;
|
||||
AppRoleSecretResponse createAppRoleSecret(final String roleName, final AppRoleSecret secret)
|
||||
throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Lookup an AppRole secret.
|
||||
@ -293,7 +297,8 @@ public interface VaultConnector {
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.4.0
|
||||
*/
|
||||
AppRoleSecretResponse lookupAppRoleSecret(final String roleName, final String secretID) throws VaultConnectorException;
|
||||
AppRoleSecretResponse lookupAppRoleSecret(final String roleName, final String secretID)
|
||||
throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Destroy an AppRole secret.
|
||||
@ -320,17 +325,31 @@ public interface VaultConnector {
|
||||
* @param roleName The role name
|
||||
* @return List of roles
|
||||
* @throws VaultConnectorException on error
|
||||
* @deprecated Use {@link #listAppRoleSecrets(String)}}. Will be removed in 0.7.0!
|
||||
*/
|
||||
List<String> listAppRoleSecretss(final String roleName) throws VaultConnectorException;
|
||||
@Deprecated
|
||||
default List<String> listAppRoleSecretss(final String roleName) throws VaultConnectorException {
|
||||
return listAppRoleSecrets(roleName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register User-ID with App-ID
|
||||
* List existing (accessible) secret IDs for AppRole role.
|
||||
*
|
||||
* @param roleName The role name
|
||||
* @return List of roles
|
||||
* @throws VaultConnectorException on error
|
||||
*/
|
||||
List<String> listAppRoleSecrets(final String roleName) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Register User-ID with App-ID.
|
||||
*
|
||||
* @param appID The App-ID
|
||||
* @param userID The User-ID
|
||||
* @return TRUE on success
|
||||
* @throws VaultConnectorException on error
|
||||
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. Consider using {@link #createAppRoleSecret} instead.
|
||||
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole.
|
||||
* Consider using {@link #createAppRoleSecret} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
boolean registerUserId(final String appID, final String userID) throws VaultConnectorException;
|
||||
@ -347,12 +366,15 @@ public interface VaultConnector {
|
||||
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole.
|
||||
*/
|
||||
@Deprecated
|
||||
default boolean registerAppUserId(final String appID, final String policy, final String displayName, final String userID) throws VaultConnectorException {
|
||||
default boolean registerAppUserId(final String appID,
|
||||
final String policy,
|
||||
final String displayName,
|
||||
final String userID) throws VaultConnectorException {
|
||||
return registerAppId(appID, policy, userID) && registerUserId(appID, userID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authorization status
|
||||
* Get authorization status.
|
||||
*
|
||||
* @return TRUE, if successfully authorized
|
||||
*/
|
||||
@ -543,7 +565,7 @@ public interface VaultConnector {
|
||||
TokenResponse lookupToken(final String token) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Read credentials for MySQL backend at default mount point
|
||||
* Read credentials for MySQL backend at default mount point.
|
||||
*
|
||||
* @param role the role name
|
||||
* @return the credentials response
|
||||
@ -555,7 +577,7 @@ public interface VaultConnector {
|
||||
}
|
||||
|
||||
/**
|
||||
* Read credentials for PostgreSQL backend at default mount point
|
||||
* Read credentials for PostgreSQL backend at default mount point.
|
||||
*
|
||||
* @param role the role name
|
||||
* @return the credentials response
|
||||
@ -567,7 +589,7 @@ public interface VaultConnector {
|
||||
}
|
||||
|
||||
/**
|
||||
* Read credentials for MSSQL backend at default mount point
|
||||
* Read credentials for MSSQL backend at default mount point.
|
||||
*
|
||||
* @param role the role name
|
||||
* @return the credentials response
|
||||
@ -579,7 +601,7 @@ public interface VaultConnector {
|
||||
}
|
||||
|
||||
/**
|
||||
* Read credentials for MSSQL backend at default mount point
|
||||
* Read credentials for MSSQL backend at default mount point.
|
||||
*
|
||||
* @param role the role name
|
||||
* @return the credentials response
|
||||
@ -599,7 +621,8 @@ public interface VaultConnector {
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.5.0
|
||||
*/
|
||||
default CredentialsResponse readDbCredentials(final String role, final String mount) throws VaultConnectorException {
|
||||
default CredentialsResponse readDbCredentials(final String role, final String mount)
|
||||
throws VaultConnectorException {
|
||||
return (CredentialsResponse) read(mount + "/creds/" + role);
|
||||
}
|
||||
}
|
||||
|
@ -19,22 +19,41 @@ package de.stklcode.jvault.connector.exception;
|
||||
/**
|
||||
* Exception thrown on problems with connection to Vault backend.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
*/
|
||||
public class ConnectionException extends VaultConnectorException {
|
||||
/**
|
||||
* Constructs a new empty exception.
|
||||
*/
|
||||
public ConnectionException() {
|
||||
}
|
||||
|
||||
public ConnectionException(String message) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message.
|
||||
*
|
||||
* @param message the detail message
|
||||
*/
|
||||
public ConnectionException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ConnectionException(Throwable cause) {
|
||||
/**
|
||||
* Constructs a new exception with the specified cause.
|
||||
*
|
||||
* @param cause the cause
|
||||
*/
|
||||
public ConnectionException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public ConnectionException(String message, Throwable cause) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and cause.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param cause the cause
|
||||
*/
|
||||
public ConnectionException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
@ -23,18 +23,37 @@ package de.stklcode.jvault.connector.exception;
|
||||
* @since 0.1
|
||||
*/
|
||||
public class InvalidRequestException extends VaultConnectorException {
|
||||
/**
|
||||
* Constructs a new empty exception.
|
||||
*/
|
||||
public InvalidRequestException() {
|
||||
}
|
||||
|
||||
public InvalidRequestException(String message) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message.
|
||||
*
|
||||
* @param message the detail message
|
||||
*/
|
||||
public InvalidRequestException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InvalidRequestException(Throwable cause) {
|
||||
/**
|
||||
* Constructs a new exception with the specified cause.
|
||||
*
|
||||
* @param cause the cause
|
||||
*/
|
||||
public InvalidRequestException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public InvalidRequestException(String message, Throwable cause) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and cause.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param cause the cause
|
||||
*/
|
||||
public InvalidRequestException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
@ -20,42 +20,160 @@ package de.stklcode.jvault.connector.exception;
|
||||
* Exception thrown when response from vault returned with erroneous status code or payload could not be parsed
|
||||
* to entity class.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
*/
|
||||
public class InvalidResponseException extends VaultConnectorException {
|
||||
private Integer statusCode;
|
||||
private String response;
|
||||
public final class InvalidResponseException extends VaultConnectorException {
|
||||
private final Integer statusCode;
|
||||
private final String response;
|
||||
|
||||
/**
|
||||
* Constructs a new empty exception.
|
||||
*/
|
||||
public InvalidResponseException() {
|
||||
this.statusCode = null;
|
||||
this.response = null;
|
||||
}
|
||||
|
||||
public InvalidResponseException(String message) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message.
|
||||
*
|
||||
* @param message the detail message
|
||||
*/
|
||||
public InvalidResponseException(final String message) {
|
||||
super(message);
|
||||
this.statusCode = null;
|
||||
this.response = null;
|
||||
}
|
||||
|
||||
public InvalidResponseException(Throwable cause) {
|
||||
/**
|
||||
* Constructs a new exception with the specified cause.
|
||||
*
|
||||
* @param cause the cause
|
||||
*/
|
||||
public InvalidResponseException(final Throwable cause) {
|
||||
super(cause);
|
||||
this.statusCode = null;
|
||||
this.response = null;
|
||||
}
|
||||
|
||||
public InvalidResponseException(String message, Throwable cause) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and cause.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param cause the cause
|
||||
*/
|
||||
public InvalidResponseException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
this.statusCode = null;
|
||||
this.response = null;
|
||||
}
|
||||
|
||||
public InvalidResponseException withStatusCode(Integer statusCode) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and status code.
|
||||
* <p>
|
||||
* The HTTP status code can be retrieved by {@link #getStatusCode()} later.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param statusCode status code of the HTTP response
|
||||
* @since 0.6.2
|
||||
*/
|
||||
public InvalidResponseException(final String message, final Integer statusCode) {
|
||||
super(message);
|
||||
this.statusCode = statusCode;
|
||||
return this;
|
||||
this.response = null;
|
||||
}
|
||||
|
||||
public InvalidResponseException withResponse(String response) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message, cause and status code.
|
||||
* <p>
|
||||
* The HTTP status code can be retrieved by {@link #getStatusCode()} later.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param statusCode status code of the HTTP response
|
||||
* @param cause the cause
|
||||
* @since 0.6.2
|
||||
*/
|
||||
public InvalidResponseException(final String message, final Integer statusCode, final Throwable cause) {
|
||||
this(message, statusCode, null, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message, cause and status code.
|
||||
* <p>
|
||||
* The HTTP status code can be retrieved by {@link #getStatusCode()} later.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param statusCode status code of the HTTP response
|
||||
* @param response HTTP response string
|
||||
* @since 0.6.2
|
||||
*/
|
||||
public InvalidResponseException(final String message,
|
||||
final Integer statusCode,
|
||||
final String response) {
|
||||
super(message);
|
||||
this.statusCode = statusCode;
|
||||
this.response = response;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message, cause and status code.
|
||||
* <p>
|
||||
* The HTTP status code can be retrieved by {@link #getStatusCode()} later.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param statusCode status code of the HTTP response
|
||||
* @param response HTTP response string
|
||||
* @param cause the cause
|
||||
* @since 0.6.2
|
||||
*/
|
||||
public InvalidResponseException(final String message,
|
||||
final Integer statusCode,
|
||||
final String response,
|
||||
final Throwable cause) {
|
||||
super(message, cause);
|
||||
this.statusCode = statusCode;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the HTTP status code. Can be retrieved by {@link #getStatusCode()} later.
|
||||
*
|
||||
* @param statusCode the status code
|
||||
* @return self
|
||||
* @deprecated as of 0.6.2, use constructor with status code argument instead
|
||||
*/
|
||||
@Deprecated
|
||||
public InvalidResponseException withStatusCode(final Integer statusCode) {
|
||||
return new InvalidResponseException(getMessage(), statusCode, getResponse(), getCause());
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the response string. Can be retrieved by {@link #getResponse()} later.
|
||||
*
|
||||
* @param response response text
|
||||
* @return self
|
||||
* @deprecated use constructor with response argument instead
|
||||
*/
|
||||
@Deprecated
|
||||
public InvalidResponseException withResponse(final String response) {
|
||||
return new InvalidResponseException(getMessage(), getStatusCode(), response, getCause());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the HTTP status code.
|
||||
*
|
||||
* @return the status code or {@code null} if none specified.
|
||||
*/
|
||||
public Integer getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the response text.
|
||||
*
|
||||
* @return the response text or {@code null} if none specified.
|
||||
*/
|
||||
public String getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
@ -23,19 +23,38 @@ package de.stklcode.jvault.connector.exception;
|
||||
* @since 0.1
|
||||
*/
|
||||
public class PermissionDeniedException extends VaultConnectorException {
|
||||
/**
|
||||
* Constructs a new empty exception.
|
||||
*/
|
||||
public PermissionDeniedException() {
|
||||
super("Permission denied");
|
||||
}
|
||||
|
||||
public PermissionDeniedException(String message) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message.
|
||||
*
|
||||
* @param message the detail message
|
||||
*/
|
||||
public PermissionDeniedException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public PermissionDeniedException(Throwable cause) {
|
||||
/**
|
||||
* Constructs a new exception with the specified cause.
|
||||
*
|
||||
* @param cause the cause
|
||||
*/
|
||||
public PermissionDeniedException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public PermissionDeniedException(String message, Throwable cause) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and cause.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param cause the cause
|
||||
*/
|
||||
public PermissionDeniedException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
@ -23,29 +23,37 @@ package de.stklcode.jvault.connector.exception;
|
||||
* @since 0.4.0
|
||||
*/
|
||||
public class TlsException extends VaultConnectorException {
|
||||
private Integer statusCode;
|
||||
private String response;
|
||||
|
||||
/**
|
||||
* Constructs a new empty exception.
|
||||
*/
|
||||
public TlsException() {
|
||||
}
|
||||
|
||||
public TlsException(String message) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message.
|
||||
*
|
||||
* @param message the detail message
|
||||
*/
|
||||
public TlsException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public TlsException(Throwable cause) {
|
||||
/**
|
||||
* Constructs a new exception with the specified cause.
|
||||
*
|
||||
* @param cause the cause
|
||||
*/
|
||||
public TlsException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public TlsException(String message, Throwable cause) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and cause.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param cause the cause
|
||||
*/
|
||||
public TlsException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public Integer getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
public String getResponse() {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
@ -23,18 +23,37 @@ package de.stklcode.jvault.connector.exception;
|
||||
* @since 0.1
|
||||
*/
|
||||
public abstract class VaultConnectorException extends Exception {
|
||||
/**
|
||||
* Constructs a new empty exception.
|
||||
*/
|
||||
public VaultConnectorException() {
|
||||
}
|
||||
|
||||
public VaultConnectorException(String message) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message.
|
||||
*
|
||||
* @param message the detail message
|
||||
*/
|
||||
public VaultConnectorException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public VaultConnectorException(Throwable cause) {
|
||||
/**
|
||||
* Constructs a new exception with the specified cause.
|
||||
*
|
||||
* @param cause the cause
|
||||
*/
|
||||
public VaultConnectorException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public VaultConnectorException(String message, Throwable cause) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and cause.
|
||||
*
|
||||
* @param message the detail message
|
||||
* @param cause the cause
|
||||
*/
|
||||
public VaultConnectorException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
package de.stklcode.jvault.connector.factory;
|
||||
|
||||
import de.stklcode.jvault.connector.HTTPVaultConnector;
|
||||
import de.stklcode.jvault.connector.exception.ConnectionException;
|
||||
import de.stklcode.jvault.connector.exception.TlsException;
|
||||
import de.stklcode.jvault.connector.exception.VaultConnectorException;
|
||||
|
||||
@ -25,8 +26,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;
|
||||
@ -38,17 +42,26 @@ import java.security.cert.X509Certificate;
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
*/
|
||||
public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
||||
public final 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,43 +72,44 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
||||
port = DEFAULT_PORT;
|
||||
tls = DEFAULT_TLS;
|
||||
prefix = DEFAULT_PREFIX;
|
||||
numberOfRetries = DEFAULT_NUMBER_OF_RETRIES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set hostname (default: 127.0.0.1)
|
||||
* Set hostname (default: 127.0.0.1).
|
||||
*
|
||||
* @param host Hostname or IP address
|
||||
* @return self
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withHost(String host) {
|
||||
public HTTPVaultConnectorFactory withHost(final String host) {
|
||||
this.host = host;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set port (default: 8200)
|
||||
* Set port (default: 8200).
|
||||
*
|
||||
* @param port Vault TCP port
|
||||
* @return self
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withPort(Integer port) {
|
||||
public HTTPVaultConnectorFactory withPort(final Integer port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set TLS usage (default: TRUE)
|
||||
* Set TLS usage (default: TRUE).
|
||||
*
|
||||
* @param useTLS use TLS or not
|
||||
* @return self
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withTLS(boolean useTLS) {
|
||||
public HTTPVaultConnectorFactory withTLS(final boolean useTLS) {
|
||||
this.tls = useTLS;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience Method for TLS usage (enabled by default)
|
||||
* Convenience Method for TLS usage (enabled by default).
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
@ -104,7 +118,7 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience Method for NOT using TLS
|
||||
* Convenience Method for NOT using TLS.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
@ -118,7 +132,7 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
||||
* @param prefix Vault API prefix (default: "/v1/"
|
||||
* @return self
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withPrefix(String prefix) {
|
||||
public HTTPVaultConnectorFactory withPrefix(final String prefix) {
|
||||
this.prefix = prefix;
|
||||
return this;
|
||||
}
|
||||
@ -131,7 +145,7 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.4.0
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withTrustedCA(Path cert) throws VaultConnectorException {
|
||||
public HTTPVaultConnectorFactory withTrustedCA(final Path cert) throws VaultConnectorException {
|
||||
if (cert != null)
|
||||
return withSslContext(createSslContext(cert));
|
||||
return this;
|
||||
@ -145,14 +159,97 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
||||
* @return self
|
||||
* @since 0.4.0
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withSslContext(SSLContext sslContext) {
|
||||
public HTTPVaultConnectorFactory withSslContext(final SSLContext sslContext) {
|
||||
this.sslContext = sslContext;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set token for automatic authentication, using {@link #buildAndAuth()}.
|
||||
*
|
||||
* @param token Vault token
|
||||
* @return self
|
||||
* @since 0.6.0
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withToken(final String token) {
|
||||
this.token = token;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build connector based on the {@code }VAULT_ADDR} and {@code VAULT_CACERT} (optional) environment variables.
|
||||
*
|
||||
* @return self
|
||||
* @throws VaultConnectorException if Vault address from environment variables is malformed
|
||||
* @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(final 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(final 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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -163,7 +260,7 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
||||
* @throws TlsException on errors
|
||||
* @since 0.4.0
|
||||
*/
|
||||
private SSLContext createSslContext(Path trustedCert) throws TlsException {
|
||||
private SSLContext createSslContext(final Path trustedCert) throws TlsException {
|
||||
try {
|
||||
SSLContext context = SSLContext.getInstance("TLS");
|
||||
context.init(null, createTrustManager(trustedCert), new SecureRandom());
|
||||
@ -181,7 +278,7 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
||||
* @throws TlsException on error
|
||||
* @since 0.4.0
|
||||
*/
|
||||
private TrustManager[] createTrustManager(Path trustedCert) throws TlsException {
|
||||
private TrustManager[] createTrustManager(final Path trustedCert) throws TlsException {
|
||||
try {
|
||||
/* Create Keystore with trusted certificate */
|
||||
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
@ -204,7 +301,7 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
||||
* @throws TlsException on error
|
||||
* @since 0.4.0
|
||||
*/
|
||||
private X509Certificate certificateFromFile(Path certFile) throws TlsException {
|
||||
private X509Certificate certificateFromFile(final Path certFile) throws TlsException {
|
||||
try (InputStream is = Files.newInputStream(certFile)) {
|
||||
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
|
||||
} catch (IOException | CertificateException e) {
|
||||
|
@ -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
|
||||
* Get Factory implementation for HTTP Vault Connector.
|
||||
*
|
||||
* @return HTTP Connector Factory
|
||||
*/
|
||||
public static HTTPVaultConnectorFactory httpFactory() {
|
||||
return new HTTPVaultConnectorFactory();
|
||||
@ -37,7 +38,17 @@ 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.
|
||||
* @throws VaultConnectorException if authentication failed
|
||||
* @since 0.6.0
|
||||
*/
|
||||
public abstract VaultConnector buildAndAuth() throws VaultConnectorException;
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
package de.stklcode.jvault.connector.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.*;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -28,7 +27,7 @@ import java.util.List;
|
||||
* @since 0.4.0
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AppRole {
|
||||
public final class AppRole {
|
||||
@JsonProperty("role_name")
|
||||
private String name;
|
||||
|
||||
@ -64,11 +63,30 @@ public class AppRole {
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Integer period;
|
||||
|
||||
/**
|
||||
* Construct empty {@link AppRole} object.
|
||||
*/
|
||||
public AppRole() {
|
||||
|
||||
}
|
||||
|
||||
public AppRole(String name, String id, Boolean bindSecretId, List<String> boundCidrList, List<String> policies, Integer secretIdNumUses, Integer secretIdTtl, Integer tokenTtl, Integer tokenMaxTtl, Integer period) {
|
||||
/**
|
||||
* Construct complete {@link AppRole} object.
|
||||
*
|
||||
* @param name Role name (required)
|
||||
* @param id Role ID (optional)
|
||||
* @param bindSecretId Bind secret ID (optional)
|
||||
* @param boundCidrList Whitelist of subnets in CIDR notation (optional)
|
||||
* @param policies List of policies (optional)
|
||||
* @param secretIdNumUses Maximum number of uses per secret (optional)
|
||||
* @param secretIdTtl Maximum TTL in seconds for secrets (optional)
|
||||
* @param tokenTtl Token TTL in seconds (optional)
|
||||
* @param tokenMaxTtl Maximum token TTL in seconds, including renewals (optional)
|
||||
* @param period Duration in seconds, if set the token is a periodic token (optional)
|
||||
*/
|
||||
public AppRole(final String name, final String id, final Boolean bindSecretId, final List<String> boundCidrList,
|
||||
final List<String> policies, final Integer secretIdNumUses, final Integer secretIdTtl,
|
||||
final Integer tokenTtl, final Integer tokenMaxTtl, final Integer period) {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
this.bindSecretId = bindSecretId;
|
||||
@ -81,27 +99,45 @@ public class AppRole {
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the role name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the role ID
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bind secret ID
|
||||
*/
|
||||
public Boolean getBindSecretId() {
|
||||
return bindSecretId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of bound CIDR subnets
|
||||
*/
|
||||
public List<String> getBoundCidrList() {
|
||||
return boundCidrList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boundCidrList list of subnets in CIDR notation to bind role to
|
||||
*/
|
||||
@JsonSetter("bound_cidr_list")
|
||||
public void setBoundCidrList(List<String> boundCidrList) {
|
||||
public void setBoundCidrList(final List<String> boundCidrList) {
|
||||
this.boundCidrList = boundCidrList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of subnets in CIDR notation as comma-separated {@link String}
|
||||
*/
|
||||
@JsonGetter("bound_cidr_list")
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public String getBoundCidrListString() {
|
||||
@ -110,15 +146,24 @@ public class AppRole {
|
||||
return String.join(",", boundCidrList);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of policies
|
||||
*/
|
||||
public List<String> getPolicies() {
|
||||
return policies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param policies list of policies
|
||||
*/
|
||||
@JsonSetter("policies")
|
||||
public void setPolicies(List<String> policies) {
|
||||
public void setPolicies(final List<String> policies) {
|
||||
this.policies = policies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of policies as comma-separated {@link String}
|
||||
*/
|
||||
@JsonGetter("policies")
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public String getPoliciesString() {
|
||||
@ -127,22 +172,37 @@ public class AppRole {
|
||||
return String.join(",", policies);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return maximum number of uses per secret
|
||||
*/
|
||||
public Integer getSecretIdNumUses() {
|
||||
return secretIdNumUses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return maximum TTL in seconds for secrets
|
||||
*/
|
||||
public Integer getSecretIdTtl() {
|
||||
return secretIdTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return token TTL in seconds
|
||||
*/
|
||||
public Integer getTokenTtl() {
|
||||
return tokenTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return maximum token TTL in seconds, including renewals
|
||||
*/
|
||||
public Integer getTokenMaxTtl() {
|
||||
return tokenMaxTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return duration in seconds, if specified
|
||||
*/
|
||||
public Integer getPeriod() {
|
||||
return period;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import java.util.List;
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
*/
|
||||
public class AppRoleBuilder {
|
||||
public final class AppRoleBuilder {
|
||||
private String name;
|
||||
private String id;
|
||||
private Boolean bindSecretId;
|
||||
@ -37,12 +37,17 @@ public class AppRoleBuilder {
|
||||
private Integer tokenMaxTtl;
|
||||
private Integer period;
|
||||
|
||||
public AppRoleBuilder(String name) {
|
||||
/**
|
||||
* Construct {@link AppRoleBuilder} with only the role name set.
|
||||
*
|
||||
* @param name Role name
|
||||
*/
|
||||
public AppRoleBuilder(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom role ID (optional)
|
||||
* Add custom role ID. (optional)
|
||||
*
|
||||
* @param id the ID
|
||||
* @return self
|
||||
@ -53,7 +58,7 @@ public class AppRoleBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if role is bound to secret ID
|
||||
* Set if role is bound to secret ID.
|
||||
*
|
||||
* @param bindSecretId the display name
|
||||
* @return self
|
||||
@ -108,7 +113,7 @@ public class AppRoleBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given policies
|
||||
* Add given policies.
|
||||
*
|
||||
* @param policies the policies
|
||||
* @return self
|
||||
|
@ -18,7 +18,6 @@ package de.stklcode.jvault.connector.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -29,7 +28,7 @@ import java.util.Map;
|
||||
* @since 0.4.0
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AppRoleSecret {
|
||||
public final class AppRoleSecret {
|
||||
@JsonProperty("secret_id")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private String id;
|
||||
@ -58,41 +57,73 @@ public class AppRoleSecret {
|
||||
@JsonProperty(value = "secret_id_ttl", access = JsonProperty.Access.WRITE_ONLY)
|
||||
private Integer ttl;
|
||||
|
||||
/**
|
||||
* Construct empty {@link AppRoleSecret} object.
|
||||
*/
|
||||
public AppRoleSecret() {
|
||||
|
||||
}
|
||||
|
||||
public AppRoleSecret(String id) {
|
||||
/**
|
||||
* Construct {@link AppRoleSecret} with secret ID.
|
||||
*
|
||||
* @param id Secret ID
|
||||
*/
|
||||
public AppRoleSecret(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public AppRoleSecret(String id, Map<String, Object> metadata, List<String> cidrList) {
|
||||
/**
|
||||
* Construct {@link AppRoleSecret} with ID and metadata.
|
||||
*
|
||||
* @param id Secret ID
|
||||
* @param metadata Secret metadata
|
||||
* @param cidrList List of subnets in CIDR notation, the role is bound to
|
||||
*/
|
||||
public AppRoleSecret(final String id, final Map<String, Object> metadata, final List<String> cidrList) {
|
||||
this.id = id;
|
||||
this.metadata = metadata;
|
||||
this.cidrList = cidrList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Secret ID
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Secret accessor
|
||||
*/
|
||||
public String getAccessor() {
|
||||
return accessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Secret metadata
|
||||
*/
|
||||
public Map<String, Object> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of bound subnets in CIDR notation
|
||||
*/
|
||||
public List<String> getCidrList() {
|
||||
return cidrList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cidrList List of subnets in CIDR notation
|
||||
*/
|
||||
@JsonSetter("cidr_list")
|
||||
public void setCidrList(List<String> cidrList) {
|
||||
public void setCidrList(final List<String> cidrList) {
|
||||
this.cidrList = cidrList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of bound subnets in CIDR notation as comma-separated {@link String}
|
||||
*/
|
||||
@JsonGetter("cidr_list")
|
||||
public String getCidrListString() {
|
||||
if (cidrList == null || cidrList.isEmpty())
|
||||
@ -100,22 +131,37 @@ public class AppRoleSecret {
|
||||
return String.join(",", cidrList);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Creation time
|
||||
*/
|
||||
public String getCreationTime() {
|
||||
return creationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Expiration time
|
||||
*/
|
||||
public String getExpirationTime() {
|
||||
return expirationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Time of last update
|
||||
*/
|
||||
public String getLastUpdatedTime() {
|
||||
return lastUpdatedTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Number of uses
|
||||
*/
|
||||
public Integer getNumUses() {
|
||||
return numUses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Time-to-live
|
||||
*/
|
||||
public Integer getTtl() {
|
||||
return ttl;
|
||||
}
|
||||
|
@ -19,23 +19,35 @@ package de.stklcode.jvault.connector.model;
|
||||
/**
|
||||
* Currently supported authentication backends.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
*/
|
||||
public enum AuthBackend {
|
||||
TOKEN("token"),
|
||||
APPID("app-id"),
|
||||
APPROLE("approle"),
|
||||
USERPASS("userpass"),
|
||||
GITHUB("github"), // Not supported yet.
|
||||
UNKNOWN("");
|
||||
|
||||
private final String type;
|
||||
|
||||
AuthBackend(String type) {
|
||||
/**
|
||||
* Construct {@link AuthBackend} of given type.
|
||||
*
|
||||
* @param type Backend type
|
||||
*/
|
||||
AuthBackend(final String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static AuthBackend forType(String type) {
|
||||
/**
|
||||
* Retrieve {@link AuthBackend} value for given type string.
|
||||
*
|
||||
* @param type Type string
|
||||
* @return Auth backend value
|
||||
*/
|
||||
public static AuthBackend forType(final String type) {
|
||||
for (AuthBackend v : values())
|
||||
if (v.type.equalsIgnoreCase(type))
|
||||
return v;
|
||||
|
@ -30,7 +30,7 @@ import java.util.Map;
|
||||
* @since 0.4.0
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Token {
|
||||
public final class Token {
|
||||
@JsonProperty("id")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private String id;
|
||||
@ -67,7 +67,28 @@ public class Token {
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Boolean renewable;
|
||||
|
||||
public Token(String id, String displayName, Boolean noParent, Boolean noDefaultPolicy, Integer ttl, Integer numUses, List<String> policies, Map<String, String> meta, Boolean renewable) {
|
||||
/**
|
||||
* Construct complete {@link Token} object.
|
||||
*
|
||||
* @param id Token ID (optional)
|
||||
* @param displayName Token display name (optional)
|
||||
* @param noParent Token has no parent (optional)
|
||||
* @param noDefaultPolicy Do not add default policy (optional)
|
||||
* @param ttl Token TTL in seconds (optional)
|
||||
* @param numUses Number of uses (optional)
|
||||
* @param policies List of policies (optional)
|
||||
* @param meta Metadata (optional)
|
||||
* @param renewable Is the token renewable (optional)
|
||||
*/
|
||||
public Token(final String id,
|
||||
final String displayName,
|
||||
final Boolean noParent,
|
||||
final Boolean noDefaultPolicy,
|
||||
final Integer ttl,
|
||||
final Integer numUses,
|
||||
final List<String> policies,
|
||||
final Map<String, String> meta,
|
||||
final Boolean renewable) {
|
||||
this.id = id;
|
||||
this.displayName = displayName;
|
||||
this.ttl = ttl;
|
||||
@ -79,38 +100,65 @@ public class Token {
|
||||
this.renewable = renewable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token ID
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token display name
|
||||
*/
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token has no parent
|
||||
*/
|
||||
public Boolean getNoParent() {
|
||||
return noParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token has no default policy
|
||||
*/
|
||||
public Boolean getNoDefaultPolicy() {
|
||||
return noDefaultPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Time-to-live in seconds
|
||||
*/
|
||||
public Integer getTtl() {
|
||||
return ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Number of uses
|
||||
*/
|
||||
public Integer getNumUses() {
|
||||
return numUses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of policies
|
||||
*/
|
||||
public List<String> getPolicies() {
|
||||
return policies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Metadata
|
||||
*/
|
||||
public Map<String, String> getMeta() {
|
||||
return meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token is renewable
|
||||
*/
|
||||
public Boolean isRenewable() {
|
||||
return renewable;
|
||||
}
|
||||
|
@ -16,17 +16,15 @@
|
||||
|
||||
package de.stklcode.jvault.connector.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A builder for vault tokens.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
*/
|
||||
public class TokenBuilder {
|
||||
public final class TokenBuilder {
|
||||
private String id;
|
||||
private String displayName;
|
||||
private Boolean noParent;
|
||||
@ -38,7 +36,7 @@ public class TokenBuilder {
|
||||
private Boolean renewable;
|
||||
|
||||
/**
|
||||
* Add token ID (optional)
|
||||
* Add token ID. (optional)
|
||||
*
|
||||
* @param id the ID
|
||||
* @return self
|
||||
@ -49,7 +47,7 @@ public class TokenBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add display name
|
||||
* Add display name.
|
||||
*
|
||||
* @param displayName the display name
|
||||
* @return self
|
||||
@ -61,6 +59,7 @@ public class TokenBuilder {
|
||||
|
||||
/**
|
||||
* Set desired time to live.
|
||||
*
|
||||
* @param ttl the ttl
|
||||
* @return self
|
||||
*/
|
||||
@ -71,6 +70,7 @@ public class TokenBuilder {
|
||||
|
||||
/**
|
||||
* Set desired number of uses.
|
||||
*
|
||||
* @param numUses the number of uses
|
||||
* @return self
|
||||
*/
|
||||
@ -80,7 +80,7 @@ public class TokenBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set TRUE if the token should be created without parent
|
||||
* Set TRUE if the token should be created without parent.
|
||||
*
|
||||
* @param noParent if TRUE, token is created as orphan
|
||||
* @return self
|
||||
@ -142,7 +142,7 @@ public class TokenBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given policies
|
||||
* Add given policies.
|
||||
*
|
||||
* @param policies the policies
|
||||
* @return self
|
||||
@ -153,7 +153,7 @@ public class TokenBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given policies
|
||||
* Add given policies.
|
||||
*
|
||||
* @param policies the policies
|
||||
* @return self
|
||||
|
@ -24,33 +24,36 @@ import de.stklcode.jvault.connector.model.AppRole;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Vault response for AppRole lookup.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AppRoleResponse extends VaultDataResponse {
|
||||
public final class AppRoleResponse extends VaultDataResponse {
|
||||
private AppRole role;
|
||||
|
||||
@Override
|
||||
public void setData(Map<String, Object> data) throws InvalidResponseException {
|
||||
public void setData(final Map<String, Object> data) throws InvalidResponseException {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
try {
|
||||
/* null empty strings on list objects */
|
||||
Map<String, Object> filteredData = new HashMap<>();
|
||||
data.forEach((k,v) -> { if (!(v instanceof String && ((String) v).isEmpty())) filteredData.put(k,v); });
|
||||
data.forEach((k, v) -> {
|
||||
if (!(v instanceof String && ((String) v).isEmpty())) filteredData.put(k, v);
|
||||
});
|
||||
this.role = mapper.readValue(mapper.writeValueAsString(filteredData), AppRole.class);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new InvalidResponseException();
|
||||
throw new InvalidResponseException("Failed deserializing response", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The role
|
||||
*/
|
||||
public AppRole getRole() {
|
||||
return role;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ package de.stklcode.jvault.connector.model.response;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import de.stklcode.jvault.connector.model.AppRole;
|
||||
import de.stklcode.jvault.connector.model.AppRoleSecret;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -29,28 +28,32 @@ import java.util.Map;
|
||||
/**
|
||||
* Vault response for AppRole lookup.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AppRoleSecretResponse extends VaultDataResponse {
|
||||
public final class AppRoleSecretResponse extends VaultDataResponse {
|
||||
private AppRoleSecret secret;
|
||||
|
||||
@Override
|
||||
public void setData(Map<String, Object> data) throws InvalidResponseException {
|
||||
public void setData(final Map<String, Object> data) throws InvalidResponseException {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
try {
|
||||
/* null empty strings on list objects */
|
||||
Map<String, Object> filteredData = new HashMap<>();
|
||||
data.forEach((k,v) -> { if (!(v instanceof String && ((String) v).isEmpty())) filteredData.put(k,v); });
|
||||
data.forEach((k, v) -> {
|
||||
if (!(v instanceof String && ((String) v).isEmpty())) filteredData.put(k, v);
|
||||
});
|
||||
this.secret = mapper.readValue(mapper.writeValueAsString(filteredData), AppRoleSecret.class);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new InvalidResponseException();
|
||||
throw new InvalidResponseException("Failed deserializing response", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The secret
|
||||
*/
|
||||
public AppRoleSecret getSecret() {
|
||||
return secret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,25 +32,32 @@ import java.util.Map;
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AuthMethodsResponse extends VaultDataResponse {
|
||||
public final class AuthMethodsResponse extends VaultDataResponse {
|
||||
private Map<String, AuthMethod> supportedMethods;
|
||||
|
||||
/**
|
||||
* Construct empty {@link AuthMethodsResponse} object.
|
||||
*/
|
||||
public AuthMethodsResponse() {
|
||||
this.supportedMethods = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setData(Map<String, Object> data) throws InvalidResponseException {
|
||||
public void setData(final Map<String, Object> data) throws InvalidResponseException {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
for (String path : data.keySet()) {
|
||||
for (Map.Entry<String, Object> entry : data.entrySet()) {
|
||||
try {
|
||||
this.supportedMethods.put(path, mapper.readValue(mapper.writeValueAsString(data.get(path)), AuthMethod.class));
|
||||
this.supportedMethods.put(entry.getKey(),
|
||||
mapper.readValue(mapper.writeValueAsString(entry.getValue()), AuthMethod.class));
|
||||
} catch (IOException e) {
|
||||
throw new InvalidResponseException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Supported authentication methods
|
||||
*/
|
||||
public Map<String, AuthMethod> getSupportedMethods() {
|
||||
return supportedMethods;
|
||||
}
|
||||
|
@ -28,35 +28,46 @@ import java.util.Map;
|
||||
/**
|
||||
* Vault response for authentication providing auth info in {@link AuthData} field.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AuthResponse extends VaultDataResponse {
|
||||
public final class AuthResponse extends VaultDataResponse {
|
||||
private Map<String, Object> data;
|
||||
|
||||
private AuthData auth;
|
||||
|
||||
/**
|
||||
* Set authentication data. The input will be mapped to the {@link AuthData} model.
|
||||
*
|
||||
* @param auth Raw authentication data
|
||||
* @throws InvalidResponseException on mapping errors
|
||||
*/
|
||||
@JsonProperty("auth")
|
||||
public void setAuth(Map<String, Object> auth) throws InvalidResponseException {
|
||||
public void setAuth(final Map<String, Object> auth) throws InvalidResponseException {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
try {
|
||||
this.auth = mapper.readValue(mapper.writeValueAsString(auth), AuthData.class);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new InvalidResponseException();
|
||||
throw new InvalidResponseException("Failed deserializing response", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setData(Map<String, Object> data) {
|
||||
public void setData(final Map<String, Object> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Raw data
|
||||
*/
|
||||
public Map<String, Object> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Authentication data
|
||||
*/
|
||||
public AuthData getAuth() {
|
||||
return auth;
|
||||
}
|
||||
|
@ -17,13 +17,6 @@
|
||||
package de.stklcode.jvault.connector.model.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Vault response from credentials lookup. Simple wrapper for data objects containing username and password fields.
|
||||
@ -32,17 +25,25 @@ import java.util.Map;
|
||||
* @since 0.5.0
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class CredentialsResponse extends SecretResponse {
|
||||
public final class CredentialsResponse extends SecretResponse {
|
||||
|
||||
/**
|
||||
* @return Username
|
||||
*/
|
||||
public String getUsername() {
|
||||
if (get("username") != null)
|
||||
return get("username").toString();
|
||||
Object username = get("username");
|
||||
if (username != null)
|
||||
return username.toString();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Password
|
||||
*/
|
||||
public String getPassword() {
|
||||
if (get("username") != null)
|
||||
return get("username").toString();
|
||||
Object password = get("password");
|
||||
if (password != null)
|
||||
return password.toString();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -28,11 +28,14 @@ import java.util.List;
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ErrorResponse implements VaultResponse {
|
||||
public final class ErrorResponse implements VaultResponse {
|
||||
@JsonProperty("errors")
|
||||
private List<String> errors;
|
||||
|
||||
public List<String > getErrors() {
|
||||
/**
|
||||
* @return List of errors
|
||||
*/
|
||||
public List<String> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,11 +26,14 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class HelpResponse implements VaultResponse {
|
||||
public final class HelpResponse implements VaultResponse {
|
||||
@JsonProperty("help")
|
||||
private String help;
|
||||
|
||||
/**
|
||||
* @return Help text
|
||||
*/
|
||||
public String getHelp() {
|
||||
return help;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,14 +27,17 @@ import java.util.Map;
|
||||
* @since 0.4.0
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class RawDataResponse extends VaultDataResponse {
|
||||
public final class RawDataResponse extends VaultDataResponse {
|
||||
private Map<String, Object> data;
|
||||
|
||||
@Override
|
||||
public void setData(Map<String, Object> data) {
|
||||
public void setData(final Map<String, Object> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Raw data {@link Map}
|
||||
*/
|
||||
public Map<String, Object> getData() {
|
||||
return data;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SealResponse implements VaultResponse {
|
||||
public final class SealResponse implements VaultResponse {
|
||||
@JsonProperty("sealed")
|
||||
private boolean sealed;
|
||||
|
||||
@ -39,18 +39,30 @@ public class SealResponse implements VaultResponse {
|
||||
@JsonProperty("progress")
|
||||
private Integer progress;
|
||||
|
||||
/**
|
||||
* @return Seal status
|
||||
*/
|
||||
public boolean isSealed() {
|
||||
return sealed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Required threshold of secret shares
|
||||
*/
|
||||
public Integer getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Number of secret shares
|
||||
*/
|
||||
public Integer getNumberOfShares() {
|
||||
return numberOfShares;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current unseal progress (remaining required shares)
|
||||
*/
|
||||
public Integer getProgress() {
|
||||
return progress;
|
||||
}
|
||||
|
@ -26,23 +26,31 @@ import java.util.Map;
|
||||
/**
|
||||
* Vault response for secret list request.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SecretListResponse extends VaultDataResponse {
|
||||
public final class SecretListResponse extends VaultDataResponse {
|
||||
private List<String> keys;
|
||||
|
||||
/**
|
||||
* Set data. Extracts list of keys from raw response data.
|
||||
*
|
||||
* @param data Raw data
|
||||
* @throws InvalidResponseException on parsing errors
|
||||
*/
|
||||
@JsonProperty("data")
|
||||
public void setData(Map<String, Object> data) throws InvalidResponseException {
|
||||
public void setData(final Map<String, Object> data) throws InvalidResponseException {
|
||||
try {
|
||||
this.keys = (List<String>)data.get("keys");
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
this.keys = (List<String>) data.get("keys");
|
||||
} catch (ClassCastException e) {
|
||||
throw new InvalidResponseException("Keys could not be parsed from data.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of secret keys
|
||||
*/
|
||||
public List<String> getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
@ -34,7 +35,7 @@ public class SecretResponse extends VaultDataResponse {
|
||||
private Map<String, Object> data;
|
||||
|
||||
@Override
|
||||
public void setData(Map<String, Object> data) throws InvalidResponseException {
|
||||
public final void setData(final Map<String, Object> data) throws InvalidResponseException {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@ -44,7 +45,9 @@ public class SecretResponse extends VaultDataResponse {
|
||||
* @return data map
|
||||
* @since 0.4.0
|
||||
*/
|
||||
public Map<String, Object> getData() {
|
||||
public final Map<String, Object> getData() {
|
||||
if (data == null)
|
||||
return new HashMap<>();
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -52,11 +55,13 @@ public class SecretResponse extends VaultDataResponse {
|
||||
* Get a single value for given key.
|
||||
*
|
||||
* @param key the key
|
||||
* @return the value or NULL if absent
|
||||
* @return the value or {@code null} if absent
|
||||
* @since 0.4.0
|
||||
*/
|
||||
public Object get(String key) {
|
||||
return data.get(key);
|
||||
public final Object get(final String key) {
|
||||
if (data == null)
|
||||
return null;
|
||||
return getData().get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,14 +72,15 @@ public class SecretResponse extends VaultDataResponse {
|
||||
* @deprecated Deprecated artifact, will be removed at latest at v1.0.0
|
||||
*/
|
||||
@Deprecated
|
||||
public String getValue() {
|
||||
if (data.get("value") == null)
|
||||
public final String getValue() {
|
||||
Object value = get("value");
|
||||
if (value == null)
|
||||
return null;
|
||||
return data.get("value").toString();
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get response parsed as JSON
|
||||
* Get response parsed as JSON.
|
||||
*
|
||||
* @param type Class to parse response
|
||||
* @param <T> Class to parse response
|
||||
@ -84,25 +90,28 @@ public class SecretResponse extends VaultDataResponse {
|
||||
* @deprecated Deprecated artifact, will be removed at latest at v1.0.0
|
||||
*/
|
||||
@Deprecated
|
||||
public <T> T getValue(Class<T> type) throws InvalidResponseException {
|
||||
public final <T> T getValue(final Class<T> type) throws InvalidResponseException {
|
||||
return get("value", type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get response parsed as JSON
|
||||
* Get response parsed as JSON.
|
||||
*
|
||||
* @param key the key
|
||||
* @param type Class to parse response
|
||||
* @param <T> Class to parse response
|
||||
* @return Parsed object
|
||||
* @return Parsed object or {@code null} if absent
|
||||
* @throws InvalidResponseException on parsing error
|
||||
* @since 0.4.0
|
||||
*/
|
||||
public <T> T get(String key, Class<T> type) throws InvalidResponseException {
|
||||
public final <T> T get(final String key, final Class<T> type) throws InvalidResponseException {
|
||||
try {
|
||||
return new ObjectMapper().readValue(get(key).toString(), type);
|
||||
Object rawValue = get(key);
|
||||
if (rawValue == null)
|
||||
return null;
|
||||
return new ObjectMapper().readValue(rawValue.toString(), type);
|
||||
} catch (IOException e) {
|
||||
throw new InvalidResponseException("Unable to parse response payload: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,27 +28,35 @@ import java.util.Map;
|
||||
/**
|
||||
* Vault response from token lookup providing Token information in {@link TokenData} field.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class TokenResponse extends VaultDataResponse {
|
||||
public final class TokenResponse extends VaultDataResponse {
|
||||
private TokenData data;
|
||||
|
||||
@JsonProperty("auth")
|
||||
private Boolean auth;
|
||||
|
||||
/**
|
||||
* Set data. Parses response data map to {@link TokenData}.
|
||||
*
|
||||
* @param data Raw response data
|
||||
* @throws InvalidResponseException on parsing errors
|
||||
*/
|
||||
@Override
|
||||
public void setData(Map<String, Object> data) throws InvalidResponseException {
|
||||
public void setData(final Map<String, Object> data) throws InvalidResponseException {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
try {
|
||||
this.data = mapper.readValue(mapper.writeValueAsString(data), TokenData.class);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new InvalidResponseException();
|
||||
throw new InvalidResponseException("Failed deserializing response", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token data
|
||||
*/
|
||||
public TokenData getData() {
|
||||
return data;
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ import java.util.Map;
|
||||
/**
|
||||
* Abstract Vault response with default payload fields.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
*/
|
||||
public abstract class VaultDataResponse implements VaultResponse {
|
||||
@JsonProperty("lease_id")
|
||||
@ -41,22 +41,40 @@ public abstract class VaultDataResponse implements VaultResponse {
|
||||
@JsonProperty("warnings")
|
||||
private List<String> warnings;
|
||||
|
||||
/**
|
||||
* Set data. To be implemented in the specific subclasses, as data can be of arbitrary structure.
|
||||
*
|
||||
* @param data Raw response data
|
||||
* @throws InvalidResponseException on parsing errors
|
||||
*/
|
||||
@JsonProperty("data")
|
||||
public abstract void setData(Map<String, Object> data) throws InvalidResponseException;
|
||||
public abstract void setData(final Map<String, Object> data) throws InvalidResponseException;
|
||||
|
||||
public String getLeaseId() {
|
||||
/**
|
||||
* @return Lease ID
|
||||
*/
|
||||
public final String getLeaseId() {
|
||||
return leaseId;
|
||||
}
|
||||
|
||||
public boolean isRenewable() {
|
||||
/**
|
||||
* @return Lease is renewable
|
||||
*/
|
||||
public final boolean isRenewable() {
|
||||
return renewable;
|
||||
}
|
||||
|
||||
public Integer getLeaseDuration() {
|
||||
/**
|
||||
* @return Lease duration
|
||||
*/
|
||||
public final Integer getLeaseDuration() {
|
||||
return leaseDuration;
|
||||
}
|
||||
|
||||
public List<String> getWarnings() {
|
||||
/**
|
||||
* @return List of warnings
|
||||
*/
|
||||
public final List<String> getWarnings() {
|
||||
return warnings;
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ import java.util.Map;
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AuthData {
|
||||
public final class AuthData {
|
||||
@JsonProperty("client_token")
|
||||
private String clientToken;
|
||||
|
||||
@ -48,27 +48,45 @@ public class AuthData {
|
||||
@JsonProperty("renewable")
|
||||
private boolean renewable;
|
||||
|
||||
/**
|
||||
* @return Client token
|
||||
*/
|
||||
public String getClientToken() {
|
||||
return clientToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token accessor
|
||||
*/
|
||||
public String getAccessor() {
|
||||
return accessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of policies
|
||||
*/
|
||||
public List<String> getPolicies() {
|
||||
return policies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Metadata
|
||||
*/
|
||||
public Map<String, Object> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Lease duration
|
||||
*/
|
||||
public Integer getLeaseDuration() {
|
||||
return leaseDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Lease is renewable
|
||||
*/
|
||||
public boolean isRenewable() {
|
||||
return renewable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ import java.util.Map;
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AuthMethod {
|
||||
public final class AuthMethod {
|
||||
private AuthBackend type;
|
||||
private String rawType;
|
||||
|
||||
@ -43,28 +43,46 @@ public class AuthMethod {
|
||||
@JsonProperty("local")
|
||||
private boolean local;
|
||||
|
||||
/**
|
||||
* @param type Backend type, passed to {@link AuthBackend#forType(String)}
|
||||
*/
|
||||
@JsonSetter("type")
|
||||
public void setType(String type) {
|
||||
public void setType(final String type) {
|
||||
this.rawType = type;
|
||||
this.type = AuthBackend.forType(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Backend type
|
||||
*/
|
||||
public AuthBackend getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Raw backend type string
|
||||
*/
|
||||
public String getRawType() {
|
||||
return rawType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Description
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Configuration data
|
||||
*/
|
||||
public Map<String, String> getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Is local backend
|
||||
*/
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class TokenData {
|
||||
public final class TokenData {
|
||||
@JsonProperty("accessor")
|
||||
private String accessor;
|
||||
|
||||
@ -34,7 +34,7 @@ public class TokenData {
|
||||
private Integer creationTime;
|
||||
|
||||
@JsonProperty("creation_ttl")
|
||||
private Integer creatinTtl;
|
||||
private Integer creationTtl;
|
||||
|
||||
@JsonProperty("display_name")
|
||||
private String name;
|
||||
@ -60,47 +60,80 @@ public class TokenData {
|
||||
@JsonProperty("ttl")
|
||||
private Integer ttl;
|
||||
|
||||
/**
|
||||
* @return Token accessor
|
||||
*/
|
||||
public String getAccessor() {
|
||||
return accessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Creation time
|
||||
*/
|
||||
public Integer getCreationTime() {
|
||||
return creationTime;
|
||||
}
|
||||
|
||||
public Integer getCreatinTtl() {
|
||||
return creatinTtl;
|
||||
/**
|
||||
* @return Creation TTL (in seconds)
|
||||
*/
|
||||
public Integer getCreationTtl() {
|
||||
return creationTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token ID
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Number of uses
|
||||
*/
|
||||
public Integer getNumUses() {
|
||||
return numUses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token is orphan
|
||||
*/
|
||||
public boolean isOrphan() {
|
||||
return orphan;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token path
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token role
|
||||
*/
|
||||
public String getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token TTL (in seconds)
|
||||
*/
|
||||
public Integer getTtl() {
|
||||
return ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Metadata
|
||||
*/
|
||||
public String getMeta() {
|
||||
return meta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,21 +16,19 @@
|
||||
|
||||
package de.stklcode.jvault.connector;
|
||||
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import de.stklcode.jvault.connector.exception.*;
|
||||
import de.stklcode.jvault.connector.model.*;
|
||||
import de.stklcode.jvault.connector.model.response.*;
|
||||
import de.stklcode.jvault.connector.factory.HTTPVaultConnectorFactory;
|
||||
import de.stklcode.jvault.connector.test.Credentials;
|
||||
import de.stklcode.jvault.connector.test.VaultConfiguration;
|
||||
import de.stklcode.jvault.connector.exception.InvalidRequestException;
|
||||
import de.stklcode.jvault.connector.exception.PermissionDeniedException;
|
||||
import de.stklcode.jvault.connector.exception.VaultConnectorException;
|
||||
import de.stklcode.jvault.connector.factory.VaultConnectorFactory;
|
||||
import org.junit.*;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.rules.TestName;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.ServerSocket;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
@ -59,7 +57,9 @@ public class HTTPVaultConnectorTest {
|
||||
private static String APPROLE_ROLE_NAME = "testrole1"; // role with secret ID
|
||||
private static String APPROLE_ROLE = "627b6400-90c3-a239-49a9-af65a448ca10";
|
||||
private static String APPROLE_SECRET = "5e8b0e99-d906-27f5-f043-ccb9bb53b5e8";
|
||||
private static String APPROLE_ROLE2 = "35b7bf43-9644-588a-e68f-2e8313bb23b7"; // role with CIDR subnet
|
||||
private static String APPROLE_SECRET_ACCESSOR = "071e2e9d-742a-fc3c-3fd3-1f4004b0420a";
|
||||
private static String APPROLE_ROLE2_NAME = "testrole2"; // role with CIDR subnet
|
||||
private static String APPROLE_ROLE2 = "35b7bf43-9644-588a-e68f-2e8313bb23b7";
|
||||
private static String SECRET_PATH = "userstore";
|
||||
private static String SECRET_KEY = "foo";
|
||||
private static String SECRET_VALUE = "bar";
|
||||
@ -113,6 +113,28 @@ public class HTTPVaultConnectorTest {
|
||||
vaultProcess.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test sealing and unsealing Vault.
|
||||
*/
|
||||
@Test
|
||||
public void sealTest() {
|
||||
SealResponse sealStatus = connector.sealStatus();
|
||||
assumeFalse(sealStatus.isSealed());
|
||||
|
||||
/* Unauthorized sealing should fail */
|
||||
assertThat("Unauthorized sealing succeeded", connector.seal(), is(false));
|
||||
assertThat("Vault sealed, although sealing failed", sealStatus.isSealed(), is(false));
|
||||
|
||||
/* Root user should be able to seal */
|
||||
authRoot();
|
||||
assumeTrue(connector.isAuthorized());
|
||||
assertThat("Sealing failed", connector.seal(), is(true));
|
||||
sealStatus = connector.sealStatus();
|
||||
assertThat("Vault not sealed", sealStatus.isSealed(), is(true));
|
||||
sealStatus = connector.unseal(KEY);
|
||||
assertThat("Vault not unsealed", sealStatus.isSealed(), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test listing of authentication backends
|
||||
*/
|
||||
@ -191,6 +213,23 @@ public class HTTPVaultConnectorTest {
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
public void authAppIdTest() {
|
||||
/* Try unauthorized access first. */
|
||||
assumeFalse(connector.isAuthorized());
|
||||
|
||||
try {
|
||||
connector.registerAppId("", "", "");
|
||||
fail("Expected exception not thrown");
|
||||
} catch (Exception e) {
|
||||
assertThat("Unexpected exception class", e, is(instanceOf(AuthorizationRequiredException.class)));
|
||||
}
|
||||
try {
|
||||
connector.registerUserId("", "");
|
||||
fail("Expected exception not thrown");
|
||||
} catch (Exception e) {
|
||||
assertThat("Unexpected exception class", e, is(instanceOf(AuthorizationRequiredException.class)));
|
||||
}
|
||||
|
||||
/* Authorize. */
|
||||
authRoot();
|
||||
assumeTrue(connector.isAuthorized());
|
||||
|
||||
@ -285,6 +324,65 @@ public class HTTPVaultConnectorTest {
|
||||
*/
|
||||
@Test
|
||||
public void createAppRoleTest() {
|
||||
/* Try unauthorized access first. */
|
||||
assumeFalse(connector.isAuthorized());
|
||||
try {
|
||||
connector.createAppRole(new AppRole());
|
||||
fail("Expected exception not thrown");
|
||||
} catch (Exception e) {
|
||||
assertThat("Unexpected exception class", e, is(instanceOf(AuthorizationRequiredException.class)));
|
||||
}
|
||||
|
||||
try {
|
||||
connector.lookupAppRole("");
|
||||
fail("Expected exception not thrown");
|
||||
} catch (Exception e) {
|
||||
assertThat("Unexpected exception class", e, is(instanceOf(AuthorizationRequiredException.class)));
|
||||
}
|
||||
|
||||
try {
|
||||
connector.deleteAppRole("");
|
||||
fail("Expected exception not thrown");
|
||||
} catch (Exception e) {
|
||||
assertThat("Unexpected exception class", e, is(instanceOf(AuthorizationRequiredException.class)));
|
||||
}
|
||||
|
||||
try {
|
||||
connector.getAppRoleID("");
|
||||
fail("Expected exception not thrown");
|
||||
} catch (Exception e) {
|
||||
assertThat("Unexpected exception class", e, is(instanceOf(AuthorizationRequiredException.class)));
|
||||
}
|
||||
|
||||
try {
|
||||
connector.setAppRoleID("", "");
|
||||
fail("Expected exception not thrown");
|
||||
} catch (Exception e) {
|
||||
assertThat("Unexpected exception class", e, is(instanceOf(AuthorizationRequiredException.class)));
|
||||
}
|
||||
|
||||
try {
|
||||
connector.createAppRoleSecret("", "");
|
||||
fail("Expected exception not thrown");
|
||||
} catch (Exception e) {
|
||||
assertThat("Unexpected exception class", e, is(instanceOf(AuthorizationRequiredException.class)));
|
||||
}
|
||||
|
||||
try {
|
||||
connector.lookupAppRoleSecret("", "");
|
||||
fail("Expected exception not thrown");
|
||||
} catch (Exception e) {
|
||||
assertThat("Unexpected exception class", e, is(instanceOf(AuthorizationRequiredException.class)));
|
||||
}
|
||||
|
||||
try {
|
||||
connector.destroyAppRoleSecret("", "");
|
||||
fail("Expected exception not thrown");
|
||||
} catch (Exception e) {
|
||||
assertThat("Unexpected exception class", e, is(instanceOf(AuthorizationRequiredException.class)));
|
||||
}
|
||||
|
||||
/* Authorize. */
|
||||
authRoot();
|
||||
assumeTrue(connector.isAuthorized());
|
||||
|
||||
@ -310,15 +408,16 @@ public class HTTPVaultConnectorTest {
|
||||
}
|
||||
|
||||
/* Lookup role ID */
|
||||
String roleID = "";
|
||||
try {
|
||||
String res = connector.getAppRoleID(roleName);
|
||||
assertThat("Role ID lookup returned empty ID.", res, is(not(emptyString())));
|
||||
roleID = connector.getAppRoleID(roleName);
|
||||
assertThat("Role ID lookup returned empty ID.", roleID, is(not(emptyString())));
|
||||
} catch (VaultConnectorException e) {
|
||||
fail("Role ID lookup failed.");
|
||||
}
|
||||
|
||||
/* Set custom role ID */
|
||||
String roleID = "custom-role-id";
|
||||
roleID = "custom-role-id";
|
||||
try {
|
||||
connector.setAppRoleID(roleName, roleID);
|
||||
} catch (VaultConnectorException e) {
|
||||
@ -444,6 +543,51 @@ public class HTTPVaultConnectorTest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test listing of AppRole roles and secrets.
|
||||
*/
|
||||
@Test
|
||||
public void listAppRoleTest() {
|
||||
/* Try unauthorized access first. */
|
||||
assumeFalse(connector.isAuthorized());
|
||||
|
||||
try {
|
||||
connector.listAppRoles();
|
||||
fail("Expected exception not thrown");
|
||||
} catch (Exception e) {
|
||||
assertThat("Unexpected exception class", e, is(instanceOf(AuthorizationRequiredException.class)));
|
||||
}
|
||||
|
||||
try {
|
||||
connector.listAppRoleSecrets("");
|
||||
fail("Expected exception not thrown");
|
||||
} catch (Exception e) {
|
||||
assertThat("Unexpected exception class", e, is(instanceOf(AuthorizationRequiredException.class)));
|
||||
}
|
||||
|
||||
/* Authorize. */
|
||||
authRoot();
|
||||
assumeTrue(connector.isAuthorized());
|
||||
|
||||
/* Verify pre-existing rules */
|
||||
try {
|
||||
List<String> res = connector.listAppRoles();
|
||||
assertThat("Unexpected number of AppRoles", res, hasSize(2));
|
||||
assertThat("Pre-configured roles not listed", res, containsInAnyOrder(APPROLE_ROLE_NAME, APPROLE_ROLE2_NAME));
|
||||
} catch (VaultConnectorException e) {
|
||||
fail("Role listing failed.");
|
||||
}
|
||||
|
||||
/* Check secret IDs */
|
||||
try {
|
||||
List<String> res = connector.listAppRoleSecrets(APPROLE_ROLE_NAME);
|
||||
assertThat("Unexpected number of AppRole secrets", res, hasSize(1));
|
||||
assertThat("Pre-configured AppRole secret not listed", res, contains(APPROLE_SECRET_ACCESSOR));
|
||||
} catch (VaultConnectorException e) {
|
||||
fail("AppRole secret listing failed.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test reading of secrets.
|
||||
*/
|
||||
@ -696,7 +840,7 @@ public class HTTPVaultConnectorTest {
|
||||
fail("Secret written to inaccessible path.");
|
||||
}
|
||||
|
||||
/* Overwrite token */
|
||||
/* Overwrite token should fail as of Vault 0.8.0 */
|
||||
token = new TokenBuilder()
|
||||
.withId("test-id2")
|
||||
.withDisplayName("test name 3")
|
||||
@ -707,19 +851,13 @@ public class HTTPVaultConnectorTest {
|
||||
.withTtl(1234)
|
||||
.build();
|
||||
try {
|
||||
AuthResponse res = connector.createToken(token);
|
||||
assertThat("Invalid token ID returned.", res.getAuth().getClientToken(), is("test-id2"));
|
||||
assertThat("Invalid number of policies returned.", res.getAuth().getPolicies(), hasSize(3));
|
||||
assertThat("Policies not returned as expected.", res.getAuth().getPolicies(), contains("default", "pol1", "pol2"));
|
||||
assertThat("Old policy not overwritten.", res.getAuth().getPolicies(), not(contains("testpolicy")));
|
||||
assertThat("Metadata not given.", res.getAuth().getMetadata(), is(notNullValue()));
|
||||
assertThat("Metadata not correct.", res.getAuth().getMetadata().get("test"), is("success"));
|
||||
assertThat("Metadata not correct.", res.getAuth().getMetadata().get("key"), is("value"));
|
||||
assertThat("Old metadata not overwritten.", res.getAuth().getMetadata().get("foo"), is(nullValue()));
|
||||
assertThat("TTL not set correctly", res.getAuth().getLeaseDuration(), is(1234));
|
||||
assertThat("Token should be renewable", res.getAuth().isRenewable(), is(true));
|
||||
connector.createToken(token);
|
||||
fail("Overwriting token should fail as of Vault 0.8.0");
|
||||
} catch (VaultConnectorException e) {
|
||||
fail("Secret written to inaccessible path.");
|
||||
assertThat(e, is(instanceOf(InvalidResponseException.class)));
|
||||
assertThat(((InvalidResponseException)e).getStatusCode(), is(400));
|
||||
/* Assert that the exception does not reveal token ID */
|
||||
assertThat(stackTrace(e), not(stringContainsInOrder(token.getId())));
|
||||
}
|
||||
}
|
||||
|
||||
@ -744,6 +882,27 @@ public class HTTPVaultConnectorTest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test closing the connector.
|
||||
*/
|
||||
@Test
|
||||
public void closeTest() {
|
||||
authUser();
|
||||
assumeTrue(connector.isAuthorized());
|
||||
|
||||
try {
|
||||
connector.close();
|
||||
assertThat("Not unauthorized after close().", connector.isAuthorized(), is(false));
|
||||
|
||||
/* Verify that (private) token has indeed been removed */
|
||||
Field tokenField = HTTPVaultConnector.class.getDeclaredField("token");
|
||||
tokenField.setAccessible(true);
|
||||
assertThat("Token not removed after close().", tokenField.get(connector), is(nullValue()));
|
||||
} catch (Exception e) {
|
||||
fail("Closing the connector failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Vault with resource datastore and generated configuration.
|
||||
*
|
||||
|
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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.exception;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Common JUnit test for Exceptions extending {@link VaultConnectorException}.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.6.2
|
||||
*/
|
||||
public class VaultConnectorExceptionTest {
|
||||
private static final String MSG = "This is a test exception!";
|
||||
private static final Throwable CAUSE = new Exception("Test-Cause");
|
||||
private static final Integer STATUS_CODE = 1337;
|
||||
private static final String RESPONSE = "Dummy response";
|
||||
|
||||
@Test
|
||||
public void authorizationRequiredExceptionTest() {
|
||||
assertEmptyConstructor(new AuthorizationRequiredException());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectionExceptionTest() {
|
||||
assertEmptyConstructor(new ConnectionException());
|
||||
assertMsgConstructor(new ConnectionException(MSG));
|
||||
assertCauseConstructor(new ConnectionException(CAUSE));
|
||||
assertMsgCauseConstructor(new ConnectionException(MSG, CAUSE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidRequestExceptionTest() {
|
||||
assertEmptyConstructor(new InvalidRequestException());
|
||||
assertMsgConstructor(new InvalidRequestException(MSG));
|
||||
assertCauseConstructor(new InvalidRequestException(CAUSE));
|
||||
assertMsgCauseConstructor(new InvalidRequestException(MSG, CAUSE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidResponseExceptionTest() {
|
||||
assertEmptyConstructor(new InvalidResponseException());
|
||||
assertMsgConstructor(new InvalidResponseException(MSG));
|
||||
assertCauseConstructor(new InvalidResponseException(CAUSE));
|
||||
assertMsgCauseConstructor(new InvalidResponseException(MSG, CAUSE));
|
||||
|
||||
// Constructor with message and status code.
|
||||
InvalidResponseException e = new InvalidResponseException(MSG, STATUS_CODE);
|
||||
assertThat(e.getMessage(), is(MSG));
|
||||
assertThat(e.getCause(), is(nullValue()));
|
||||
assertThat(e.getStatusCode(), is(STATUS_CODE));
|
||||
assertThat(e.getResponse(), is(nullValue()));
|
||||
|
||||
// Constructor with message, status code and cause.
|
||||
e = new InvalidResponseException(MSG, STATUS_CODE, CAUSE);
|
||||
assertThat(e.getMessage(), is(MSG));
|
||||
assertThat(e.getCause(), is(CAUSE));
|
||||
assertThat(e.getStatusCode(), is(STATUS_CODE));
|
||||
assertThat(e.getResponse(), is(nullValue()));
|
||||
|
||||
// Constructor with message, status code and response.
|
||||
e = new InvalidResponseException(MSG, STATUS_CODE, RESPONSE);
|
||||
assertThat(e.getMessage(), is(MSG));
|
||||
assertThat(e.getCause(), is(nullValue()));
|
||||
assertThat(e.getStatusCode(), is(STATUS_CODE));
|
||||
assertThat(e.getResponse(), is(RESPONSE));
|
||||
|
||||
// Constructor with message, status code, response and cause.
|
||||
e = new InvalidResponseException(MSG, STATUS_CODE, RESPONSE, CAUSE);
|
||||
assertThat(e.getMessage(), is(MSG));
|
||||
assertThat(e.getCause(), is(CAUSE));
|
||||
assertThat(e.getStatusCode(), is(STATUS_CODE));
|
||||
assertThat(e.getResponse(), is(RESPONSE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void permissionDeniedExceptionTest() {
|
||||
// Default message overwritten.
|
||||
PermissionDeniedException e = new PermissionDeniedException();
|
||||
assertThat(e, is(instanceOf(VaultConnectorException.class)));
|
||||
assertThat(e, is(instanceOf(Exception.class)));
|
||||
assertThat(e, is(instanceOf(Throwable.class)));
|
||||
assertThat(e.getMessage(), is("Permission denied"));
|
||||
assertThat(e.getCause(), is(nullValue()));
|
||||
|
||||
assertMsgConstructor(new PermissionDeniedException(MSG));
|
||||
assertCauseConstructor(new PermissionDeniedException(CAUSE));
|
||||
assertMsgCauseConstructor(new PermissionDeniedException(MSG, CAUSE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tlsExceptionTest() {
|
||||
assertEmptyConstructor(new TlsException());
|
||||
assertMsgConstructor(new TlsException(MSG));
|
||||
assertCauseConstructor(new TlsException(CAUSE));
|
||||
assertMsgCauseConstructor(new TlsException(MSG, CAUSE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assertions for empty constructor.
|
||||
*
|
||||
* @param e the exception
|
||||
*/
|
||||
private void assertEmptyConstructor(VaultConnectorException e) {
|
||||
assertThat(e, is(instanceOf(VaultConnectorException.class)));
|
||||
assertThat(e, is(instanceOf(Exception.class)));
|
||||
assertThat(e, is(instanceOf(Throwable.class)));
|
||||
assertThat(e.getMessage(), is(nullValue()));
|
||||
assertThat(e.getCause(), is(nullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assertions for constructor with message.
|
||||
*
|
||||
* @param e the exception
|
||||
*/
|
||||
private void assertMsgConstructor(VaultConnectorException e) {
|
||||
assertThat(e.getMessage(), is(MSG));
|
||||
assertThat(e.getCause(), is(nullValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assertions for constructor with cause.
|
||||
*
|
||||
* @param e the exception
|
||||
*/
|
||||
private void assertCauseConstructor(VaultConnectorException e) {
|
||||
assertThat(e.getMessage(), is(CAUSE.toString()));
|
||||
assertThat(e.getCause(), is(CAUSE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assertions for constructor with message and cause.
|
||||
*
|
||||
* @param e the exception
|
||||
*/
|
||||
private void assertMsgCauseConstructor(VaultConnectorException e) {
|
||||
assertThat(e.getMessage(), is(MSG));
|
||||
assertThat(e.getCause(), is(CAUSE));
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@ public class AuthBackendTest {
|
||||
assertThat(AuthBackend.forType("token"), is(AuthBackend.TOKEN));
|
||||
assertThat(AuthBackend.forType("app-id"), is(AuthBackend.APPID));
|
||||
assertThat(AuthBackend.forType("userpass"), is(AuthBackend.USERPASS));
|
||||
assertThat(AuthBackend.forType("github"), is(AuthBackend.GITHUB));
|
||||
assertThat(AuthBackend.forType(""), is(AuthBackend.UNKNOWN));
|
||||
assertThat(AuthBackend.forType("foobar"), is(AuthBackend.UNKNOWN));
|
||||
}
|
||||
|
@ -0,0 +1,101 @@
|
||||
package de.stklcode.jvault.connector.model.response;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import de.stklcode.jvault.connector.model.AppRole;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link AppRoleResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.6.2
|
||||
*/
|
||||
public class AppRoleResponseTest {
|
||||
private static final Integer ROLE_TOKEN_TTL = 1200;
|
||||
private static final Integer ROLE_TOKEN_MAX_TTL = 1800;
|
||||
private static final Integer ROLE_SECRET_TTL = 600;
|
||||
private static final Integer ROLE_SECRET_NUM_USES = 40;
|
||||
private static final String ROLE_POLICY = "default";
|
||||
private static final Integer ROLE_PERIOD = 0;
|
||||
private static final Boolean ROLE_BIND_SECRET = true;
|
||||
|
||||
private static final String RES_JSON = "{\n" +
|
||||
" \"auth\": null,\n" +
|
||||
" \"warnings\": null,\n" +
|
||||
" \"wrap_info\": null,\n" +
|
||||
" \"data\": {\n" +
|
||||
" \"token_ttl\": " + ROLE_TOKEN_TTL + ",\n" +
|
||||
" \"token_max_ttl\": " + ROLE_TOKEN_MAX_TTL + ",\n" +
|
||||
" \"secret_id_ttl\": " + ROLE_SECRET_TTL + ",\n" +
|
||||
" \"secret_id_num_uses\": " + ROLE_SECRET_NUM_USES + ",\n" +
|
||||
" \"policies\": [\n" +
|
||||
" \"" + ROLE_POLICY + "\"\n" +
|
||||
" ],\n" +
|
||||
" \"period\": " + ROLE_PERIOD + ",\n" +
|
||||
" \"bind_secret_id\": " + ROLE_BIND_SECRET + ",\n" +
|
||||
" \"bound_cidr_list\": \"\"\n" +
|
||||
" },\n" +
|
||||
" \"lease_duration\": 0,\n" +
|
||||
" \"renewable\": false,\n" +
|
||||
" \"lease_id\": \"\"\n" +
|
||||
"}";
|
||||
|
||||
private static final Map<String, Object> INVALID_DATA = new HashMap<>();
|
||||
|
||||
static {
|
||||
INVALID_DATA.put("policies", "fancy-policy");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getter, setter and get-methods for response data.
|
||||
*/
|
||||
@Test
|
||||
public void getDataRoundtrip() {
|
||||
// Create empty Object.
|
||||
AppRoleResponse res = new AppRoleResponse();
|
||||
assertThat("Initial data should be empty", res.getRole(), is(nullValue()));
|
||||
|
||||
// Parsing invalid auth data map should fail.
|
||||
try {
|
||||
res.setData(INVALID_DATA);
|
||||
fail("Parsing invalid data succeeded");
|
||||
} catch (Exception e) {
|
||||
assertThat(e, is(instanceOf(InvalidResponseException.class)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
public void jsonRoundtrip() {
|
||||
try {
|
||||
AppRoleResponse res = new ObjectMapper().readValue(RES_JSON, AppRoleResponse.class);
|
||||
assertThat("Parsed response is NULL", res, is(notNullValue()));
|
||||
// Extract role data.
|
||||
AppRole role = res.getRole();
|
||||
assertThat("Role data is NULL", role, is(notNullValue()));
|
||||
assertThat("Incorrect token TTL", role.getTokenTtl(), is(ROLE_TOKEN_TTL));
|
||||
assertThat("Incorrect token max TTL", role.getTokenMaxTtl(), is(ROLE_TOKEN_MAX_TTL));
|
||||
assertThat("Incorrect secret ID TTL", role.getSecretIdTtl(), is(ROLE_SECRET_TTL));
|
||||
assertThat("Incorrect secret ID umber of uses", role.getSecretIdNumUses(), is(ROLE_SECRET_NUM_USES));
|
||||
assertThat("Incorrect number of policies", role.getPolicies(), hasSize(1));
|
||||
assertThat("Incorrect role policies", role.getPolicies(), contains(ROLE_POLICY));
|
||||
assertThat("Incorrect role period", role.getPeriod(), is(ROLE_PERIOD));
|
||||
assertThat("Incorrect role bind secret ID flag", role.getBindSecretId(), is(ROLE_BIND_SECRET));
|
||||
assertThat("Incorrect biund CIDR list", role.getBoundCidrList(), is(nullValue()));
|
||||
assertThat("Incorrect biund CIDR list string", role.getBoundCidrListString(), is(emptyString()));
|
||||
} catch (IOException e) {
|
||||
fail("AuthResponse deserialization failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
package de.stklcode.jvault.connector.model.response;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import de.stklcode.jvault.connector.model.AuthBackend;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.AuthData;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.AuthMethod;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link AuthMethodsResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.6.2
|
||||
*/
|
||||
public class AuthMethodsResponseTest {
|
||||
private static final String GH_PATH = "github/";
|
||||
private static final String GH_TYPE = "github";
|
||||
private static final String GH_DESCR = "GitHub auth";
|
||||
private static final String TK_PATH = "token/";
|
||||
private static final String TK_TYPE = "token";
|
||||
private static final String TK_DESCR = "token based credentials";
|
||||
private static final Integer TK_LEASE_TTL = 0;
|
||||
private static final Integer TK_MAX_LEASE_TTL = 0;
|
||||
|
||||
private static final String RES_JSON = "{\n" +
|
||||
" \"data\": {" +
|
||||
" \"" + GH_PATH + "\": {\n" +
|
||||
" \"type\": \"" + GH_TYPE + "\",\n" +
|
||||
" \"description\": \"" + GH_DESCR + "\"\n" +
|
||||
" },\n" +
|
||||
" \"" + TK_PATH + "\": {\n" +
|
||||
" \"config\": {\n" +
|
||||
" \"default_lease_ttl\": " + TK_LEASE_TTL + ",\n" +
|
||||
" \"max_lease_ttl\": " + TK_MAX_LEASE_TTL + "\n" +
|
||||
" },\n" +
|
||||
" \"description\": \"" + TK_DESCR + "\",\n" +
|
||||
" \"type\": \"" + TK_TYPE + "\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
private static final Map<String, Object> INVALID_DATA = new HashMap<>();
|
||||
|
||||
static {
|
||||
INVALID_DATA.put("dummy/", new Dummy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getter, setter and get-methods for response data.
|
||||
*/
|
||||
@Test
|
||||
public void getDataRoundtrip() {
|
||||
// Create empty Object.
|
||||
AuthMethodsResponse res = new AuthMethodsResponse();
|
||||
assertThat("Initial method map should be empty", res.getSupportedMethods(), is(anEmptyMap()));
|
||||
|
||||
// Parsing invalid data map should fail.
|
||||
try {
|
||||
res.setData(INVALID_DATA);
|
||||
fail("Parsing invalid data succeeded");
|
||||
} catch (Exception e) {
|
||||
assertThat(e, is(instanceOf(InvalidResponseException.class)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
public void jsonRoundtrip() {
|
||||
try {
|
||||
AuthMethodsResponse res = new ObjectMapper().readValue(RES_JSON, AuthMethodsResponse.class);
|
||||
assertThat("Parsed response is NULL", res, is(notNullValue()));
|
||||
// Extract auth data.
|
||||
Map<String, AuthMethod> supported = res.getSupportedMethods();
|
||||
assertThat("Auth data is NULL", supported, is(notNullValue()));
|
||||
assertThat("Incorrect number of supported methods", supported.entrySet(), hasSize(2));
|
||||
assertThat("Incorrect method paths", supported.keySet(), containsInAnyOrder(GH_PATH, TK_PATH));
|
||||
|
||||
// Verify first method.
|
||||
AuthMethod method = supported.get(GH_PATH);
|
||||
assertThat("Incorrect raw type for GitHub", method.getRawType(), is(GH_TYPE));
|
||||
assertThat("Incorrect parsed type for GitHub", method.getType(), is(AuthBackend.GITHUB));
|
||||
assertThat("Incorrect description for GitHub", method.getDescription(), is(GH_DESCR));
|
||||
assertThat("Unexpected config for GitHub", method.getConfig(), is(nullValue()));
|
||||
|
||||
// Verify first method.
|
||||
method = supported.get(TK_PATH);
|
||||
assertThat("Incorrect raw type for Token", method.getRawType(), is(TK_TYPE));
|
||||
assertThat("Incorrect parsed type for Token", method.getType(), is(AuthBackend.TOKEN));
|
||||
assertThat("Incorrect description for Token", method.getDescription(), is(TK_DESCR));
|
||||
assertThat("Missing config for Token", method.getConfig(), is(notNullValue()));
|
||||
assertThat("Unexpected config size for Token", method.getConfig().keySet(), hasSize(2));
|
||||
assertThat("Incorrect lease TTL config", method.getConfig().get("default_lease_ttl"), is(TK_LEASE_TTL.toString()));
|
||||
assertThat("Incorrect max lease TTL config", method.getConfig().get("max_lease_ttl"), is(TK_MAX_LEASE_TTL.toString()));
|
||||
} catch (IOException e) {
|
||||
fail("AuthResponse deserialization failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static class Dummy {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package de.stklcode.jvault.connector.model.response;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.AuthData;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link AuthResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.6.2
|
||||
*/
|
||||
public class AuthResponseTest {
|
||||
private static final String AUTH_ACCESSOR = "2c84f488-2133-4ced-87b0-570f93a76830";
|
||||
private static final String AUTH_CLIENT_TOKEN = "ABCD";
|
||||
private static final String AUTH_POLICY_1 = "web";
|
||||
private static final String AUTH_POLICY_2 = "stage";
|
||||
private static final String AUTH_META_KEY = "user";
|
||||
private static final String AUTH_META_VALUE = "armon";
|
||||
private static final Integer AUTH_LEASE_DURATION = 3600;
|
||||
private static final Boolean AUTH_RENEWABLE = true;
|
||||
|
||||
private static final String RES_JSON = "{\n" +
|
||||
" \"auth\": {\n" +
|
||||
" \"accessor\": \"" + AUTH_ACCESSOR + "\",\n" +
|
||||
" \"client_token\": \"" + AUTH_CLIENT_TOKEN + "\",\n" +
|
||||
" \"policies\": [\n" +
|
||||
" \"" + AUTH_POLICY_1 + "\", \n" +
|
||||
" \"" + AUTH_POLICY_2 + "\"\n" +
|
||||
" ],\n" +
|
||||
" \"metadata\": {\n" +
|
||||
" \"" + AUTH_META_KEY + "\": \"" + AUTH_META_VALUE + "\"\n" +
|
||||
" },\n" +
|
||||
" \"lease_duration\": " + AUTH_LEASE_DURATION + ",\n" +
|
||||
" \"renewable\": " + AUTH_RENEWABLE + "\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
private static final Map<String, Object> INVALID_AUTH_DATA = new HashMap<>();
|
||||
|
||||
static {
|
||||
INVALID_AUTH_DATA.put("policies", "fancy-policy");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getter, setter and get-methods for response data.
|
||||
*/
|
||||
@Test
|
||||
public void getDataRoundtrip() {
|
||||
// Create empty Object.
|
||||
AuthResponse res = new AuthResponse();
|
||||
assertThat("Initial data should be empty", res.getData(), is(nullValue()));
|
||||
|
||||
// Parsing invalid auth data map should fail.
|
||||
try {
|
||||
res.setAuth(INVALID_AUTH_DATA);
|
||||
fail("Parsing invalid auth data succeeded");
|
||||
} catch (Exception e) {
|
||||
assertThat(e, is(instanceOf(InvalidResponseException.class)));
|
||||
}
|
||||
|
||||
// Data method should be agnostic.
|
||||
res.setData(INVALID_AUTH_DATA);
|
||||
assertThat("Data not passed through", res.getData(), is(INVALID_AUTH_DATA));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
public void jsonRoundtrip() {
|
||||
try {
|
||||
AuthResponse res = new ObjectMapper().readValue(RES_JSON, AuthResponse.class);
|
||||
assertThat("Parsed response is NULL", res, is(notNullValue()));
|
||||
// Extract auth data.
|
||||
AuthData data = res.getAuth();
|
||||
assertThat("Auth data is NULL", data, is(notNullValue()));
|
||||
assertThat("Incorrect auth accessor", data.getAccessor(), is(AUTH_ACCESSOR));
|
||||
assertThat("Incorrect auth client token", data.getClientToken(), is(AUTH_CLIENT_TOKEN));
|
||||
assertThat("Incorrect auth lease duration", data.getLeaseDuration(), is(AUTH_LEASE_DURATION));
|
||||
assertThat("Incorrect auth renewable flag", data.isRenewable(), is(AUTH_RENEWABLE));
|
||||
assertThat("Incorrect number of policies", data.getPolicies(), hasSize(2));
|
||||
assertThat("Incorrect auth policies", data.getPolicies(), containsInAnyOrder(AUTH_POLICY_1, AUTH_POLICY_2));
|
||||
} catch (IOException e) {
|
||||
fail("AuthResponse deserialization failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
package de.stklcode.jvault.connector.model.response;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link SecretResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.6.2
|
||||
*/
|
||||
public class SecretResponseTest {
|
||||
private static final Map<String, Object> DATA = new HashMap<>();
|
||||
private static final String KEY_UNKNOWN = "unknown";
|
||||
private static final String KEY_STRING = "test1";
|
||||
private static final String VAL_STRING = "testvalue";
|
||||
private static final String KEY_INTEGER = "test2";
|
||||
private static final Integer VAL_INTEGER = 42;
|
||||
private static final String KEY_LIST = "list";
|
||||
private static final String VAL_LIST = "[\"first\",\"second\"]";
|
||||
|
||||
private static final String SECRET_REQUEST_ID = "68315073-6658-e3ff-2da7-67939fb91bbd";
|
||||
private static final String SECRET_LEASE_ID = "";
|
||||
private static final Integer SECRET_LEASE_DURATION = 2764800;
|
||||
private static final boolean SECRET_RENEWABLE = false;
|
||||
private static final String SECRET_DATA_K1 = "excited";
|
||||
private static final String SECRET_DATA_V1 = "yes";
|
||||
private static final String SECRET_DATA_K2 = "value";
|
||||
private static final String SECRET_DATA_V2 = "world";
|
||||
private static final List<String> SECRET_WARNINGS = null;
|
||||
private static final String SECRET_JSON = "{\n" +
|
||||
" \"request_id\": \"" + SECRET_REQUEST_ID + "\",\n" +
|
||||
" \"lease_id\": \"" + SECRET_LEASE_ID + "\",\n" +
|
||||
" \"lease_duration\": " + SECRET_LEASE_DURATION + ",\n" +
|
||||
" \"renewable\": " + SECRET_RENEWABLE + ",\n" +
|
||||
" \"data\": {\n" +
|
||||
" \"" + SECRET_DATA_K1 + "\": \"" + SECRET_DATA_V1 + "\",\n" +
|
||||
" \"" + SECRET_DATA_K2 + "\": \"" + SECRET_DATA_V2 + "\"\n" +
|
||||
" },\n" +
|
||||
" \"warnings\": " + SECRET_WARNINGS + "\n" +
|
||||
"}";
|
||||
|
||||
|
||||
static {
|
||||
DATA.put(KEY_STRING, VAL_STRING);
|
||||
DATA.put(KEY_INTEGER, VAL_INTEGER);
|
||||
DATA.put(KEY_LIST, VAL_LIST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getter, setter and get-methods for response data.
|
||||
*
|
||||
* @throws InvalidResponseException Should not occur
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getDataRoundtrip() throws InvalidResponseException {
|
||||
// Create empty Object.
|
||||
SecretResponse res = new SecretResponse();
|
||||
assertThat("Initial data should be Map", res.getData(), is(instanceOf(Map.class)));
|
||||
assertThat("Initial data should be empty", res.getData().entrySet(), empty());
|
||||
assertThat("Getter should return NULL on empty data map", res.get(KEY_STRING), is(nullValue()));
|
||||
|
||||
// Fill data map.
|
||||
res.setData(DATA);
|
||||
assertThat("Data setter/getter not transparent", res.getData(), is(DATA));
|
||||
assertThat("Data size modified", res.getData().keySet(), hasSize(DATA.size()));
|
||||
assertThat("Data keys not passed correctly", res.getData().keySet(), containsInAnyOrder(KEY_STRING, KEY_INTEGER, KEY_LIST));
|
||||
assertThat("Data values not passed correctly", res.get(KEY_STRING), is(VAL_STRING));
|
||||
assertThat("Data values not passed correctly", res.get(KEY_INTEGER), is(VAL_INTEGER));
|
||||
assertThat("Non-Null returned on unknown key", res.get(KEY_UNKNOWN), is(nullValue()));
|
||||
|
||||
// Try explicit JSON conversion.
|
||||
final List list = res.get(KEY_LIST, List.class);
|
||||
assertThat("JSON parsing of list failed", list, is(notNullValue()));
|
||||
assertThat("JSON parsing of list returned incorrect size", list.size(), is(2));
|
||||
assertThat("JSON parsing of list returned incorrect elements", (List<Object>)list, contains("first", "second"));
|
||||
assertThat("Non-Null returned on unknown key", res.get(KEY_UNKNOWN, Object.class), is(nullValue()));
|
||||
|
||||
// Requesting invalid class should result in Exception.
|
||||
try {
|
||||
res.get(KEY_LIST, Double.class);
|
||||
fail("JSON parsing to incorrect type succeeded.");
|
||||
} catch (Exception e) {
|
||||
assertThat(e, is(instanceOf(InvalidResponseException.class)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
public void jsonRoundtrip() {
|
||||
try {
|
||||
SecretResponse res = new ObjectMapper().readValue(SECRET_JSON, SecretResponse.class);
|
||||
assertThat("Parsed response is NULL", res, is(notNullValue()));
|
||||
assertThat("Incorrect lease ID", res.getLeaseId(), is(SECRET_LEASE_ID));
|
||||
assertThat("Incorrect lease duration", res.getLeaseDuration(), is(SECRET_LEASE_DURATION));
|
||||
assertThat("Incorrect renewable status", res.isRenewable(), is(SECRET_RENEWABLE));
|
||||
assertThat("Incorrect warnings", res.getWarnings(), is(SECRET_WARNINGS));
|
||||
assertThat("Response does not contain correct data", res.get(SECRET_DATA_K1), is(SECRET_DATA_V1));
|
||||
assertThat("Response does not contain correct data", res.get(SECRET_DATA_K2), is(SECRET_DATA_V2));
|
||||
} catch (IOException e) {
|
||||
fail("SecretResponse deserialization failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
package de.stklcode.jvault.connector.model.response;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link TokenResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.6.2
|
||||
*/
|
||||
public class TokenResponseTest {
|
||||
private static final Integer TOKEN_CREATION_TIME = 1457533232;
|
||||
private static final Integer TOKEN_TTL = 2764800;
|
||||
private static final String TOKEN_DISPLAY_NAME = "token";
|
||||
private static final Integer TOKEN_NUM_USES = 0;
|
||||
private static final Boolean TOKEN_ORPHAN = false;
|
||||
private static final String TOKEN_PATH = "auth/token/create";
|
||||
private static final String TOKEN_POLICY_1 = "default";
|
||||
private static final String TOKEN_POLICY_2 = "web";
|
||||
private static final Boolean RES_RENEWABLE = false;
|
||||
private static final Integer RES_TTL = 2591976;
|
||||
private static final Integer RES_LEASE_DURATION = 0;
|
||||
|
||||
private static final String RES_JSON = "{\n" +
|
||||
" \"lease_id\": \"\",\n" +
|
||||
" \"renewable\": " + RES_RENEWABLE + ",\n" +
|
||||
" \"lease_duration\": " + RES_LEASE_DURATION + ",\n" +
|
||||
" \"data\": {\n" +
|
||||
" \"creation_time\": " + TOKEN_CREATION_TIME + ",\n" +
|
||||
" \"creation_ttl\": " + TOKEN_TTL + ",\n" +
|
||||
" \"display_name\": \"" + TOKEN_DISPLAY_NAME + "\",\n" +
|
||||
" \"meta\": null,\n" +
|
||||
" \"num_uses\": " + TOKEN_NUM_USES + ",\n" +
|
||||
" \"orphan\": " + TOKEN_ORPHAN + ",\n" +
|
||||
" \"path\": \"" + TOKEN_PATH + "\",\n" +
|
||||
" \"policies\": [\n" +
|
||||
" \"" + TOKEN_POLICY_1 + "\", \n" +
|
||||
" \"" + TOKEN_POLICY_2 + "\"\n" +
|
||||
" ],\n" +
|
||||
" \"ttl\": " + RES_TTL + "\n" +
|
||||
" },\n" +
|
||||
" \"warnings\": null,\n" +
|
||||
" \"auth\": null\n" +
|
||||
"}";
|
||||
|
||||
private static final Map<String, Object> INVALID_TOKEN_DATA = new HashMap<>();
|
||||
|
||||
static {
|
||||
INVALID_TOKEN_DATA.put("num_uses", "fourtytwo");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getter, setter and get-methods for response data.
|
||||
*/
|
||||
@Test
|
||||
public void getDataRoundtrip() {
|
||||
// Create empty Object.
|
||||
TokenResponse res = new TokenResponse();
|
||||
assertThat("Initial data should be empty", res.getData(), is(nullValue()));
|
||||
|
||||
// Parsing invalid data map should fail.
|
||||
try {
|
||||
res.setData(INVALID_TOKEN_DATA);
|
||||
fail("Parsing invalid token data succeeded");
|
||||
} catch (Exception e) {
|
||||
assertThat(e, is(instanceOf(InvalidResponseException.class)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
public void jsonRoundtrip() {
|
||||
try {
|
||||
TokenResponse res = new ObjectMapper().readValue(RES_JSON, TokenResponse.class);
|
||||
assertThat("Parsed response is NULL", res, is(notNullValue()));
|
||||
assertThat("Incorrect lease duration", res.getLeaseDuration(), is(RES_LEASE_DURATION));
|
||||
assertThat("Incorrect renewable status", res.isRenewable(), is(RES_RENEWABLE));
|
||||
// Extract token data.
|
||||
TokenData data = res.getData();
|
||||
assertThat("Token data is NULL", data, is(notNullValue()));
|
||||
assertThat("Incorrect token creation time", data.getCreationTime(), is(TOKEN_CREATION_TIME));
|
||||
assertThat("Incorrect token creation TTL", data.getCreationTtl(), is(TOKEN_TTL));
|
||||
assertThat("Incorrect token display name", data.getName(), is(TOKEN_DISPLAY_NAME));
|
||||
assertThat("Incorrect token number of uses", data.getNumUses(), is(TOKEN_NUM_USES));
|
||||
assertThat("Incorrect token orphan flag", data.isOrphan(), is(TOKEN_ORPHAN));
|
||||
assertThat("Incorrect token path", data.getPath(), is(TOKEN_PATH));
|
||||
assertThat("Incorrect response renewable flag", res.isRenewable(), is(RES_RENEWABLE));
|
||||
assertThat("Incorrect response TTL", data.getTtl(), is(RES_TTL));
|
||||
assertThat("Incorrect response lease duration", res.getLeaseDuration(), is(RES_LEASE_DURATION));
|
||||
} catch (IOException e) {
|
||||
fail("TokenResponse deserialization failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user