Compare commits
78 Commits
Author | SHA1 | Date | |
---|---|---|---|
ed2b9d62a3 | |||
007b523295 | |||
061c1e9743 | |||
6904ed6817 | |||
1ed5d8d992 | |||
f70fc084be | |||
4b14ab3f4b | |||
29776f459e | |||
4ca8aa56d2 | |||
32ab9f4bb1 | |||
e002fc749a | |||
b9ad2d1551 | |||
35a8c2e0fa | |||
89f7581d17 | |||
43511dc20b | |||
05b44759c0 | |||
ba17286ab3 | |||
51e505313a | |||
a1784245a3 | |||
df7de5dd73 | |||
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 | |||
594b80f62b | |||
4bd614a633 | |||
0f6bccff02 | |||
fca6e496d8 | |||
0f5540913a | |||
8129017ad0 | |||
c0ad451134 | |||
5f3e285a8a | |||
107244cb81 | |||
e877d377c0 | |||
a565411b22 | |||
6f13af5c91 | |||
ce2de2df81 | |||
d7e4e7e5be | |||
2f312d3937 | |||
2f5b6d1523 | |||
69874bdceb | |||
8ab9c23605 | |||
324bff7e58 | |||
b036b73e11 |
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/target/
|
||||||
|
/*.iml
|
||||||
|
/.idea/
|
||||||
|
/*.project
|
||||||
|
*~
|
28
.travis.yml
Normal file
28
.travis.yml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
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.8.3/vault_0.8.3_linux_amd64.zip
|
||||||
|
- unzip vault_0.8.3_linux_amd64.zip
|
||||||
|
- rm vault_0.8.3_linux_amd64.zip
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- '$HOME/.m2/repository'
|
||||||
|
- '$HOME/.sonar/cache'
|
||||||
|
script:
|
||||||
|
- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar
|
||||||
|
notifications:
|
||||||
|
slack:
|
||||||
|
secure: "YyE5GePOLkCVTtCy8j507BRmQrtrWhtvmUt4kY0Z2/ptf0LzfuDEJQ4ZbCxO5ri5IDJrrvyPAedjft818+bMzdFfxvi1oviIL+LZNhyev8gfeIBF/U2pvSLGKCRX4g4aZ6NKN3Untjdm8lmiVTltOyZ59JizQVwXzAl3LiOpnJugyBqbhOx4EIqBzwW3gaYAofMqY2LczW5W/M+99HJCst8Mb8H06GstCPEHCizAq7VRaUS68PstlxQMV0Q6bsSYMLFbLWmhuXs96WHqOrT+nNsl07ikr3N8c4HafhFutt2Jyc1+8gXO417+eSvVM0iBpHGwTmfGFfCqx/4Pf62DTJuvh8dR4fLgLDiqEeDrBEcRRDOs9cvXVOO22NN1HuBBJY8VRiFcwNAvuVMXCtnC+1RJRAZB2zubsANiFe+ygk/ywj37cVXY+NpqlBwcSph6jPHo2hD6cIl2rTWn1EnZH519Rh38xTSv6MRzAO9kWNVrAlX+UtvYS8Sk7Owrc0tET9Lc4zj6aI5tsA1wYbN3Jk6EbMhsF6K/XF2npt2qg09pxkj8wmxoUoR6/rGuSv55aSxTdLDmH+en4ahEm3uc4h1lYoVCk0yrZoTAas3zS4WpBCKnl+mweuKNxaejyy0Wv6NR9ZCTaS3yFgibNOjvDpxZxTAPdNBL7hn+k4LwgN4="
|
38
CHANGELOG.md
38
CHANGELOG.md
@ -1,6 +1,40 @@
|
|||||||
|
## 0.7.0 [2017-10-03]
|
||||||
|
* [feature] Retrieval of health status via `getHealth()` (#15)
|
||||||
|
* [improvement] `seal()`, `unseal()` are now `void` and throw Exception on error (#12)
|
||||||
|
* [compatibility] Adaptation to Vault 0.8 endpoints for `renew` and `revoke`, **breaking** 0.7 compatibility (#11)
|
||||||
|
* [deletion] Removed deprecated `listAppRoleSecretss()` (use `listAppRoleSecrets()`) (#14)
|
||||||
|
* [test] Tested against Vault 0.8.3
|
||||||
|
|
||||||
|
## 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
|
||||||
|
* [deprecation] `SecretResponse.getValue()` deprecated
|
||||||
|
* [test] Tested against Vault 0.7.0
|
||||||
|
|
||||||
## 0.4.1 [2016-12-24]
|
## 0.4.1 [2016-12-24]
|
||||||
* [fix] Factory Null-tolerant for trusted certificate (#6)
|
* [fix] Factory Null-tolerant for trusted certificate (#6)
|
||||||
* [test] StackTraces testet for secret leaks
|
* [test] StackTraces tested for secret leaks
|
||||||
* [test] Tested against Vault 0.6.4
|
* [test] Tested against Vault 0.6.4
|
||||||
|
|
||||||
## 0.4.0 [2016-11-06]
|
## 0.4.0 [2016-11-06]
|
||||||
@ -25,4 +59,4 @@
|
|||||||
* [test] Tested against Vault 0.6.0
|
* [test] Tested against Vault 0.6.0
|
||||||
|
|
||||||
## 0.1.0 [2016-03-29]
|
## 0.1.0 [2016-03-29]
|
||||||
* First release
|
* First release
|
||||||
|
104
README.md
104
README.md
@ -1,12 +1,20 @@
|
|||||||
Java Vault Connector
|
# 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)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Java Vault Connector is a connector library for [Vault](https://www.vaultproject.io) by [Hashicorp](https://www.hashicorp.com) written in Java. The connector allows simple usage of Vault's secret store in own applications.
|
Java Vault Connector is a connector library for [Vault](https://www.vaultproject.io) by [Hashicorp](https://www.hashicorp.com) written in Java. The connector allows simple usage of Vault's secret store in own applications.
|
||||||
|
|
||||||
**Current available features:**
|
## Features:
|
||||||
|
|
||||||
* HTTP(S) backend connector
|
* HTTP(S) backend connector
|
||||||
* Ability to provide or enforce custom CA certificate
|
* Ability to provide or enforce custom CA certificate
|
||||||
* Authorization methods:
|
* Optional initialization from environment variables
|
||||||
|
* Authorization methods
|
||||||
* Token
|
* Token
|
||||||
* Username/Password
|
* Username/Password
|
||||||
* AppID (register and authenticate) [_deprecated_]
|
* AppID (register and authenticate) [_deprecated_]
|
||||||
@ -21,46 +29,104 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
|
|||||||
* Delete secrets
|
* Delete secrets
|
||||||
* Renew/revoke leases
|
* Renew/revoke leases
|
||||||
* Raw secret content or JSON decoding
|
* Raw secret content or JSON decoding
|
||||||
|
* SQL secret handling
|
||||||
* Connector Factory with builder pattern
|
* Connector Factory with builder pattern
|
||||||
* Tested against Vault 0.6.4
|
* Tested against Vault 0.8.3
|
||||||
|
|
||||||
**Usage Example**
|
|
||||||
|
## Maven Artifact
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>de.stklcode.jvault</groupId>
|
||||||
|
<artifactId>connector</artifactId>
|
||||||
|
<version>0.7.0</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Initialization
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// Instanciate using builder pattern style factory
|
// Instantiate using builder pattern style factory (TLS enabled by default)
|
||||||
VaultConnector vault = VaultConnectorFactory.httpFactory()
|
VaultConnector vault = VaultConnectorFactory.httpFactory()
|
||||||
.withHost("127.0.0.1")
|
.withHost("127.0.0.1")
|
||||||
.withPort(8200)
|
.withPort(8200)
|
||||||
.withTLS()
|
.withTLS()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
//authenticate with token
|
// Instantiate with custom SSL context
|
||||||
|
VaultConnector vault = VaultConnectorFactory.httpFactory()
|
||||||
|
.withHost("example.com")
|
||||||
|
.withPort(8200)
|
||||||
|
.withTrustedCA(Paths.get("/path/to/CA.pem"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Initialization from environment variables
|
||||||
|
VaultConnector vault = VaultConnectorFactory.httpFactory()
|
||||||
|
.fromEnv()
|
||||||
|
.build();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Authenticate with token
|
||||||
vault.authToken("01234567-89ab-cdef-0123-456789abcdef");
|
vault.authToken("01234567-89ab-cdef-0123-456789abcdef");
|
||||||
|
|
||||||
// retrieve secret
|
// Authenticate with username and password
|
||||||
|
vault.authUserPass("username", "p4ssw0rd");
|
||||||
|
|
||||||
|
// Authenticate with AppID (secret - 2nd argument - is optional)
|
||||||
|
vault.authAppId("01234567-89ab-cdef-0123-456789abcdef", "fedcba98-7654-3210-fedc-ba9876543210");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Secret read & write
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Retrieve secret (prefix "secret/" assumed, use read() to read arbitrary paths)
|
||||||
String secret = vault.readSecret("some/secret/key").getValue();
|
String secret = vault.readSecret("some/secret/key").getValue();
|
||||||
|
|
||||||
|
// Complex secret
|
||||||
|
Map<String, Object> secretData = vault.readSecret("another/secret/key").getData();
|
||||||
|
|
||||||
|
// Write simple secret
|
||||||
|
vault.writeSecret("new/secret/key", "secret value");
|
||||||
|
|
||||||
|
// Write complex data to arbitraty path
|
||||||
|
Map<String, Object> map = [...]
|
||||||
|
vault.write("any/path/to/write", map);
|
||||||
|
|
||||||
|
// Delete secret
|
||||||
|
vault.delete("any/path/to/write");
|
||||||
```
|
```
|
||||||
|
|
||||||
**Maven Artifact**
|
### Token and role creation
|
||||||
```
|
|
||||||
<dependency>
|
```java
|
||||||
<groupId>de.stklcode.jvault</groupId>
|
// Create token using TokenBuilder
|
||||||
<artifactId>connector</artifactId>
|
Token token = new TokenBuilder().withId("token id")
|
||||||
<version>0.4.1</version>
|
.withDisplayName("new test token")
|
||||||
</dependency>
|
.withPolicies("pol1", "pol2")
|
||||||
|
.build();
|
||||||
|
vault.createToken(token);
|
||||||
|
|
||||||
|
// Create AppRole credentials
|
||||||
|
vault.createAppRole("testrole", policyList);
|
||||||
|
AppRoleSecretResponse secret = vault.createAppRoleSecret("testrole");
|
||||||
```
|
```
|
||||||
|
|
||||||
**Links**
|
## Links
|
||||||
|
|
||||||
[Project Page](http://jvault.stklcode.de)
|
[Project Page](http://jvault.stklcode.de)
|
||||||
|
|
||||||
[JavaDoc API](http://jvault.stklcode.de/apidocs/)
|
[JavaDoc API](http://jvault.stklcode.de/apidocs/)
|
||||||
|
|
||||||
**Planned features:**
|
## Planned features
|
||||||
|
|
||||||
* Creation and modification of policies
|
* Creation and modification of policies
|
||||||
* Implement more authentication methods
|
* Implement more authentication methods
|
||||||
|
|
||||||
**License**
|
## License
|
||||||
|
|
||||||
The project is licensed under [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0).
|
The project is licensed under [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
BIN
assets/logo.png
Normal file
BIN
assets/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
12
assets/logo.svg
Normal file
12
assets/logo.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128">
|
||||||
|
<path d="M4,12 l60,104 l60,-104 z" stroke="none" fill="#000000" />
|
||||||
|
<circle cx="78" cy="24" r="6" stroke="none" fill="#00a9c7" />
|
||||||
|
<circle cx="78" cy="38" r="6" stroke="none" fill="#00a9c7" />
|
||||||
|
<circle cx="78" cy="52" r="6" stroke="none" fill="#00a9c7" />
|
||||||
|
<circle cx="78" cy="66" r="6" stroke="none" fill="#00a9c7" />
|
||||||
|
<circle cx="72" cy="78" r="6" stroke="none" fill="#00a9c7" />
|
||||||
|
<circle cx="58" cy="78" r="6" stroke="none" fill="#00a9c7" />
|
||||||
|
<circle cx="52" cy="66" r="6" stroke="none" fill="#00a9c7" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 759 B |
76
pom.xml
76
pom.xml
@ -2,11 +2,23 @@
|
|||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<name>jVaultConnector</name>
|
|
||||||
|
|
||||||
<groupId>de.stklcode.jvault</groupId>
|
<groupId>de.stklcode.jvault</groupId>
|
||||||
<artifactId>connector</artifactId>
|
<artifactId>connector</artifactId>
|
||||||
<version>0.4.1</version>
|
<version>0.7.0</version>
|
||||||
|
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>jVaultConnector</name>
|
||||||
|
<description>Connector artifact for Hashicorp's Vault secret management</description>
|
||||||
|
<url>https://jvault.stklcode.de</url>
|
||||||
|
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>Apache License 2.0</name>
|
||||||
|
<url>http://www.apache.org/licenses/LICENSE-2.0.html</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
@ -17,36 +29,64 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.6.0</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-clean-plugin</artifactId>
|
||||||
|
<version>3.0.0</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
|
<version>3.0.2</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>3.0.2</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-install-plugin</artifactId>
|
||||||
|
<version>2.5.2</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>2.20.1</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
</build>
|
</build>
|
||||||
<packaging>jar</packaging>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
<artifactId>httpcore</artifactId>
|
<artifactId>httpcore</artifactId>
|
||||||
<version>4.4.5</version>
|
<version>4.4.7</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
<artifactId>httpclient</artifactId>
|
<artifactId>httpclient</artifactId>
|
||||||
<version>4.5.2</version>
|
<version>4.5.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-core</artifactId>
|
<artifactId>jackson-core</artifactId>
|
||||||
<version>2.8.5</version>
|
<version>2.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
<version>2.8.5</version>
|
<version>2.9.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -61,5 +101,23 @@
|
|||||||
<version>2.0.0.0</version>
|
<version>2.0.0.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.stefanbirkner</groupId>
|
||||||
|
<artifactId>system-rules</artifactId>
|
||||||
|
<version>1.16.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.powermock</groupId>
|
||||||
|
<artifactId>powermock-module-junit4</artifactId>
|
||||||
|
<version>1.7.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.powermock</groupId>
|
||||||
|
<artifactId>powermock-api-mockito</artifactId>
|
||||||
|
<version>1.7.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -19,10 +19,14 @@ package de.stklcode.jvault.connector;
|
|||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import de.stklcode.jvault.connector.exception.*;
|
import de.stklcode.jvault.connector.exception.*;
|
||||||
import de.stklcode.jvault.connector.model.*;
|
import de.stklcode.jvault.connector.model.AppRole;
|
||||||
|
import de.stklcode.jvault.connector.model.AppRoleSecret;
|
||||||
|
import de.stklcode.jvault.connector.model.AuthBackend;
|
||||||
|
import de.stklcode.jvault.connector.model.Token;
|
||||||
import de.stklcode.jvault.connector.model.response.*;
|
import de.stklcode.jvault.connector.model.response.*;
|
||||||
import de.stklcode.jvault.connector.model.response.embedded.AuthMethod;
|
import de.stklcode.jvault.connector.model.response.embedded.AuthMethod;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.config.RequestConfig;
|
||||||
import org.apache.http.client.methods.*;
|
import org.apache.http.client.methods.*;
|
||||||
import org.apache.http.client.utils.URIBuilder;
|
import org.apache.http.client.utils.URIBuilder;
|
||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.http.entity.StringEntity;
|
||||||
@ -30,14 +34,18 @@ import org.apache.http.impl.client.CloseableHttpClient;
|
|||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
import org.apache.http.util.EntityUtils;
|
import org.apache.http.util.EntityUtils;
|
||||||
|
|
||||||
import javax.net.ssl.*;
|
import javax.net.ssl.SSLContext;
|
||||||
import java.io.*;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vault Connector implementatin using Vault's HTTP API.
|
* Vault Connector implementatin using Vault's HTTP API.
|
||||||
*
|
*
|
||||||
@ -49,7 +57,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
private static final String PATH_SEAL_STATUS = "sys/seal-status";
|
private static final String PATH_SEAL_STATUS = "sys/seal-status";
|
||||||
private static final String PATH_SEAL = "sys/seal";
|
private static final String PATH_SEAL = "sys/seal";
|
||||||
private static final String PATH_UNSEAL = "sys/unseal";
|
private static final String PATH_UNSEAL = "sys/unseal";
|
||||||
private static final String PATH_RENEW = "sys/renew";
|
private static final String PATH_RENEW = "sys/leases/renew";
|
||||||
private static final String PATH_AUTH = "sys/auth";
|
private static final String PATH_AUTH = "sys/auth";
|
||||||
private static final String PATH_TOKEN = "auth/token";
|
private static final String PATH_TOKEN = "auth/token";
|
||||||
private static final String PATH_LOOKUP = "/lookup";
|
private static final String PATH_LOOKUP = "/lookup";
|
||||||
@ -58,13 +66,18 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
private static final String PATH_AUTH_USERPASS = "auth/userpass/login/";
|
private static final String PATH_AUTH_USERPASS = "auth/userpass/login/";
|
||||||
private static final String PATH_AUTH_APPID = "auth/app-id/";
|
private static final String PATH_AUTH_APPID = "auth/app-id/";
|
||||||
private static final String PATH_AUTH_APPROLE = "auth/approle/";
|
private static final String PATH_AUTH_APPROLE = "auth/approle/";
|
||||||
private static final String PATH_SECRET = "secret";
|
private static final String PATH_AUTH_APPROLE_ROLE = "auth/approle/role/%s%s";
|
||||||
private static final String PATH_REVOKE = "sys/revoke/";
|
private static final String PATH_REVOKE = "sys/leases/revoke/";
|
||||||
|
private static final String PATH_HEALTH = "sys/health";
|
||||||
|
|
||||||
|
private static final String HEADER_VAULT_TOKEN = "X-Vault-Token";
|
||||||
|
|
||||||
private final ObjectMapper jsonMapper;
|
private final ObjectMapper jsonMapper;
|
||||||
|
|
||||||
private final String baseURL; /* Base URL of Vault */
|
private final String baseURL; /* Base URL of Vault */
|
||||||
private final SSLContext sslContext; /* Custom SSLSocketFactory */
|
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 boolean authorized = false; /* authorization status */
|
||||||
private String token; /* current token */
|
private String token; /* current token */
|
||||||
@ -76,7 +89,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
* @param hostname The hostname
|
* @param hostname The hostname
|
||||||
* @param useTLS If TRUE, use HTTPS, otherwise HTTP
|
* @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);
|
this(hostname, useTLS, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +100,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
* @param useTLS If TRUE, use HTTPS, otherwise HTTP
|
* @param useTLS If TRUE, use HTTPS, otherwise HTTP
|
||||||
* @param port The port
|
* @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);
|
this(hostname, useTLS, port, PATH_PREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,11 +112,11 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
* @param port The port
|
* @param port The port
|
||||||
* @param prefix HTTP API prefix (default: /v1/)
|
* @param prefix HTTP API prefix (default: /v1/)
|
||||||
*/
|
*/
|
||||||
public HTTPVaultConnector(String hostname, boolean useTLS, Integer port, String prefix) {
|
public HTTPVaultConnector(final String hostname, final boolean useTLS, final Integer port, final String prefix) {
|
||||||
this(((useTLS) ? "https" : "http") +
|
this(((useTLS) ? "https" : "http")
|
||||||
"://" + hostname +
|
+ "://" + hostname
|
||||||
((port != null) ? ":" + port : "") +
|
+ ((port != null) ? ":" + port : "")
|
||||||
prefix);
|
+ prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,12 +128,39 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
* @param prefix HTTP API prefix (default: /v1/)
|
* @param prefix HTTP API prefix (default: /v1/)
|
||||||
* @param sslContext Custom SSL Context
|
* @param sslContext Custom SSL Context
|
||||||
*/
|
*/
|
||||||
public HTTPVaultConnector(String hostname, boolean useTLS, Integer port, String prefix, SSLContext sslContext) {
|
public HTTPVaultConnector(final String hostname,
|
||||||
this(((useTLS) ? "https" : "http") +
|
final boolean useTLS,
|
||||||
"://" + hostname +
|
final Integer port,
|
||||||
((port != null) ? ":" + port : "") +
|
final String prefix,
|
||||||
prefix,
|
final SSLContext 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,7 +168,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
*
|
*
|
||||||
* @param baseURL The URL
|
* @param baseURL The URL
|
||||||
*/
|
*/
|
||||||
public HTTPVaultConnector(String baseURL) {
|
public HTTPVaultConnector(final String baseURL) {
|
||||||
this(baseURL, null);
|
this(baseURL, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,46 +178,67 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
* @param baseURL The URL
|
* @param baseURL The URL
|
||||||
* @param sslContext Custom SSL Context
|
* @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.baseURL = baseURL;
|
||||||
this.sslContext = sslContext;
|
this.sslContext = sslContext;
|
||||||
|
this.retries = numberOfRetries;
|
||||||
|
this.timeout = timeout;
|
||||||
this.jsonMapper = new ObjectMapper();
|
this.jsonMapper = new ObjectMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resetAuth() {
|
public final void resetAuth() {
|
||||||
token = null;
|
token = null;
|
||||||
tokenTTL = 0;
|
tokenTTL = 0;
|
||||||
authorized = false;
|
authorized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SealResponse sealStatus() {
|
public final SealResponse sealStatus() throws VaultConnectorException {
|
||||||
try {
|
try {
|
||||||
String response = requestGet(PATH_SEAL_STATUS, new HashMap<>());
|
String response = requestGet(PATH_SEAL_STATUS, new HashMap<>());
|
||||||
return jsonMapper.readValue(response, SealResponse.class);
|
return jsonMapper.readValue(response, SealResponse.class);
|
||||||
} catch (VaultConnectorException | IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
return null;
|
|
||||||
} catch (URISyntaxException ignored) {
|
} catch (URISyntaxException ignored) {
|
||||||
/* this should never occur and may leak sensible information */
|
/* this should never occur and may leak sensible information */
|
||||||
return null;
|
throw new InvalidRequestException(Error.URI_FORMAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean seal() {
|
public final void seal() throws VaultConnectorException {
|
||||||
try {
|
requestPut(PATH_SEAL, new HashMap<>());
|
||||||
requestPut(PATH_SEAL, new HashMap<>());
|
|
||||||
return true;
|
|
||||||
} catch (VaultConnectorException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SealResponse unseal(final String key, final Boolean reset) {
|
public final SealResponse unseal(final String key, final Boolean reset) throws VaultConnectorException {
|
||||||
Map<String, String> param = new HashMap<>();
|
Map<String, String> param = new HashMap<>();
|
||||||
param.put("key", key);
|
param.put("key", key);
|
||||||
if (reset != null)
|
if (reset != null)
|
||||||
@ -185,34 +246,52 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
try {
|
try {
|
||||||
String response = requestPut(PATH_UNSEAL, param);
|
String response = requestPut(PATH_UNSEAL, param);
|
||||||
return jsonMapper.readValue(response, SealResponse.class);
|
return jsonMapper.readValue(response, SealResponse.class);
|
||||||
} catch (VaultConnectorException | IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAuthorized() {
|
public HealthResponse getHealth() throws VaultConnectorException {
|
||||||
|
/* Force status code to be 200, so we don't need to modify the request sequence. */
|
||||||
|
Map<String, String> param = new HashMap<>();
|
||||||
|
param.put("standbycode", "200"); // Default: 429.
|
||||||
|
param.put("sealedcode", "200"); // Default: 503.
|
||||||
|
param.put("uninitcode", "200"); // Default: 501.
|
||||||
|
try {
|
||||||
|
String response = requestGet(PATH_HEALTH, param);
|
||||||
|
/* Parse response */
|
||||||
|
return jsonMapper.readValue(response, HealthResponse.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
/* this should never occur and may leak sensible information */
|
||||||
|
throw new InvalidRequestException(Error.URI_FORMAT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean isAuthorized() {
|
||||||
return authorized && (tokenTTL == 0 || tokenTTL >= System.currentTimeMillis());
|
return authorized && (tokenTTL == 0 || tokenTTL >= System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<AuthBackend> getAuthBackends() throws VaultConnectorException {
|
public final List<AuthBackend> getAuthBackends() throws VaultConnectorException {
|
||||||
try {
|
try {
|
||||||
String response = requestGet(PATH_AUTH, new HashMap<>());
|
String response = requestGet(PATH_AUTH, new HashMap<>());
|
||||||
/* Parse response */
|
/* Parse response */
|
||||||
AuthMethodsResponse amr = jsonMapper.readValue(response, AuthMethodsResponse.class);
|
AuthMethodsResponse amr = jsonMapper.readValue(response, AuthMethodsResponse.class);
|
||||||
return amr.getSupportedMethods().values().stream().map(AuthMethod::getType).collect(Collectors.toList());
|
return amr.getSupportedMethods().values().stream().map(AuthMethod::getType).collect(Collectors.toList());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response", e);
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
} catch (URISyntaxException ignored) {
|
} catch (URISyntaxException ignored) {
|
||||||
/* this should never occur and may leak sensible information */
|
/* this should never occur and may leak sensible information */
|
||||||
throw new InvalidRequestException("Invalid URI format.");
|
throw new InvalidRequestException(Error.URI_FORMAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TokenResponse authToken(final String token) throws VaultConnectorException {
|
public final TokenResponse authToken(final String token) throws VaultConnectorException {
|
||||||
/* set token */
|
/* set token */
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.tokenTTL = 0;
|
this.tokenTTL = 0;
|
||||||
@ -222,12 +301,13 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
authorized = true;
|
authorized = true;
|
||||||
return res;
|
return res;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response", e);
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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<>();
|
final Map<String, String> payload = new HashMap<>();
|
||||||
payload.put("password", password);
|
payload.put("password", password);
|
||||||
return queryAuth(PATH_AUTH_USERPASS + username, payload);
|
return queryAuth(PATH_AUTH_USERPASS + username, payload);
|
||||||
@ -235,7 +315,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@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<>();
|
final Map<String, String> payload = new HashMap<>();
|
||||||
payload.put("app_id", appID);
|
payload.put("app_id", appID);
|
||||||
payload.put("user_id", userID);
|
payload.put("user_id", userID);
|
||||||
@ -243,7 +323,7 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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<>();
|
final Map<String, String> payload = new HashMap<>();
|
||||||
payload.put("role_id", roleID);
|
payload.put("role_id", roleID);
|
||||||
if (secretID != null)
|
if (secretID != null)
|
||||||
@ -252,14 +332,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 path The path to request
|
||||||
* @param payload Payload (credentials)
|
* @param payload Payload (credentials)
|
||||||
* @return The AuthResponse
|
* @return The AuthResponse
|
||||||
* @throws VaultConnectorException on errors
|
* @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 {
|
try {
|
||||||
/* Get response */
|
/* Get response */
|
||||||
String response = requestPost(path, payload);
|
String response = requestPost(path, payload);
|
||||||
@ -271,13 +352,14 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
this.authorized = true;
|
this.authorized = true;
|
||||||
return auth;
|
return auth;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response", e);
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@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())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
Map<String, String> payload = new HashMap<>();
|
Map<String, String> payload = new HashMap<>();
|
||||||
@ -286,14 +368,14 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
/* Get response */
|
/* Get response */
|
||||||
String response = requestPost(PATH_AUTH_APPID + "map/app-id/" + appID, payload);
|
String response = requestPost(PATH_AUTH_APPID + "map/app-id/" + appID, payload);
|
||||||
/* Response should be code 204 without content */
|
/* Response should be code 204 without content */
|
||||||
if (!response.equals(""))
|
if (!response.isEmpty())
|
||||||
throw new InvalidResponseException("Received response where non was expected.");
|
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@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())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
Map<String, String> payload = new HashMap<>();
|
Map<String, String> payload = new HashMap<>();
|
||||||
@ -301,135 +383,142 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
/* Get response */
|
/* Get response */
|
||||||
String response = requestPost(PATH_AUTH_APPID + "map/user-id/" + userID, payload);
|
String response = requestPost(PATH_AUTH_APPID + "map/user-id/" + userID, payload);
|
||||||
/* Response should be code 204 without content */
|
/* Response should be code 204 without content */
|
||||||
if (!response.equals(""))
|
if (!response.isEmpty())
|
||||||
throw new InvalidResponseException("Received response where non was expected.");
|
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean createAppRole(final AppRole role) throws VaultConnectorException {
|
public final boolean createAppRole(final AppRole role) throws VaultConnectorException {
|
||||||
if (!isAuthorized())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
/* Get response */
|
/* Get response */
|
||||||
String response = requestPost(PATH_AUTH_APPROLE + "role/" + role.getName(), role);
|
String response = requestPost(String.format(PATH_AUTH_APPROLE_ROLE, role.getName(), ""), role);
|
||||||
/* Response should be code 204 without content */
|
/* Response should be code 204 without content */
|
||||||
if (!response.equals(""))
|
if (!response.isEmpty())
|
||||||
throw new InvalidResponseException("Received response where non was expected.");
|
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
|
||||||
|
|
||||||
/* Set custom ID if provided */
|
/* Set custom ID if provided */
|
||||||
return !(role.getId() != null && !role.getId().isEmpty()) || setAppRoleID(role.getName(), role.getId());
|
return !(role.getId() != null && !role.getId().isEmpty()) || setAppRoleID(role.getName(), role.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AppRoleResponse lookupAppRole(final String roleName) throws VaultConnectorException {
|
public final AppRoleResponse lookupAppRole(final String roleName) throws VaultConnectorException {
|
||||||
if (!isAuthorized())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
/* Request HTTP response and parse Secret */
|
/* Request HTTP response and parse Secret */
|
||||||
try {
|
try {
|
||||||
String response = requestGet(PATH_AUTH_APPROLE + "role/" + roleName, new HashMap<>());
|
String response = requestGet(String.format(PATH_AUTH_APPROLE_ROLE, roleName, ""), new HashMap<>());
|
||||||
return jsonMapper.readValue(response, AppRoleResponse.class);
|
return jsonMapper.readValue(response, AppRoleResponse.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response", e);
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
} catch (URISyntaxException ignored) {
|
} catch (URISyntaxException ignored) {
|
||||||
/* this should never occur and may leak sensible information */
|
/* this should never occur and may leak sensible information */
|
||||||
throw new InvalidRequestException("Invalid URI format.");
|
throw new InvalidRequestException(Error.URI_FORMAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteAppRole(String roleName) throws VaultConnectorException {
|
public final boolean deleteAppRole(final String roleName) throws VaultConnectorException {
|
||||||
if (!isAuthorized())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
|
|
||||||
/* Request HTTP response and expect empty result */
|
/* Request HTTP response and expect empty result */
|
||||||
String response = requestDelete(PATH_AUTH_APPROLE + "role/" + roleName);
|
String response = requestDelete(String.format(PATH_AUTH_APPROLE_ROLE, roleName, ""));
|
||||||
|
|
||||||
/* Response should be code 204 without content */
|
/* Response should be code 204 without content */
|
||||||
if (!response.equals(""))
|
if (!response.isEmpty())
|
||||||
throw new InvalidResponseException("Received response where non was expected.");
|
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getAppRoleID(final String roleName) throws VaultConnectorException {
|
public final String getAppRoleID(final String roleName) throws VaultConnectorException {
|
||||||
if (!isAuthorized())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
/* Request HTTP response and parse Secret */
|
/* Request HTTP response and parse Secret */
|
||||||
try {
|
try {
|
||||||
String response = requestGet(PATH_AUTH_APPROLE + "role/" + roleName + "/role-id", new HashMap<>());
|
String response = requestGet(String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/role-id"), new HashMap<>());
|
||||||
return jsonMapper.readValue(response, RawDataResponse.class).getData().get("role_id").toString();
|
return jsonMapper.readValue(response, RawDataResponse.class).getData().get("role_id").toString();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response", e);
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
} catch (URISyntaxException ignored) {
|
} catch (URISyntaxException ignored) {
|
||||||
/* this should never occur and may leak sensible information */
|
/* this should never occur and may leak sensible information */
|
||||||
throw new InvalidRequestException("Invalid URI format.");
|
throw new InvalidRequestException(Error.URI_FORMAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
/* Request HTTP response and parse Secret */
|
/* Request HTTP response and parse Secret */
|
||||||
Map<String, String> payload = new HashMap<>();
|
Map<String, String> payload = new HashMap<>();
|
||||||
payload.put("role_id", roleID);
|
payload.put("role_id", roleID);
|
||||||
String response = requestPost(PATH_AUTH_APPROLE + "role/" + roleName + "/role-id", payload);
|
String response = requestPost(String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/role-id"), payload);
|
||||||
/* Response should be code 204 without content */
|
/* Response should be code 204 without content */
|
||||||
if (!response.equals(""))
|
if (!response.isEmpty())
|
||||||
throw new InvalidResponseException("Received response where non was expected.");
|
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
/* Get response */
|
/* Get response */
|
||||||
String response;
|
String response;
|
||||||
if (secret.getId() != null && !secret.getId().isEmpty())
|
if (secret.getId() != null && !secret.getId().isEmpty())
|
||||||
response = requestPost(PATH_AUTH_APPROLE + "role/" + roleName + "/custom-secret-id", secret);
|
response = requestPost(String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/custom-secret-id"), secret);
|
||||||
else
|
else
|
||||||
response = requestPost(PATH_AUTH_APPROLE + "role/" + roleName + "/secret-id", secret);
|
response = requestPost(String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id"), secret);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/* Extract the secret ID from response */
|
/* Extract the secret ID from response */
|
||||||
return jsonMapper.readValue(response, AppRoleSecretResponse.class);
|
return jsonMapper.readValue(response, AppRoleSecretResponse.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response.");
|
throw new InvalidResponseException(Error.PARSE_RESPONSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
/* Request HTTP response and parse Secret */
|
/* Request HTTP response and parse Secret */
|
||||||
try {
|
try {
|
||||||
String response = requestPost(PATH_AUTH_APPROLE + "role/" + roleName + "/secret-id/lookup", new AppRoleSecret(secretID));
|
String response = requestPost(
|
||||||
|
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id/lookup"),
|
||||||
|
new AppRoleSecret(secretID));
|
||||||
return jsonMapper.readValue(response, AppRoleSecretResponse.class);
|
return jsonMapper.readValue(response, AppRoleSecretResponse.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response", e);
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
|
|
||||||
/* Request HTTP response and expect empty result */
|
/* Request HTTP response and expect empty result */
|
||||||
String response = requestPost(PATH_AUTH_APPROLE + "role/" + roleName + "/secret-id/destroy", new AppRoleSecret(secretID));
|
String response = requestPost(
|
||||||
|
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id/destroy"),
|
||||||
|
new AppRoleSecret(secretID));
|
||||||
|
|
||||||
/* Response should be code 204 without content */
|
/* Response should be code 204 without content */
|
||||||
if (!response.equals(""))
|
if (!response.isEmpty())
|
||||||
throw new InvalidResponseException("Received response where non was expected.");
|
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> listAppRoles() throws VaultConnectorException {
|
public final List<String> listAppRoles() throws VaultConnectorException {
|
||||||
if (!isAuthorized())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
|
|
||||||
@ -438,92 +527,92 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
SecretListResponse secrets = jsonMapper.readValue(response, SecretListResponse.class);
|
SecretListResponse secrets = jsonMapper.readValue(response, SecretListResponse.class);
|
||||||
return secrets.getKeys();
|
return secrets.getKeys();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response", e);
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
} catch (URISyntaxException ignored) {
|
} catch (URISyntaxException ignored) {
|
||||||
/* this should never occur and may leak sensible information */
|
/* this should never occur and may leak sensible information */
|
||||||
throw new InvalidRequestException("Invalid URI format.");
|
throw new InvalidRequestException(Error.URI_FORMAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> listAppRoleSecretss(final String roleName) throws VaultConnectorException {
|
public final List<String> listAppRoleSecrets(final String roleName) throws VaultConnectorException {
|
||||||
if (!isAuthorized())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String response = requestGet(PATH_AUTH_APPROLE + "role/" + roleName + "/secret-id?list=true", new HashMap<>());
|
String response = requestGet(
|
||||||
|
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id?list=true"),
|
||||||
|
new HashMap<>());
|
||||||
SecretListResponse secrets = jsonMapper.readValue(response, SecretListResponse.class);
|
SecretListResponse secrets = jsonMapper.readValue(response, SecretListResponse.class);
|
||||||
return secrets.getKeys();
|
return secrets.getKeys();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response", e);
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
} catch (URISyntaxException ignored) {
|
} catch (URISyntaxException ignored) {
|
||||||
/* this should never occur and may leak sensible information */
|
/* this should never occur and may leak sensible information */
|
||||||
throw new InvalidRequestException("Invalid URI format.");
|
throw new InvalidRequestException(Error.URI_FORMAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecretResponse readSecret(final String key) throws VaultConnectorException {
|
public final SecretResponse read(final String key) throws VaultConnectorException {
|
||||||
if (!isAuthorized())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
/* Request HTTP response and parse Secret */
|
/* Request HTTP response and parse Secret */
|
||||||
try {
|
try {
|
||||||
String response = requestGet(PATH_SECRET + "/" + key, new HashMap<>());
|
String response = requestGet(key, new HashMap<>());
|
||||||
return jsonMapper.readValue(response, SecretResponse.class);
|
return jsonMapper.readValue(response, SecretResponse.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response", e);
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
} catch (URISyntaxException ignored) {
|
} catch (URISyntaxException ignored) {
|
||||||
/* this should never occur and may leak sensible information */
|
/* this should never occur and may leak sensible information */
|
||||||
throw new InvalidRequestException("Invalid URI format.");
|
throw new InvalidRequestException(Error.URI_FORMAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> listSecrets(final String path) throws VaultConnectorException {
|
public final List<String> list(final String path) throws VaultConnectorException {
|
||||||
if (!isAuthorized())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String response = requestGet(PATH_SECRET + "/" + path + "/?list=true", new HashMap<>());
|
String response = requestGet(path + "/?list=true", new HashMap<>());
|
||||||
SecretListResponse secrets = jsonMapper.readValue(response, SecretListResponse.class);
|
SecretListResponse secrets = jsonMapper.readValue(response, SecretListResponse.class);
|
||||||
return secrets.getKeys();
|
return secrets.getKeys();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response", e);
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
} catch (URISyntaxException ignored) {
|
} catch (URISyntaxException ignored) {
|
||||||
/* this should never occur and may leak sensible information */
|
/* this should never occur and may leak sensible information */
|
||||||
throw new InvalidRequestException("Invalid URI format.");
|
throw new InvalidRequestException(Error.URI_FORMAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeSecret(final String key, final String value) throws VaultConnectorException {
|
public final void write(final String key, final Map<String, Object> data) throws VaultConnectorException {
|
||||||
if (!isAuthorized())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
|
|
||||||
if (key == null || key.isEmpty())
|
if (key == null || key.isEmpty())
|
||||||
throw new InvalidRequestException("Secret path must not be empty.");
|
throw new InvalidRequestException("Secret path must not be empty.");
|
||||||
|
|
||||||
Map<String, String> param = new HashMap<>();
|
if (!requestPost(key, data).isEmpty())
|
||||||
param.put("value", value);
|
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
|
||||||
if (!requestPost(PATH_SECRET + "/" + key, param).equals(""))
|
|
||||||
throw new InvalidResponseException("Received response where none was expected.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteSecret(String key) throws VaultConnectorException {
|
public final void delete(final String key) throws VaultConnectorException {
|
||||||
if (!isAuthorized())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
|
|
||||||
/* Request HTTP response and expect empty result */
|
/* Request HTTP response and expect empty result */
|
||||||
String response = requestDelete(PATH_SECRET + "/" + key);
|
String response = requestDelete(key);
|
||||||
|
|
||||||
/* Response should be code 204 without content */
|
/* Response should be code 204 without content */
|
||||||
if (!response.equals(""))
|
if (!response.isEmpty())
|
||||||
throw new InvalidResponseException("Received response where none was expected.");
|
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void revoke(String leaseID) throws VaultConnectorException {
|
public final void revoke(final String leaseID) throws VaultConnectorException {
|
||||||
if (!isAuthorized())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
|
|
||||||
@ -531,12 +620,12 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
String response = requestPut(PATH_REVOKE + leaseID, new HashMap<>());
|
String response = requestPut(PATH_REVOKE + leaseID, new HashMap<>());
|
||||||
|
|
||||||
/* Response should be code 204 without content */
|
/* Response should be code 204 without content */
|
||||||
if (!response.equals(""))
|
if (!response.isEmpty())
|
||||||
throw new InvalidResponseException("Received response where none was expected.");
|
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecretResponse renew(String leaseID, Integer increment) throws VaultConnectorException {
|
public final SecretResponse renew(final String leaseID, final Integer increment) throws VaultConnectorException {
|
||||||
if (!isAuthorized())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
|
|
||||||
@ -550,27 +639,34 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
String response = requestPut(PATH_RENEW, payload);
|
String response = requestPut(PATH_RENEW, payload);
|
||||||
return jsonMapper.readValue(response, SecretResponse.class);
|
return jsonMapper.readValue(response, SecretResponse.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response", e);
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
return createTokenInternal(token, PATH_TOKEN + PATH_CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
return createTokenInternal(token, PATH_TOKEN + PATH_CREATE_ORPHAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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())
|
if (role == null || role.isEmpty())
|
||||||
throw new InvalidRequestException("No role name specified.");
|
throw new InvalidRequestException("No role name specified.");
|
||||||
return createTokenInternal(token, PATH_TOKEN + PATH_CREATE + "/" + role);
|
return createTokenInternal(token, PATH_TOKEN + PATH_CREATE + "/" + role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void close() {
|
||||||
|
authorized = false;
|
||||||
|
token = null;
|
||||||
|
tokenTTL = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create token.
|
* Create token.
|
||||||
* Centralized method to handle different token creation requests.
|
* Centralized method to handle different token creation requests.
|
||||||
@ -591,12 +687,12 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
try {
|
try {
|
||||||
return jsonMapper.readValue(response, AuthResponse.class);
|
return jsonMapper.readValue(response, AuthResponse.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response", e);
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TokenResponse lookupToken(final String token) throws VaultConnectorException {
|
public final TokenResponse lookupToken(final String token) throws VaultConnectorException {
|
||||||
if (!isAuthorized())
|
if (!isAuthorized())
|
||||||
throw new AuthorizationRequiredException();
|
throw new AuthorizationRequiredException();
|
||||||
/* Request HTTP response and parse Secret */
|
/* Request HTTP response and parse Secret */
|
||||||
@ -604,10 +700,10 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
String response = requestGet(PATH_TOKEN + "/lookup/" + token, new HashMap<>());
|
String response = requestGet(PATH_TOKEN + "/lookup/" + token, new HashMap<>());
|
||||||
return jsonMapper.readValue(response, TokenResponse.class);
|
return jsonMapper.readValue(response, TokenResponse.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response", e);
|
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||||
} catch (URISyntaxException ignored) {
|
} catch (URISyntaxException ignored) {
|
||||||
/* this should never occur and may leak sensible information */
|
/* this should never occur and may leak sensible information */
|
||||||
throw new InvalidRequestException("Invalid URI format.");
|
throw new InvalidRequestException(Error.URI_FORMAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -629,16 +725,16 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
try {
|
try {
|
||||||
input = new StringEntity(jsonMapper.writeValueAsString(payload), StandardCharsets.UTF_8);
|
input = new StringEntity(jsonMapper.writeValueAsString(payload), StandardCharsets.UTF_8);
|
||||||
} catch (JsonProcessingException e) {
|
} catch (JsonProcessingException e) {
|
||||||
throw new InvalidRequestException("Unable to parse response", e);
|
throw new InvalidRequestException(Error.PARSE_RESPONSE, e);
|
||||||
}
|
}
|
||||||
input.setContentEncoding("UTF-8");
|
input.setContentEncoding("UTF-8");
|
||||||
input.setContentType("application/json");
|
input.setContentType("application/json");
|
||||||
post.setEntity(input);
|
post.setEntity(input);
|
||||||
/* Set X-Vault-Token header */
|
/* Set X-Vault-Token header */
|
||||||
if (token != null)
|
if (token != null)
|
||||||
post.addHeader("X-Vault-Token", token);
|
post.addHeader(HEADER_VAULT_TOKEN, token);
|
||||||
|
|
||||||
return request(post);
|
return request(post, retries);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -657,15 +753,15 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
try {
|
try {
|
||||||
entity = new StringEntity(jsonMapper.writeValueAsString(payload));
|
entity = new StringEntity(jsonMapper.writeValueAsString(payload));
|
||||||
} catch (UnsupportedEncodingException | JsonProcessingException e) {
|
} catch (UnsupportedEncodingException | JsonProcessingException e) {
|
||||||
e.printStackTrace();
|
throw new InvalidRequestException("Payload serialization failed", e);
|
||||||
}
|
}
|
||||||
/* Parse parameters */
|
/* Parse parameters */
|
||||||
put.setEntity(entity);
|
put.setEntity(entity);
|
||||||
/* Set X-Vault-Token header */
|
/* Set X-Vault-Token header */
|
||||||
if (token != null)
|
if (token != null)
|
||||||
put.addHeader("X-Vault-Token", token);
|
put.addHeader(HEADER_VAULT_TOKEN, token);
|
||||||
|
|
||||||
return request(put);
|
return request(put, retries);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -680,9 +776,9 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
HttpDelete delete = new HttpDelete(baseURL + path);
|
HttpDelete delete = new HttpDelete(baseURL + path);
|
||||||
/* Set X-Vault-Token header */
|
/* Set X-Vault-Token header */
|
||||||
if (token != null)
|
if (token != null)
|
||||||
delete.addHeader("X-Vault-Token", token);
|
delete.addHeader(HEADER_VAULT_TOKEN, token);
|
||||||
|
|
||||||
return request(delete);
|
return request(delete, retries);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -692,8 +788,10 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
* @param payload Map of payload values (will be converted to JSON)
|
* @param payload Map of payload values (will be converted to JSON)
|
||||||
* @return HTTP response
|
* @return HTTP response
|
||||||
* @throws VaultConnectorException on connection error
|
* @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 */
|
/* Add parameters to URI */
|
||||||
URIBuilder uriBuilder = new URIBuilder(baseURL + path);
|
URIBuilder uriBuilder = new URIBuilder(baseURL + path);
|
||||||
payload.forEach(uriBuilder::addParameter);
|
payload.forEach(uriBuilder::addParameter);
|
||||||
@ -703,24 +801,29 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
|
|
||||||
/* Set X-Vault-Token header */
|
/* Set X-Vault-Token header */
|
||||||
if (token != null)
|
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.
|
* Execute prepared HTTP request and return result.
|
||||||
*
|
*
|
||||||
* @param base Prepares Request
|
* @param base Prepares Request
|
||||||
|
* @param retries number of retries
|
||||||
* @return HTTP response
|
* @return HTTP response
|
||||||
* @throws VaultConnectorException on connection error
|
* @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 */
|
/* Set JSON Header */
|
||||||
base.addHeader("accept", "application/json");
|
base.addHeader("accept", "application/json");
|
||||||
|
|
||||||
HttpResponse response = null;
|
HttpResponse response = null;
|
||||||
try (CloseableHttpClient httpClient = HttpClientBuilder.create().setSSLContext(sslContext).build()) {
|
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);
|
response = httpClient.execute(base);
|
||||||
/* Check if response is valid */
|
/* Check if response is valid */
|
||||||
if (response == null)
|
if (response == null)
|
||||||
@ -728,38 +831,90 @@ public class HTTPVaultConnector implements VaultConnector {
|
|||||||
|
|
||||||
switch (response.getStatusLine().getStatusCode()) {
|
switch (response.getStatusLine().getStatusCode()) {
|
||||||
case 200:
|
case 200:
|
||||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) {
|
return handleResult(response);
|
||||||
return br.lines().collect(Collectors.joining("\n"));
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
case 204:
|
case 204:
|
||||||
return "";
|
return "";
|
||||||
case 403:
|
case 403:
|
||||||
throw new PermissionDeniedException();
|
throw new PermissionDeniedException();
|
||||||
default:
|
default:
|
||||||
InvalidResponseException ex = new InvalidResponseException("Invalid response code")
|
if (response.getStatusLine().getStatusCode() >= 500
|
||||||
.withStatusCode(response.getStatusLine().getStatusCode());
|
&& response.getStatusLine().getStatusCode() < 600 && retries > 0) {
|
||||||
if (response.getEntity() != null) {
|
/* Retry on 5xx errors */
|
||||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) {
|
return request(base, retries - 1);
|
||||||
String responseString = br.lines().collect(Collectors.joining("\n"));
|
} else {
|
||||||
ErrorResponse er = jsonMapper.readValue(responseString, ErrorResponse.class);
|
/* Fail on different error code and/or no retries left */
|
||||||
/* Check for "permission denied" response */
|
handleError(response);
|
||||||
if (er.getErrors().size() > 0 && er.getErrors().get(0).equals("permission denied"))
|
|
||||||
throw new PermissionDeniedException();
|
/* Throw exception withoud details, if response entity is empty. */
|
||||||
throw ex.withResponse(er.toString());
|
throw new InvalidResponseException(Error.RESPONSE_CODE,
|
||||||
} catch (IOException ignored) {
|
response.getStatusLine().getStatusCode());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throw ex;
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to read response", e);
|
throw new InvalidResponseException(Error.READ_RESPONSE, e);
|
||||||
} finally {
|
} finally {
|
||||||
if (response != null && response.getEntity() != null)
|
if (response != null && response.getEntity() != null)
|
||||||
try {
|
try {
|
||||||
EntityUtils.consume(response.getEntity());
|
EntityUtils.consume(response.getEntity());
|
||||||
} catch (IOException ignored) {
|
} catch (IOException ignored) {
|
||||||
|
// Exception ignored.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle successful result.
|
||||||
|
*
|
||||||
|
* @param response The raw HTTP response (assuming status code 200)
|
||||||
|
* @return Complete response body as String
|
||||||
|
* @throws InvalidResponseException on reading errors
|
||||||
|
*/
|
||||||
|
private String handleResult(final HttpResponse response) throws InvalidResponseException {
|
||||||
|
try (BufferedReader br = new BufferedReader(
|
||||||
|
new InputStreamReader(response.getEntity().getContent()))) {
|
||||||
|
return br.lines().collect(Collectors.joining("\n"));
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
throw new InvalidResponseException(Error.READ_RESPONSE, 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle unsuccessful response. Throw detailed exception if possible.
|
||||||
|
*
|
||||||
|
* @param response The raw HTTP response (assuming status code 5xx)
|
||||||
|
* @throws VaultConnectorException Expected exception with details to throw
|
||||||
|
*/
|
||||||
|
private void handleError(final HttpResponse response) throws VaultConnectorException {
|
||||||
|
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(Error.RESPONSE_CODE,
|
||||||
|
response.getStatusLine().getStatusCode(), er.toString());
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
// Exception ignored.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inner class to bundle common error messages.
|
||||||
|
*/
|
||||||
|
private static final class Error {
|
||||||
|
private static final String READ_RESPONSE = "Unable to read response";
|
||||||
|
private static final String PARSE_RESPONSE = "Unable to parse response";
|
||||||
|
private static final String UNEXPECTED_RESPONSE = "Received response where none was expected";
|
||||||
|
private static final String URI_FORMAT = "Invalid URI format";
|
||||||
|
private static final String RESPONSE_CODE = "Invalid response code";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor hidden, this class should not be instantiated.
|
||||||
|
*/
|
||||||
|
private Error() {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -16,13 +16,15 @@
|
|||||||
|
|
||||||
package de.stklcode.jvault.connector;
|
package de.stklcode.jvault.connector;
|
||||||
|
|
||||||
import de.stklcode.jvault.connector.exception.AuthorizationRequiredException;
|
import de.stklcode.jvault.connector.exception.InvalidRequestException;
|
||||||
import de.stklcode.jvault.connector.exception.VaultConnectorException;
|
import de.stklcode.jvault.connector.exception.VaultConnectorException;
|
||||||
import de.stklcode.jvault.connector.model.*;
|
import de.stklcode.jvault.connector.model.*;
|
||||||
import de.stklcode.jvault.connector.model.response.*;
|
import de.stklcode.jvault.connector.model.response.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vault Connector interface.
|
* Vault Connector interface.
|
||||||
@ -31,7 +33,12 @@ import java.util.List;
|
|||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
public interface VaultConnector {
|
public interface VaultConnector extends AutoCloseable {
|
||||||
|
/**
|
||||||
|
* Default sub-path for Vault secrets.
|
||||||
|
*/
|
||||||
|
String PATH_SECRET = "secret";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset authorization information.
|
* Reset authorization information.
|
||||||
*/
|
*/
|
||||||
@ -41,35 +48,47 @@ public interface VaultConnector {
|
|||||||
* Retrieve status of vault seal.
|
* Retrieve status of vault seal.
|
||||||
*
|
*
|
||||||
* @return Seal status
|
* @return Seal status
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
*/
|
*/
|
||||||
SealResponse sealStatus();
|
SealResponse sealStatus() throws VaultConnectorException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Seal vault.
|
* Seal vault.
|
||||||
*
|
*
|
||||||
* @return TRUE on success
|
* @throws VaultConnectorException on error
|
||||||
*/
|
*/
|
||||||
boolean seal();
|
void seal() throws VaultConnectorException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unseal vault.
|
* Unseal vault.
|
||||||
*
|
*
|
||||||
* @param key A single master share key
|
* @param key A single master share key
|
||||||
* @param reset Discard previously provided keys (optional)
|
* @param reset Discard previously provided keys (optional)
|
||||||
* @return TRUE on success
|
* @return Response with seal status
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
*/
|
*/
|
||||||
SealResponse unseal(final String key, final Boolean reset);
|
SealResponse unseal(final String key, final Boolean reset) throws VaultConnectorException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unseal vault.
|
* Unseal vault.
|
||||||
*
|
*
|
||||||
* @param key A single master share key
|
* @param key A single master share key
|
||||||
* @return TRUE on success
|
* @return Response with seal status
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
*/
|
*/
|
||||||
default SealResponse unseal(final String key) {
|
default SealResponse unseal(final String key) throws VaultConnectorException {
|
||||||
return unseal(key, null);
|
return unseal(key, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query server health information.
|
||||||
|
*
|
||||||
|
* @return Health information.
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
|
* @since 0.7.0
|
||||||
|
*/
|
||||||
|
HealthResponse getHealth() throws VaultConnectorException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all availale authentication backends.
|
* Get all availale authentication backends.
|
||||||
*
|
*
|
||||||
@ -102,7 +121,7 @@ public interface VaultConnector {
|
|||||||
*
|
*
|
||||||
* @param appID The App ID
|
* @param appID The App ID
|
||||||
* @param userID The User ID
|
* @param userID The User ID
|
||||||
* @return TRUE on success
|
* @return The {@link AuthResponse}
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. Consider using {@link #authAppRole} instead.
|
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. Consider using {@link #authAppRole} instead.
|
||||||
*/
|
*/
|
||||||
@ -113,7 +132,7 @@ public interface VaultConnector {
|
|||||||
* Authorize to Vault using AppRole method without secret ID.
|
* Authorize to Vault using AppRole method without secret ID.
|
||||||
*
|
*
|
||||||
* @param roleID The role ID
|
* @param roleID The role ID
|
||||||
* @return TRUE on success
|
* @return The {@link AuthResponse}
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
@ -126,7 +145,7 @@ public interface VaultConnector {
|
|||||||
*
|
*
|
||||||
* @param roleID The role ID
|
* @param roleID The role ID
|
||||||
* @param secretID The secret ID
|
* @param secretID The secret ID
|
||||||
* @return TRUE on success
|
* @return The {@link AuthResponse}
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
@ -138,18 +157,19 @@ public interface VaultConnector {
|
|||||||
* @param appID The unique App-ID
|
* @param appID The unique App-ID
|
||||||
* @param policy The policy to associate with
|
* @param policy The policy to associate with
|
||||||
* @param displayName Arbitrary name to display
|
* @param displayName Arbitrary name to display
|
||||||
* @return TRUE on success
|
* @return {@code true} on success
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. Consider using {@link #createAppRole} instead.
|
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. Consider using {@link #createAppRole} instead.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@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.
|
* Register a new AppRole role from given metamodel.
|
||||||
*
|
*
|
||||||
* @param role The role
|
* @param role The role
|
||||||
* @return TRUE on success
|
* @return {@code true} on success
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
@ -159,7 +179,7 @@ public interface VaultConnector {
|
|||||||
* Register new AppRole role with default policy.
|
* Register new AppRole role with default policy.
|
||||||
*
|
*
|
||||||
* @param roleName The role name
|
* @param roleName The role name
|
||||||
* @return TRUE on success
|
* @return {@code true} on success
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
@ -172,7 +192,7 @@ public interface VaultConnector {
|
|||||||
*
|
*
|
||||||
* @param roleName The role name
|
* @param roleName The role name
|
||||||
* @param policies The policies to associate with
|
* @param policies The policies to associate with
|
||||||
* @return TRUE on success
|
* @return {@code true} on success
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
@ -185,7 +205,7 @@ public interface VaultConnector {
|
|||||||
*
|
*
|
||||||
* @param roleName The role name
|
* @param roleName The role name
|
||||||
* @param roleID A custom role ID
|
* @param roleID A custom role ID
|
||||||
* @return TRUE on success
|
* @return {@code true} on success
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
@ -199,11 +219,12 @@ public interface VaultConnector {
|
|||||||
* @param roleName The role name
|
* @param roleName The role name
|
||||||
* @param policies The policies to associate with
|
* @param policies The policies to associate with
|
||||||
* @param roleID A custom role ID
|
* @param roleID A custom role ID
|
||||||
* @return TRUE on success
|
* @return {@code true} on success
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @since 0.4.0
|
* @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());
|
return createAppRole(new AppRoleBuilder(roleName).withPolicies(policies).withId(roleID).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +232,7 @@ public interface VaultConnector {
|
|||||||
* Delete AppRole role from Vault.
|
* Delete AppRole role from Vault.
|
||||||
*
|
*
|
||||||
* @param roleName The role anme
|
* @param roleName The role anme
|
||||||
* @return TRUE on succevss
|
* @return {@code true} on succevss
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
*/
|
*/
|
||||||
boolean deleteAppRole(final String roleName) throws VaultConnectorException;
|
boolean deleteAppRole(final String roleName) throws VaultConnectorException;
|
||||||
@ -241,7 +262,7 @@ public interface VaultConnector {
|
|||||||
*
|
*
|
||||||
* @param roleName The role name
|
* @param roleName The role name
|
||||||
* @param roleID The role ID
|
* @param roleID The role ID
|
||||||
* @return TRUE on success
|
* @return {@code true} on success
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
@ -268,7 +289,8 @@ public interface VaultConnector {
|
|||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @since 0.4.0
|
* @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));
|
return createAppRoleSecret(roleName, new AppRoleSecret(secretID));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +303,8 @@ public interface VaultConnector {
|
|||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @since 0.4.0
|
* @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.
|
* Lookup an AppRole secret.
|
||||||
@ -292,7 +315,8 @@ public interface VaultConnector {
|
|||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @since 0.4.0
|
* @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.
|
* Destroy an AppRole secret.
|
||||||
@ -320,16 +344,17 @@ public interface VaultConnector {
|
|||||||
* @return List of roles
|
* @return List of roles
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
*/
|
*/
|
||||||
List<String> listAppRoleSecretss(final String roleName) throws VaultConnectorException;
|
List<String> listAppRoleSecrets(final String roleName) throws VaultConnectorException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register User-ID with App-ID
|
* Register User-ID with App-ID.
|
||||||
*
|
*
|
||||||
* @param appID The App-ID
|
* @param appID The App-ID
|
||||||
* @param userID The User-ID
|
* @param userID The User-ID
|
||||||
* @return TRUE on success
|
* @return {@code true} on success
|
||||||
* @throws VaultConnectorException on error
|
* @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
|
@Deprecated
|
||||||
boolean registerUserId(final String appID, final String userID) throws VaultConnectorException;
|
boolean registerUserId(final String appID, final String userID) throws VaultConnectorException;
|
||||||
@ -341,56 +366,142 @@ public interface VaultConnector {
|
|||||||
* @param policy The policy to associate with
|
* @param policy The policy to associate with
|
||||||
* @param displayName Arbitrary name to display
|
* @param displayName Arbitrary name to display
|
||||||
* @param userID The User-ID
|
* @param userID The User-ID
|
||||||
* @return TRUE on success
|
* @return {@code true} on success
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole.
|
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@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);
|
return registerAppId(appID, policy, userID) && registerUserId(appID, userID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get authorization status
|
* Get authorization status.
|
||||||
*
|
*
|
||||||
* @return TRUE, if successfully authorized
|
* @return TRUE, if successfully authorized
|
||||||
*/
|
*/
|
||||||
boolean isAuthorized();
|
boolean isAuthorized();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve secret form Vault.
|
* Retrieve any nodes content from Vault.
|
||||||
|
*
|
||||||
|
* @param key Secret identifier
|
||||||
|
* @return Secret response
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
SecretResponse read(final String key) throws VaultConnectorException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve secret from Vault.
|
||||||
|
* Prefix "secret/" is automatically added to key.
|
||||||
*
|
*
|
||||||
* @param key Secret identifier
|
* @param key Secret identifier
|
||||||
* @return Secret response
|
* @return Secret response
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
*/
|
*/
|
||||||
SecretResponse readSecret(final String key) throws VaultConnectorException;
|
default SecretResponse readSecret(final String key) throws VaultConnectorException {
|
||||||
|
return read(PATH_SECRET + "/" + key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List available nodes from Vault.
|
||||||
|
*
|
||||||
|
* @param path Root path to search
|
||||||
|
* @return List of secret keys
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
List<String> list(final String path) throws VaultConnectorException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List available secrets from Vault.
|
* List available secrets from Vault.
|
||||||
|
* Prefix "secret/" is automatically added to path.
|
||||||
*
|
*
|
||||||
* @param path Root path to search
|
* @param path Root path to search
|
||||||
* @return List of secret keys
|
* @return List of secret keys
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
*/
|
*/
|
||||||
List<String> listSecrets(final String path) throws VaultConnectorException;
|
default List<String> listSecrets(final String path) throws VaultConnectorException {
|
||||||
|
return list(PATH_SECRET + "/" + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write simple value to Vault.
|
||||||
|
*
|
||||||
|
* @param key Secret path
|
||||||
|
* @param value Secret value
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
default void write(final String key, final String value) throws VaultConnectorException {
|
||||||
|
Map<String, Object> param = new HashMap<>();
|
||||||
|
param.put("value", value);
|
||||||
|
write(key, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write value to Vault.
|
||||||
|
*
|
||||||
|
* @param key Secret path
|
||||||
|
* @param data Secret content. Value must be be JSON serializable.
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
void write(final String key, final Map<String, Object> data) throws VaultConnectorException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write secret to Vault.
|
* Write secret to Vault.
|
||||||
|
* Prefix "secret/" is automatically added to path.
|
||||||
*
|
*
|
||||||
* @param key Secret path
|
* @param key Secret path
|
||||||
* @param value Secret value
|
* @param value Secret value
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
*/
|
*/
|
||||||
void writeSecret(final String key, final String value) throws VaultConnectorException;
|
default void writeSecret(final String key, final String value) throws VaultConnectorException {
|
||||||
|
Map<String, Object> param = new HashMap<>();
|
||||||
|
param.put("value", value);
|
||||||
|
writeSecret(key, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write secret to Vault.
|
||||||
|
* Prefix "secret/" is automatically added to path.
|
||||||
|
*
|
||||||
|
* @param key Secret path
|
||||||
|
* @param data Secret content. Value must be be JSON serializable.
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
default void writeSecret(final String key, final Map<String, Object> data) throws VaultConnectorException {
|
||||||
|
if (key == null || key.isEmpty()) {
|
||||||
|
throw new InvalidRequestException("Secret path must not be empty.");
|
||||||
|
}
|
||||||
|
write(PATH_SECRET + "/" + key, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete key from Vault.
|
||||||
|
*
|
||||||
|
* @param key Secret path
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
void delete(final String key) throws VaultConnectorException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete secret from Vault.
|
* Delete secret from Vault.
|
||||||
|
* Prefix "secret/" is automatically added to path.
|
||||||
*
|
*
|
||||||
* @param key Secret path
|
* @param key Secret path
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
*/
|
*/
|
||||||
void deleteSecret(final String key) throws VaultConnectorException;
|
default void deleteSecret(final String key) throws VaultConnectorException {
|
||||||
|
delete(PATH_SECRET + "/" + key);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Revoke given lease immediately.
|
* Revoke given lease immediately.
|
||||||
@ -403,7 +514,7 @@ public interface VaultConnector {
|
|||||||
/**
|
/**
|
||||||
* Renew lease with given ID.
|
* Renew lease with given ID.
|
||||||
*
|
*
|
||||||
* @param leaseID the lase ID
|
* @param leaseID the lase ID
|
||||||
* @return Renewed lease
|
* @return Renewed lease
|
||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
*/
|
*/
|
||||||
@ -458,4 +569,66 @@ public interface VaultConnector {
|
|||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
*/
|
*/
|
||||||
TokenResponse lookupToken(final String token) throws VaultConnectorException;
|
TokenResponse lookupToken(final String token) throws VaultConnectorException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read credentials for MySQL backend at default mount point.
|
||||||
|
*
|
||||||
|
* @param role the role name
|
||||||
|
* @return the credentials response
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
default CredentialsResponse readMySqlCredentials(final String role) throws VaultConnectorException {
|
||||||
|
return readDbCredentials(role, "mysql");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read credentials for PostgreSQL backend at default mount point.
|
||||||
|
*
|
||||||
|
* @param role the role name
|
||||||
|
* @return the credentials response
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
default CredentialsResponse readPostgreSqlCredentials(final String role) throws VaultConnectorException {
|
||||||
|
return readDbCredentials(role, "postgresql");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read credentials for MSSQL backend at default mount point.
|
||||||
|
*
|
||||||
|
* @param role the role name
|
||||||
|
* @return the credentials response
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
default CredentialsResponse readMsSqlCredentials(final String role) throws VaultConnectorException {
|
||||||
|
return readDbCredentials(role, "mssql");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read credentials for MSSQL backend at default mount point.
|
||||||
|
*
|
||||||
|
* @param role the role name
|
||||||
|
* @return the credentials response
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
default CredentialsResponse readMongoDbCredentials(final String role) throws VaultConnectorException {
|
||||||
|
return readDbCredentials(role, "mongodb");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read credentials for SQL backends.
|
||||||
|
*
|
||||||
|
* @param role the role name
|
||||||
|
* @param mount mount point of the SQL backend
|
||||||
|
* @return the credentials response
|
||||||
|
* @throws VaultConnectorException on error
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
default CredentialsResponse readDbCredentials(final String role, final String mount)
|
||||||
|
throws VaultConnectorException {
|
||||||
|
return (CredentialsResponse) read(mount + "/creds/" + role);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -19,22 +19,41 @@ package de.stklcode.jvault.connector.exception;
|
|||||||
/**
|
/**
|
||||||
* Exception thrown on problems with connection to Vault backend.
|
* Exception thrown on problems with connection to Vault backend.
|
||||||
*
|
*
|
||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
public class ConnectionException extends VaultConnectorException {
|
public class ConnectionException extends VaultConnectorException {
|
||||||
|
/**
|
||||||
|
* Constructs a new empty exception.
|
||||||
|
*/
|
||||||
public ConnectionException() {
|
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);
|
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);
|
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);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -23,18 +23,37 @@ package de.stklcode.jvault.connector.exception;
|
|||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
public class InvalidRequestException extends VaultConnectorException {
|
public class InvalidRequestException extends VaultConnectorException {
|
||||||
|
/**
|
||||||
|
* Constructs a new empty exception.
|
||||||
|
*/
|
||||||
public InvalidRequestException() {
|
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);
|
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);
|
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);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -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
|
* Exception thrown when response from vault returned with erroneous status code or payload could not be parsed
|
||||||
* to entity class.
|
* to entity class.
|
||||||
*
|
*
|
||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
public class InvalidResponseException extends VaultConnectorException {
|
public final class InvalidResponseException extends VaultConnectorException {
|
||||||
private Integer statusCode;
|
private final Integer statusCode;
|
||||||
private String response;
|
private final String response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new empty exception.
|
||||||
|
*/
|
||||||
public InvalidResponseException() {
|
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);
|
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);
|
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);
|
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;
|
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;
|
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() {
|
public Integer getStatusCode() {
|
||||||
return statusCode;
|
return statusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the response text.
|
||||||
|
*
|
||||||
|
* @return The response text or {@code null} if none specified.
|
||||||
|
*/
|
||||||
public String getResponse() {
|
public String getResponse() {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -23,19 +23,38 @@ package de.stklcode.jvault.connector.exception;
|
|||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
public class PermissionDeniedException extends VaultConnectorException {
|
public class PermissionDeniedException extends VaultConnectorException {
|
||||||
|
/**
|
||||||
|
* Constructs a new empty exception.
|
||||||
|
*/
|
||||||
public PermissionDeniedException() {
|
public PermissionDeniedException() {
|
||||||
super("Permission denied");
|
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);
|
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);
|
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);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -23,29 +23,37 @@ package de.stklcode.jvault.connector.exception;
|
|||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
public class TlsException extends VaultConnectorException {
|
public class TlsException extends VaultConnectorException {
|
||||||
private Integer statusCode;
|
/**
|
||||||
private String response;
|
* Constructs a new empty exception.
|
||||||
|
*/
|
||||||
public TlsException() {
|
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);
|
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);
|
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);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getStatusCode() {
|
|
||||||
return statusCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getResponse() {
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -23,18 +23,37 @@ package de.stklcode.jvault.connector.exception;
|
|||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
public abstract class VaultConnectorException extends Exception {
|
public abstract class VaultConnectorException extends Exception {
|
||||||
|
/**
|
||||||
|
* Constructs a new empty exception.
|
||||||
|
*/
|
||||||
public VaultConnectorException() {
|
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);
|
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);
|
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);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -17,6 +17,7 @@
|
|||||||
package de.stklcode.jvault.connector.factory;
|
package de.stklcode.jvault.connector.factory;
|
||||||
|
|
||||||
import de.stklcode.jvault.connector.HTTPVaultConnector;
|
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.TlsException;
|
||||||
import de.stklcode.jvault.connector.exception.VaultConnectorException;
|
import de.stklcode.jvault.connector.exception.VaultConnectorException;
|
||||||
|
|
||||||
@ -25,8 +26,11 @@ import javax.net.ssl.TrustManager;
|
|||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
@ -38,17 +42,26 @@ import java.security.cert.X509Certificate;
|
|||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.1
|
* @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 String DEFAULT_HOST = "127.0.0.1";
|
||||||
public static final Integer DEFAULT_PORT = 8200;
|
public static final Integer DEFAULT_PORT = 8200;
|
||||||
public static final boolean DEFAULT_TLS = true;
|
public static final boolean DEFAULT_TLS = true;
|
||||||
public static final String DEFAULT_PREFIX = "/v1/";
|
public static final String DEFAULT_PREFIX = "/v1/";
|
||||||
|
public static final int DEFAULT_NUMBER_OF_RETRIES = 0;
|
||||||
|
|
||||||
private String host;
|
private String host;
|
||||||
private Integer port;
|
private Integer port;
|
||||||
private boolean tls;
|
private boolean tls;
|
||||||
private String prefix;
|
private String prefix;
|
||||||
private SSLContext sslContext;
|
private SSLContext sslContext;
|
||||||
|
private int numberOfRetries;
|
||||||
|
private Integer timeout;
|
||||||
|
private String token;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default empty constructor.
|
* Default empty constructor.
|
||||||
@ -59,43 +72,44 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
|||||||
port = DEFAULT_PORT;
|
port = DEFAULT_PORT;
|
||||||
tls = DEFAULT_TLS;
|
tls = DEFAULT_TLS;
|
||||||
prefix = DEFAULT_PREFIX;
|
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
|
* @param host Hostname or IP address
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
public HTTPVaultConnectorFactory withHost(String host) {
|
public HTTPVaultConnectorFactory withHost(final String host) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set port (default: 8200)
|
* Set port (default: 8200).
|
||||||
*
|
*
|
||||||
* @param port Vault TCP port
|
* @param port Vault TCP port
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
public HTTPVaultConnectorFactory withPort(Integer port) {
|
public HTTPVaultConnectorFactory withPort(final Integer port) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set TLS usage (default: TRUE)
|
* Set TLS usage (default: TRUE).
|
||||||
*
|
*
|
||||||
* @param useTLS use TLS or not
|
* @param useTLS use TLS or not
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
public HTTPVaultConnectorFactory withTLS(boolean useTLS) {
|
public HTTPVaultConnectorFactory withTLS(final boolean useTLS) {
|
||||||
this.tls = useTLS;
|
this.tls = useTLS;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience Method for TLS usage (enabled by default)
|
* Convenience Method for TLS usage (enabled by default).
|
||||||
*
|
*
|
||||||
* @return self
|
* @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
|
* @return self
|
||||||
*/
|
*/
|
||||||
@ -118,7 +132,7 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
|||||||
* @param prefix Vault API prefix (default: "/v1/"
|
* @param prefix Vault API prefix (default: "/v1/"
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
public HTTPVaultConnectorFactory withPrefix(String prefix) {
|
public HTTPVaultConnectorFactory withPrefix(final String prefix) {
|
||||||
this.prefix = prefix;
|
this.prefix = prefix;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -131,7 +145,7 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
|||||||
* @throws VaultConnectorException on error
|
* @throws VaultConnectorException on error
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
public HTTPVaultConnectorFactory withTrustedCA(Path cert) throws VaultConnectorException {
|
public HTTPVaultConnectorFactory withTrustedCA(final Path cert) throws VaultConnectorException {
|
||||||
if (cert != null)
|
if (cert != null)
|
||||||
return withSslContext(createSslContext(cert));
|
return withSslContext(createSslContext(cert));
|
||||||
return this;
|
return this;
|
||||||
@ -145,14 +159,98 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
|||||||
* @return self
|
* @return self
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
public HTTPVaultConnectorFactory withSslContext(SSLContext sslContext) {
|
public HTTPVaultConnectorFactory withSslContext(final SSLContext sslContext) {
|
||||||
this.sslContext = sslContext;
|
this.sslContext = sslContext;
|
||||||
return this;
|
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) {
|
||||||
|
/* Ignore malformed values. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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
|
@Override
|
||||||
public HTTPVaultConnector build() {
|
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 +261,7 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
|||||||
* @throws TlsException on errors
|
* @throws TlsException on errors
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
private SSLContext createSslContext(Path trustedCert) throws TlsException {
|
private SSLContext createSslContext(final Path trustedCert) throws TlsException {
|
||||||
try {
|
try {
|
||||||
SSLContext context = SSLContext.getInstance("TLS");
|
SSLContext context = SSLContext.getInstance("TLS");
|
||||||
context.init(null, createTrustManager(trustedCert), new SecureRandom());
|
context.init(null, createTrustManager(trustedCert), new SecureRandom());
|
||||||
@ -181,7 +279,7 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
|||||||
* @throws TlsException on error
|
* @throws TlsException on error
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
private TrustManager[] createTrustManager(Path trustedCert) throws TlsException {
|
private TrustManager[] createTrustManager(final Path trustedCert) throws TlsException {
|
||||||
try {
|
try {
|
||||||
/* Create Keystore with trusted certificate */
|
/* Create Keystore with trusted certificate */
|
||||||
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||||
@ -204,7 +302,7 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
|||||||
* @throws TlsException on error
|
* @throws TlsException on error
|
||||||
* @since 0.4.0
|
* @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)) {
|
try (InputStream is = Files.newInputStream(certFile)) {
|
||||||
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
|
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
|
||||||
} catch (IOException | CertificateException e) {
|
} catch (IOException | CertificateException e) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -23,13 +23,14 @@ import de.stklcode.jvault.connector.exception.VaultConnectorException;
|
|||||||
* Abstract Vault Connector Factory interface.
|
* Abstract Vault Connector Factory interface.
|
||||||
* Provides builder pattern style factory for Vault connectors.
|
* Provides builder pattern style factory for Vault connectors.
|
||||||
*
|
*
|
||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
public abstract class VaultConnectorFactory {
|
public abstract class VaultConnectorFactory {
|
||||||
/**
|
/**
|
||||||
* Get Factory implementation for HTTP Vault Connector
|
* Get Factory implementation for HTTP Vault Connector.
|
||||||
* @return HTTP Connector Factory
|
*
|
||||||
|
* @return HTTP Connector Factory
|
||||||
*/
|
*/
|
||||||
public static HTTPVaultConnectorFactory httpFactory() {
|
public static HTTPVaultConnectorFactory httpFactory() {
|
||||||
return new HTTPVaultConnectorFactory();
|
return new HTTPVaultConnectorFactory();
|
||||||
@ -37,7 +38,17 @@ public abstract class VaultConnectorFactory {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Build command, produces connector after initialization.
|
* Build command, produces connector after initialization.
|
||||||
* @return Vault Connector instance.
|
*
|
||||||
|
* @return Vault Connector instance.
|
||||||
*/
|
*/
|
||||||
public abstract VaultConnector build();
|
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;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -17,7 +17,6 @@
|
|||||||
package de.stklcode.jvault.connector.model;
|
package de.stklcode.jvault.connector.model;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.*;
|
import com.fasterxml.jackson.annotation.*;
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -28,7 +27,7 @@ import java.util.List;
|
|||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class AppRole {
|
public final class AppRole {
|
||||||
@JsonProperty("role_name")
|
@JsonProperty("role_name")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@ -64,11 +63,30 @@ public class AppRole {
|
|||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
private Integer period;
|
private Integer period;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct empty {@link AppRole} object.
|
||||||
|
*/
|
||||||
public AppRole() {
|
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.name = name;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.bindSecretId = bindSecretId;
|
this.bindSecretId = bindSecretId;
|
||||||
@ -81,27 +99,45 @@ public class AppRole {
|
|||||||
this.period = period;
|
this.period = period;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the role name
|
||||||
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the role ID
|
||||||
|
*/
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bind secret ID
|
||||||
|
*/
|
||||||
public Boolean getBindSecretId() {
|
public Boolean getBindSecretId() {
|
||||||
return bindSecretId;
|
return bindSecretId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list of bound CIDR subnets
|
||||||
|
*/
|
||||||
public List<String> getBoundCidrList() {
|
public List<String> getBoundCidrList() {
|
||||||
return boundCidrList;
|
return boundCidrList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param boundCidrList list of subnets in CIDR notation to bind role to
|
||||||
|
*/
|
||||||
@JsonSetter("bound_cidr_list")
|
@JsonSetter("bound_cidr_list")
|
||||||
public void setBoundCidrList(List<String> boundCidrList) {
|
public void setBoundCidrList(final List<String> boundCidrList) {
|
||||||
this.boundCidrList = boundCidrList;
|
this.boundCidrList = boundCidrList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list of subnets in CIDR notation as comma-separated {@link String}
|
||||||
|
*/
|
||||||
@JsonGetter("bound_cidr_list")
|
@JsonGetter("bound_cidr_list")
|
||||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||||
public String getBoundCidrListString() {
|
public String getBoundCidrListString() {
|
||||||
@ -110,15 +146,24 @@ public class AppRole {
|
|||||||
return String.join(",", boundCidrList);
|
return String.join(",", boundCidrList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list of policies
|
||||||
|
*/
|
||||||
public List<String> getPolicies() {
|
public List<String> getPolicies() {
|
||||||
return policies;
|
return policies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param policies list of policies
|
||||||
|
*/
|
||||||
@JsonSetter("policies")
|
@JsonSetter("policies")
|
||||||
public void setPolicies(List<String> policies) {
|
public void setPolicies(final List<String> policies) {
|
||||||
this.policies = policies;
|
this.policies = policies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list of policies as comma-separated {@link String}
|
||||||
|
*/
|
||||||
@JsonGetter("policies")
|
@JsonGetter("policies")
|
||||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||||
public String getPoliciesString() {
|
public String getPoliciesString() {
|
||||||
@ -127,22 +172,37 @@ public class AppRole {
|
|||||||
return String.join(",", policies);
|
return String.join(",", policies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return maximum number of uses per secret
|
||||||
|
*/
|
||||||
public Integer getSecretIdNumUses() {
|
public Integer getSecretIdNumUses() {
|
||||||
return secretIdNumUses;
|
return secretIdNumUses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return maximum TTL in seconds for secrets
|
||||||
|
*/
|
||||||
public Integer getSecretIdTtl() {
|
public Integer getSecretIdTtl() {
|
||||||
return secretIdTtl;
|
return secretIdTtl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return token TTL in seconds
|
||||||
|
*/
|
||||||
public Integer getTokenTtl() {
|
public Integer getTokenTtl() {
|
||||||
return tokenTtl;
|
return tokenTtl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return maximum token TTL in seconds, including renewals
|
||||||
|
*/
|
||||||
public Integer getTokenMaxTtl() {
|
public Integer getTokenMaxTtl() {
|
||||||
return tokenMaxTtl;
|
return tokenMaxTtl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return duration in seconds, if specified
|
||||||
|
*/
|
||||||
public Integer getPeriod() {
|
public Integer getPeriod() {
|
||||||
return period;
|
return period;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -25,7 +25,7 @@ import java.util.List;
|
|||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
public class AppRoleBuilder {
|
public final class AppRoleBuilder {
|
||||||
private String name;
|
private String name;
|
||||||
private String id;
|
private String id;
|
||||||
private Boolean bindSecretId;
|
private Boolean bindSecretId;
|
||||||
@ -37,12 +37,17 @@ public class AppRoleBuilder {
|
|||||||
private Integer tokenMaxTtl;
|
private Integer tokenMaxTtl;
|
||||||
private Integer period;
|
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;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add custom role ID (optional)
|
* Add custom role ID. (optional)
|
||||||
*
|
*
|
||||||
* @param id the ID
|
* @param id the ID
|
||||||
* @return self
|
* @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
|
* @param bindSecretId the display name
|
||||||
* @return self
|
* @return self
|
||||||
@ -108,7 +113,7 @@ public class AppRoleBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add given policies
|
* Add given policies.
|
||||||
*
|
*
|
||||||
* @param policies the policies
|
* @param policies the policies
|
||||||
* @return self
|
* @return self
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -28,7 +28,7 @@ import java.util.Map;
|
|||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class AppRoleSecret {
|
public final class AppRoleSecret {
|
||||||
@JsonProperty("secret_id")
|
@JsonProperty("secret_id")
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
private String id;
|
private String id;
|
||||||
@ -57,41 +57,73 @@ public class AppRoleSecret {
|
|||||||
@JsonProperty(value = "secret_id_ttl", access = JsonProperty.Access.WRITE_ONLY)
|
@JsonProperty(value = "secret_id_ttl", access = JsonProperty.Access.WRITE_ONLY)
|
||||||
private Integer ttl;
|
private Integer ttl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct empty {@link AppRoleSecret} object.
|
||||||
|
*/
|
||||||
public AppRoleSecret() {
|
public AppRoleSecret() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public AppRoleSecret(String id) {
|
/**
|
||||||
|
* Construct {@link AppRoleSecret} with secret ID.
|
||||||
|
*
|
||||||
|
* @param id Secret ID
|
||||||
|
*/
|
||||||
|
public AppRoleSecret(final String id) {
|
||||||
this.id = 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.id = id;
|
||||||
this.metadata = metadata;
|
this.metadata = metadata;
|
||||||
this.cidrList = cidrList;
|
this.cidrList = cidrList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Secret ID
|
||||||
|
*/
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Secret accessor
|
||||||
|
*/
|
||||||
public String getAccessor() {
|
public String getAccessor() {
|
||||||
return accessor;
|
return accessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Secret metadata
|
||||||
|
*/
|
||||||
public Map<String, Object> getMetadata() {
|
public Map<String, Object> getMetadata() {
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return List of bound subnets in CIDR notation
|
||||||
|
*/
|
||||||
public List<String> getCidrList() {
|
public List<String> getCidrList() {
|
||||||
return cidrList;
|
return cidrList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cidrList List of subnets in CIDR notation
|
||||||
|
*/
|
||||||
@JsonSetter("cidr_list")
|
@JsonSetter("cidr_list")
|
||||||
public void setCidrList(List<String> cidrList) {
|
public void setCidrList(final List<String> cidrList) {
|
||||||
this.cidrList = cidrList;
|
this.cidrList = cidrList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return List of bound subnets in CIDR notation as comma-separated {@link String}
|
||||||
|
*/
|
||||||
@JsonGetter("cidr_list")
|
@JsonGetter("cidr_list")
|
||||||
public String getCidrListString() {
|
public String getCidrListString() {
|
||||||
if (cidrList == null || cidrList.isEmpty())
|
if (cidrList == null || cidrList.isEmpty())
|
||||||
@ -99,22 +131,37 @@ public class AppRoleSecret {
|
|||||||
return String.join(",", cidrList);
|
return String.join(",", cidrList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Creation time
|
||||||
|
*/
|
||||||
public String getCreationTime() {
|
public String getCreationTime() {
|
||||||
return creationTime;
|
return creationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Expiration time
|
||||||
|
*/
|
||||||
public String getExpirationTime() {
|
public String getExpirationTime() {
|
||||||
return expirationTime;
|
return expirationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Time of last update
|
||||||
|
*/
|
||||||
public String getLastUpdatedTime() {
|
public String getLastUpdatedTime() {
|
||||||
return lastUpdatedTime;
|
return lastUpdatedTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Number of uses
|
||||||
|
*/
|
||||||
public Integer getNumUses() {
|
public Integer getNumUses() {
|
||||||
return numUses;
|
return numUses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Time-to-live
|
||||||
|
*/
|
||||||
public Integer getTtl() {
|
public Integer getTtl() {
|
||||||
return ttl;
|
return ttl;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -19,23 +19,35 @@ package de.stklcode.jvault.connector.model;
|
|||||||
/**
|
/**
|
||||||
* Currently supported authentication backends.
|
* Currently supported authentication backends.
|
||||||
*
|
*
|
||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
public enum AuthBackend {
|
public enum AuthBackend {
|
||||||
TOKEN("token"),
|
TOKEN("token"),
|
||||||
APPID("app-id"),
|
APPID("app-id"),
|
||||||
APPROLE("approle"),
|
APPROLE("approle"),
|
||||||
USERPASS("userpass"),
|
USERPASS("userpass"),
|
||||||
|
GITHUB("github"), // Not supported yet.
|
||||||
UNKNOWN("");
|
UNKNOWN("");
|
||||||
|
|
||||||
private final String type;
|
private final String type;
|
||||||
|
|
||||||
AuthBackend(String type) {
|
/**
|
||||||
|
* Construct {@link AuthBackend} of given type.
|
||||||
|
*
|
||||||
|
* @param type Backend type
|
||||||
|
*/
|
||||||
|
AuthBackend(final String type) {
|
||||||
this.type = 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())
|
for (AuthBackend v : values())
|
||||||
if (v.type.equalsIgnoreCase(type))
|
if (v.type.equalsIgnoreCase(type))
|
||||||
return v;
|
return v;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -30,7 +30,7 @@ import java.util.Map;
|
|||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class Token {
|
public final class Token {
|
||||||
@JsonProperty("id")
|
@JsonProperty("id")
|
||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
private String id;
|
private String id;
|
||||||
@ -67,7 +67,28 @@ public class Token {
|
|||||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
private Boolean renewable;
|
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.id = id;
|
||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
this.ttl = ttl;
|
this.ttl = ttl;
|
||||||
@ -79,38 +100,65 @@ public class Token {
|
|||||||
this.renewable = renewable;
|
this.renewable = renewable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Token ID
|
||||||
|
*/
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Token display name
|
||||||
|
*/
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
return displayName;
|
return displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Token has no parent
|
||||||
|
*/
|
||||||
public Boolean getNoParent() {
|
public Boolean getNoParent() {
|
||||||
return noParent;
|
return noParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Token has no default policy
|
||||||
|
*/
|
||||||
public Boolean getNoDefaultPolicy() {
|
public Boolean getNoDefaultPolicy() {
|
||||||
return noDefaultPolicy;
|
return noDefaultPolicy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Time-to-live in seconds
|
||||||
|
*/
|
||||||
public Integer getTtl() {
|
public Integer getTtl() {
|
||||||
return ttl;
|
return ttl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Number of uses
|
||||||
|
*/
|
||||||
public Integer getNumUses() {
|
public Integer getNumUses() {
|
||||||
return numUses;
|
return numUses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return List of policies
|
||||||
|
*/
|
||||||
public List<String> getPolicies() {
|
public List<String> getPolicies() {
|
||||||
return policies;
|
return policies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Metadata
|
||||||
|
*/
|
||||||
public Map<String, String> getMeta() {
|
public Map<String, String> getMeta() {
|
||||||
return meta;
|
return meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Token is renewable
|
||||||
|
*/
|
||||||
public Boolean isRenewable() {
|
public Boolean isRenewable() {
|
||||||
return renewable;
|
return renewable;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -16,20 +16,15 @@
|
|||||||
|
|
||||||
package de.stklcode.jvault.connector.model;
|
package de.stklcode.jvault.connector.model;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import java.util.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A builder for vault tokens.
|
* A builder for vault tokens.
|
||||||
*
|
*
|
||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
public class TokenBuilder {
|
public final class TokenBuilder {
|
||||||
private String id;
|
private String id;
|
||||||
private String displayName;
|
private String displayName;
|
||||||
private Boolean noParent;
|
private Boolean noParent;
|
||||||
@ -41,7 +36,7 @@ public class TokenBuilder {
|
|||||||
private Boolean renewable;
|
private Boolean renewable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add token ID (optional)
|
* Add token ID. (optional)
|
||||||
*
|
*
|
||||||
* @param id the ID
|
* @param id the ID
|
||||||
* @return self
|
* @return self
|
||||||
@ -52,7 +47,7 @@ public class TokenBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add display name
|
* Add display name.
|
||||||
*
|
*
|
||||||
* @param displayName the display name
|
* @param displayName the display name
|
||||||
* @return self
|
* @return self
|
||||||
@ -64,6 +59,7 @@ public class TokenBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set desired time to live.
|
* Set desired time to live.
|
||||||
|
*
|
||||||
* @param ttl the ttl
|
* @param ttl the ttl
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
@ -74,6 +70,7 @@ public class TokenBuilder {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set desired number of uses.
|
* Set desired number of uses.
|
||||||
|
*
|
||||||
* @param numUses the number of uses
|
* @param numUses the number of uses
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
@ -83,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
|
* @param noParent if TRUE, token is created as orphan
|
||||||
* @return self
|
* @return self
|
||||||
@ -145,7 +142,18 @@ public class TokenBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add given policies
|
* Add given policies.
|
||||||
|
*
|
||||||
|
* @param policies the policies
|
||||||
|
* @return self
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
public TokenBuilder withPolicies(final String... policies) {
|
||||||
|
return withPolicies(Arrays.asList(policies));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add given policies.
|
||||||
*
|
*
|
||||||
* @param policies the policies
|
* @param policies the policies
|
||||||
* @return self
|
* @return self
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -24,33 +24,36 @@ import de.stklcode.jvault.connector.model.AppRole;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vault response for AppRole lookup.
|
* Vault response for AppRole lookup.
|
||||||
*
|
*
|
||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class AppRoleResponse extends VaultDataResponse {
|
public final class AppRoleResponse extends VaultDataResponse {
|
||||||
private AppRole role;
|
private AppRole role;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setData(Map<String, Object> data) throws InvalidResponseException {
|
public void setData(final Map<String, Object> data) throws InvalidResponseException {
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
try {
|
try {
|
||||||
/* null empty strings on list objects */
|
/* null empty strings on list objects */
|
||||||
Map<String, Object> filteredData = new HashMap<>();
|
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);
|
this.role = mapper.readValue(mapper.writeValueAsString(filteredData), AppRole.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
throw new InvalidResponseException("Failed deserializing response", e);
|
||||||
throw new InvalidResponseException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The role
|
||||||
|
*/
|
||||||
public AppRole getRole() {
|
public AppRole getRole() {
|
||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -19,7 +19,6 @@ package de.stklcode.jvault.connector.model.response;
|
|||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||||
import de.stklcode.jvault.connector.model.AppRole;
|
|
||||||
import de.stklcode.jvault.connector.model.AppRoleSecret;
|
import de.stklcode.jvault.connector.model.AppRoleSecret;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -29,28 +28,32 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* Vault response for AppRole lookup.
|
* Vault response for AppRole lookup.
|
||||||
*
|
*
|
||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class AppRoleSecretResponse extends VaultDataResponse {
|
public final class AppRoleSecretResponse extends VaultDataResponse {
|
||||||
private AppRoleSecret secret;
|
private AppRoleSecret secret;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setData(Map<String, Object> data) throws InvalidResponseException {
|
public void setData(final Map<String, Object> data) throws InvalidResponseException {
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
try {
|
try {
|
||||||
/* null empty strings on list objects */
|
/* null empty strings on list objects */
|
||||||
Map<String, Object> filteredData = new HashMap<>();
|
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);
|
this.secret = mapper.readValue(mapper.writeValueAsString(filteredData), AppRoleSecret.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
throw new InvalidResponseException("Failed deserializing response", e);
|
||||||
throw new InvalidResponseException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The secret
|
||||||
|
*/
|
||||||
public AppRoleSecret getSecret() {
|
public AppRoleSecret getSecret() {
|
||||||
return secret;
|
return secret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -32,25 +32,32 @@ import java.util.Map;
|
|||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class AuthMethodsResponse extends VaultDataResponse {
|
public final class AuthMethodsResponse extends VaultDataResponse {
|
||||||
private Map<String, AuthMethod> supportedMethods;
|
private Map<String, AuthMethod> supportedMethods;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct empty {@link AuthMethodsResponse} object.
|
||||||
|
*/
|
||||||
public AuthMethodsResponse() {
|
public AuthMethodsResponse() {
|
||||||
this.supportedMethods = new HashMap<>();
|
this.supportedMethods = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setData(Map<String, Object> data) throws InvalidResponseException {
|
public void setData(final Map<String, Object> data) throws InvalidResponseException {
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
for (String path : data.keySet()) {
|
for (Map.Entry<String, Object> entry : data.entrySet()) {
|
||||||
try {
|
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) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException();
|
throw new InvalidResponseException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Supported authentication methods
|
||||||
|
*/
|
||||||
public Map<String, AuthMethod> getSupportedMethods() {
|
public Map<String, AuthMethod> getSupportedMethods() {
|
||||||
return supportedMethods;
|
return supportedMethods;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -28,35 +28,46 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* Vault response for authentication providing auth info in {@link AuthData} field.
|
* Vault response for authentication providing auth info in {@link AuthData} field.
|
||||||
*
|
*
|
||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class AuthResponse extends VaultDataResponse {
|
public final class AuthResponse extends VaultDataResponse {
|
||||||
private Map<String, Object> data;
|
private Map<String, Object> data;
|
||||||
|
|
||||||
private AuthData auth;
|
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")
|
@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();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
try {
|
try {
|
||||||
this.auth = mapper.readValue(mapper.writeValueAsString(auth), AuthData.class);
|
this.auth = mapper.readValue(mapper.writeValueAsString(auth), AuthData.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
throw new InvalidResponseException("Failed deserializing response", e);
|
||||||
throw new InvalidResponseException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setData(Map<String, Object> data) {
|
public void setData(final Map<String, Object> data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Raw data
|
||||||
|
*/
|
||||||
public Map<String, Object> getData() {
|
public Map<String, Object> getData() {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Authentication data
|
||||||
|
*/
|
||||||
public AuthData getAuth() {
|
public AuthData getAuth() {
|
||||||
return auth;
|
return auth;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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.model.response;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vault response from credentials lookup. Simple wrapper for data objects containing username and password fields.
|
||||||
|
*
|
||||||
|
* @author Stefan Kalscheuer
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public final class CredentialsResponse extends SecretResponse {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Username
|
||||||
|
*/
|
||||||
|
public String getUsername() {
|
||||||
|
Object username = get("username");
|
||||||
|
if (username != null)
|
||||||
|
return username.toString();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Password
|
||||||
|
*/
|
||||||
|
public String getPassword() {
|
||||||
|
Object password = get("password");
|
||||||
|
if (password != null)
|
||||||
|
return password.toString();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -28,11 +28,23 @@ import java.util.List;
|
|||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class ErrorResponse implements VaultResponse {
|
public final class ErrorResponse implements VaultResponse {
|
||||||
@JsonProperty("errors")
|
@JsonProperty("errors")
|
||||||
private List<String> errors;
|
private List<String> errors;
|
||||||
|
|
||||||
public List<String > getErrors() {
|
/**
|
||||||
|
* @return List of errors
|
||||||
|
*/
|
||||||
|
public List<String> getErrors() {
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
if (errors == null || errors.isEmpty()) {
|
||||||
|
return "error response";
|
||||||
|
} else {
|
||||||
|
return errors.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* 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.model.response;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vault response for health query.
|
||||||
|
*
|
||||||
|
* @author Stefan Kalscheuer
|
||||||
|
* @since 0.7.0
|
||||||
|
*/
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public final class HealthResponse implements VaultResponse {
|
||||||
|
@JsonProperty("cluster_id")
|
||||||
|
private String clusterID;
|
||||||
|
|
||||||
|
@JsonProperty("cluster_name")
|
||||||
|
private String clusterName;
|
||||||
|
|
||||||
|
@JsonProperty("version")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
@JsonProperty("server_time_utc")
|
||||||
|
private Long serverTimeUTC;
|
||||||
|
|
||||||
|
@JsonProperty("standby")
|
||||||
|
private Boolean standby;
|
||||||
|
|
||||||
|
@JsonProperty("sealed")
|
||||||
|
private Boolean sealed;
|
||||||
|
|
||||||
|
@JsonProperty("initialized")
|
||||||
|
private Boolean initialized;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The Cluster ID.
|
||||||
|
*/
|
||||||
|
public String getClusterID() {
|
||||||
|
return clusterID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The Cluster name.
|
||||||
|
*/
|
||||||
|
public String getClusterName() {
|
||||||
|
return clusterName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Vault version.
|
||||||
|
*/
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Server time UTC (timestamp).
|
||||||
|
*/
|
||||||
|
public Long getServerTimeUTC() {
|
||||||
|
return serverTimeUTC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Server standby status.
|
||||||
|
*/
|
||||||
|
public Boolean isStandby() {
|
||||||
|
return standby;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Server seal status.
|
||||||
|
*/
|
||||||
|
public Boolean isSealed() {
|
||||||
|
return sealed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Server initialization status.
|
||||||
|
*/
|
||||||
|
public Boolean isInitialized() {
|
||||||
|
return initialized;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -26,11 +26,14 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class HelpResponse implements VaultResponse {
|
public final class HelpResponse implements VaultResponse {
|
||||||
@JsonProperty("help")
|
@JsonProperty("help")
|
||||||
private String help;
|
private String help;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Help text
|
||||||
|
*/
|
||||||
public String getHelp() {
|
public String getHelp() {
|
||||||
return help;
|
return help;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -27,14 +27,17 @@ import java.util.Map;
|
|||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class RawDataResponse extends VaultDataResponse {
|
public final class RawDataResponse extends VaultDataResponse {
|
||||||
private Map<String, Object> data;
|
private Map<String, Object> data;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setData(Map<String, Object> data) {
|
public void setData(final Map<String, Object> data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Raw data {@link Map}
|
||||||
|
*/
|
||||||
public Map<String, Object> getData() {
|
public Map<String, Object> getData() {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -26,7 +26,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class SealResponse implements VaultResponse {
|
public final class SealResponse implements VaultResponse {
|
||||||
@JsonProperty("sealed")
|
@JsonProperty("sealed")
|
||||||
private boolean sealed;
|
private boolean sealed;
|
||||||
|
|
||||||
@ -39,18 +39,30 @@ public class SealResponse implements VaultResponse {
|
|||||||
@JsonProperty("progress")
|
@JsonProperty("progress")
|
||||||
private Integer progress;
|
private Integer progress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Seal status
|
||||||
|
*/
|
||||||
public boolean isSealed() {
|
public boolean isSealed() {
|
||||||
return sealed;
|
return sealed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Required threshold of secret shares
|
||||||
|
*/
|
||||||
public Integer getThreshold() {
|
public Integer getThreshold() {
|
||||||
return threshold;
|
return threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Number of secret shares
|
||||||
|
*/
|
||||||
public Integer getNumberOfShares() {
|
public Integer getNumberOfShares() {
|
||||||
return numberOfShares;
|
return numberOfShares;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Current unseal progress (remaining required shares)
|
||||||
|
*/
|
||||||
public Integer getProgress() {
|
public Integer getProgress() {
|
||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -26,23 +26,31 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* Vault response for secret list request.
|
* Vault response for secret list request.
|
||||||
*
|
*
|
||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class SecretListResponse extends VaultDataResponse {
|
public final class SecretListResponse extends VaultDataResponse {
|
||||||
private List<String> keys;
|
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")
|
@JsonProperty("data")
|
||||||
public void setData(Map<String, Object> data) throws InvalidResponseException {
|
public void setData(final Map<String, Object> data) throws InvalidResponseException {
|
||||||
try {
|
try {
|
||||||
this.keys = (List<String>)data.get("keys");
|
this.keys = (List<String>) data.get("keys");
|
||||||
}
|
} catch (ClassCastException e) {
|
||||||
catch (ClassCastException e) {
|
|
||||||
throw new InvalidResponseException("Keys could not be parsed from data.", e);
|
throw new InvalidResponseException("Keys could not be parsed from data.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return List of secret keys
|
||||||
|
*/
|
||||||
public List<String> getKeys() {
|
public List<String> getKeys() {
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,7 +35,7 @@ public class SecretResponse extends VaultDataResponse {
|
|||||||
private Map<String, Object> data;
|
private Map<String, Object> data;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setData(Map<String, Object> data) throws InvalidResponseException {
|
public final void setData(final Map<String, Object> data) throws InvalidResponseException {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +45,9 @@ public class SecretResponse extends VaultDataResponse {
|
|||||||
* @return data map
|
* @return data map
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
public Map<String, Object> getData() {
|
public final Map<String, Object> getData() {
|
||||||
|
if (data == null)
|
||||||
|
return new HashMap<>();
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,11 +55,13 @@ public class SecretResponse extends VaultDataResponse {
|
|||||||
* Get a single value for given key.
|
* Get a single value for given key.
|
||||||
*
|
*
|
||||||
* @param key the key
|
* @param key the key
|
||||||
* @return the value or NULL if absent
|
* @return the value or {@code null} if absent
|
||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
public Object get(String key) {
|
public final Object get(final String key) {
|
||||||
return data.get(key);
|
if (data == null)
|
||||||
|
return null;
|
||||||
|
return getData().get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,41 +69,49 @@ public class SecretResponse extends VaultDataResponse {
|
|||||||
* Method for backwards compatibility in case of simple secrets.
|
* Method for backwards compatibility in case of simple secrets.
|
||||||
*
|
*
|
||||||
* @return the value
|
* @return the value
|
||||||
|
* @deprecated Deprecated artifact, will be removed at latest at v1.0.0
|
||||||
*/
|
*/
|
||||||
public String getValue() {
|
@Deprecated
|
||||||
if (data.get("value") == null)
|
public final String getValue() {
|
||||||
|
Object value = get("value");
|
||||||
|
if (value == null)
|
||||||
return 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 type Class to parse response
|
||||||
* @param <T> Class to parse response
|
* @param <T> Class to parse response
|
||||||
* @return Parsed object
|
* @return Parsed object
|
||||||
* @throws InvalidResponseException on parsing error
|
* @throws InvalidResponseException on parsing error
|
||||||
* @since 0.3
|
* @since 0.3
|
||||||
|
* @deprecated Deprecated artifact, will be removed at latest at v1.0.0
|
||||||
*/
|
*/
|
||||||
public <T> T getValue(Class<T> type) throws InvalidResponseException {
|
@Deprecated
|
||||||
|
public final <T> T getValue(final Class<T> type) throws InvalidResponseException {
|
||||||
return get("value", type);
|
return get("value", type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get response parsed as JSON
|
* Get response parsed as JSON.
|
||||||
*
|
*
|
||||||
* @param key the key
|
* @param key the key
|
||||||
* @param type Class to parse response
|
* @param type Class to parse response
|
||||||
* @param <T> 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
|
* @throws InvalidResponseException on parsing error
|
||||||
* @since 0.4.0
|
* @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 {
|
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) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response payload: " + e.getMessage());
|
throw new InvalidResponseException("Unable to parse response payload: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -28,27 +28,35 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* Vault response from token lookup providing Token information in {@link TokenData} field.
|
* Vault response from token lookup providing Token information in {@link TokenData} field.
|
||||||
*
|
*
|
||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class TokenResponse extends VaultDataResponse {
|
public final class TokenResponse extends VaultDataResponse {
|
||||||
private TokenData data;
|
private TokenData data;
|
||||||
|
|
||||||
@JsonProperty("auth")
|
@JsonProperty("auth")
|
||||||
private Boolean auth;
|
private Boolean auth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set data. Parses response data map to {@link TokenData}.
|
||||||
|
*
|
||||||
|
* @param data Raw response data
|
||||||
|
* @throws InvalidResponseException on parsing errors
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setData(Map<String, Object> data) throws InvalidResponseException {
|
public void setData(final Map<String, Object> data) throws InvalidResponseException {
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
try {
|
try {
|
||||||
this.data = mapper.readValue(mapper.writeValueAsString(data), TokenData.class);
|
this.data = mapper.readValue(mapper.writeValueAsString(data), TokenData.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
throw new InvalidResponseException("Failed deserializing response", e);
|
||||||
throw new InvalidResponseException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Token data
|
||||||
|
*/
|
||||||
public TokenData getData() {
|
public TokenData getData() {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -25,8 +25,8 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* Abstract Vault response with default payload fields.
|
* Abstract Vault response with default payload fields.
|
||||||
*
|
*
|
||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
public abstract class VaultDataResponse implements VaultResponse {
|
public abstract class VaultDataResponse implements VaultResponse {
|
||||||
@JsonProperty("lease_id")
|
@JsonProperty("lease_id")
|
||||||
@ -41,22 +41,40 @@ public abstract class VaultDataResponse implements VaultResponse {
|
|||||||
@JsonProperty("warnings")
|
@JsonProperty("warnings")
|
||||||
private List<String> 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")
|
@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;
|
return leaseId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRenewable() {
|
/**
|
||||||
|
* @return Lease is renewable
|
||||||
|
*/
|
||||||
|
public final boolean isRenewable() {
|
||||||
return renewable;
|
return renewable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getLeaseDuration() {
|
/**
|
||||||
|
* @return Lease duration
|
||||||
|
*/
|
||||||
|
public final Integer getLeaseDuration() {
|
||||||
return leaseDuration;
|
return leaseDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getWarnings() {
|
/**
|
||||||
|
* @return List of warnings
|
||||||
|
*/
|
||||||
|
public final List<String> getWarnings() {
|
||||||
return warnings;
|
return warnings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -29,7 +29,7 @@ import java.util.Map;
|
|||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class AuthData {
|
public final class AuthData {
|
||||||
@JsonProperty("client_token")
|
@JsonProperty("client_token")
|
||||||
private String clientToken;
|
private String clientToken;
|
||||||
|
|
||||||
@ -48,27 +48,45 @@ public class AuthData {
|
|||||||
@JsonProperty("renewable")
|
@JsonProperty("renewable")
|
||||||
private boolean renewable;
|
private boolean renewable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Client token
|
||||||
|
*/
|
||||||
public String getClientToken() {
|
public String getClientToken() {
|
||||||
return clientToken;
|
return clientToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Token accessor
|
||||||
|
*/
|
||||||
public String getAccessor() {
|
public String getAccessor() {
|
||||||
return accessor;
|
return accessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return List of policies
|
||||||
|
*/
|
||||||
public List<String> getPolicies() {
|
public List<String> getPolicies() {
|
||||||
return policies;
|
return policies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Metadata
|
||||||
|
*/
|
||||||
public Map<String, Object> getMetadata() {
|
public Map<String, Object> getMetadata() {
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Lease duration
|
||||||
|
*/
|
||||||
public Integer getLeaseDuration() {
|
public Integer getLeaseDuration() {
|
||||||
return leaseDuration;
|
return leaseDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Lease is renewable
|
||||||
|
*/
|
||||||
public boolean isRenewable() {
|
public boolean isRenewable() {
|
||||||
return renewable;
|
return renewable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package de.stklcode.jvault.connector.model.response.embedded;
|
package de.stklcode.jvault.connector.model.response.embedded;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.annotation.JsonSetter;
|
import com.fasterxml.jackson.annotation.JsonSetter;
|
||||||
import de.stklcode.jvault.connector.model.AuthBackend;
|
import de.stklcode.jvault.connector.model.AuthBackend;
|
||||||
@ -28,7 +29,8 @@ import java.util.Map;
|
|||||||
* @author Stefan Kalscheuer
|
* @author Stefan Kalscheuer
|
||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
public class AuthMethod {
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public final class AuthMethod {
|
||||||
private AuthBackend type;
|
private AuthBackend type;
|
||||||
private String rawType;
|
private String rawType;
|
||||||
|
|
||||||
@ -38,25 +40,50 @@ public class AuthMethod {
|
|||||||
@JsonProperty("config")
|
@JsonProperty("config")
|
||||||
private Map<String, String> config;
|
private Map<String, String> config;
|
||||||
|
|
||||||
|
@JsonProperty("local")
|
||||||
|
private boolean local;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type Backend type, passed to {@link AuthBackend#forType(String)}
|
||||||
|
*/
|
||||||
@JsonSetter("type")
|
@JsonSetter("type")
|
||||||
public void setType(String type) {
|
public void setType(final String type) {
|
||||||
this.rawType = type;
|
this.rawType = type;
|
||||||
this.type = AuthBackend.forType(type);
|
this.type = AuthBackend.forType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Backend type
|
||||||
|
*/
|
||||||
public AuthBackend getType() {
|
public AuthBackend getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Raw backend type string
|
||||||
|
*/
|
||||||
public String getRawType() {
|
public String getRawType() {
|
||||||
return rawType;
|
return rawType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Description
|
||||||
|
*/
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Configuration data
|
||||||
|
*/
|
||||||
public Map<String, String> getConfig() {
|
public Map<String, String> getConfig() {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Is local backend
|
||||||
|
*/
|
||||||
|
public boolean isLocal() {
|
||||||
|
return local;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -26,7 +26,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class TokenData {
|
public final class TokenData {
|
||||||
@JsonProperty("accessor")
|
@JsonProperty("accessor")
|
||||||
private String accessor;
|
private String accessor;
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ public class TokenData {
|
|||||||
private Integer creationTime;
|
private Integer creationTime;
|
||||||
|
|
||||||
@JsonProperty("creation_ttl")
|
@JsonProperty("creation_ttl")
|
||||||
private Integer creatinTtl;
|
private Integer creationTtl;
|
||||||
|
|
||||||
@JsonProperty("display_name")
|
@JsonProperty("display_name")
|
||||||
private String name;
|
private String name;
|
||||||
@ -60,47 +60,80 @@ public class TokenData {
|
|||||||
@JsonProperty("ttl")
|
@JsonProperty("ttl")
|
||||||
private Integer ttl;
|
private Integer ttl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Token accessor
|
||||||
|
*/
|
||||||
public String getAccessor() {
|
public String getAccessor() {
|
||||||
return accessor;
|
return accessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Creation time
|
||||||
|
*/
|
||||||
public Integer getCreationTime() {
|
public Integer getCreationTime() {
|
||||||
return creationTime;
|
return creationTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getCreatinTtl() {
|
/**
|
||||||
return creatinTtl;
|
* @return Creation TTL (in seconds)
|
||||||
|
*/
|
||||||
|
public Integer getCreationTtl() {
|
||||||
|
return creationTtl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Token name
|
||||||
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Token ID
|
||||||
|
*/
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Number of uses
|
||||||
|
*/
|
||||||
public Integer getNumUses() {
|
public Integer getNumUses() {
|
||||||
return numUses;
|
return numUses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Token is orphan
|
||||||
|
*/
|
||||||
public boolean isOrphan() {
|
public boolean isOrphan() {
|
||||||
return orphan;
|
return orphan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Token path
|
||||||
|
*/
|
||||||
public String getPath() {
|
public String getPath() {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Token role
|
||||||
|
*/
|
||||||
public String getRole() {
|
public String getRole() {
|
||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Token TTL (in seconds)
|
||||||
|
*/
|
||||||
public Integer getTtl() {
|
public Integer getTtl() {
|
||||||
return ttl;
|
return ttl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Metadata
|
||||||
|
*/
|
||||||
public String getMeta() {
|
public String getMeta() {
|
||||||
return meta;
|
return meta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,466 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import de.stklcode.jvault.connector.exception.InvalidRequestException;
|
||||||
|
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||||
|
import de.stklcode.jvault.connector.exception.PermissionDeniedException;
|
||||||
|
import de.stklcode.jvault.connector.exception.VaultConnectorException;
|
||||||
|
import org.apache.http.ProtocolVersion;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
|
import org.apache.http.message.BasicStatusLine;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||||
|
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||||
|
import org.powermock.modules.junit4.PowerMockRunner;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
|
import static org.hamcrest.CoreMatchers.nullValue;
|
||||||
|
import static org.hamcrest.core.Is.is;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.powermock.api.mockito.PowerMockito.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JUnit test for HTTP Vault connector.
|
||||||
|
* This test suite contains tests that do not require connection to an actual Vault instance.
|
||||||
|
*
|
||||||
|
* @author Stefan Kalscheuer
|
||||||
|
* @since 0.7.0
|
||||||
|
*/
|
||||||
|
@RunWith(PowerMockRunner.class)
|
||||||
|
@PrepareForTest({HttpClientBuilder.class})
|
||||||
|
@PowerMockIgnore({"javax.net.ssl.*"})
|
||||||
|
public class HTTPVaultConnectorOfflineTest {
|
||||||
|
private static final String INVALID_URL = "foo:/\\1nv4l1d_UrL";
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private HttpClientBuilder httpMockBuilder;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private CloseableHttpClient httpMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private CloseableHttpResponse responseMock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test exceptions thrown during request.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void requestExceptionTest() throws IOException {
|
||||||
|
HTTPVaultConnector connector = new HTTPVaultConnector("http://127.0.0.1", null, 0, 250);
|
||||||
|
|
||||||
|
// Test invalid response code.
|
||||||
|
initHttpMock();
|
||||||
|
final int responseCode = 400;
|
||||||
|
mockResponse(responseCode, "", ContentType.APPLICATION_JSON);
|
||||||
|
try {
|
||||||
|
connector.getHealth();
|
||||||
|
fail("Querying health status succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertThat("Unexpected type of exception", e, instanceOf(InvalidResponseException.class));
|
||||||
|
assertThat("Unexpected exception message", e.getMessage(), is("Invalid response code"));
|
||||||
|
assertThat("Unexpected status code in exception", ((InvalidResponseException) e).getStatusCode(), is(responseCode));
|
||||||
|
assertThat("Response message where none was expected", ((InvalidResponseException) e).getResponse(), is(nullValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate permission denied response.
|
||||||
|
mockResponse(responseCode, "{\"errors\":[\"permission denied\"]}", ContentType.APPLICATION_JSON);
|
||||||
|
try {
|
||||||
|
connector.getHealth();
|
||||||
|
fail("Querying health status succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertThat("Unexpected type of exception", e, instanceOf(PermissionDeniedException.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test exception thrown during request.
|
||||||
|
when(httpMock.execute(any())).thenThrow(new IOException("Test Exception"));
|
||||||
|
try {
|
||||||
|
connector.getHealth();
|
||||||
|
fail("Querying health status succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertThat("Unexpected type of exception", e, instanceOf(InvalidResponseException.class));
|
||||||
|
assertThat("Unexpected exception message", e.getMessage(), is("Unable to read response"));
|
||||||
|
assertThat("Unexpected cause", e.getCause(), instanceOf(IOException.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now simulate a failing request that succeeds on second try.
|
||||||
|
connector = new HTTPVaultConnector("https://127.0.0.1", null, 1, 250);
|
||||||
|
doReturn(responseMock).doReturn(responseMock).when(httpMock).execute(any());
|
||||||
|
doReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, ""))
|
||||||
|
.doReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, ""))
|
||||||
|
.doReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, ""))
|
||||||
|
.doReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, ""))
|
||||||
|
.when(responseMock).getStatusLine();
|
||||||
|
when(responseMock.getEntity()).thenReturn(new StringEntity("{}", ContentType.APPLICATION_JSON));
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.getHealth();
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail("Request failed unexpectedly: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test constductors of the {@link HTTPVaultConnector} class.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void constructorTest() throws NoSuchAlgorithmException {
|
||||||
|
final String url = "https://vault.example.net/test/";
|
||||||
|
final String hostname = "vault.example.com";
|
||||||
|
final Integer port = 1337;
|
||||||
|
final String prefix = "/custom/prefix/";
|
||||||
|
final Integer retries = 42;
|
||||||
|
final String expectedNoTls = "http://" + hostname + "/v1/";
|
||||||
|
final String expectedCustomPort = "https://" + hostname + ":" + port + "/v1/";
|
||||||
|
final String expectedCustomPrefix = "https://" + hostname + ":" + port + prefix;
|
||||||
|
final SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||||
|
|
||||||
|
// Most basic constructor expects complete URL.
|
||||||
|
HTTPVaultConnector connector = new HTTPVaultConnector(url);
|
||||||
|
assertThat("Unexpected base URL", getPrivate(connector, "baseURL"), is(url));
|
||||||
|
|
||||||
|
// Now override TLS usage.
|
||||||
|
connector = new HTTPVaultConnector(hostname, false);
|
||||||
|
assertThat("Unexpected base URL with TLS disabled", getPrivate(connector, "baseURL"), is(expectedNoTls));
|
||||||
|
|
||||||
|
// Specify custom port.
|
||||||
|
connector = new HTTPVaultConnector(hostname, true, port);
|
||||||
|
assertThat("Unexpected base URL with custom port", getPrivate(connector, "baseURL"), is(expectedCustomPort));
|
||||||
|
|
||||||
|
// Specify custom prefix.
|
||||||
|
connector = new HTTPVaultConnector(hostname, true, port, prefix);
|
||||||
|
assertThat("Unexpected base URL with custom prefix", getPrivate(connector, "baseURL"), is(expectedCustomPrefix));
|
||||||
|
assertThat("SSL context set, but not specified", getPrivate(connector, "sslContext"), is(nullValue()));
|
||||||
|
|
||||||
|
// Provide custom SSL context.
|
||||||
|
connector = new HTTPVaultConnector(hostname, true, port, prefix, sslContext);
|
||||||
|
assertThat("Unexpected base URL with custom prefix", getPrivate(connector, "baseURL"), is(expectedCustomPrefix));
|
||||||
|
assertThat("SSL context not filled correctly", getPrivate(connector, "sslContext"), is(sslContext));
|
||||||
|
|
||||||
|
// Specify number of retries.
|
||||||
|
connector = new HTTPVaultConnector(url, sslContext, retries);
|
||||||
|
assertThat("Number of retries not set correctly", getPrivate(connector, "retries"), is(retries));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test is designed to test exceptions caught and thrown by seal-methods if Vault is not reachable.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void sealExceptionTest() throws IOException {
|
||||||
|
HTTPVaultConnector connector = new HTTPVaultConnector(INVALID_URL);
|
||||||
|
try {
|
||||||
|
connector.sealStatus();
|
||||||
|
fail("Querying seal status succeeded on invalid URL");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertThat("Unexpected type of exception", e, instanceOf(InvalidRequestException.class));
|
||||||
|
assertThat("Unexpected exception message", e.getMessage(), is("Invalid URI format"));
|
||||||
|
}
|
||||||
|
|
||||||
|
connector = new HTTPVaultConnector("https://127.0.0.1", null, 0, 250);
|
||||||
|
|
||||||
|
// Simulate NULL response (mock not supplied with data).
|
||||||
|
initHttpMock();
|
||||||
|
try {
|
||||||
|
connector.sealStatus();
|
||||||
|
fail("Querying seal status succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertThat("Unexpected type of exception", e, instanceOf(InvalidResponseException.class));
|
||||||
|
assertThat("Unexpected exception message", e.getMessage(), is("Response unavailable"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test is designed to test exceptions caught and thrown by seal-methods if Vault is not reachable.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void healthExceptionTest() throws IOException {
|
||||||
|
HTTPVaultConnector connector = new HTTPVaultConnector(INVALID_URL);
|
||||||
|
try {
|
||||||
|
connector.getHealth();
|
||||||
|
fail("Querying health status succeeded on invalid URL");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertThat("Unexpected type of exception", e, instanceOf(InvalidRequestException.class));
|
||||||
|
assertThat("Unexpected exception message", e.getMessage(), is("Invalid URI format"));
|
||||||
|
}
|
||||||
|
|
||||||
|
connector = new HTTPVaultConnector("https://127.0.0.1", null, 0, 250);
|
||||||
|
|
||||||
|
// Simulate NULL response (mock not supplied with data).
|
||||||
|
initHttpMock();
|
||||||
|
try {
|
||||||
|
connector.getHealth();
|
||||||
|
fail("Querying health status succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertThat("Unexpected type of exception", e, instanceOf(InvalidResponseException.class));
|
||||||
|
assertThat("Unexpected exception message", e.getMessage(), is("Response unavailable"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test behavior on unparsable responses.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void parseExceptionTest() throws IOException {
|
||||||
|
HTTPVaultConnector connector = new HTTPVaultConnector("https://127.0.0.1", null, 0, 250);
|
||||||
|
// Mock authorization.
|
||||||
|
setPrivate(connector, "authorized", true);
|
||||||
|
// Mock response.
|
||||||
|
initHttpMock();
|
||||||
|
mockResponse(200, "invalid", ContentType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
// Now test the methods.
|
||||||
|
try {
|
||||||
|
connector.sealStatus();
|
||||||
|
fail("sealStatus() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.unseal("key");
|
||||||
|
fail("unseal() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.getHealth();
|
||||||
|
fail("getHealth() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.getAuthBackends();
|
||||||
|
fail("getAuthBackends() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.authToken("token");
|
||||||
|
fail("authToken() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.lookupAppRole("roleName");
|
||||||
|
fail("lookupAppRole() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.getAppRoleID("roleName");
|
||||||
|
fail("getAppRoleID() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.createAppRoleSecret("roleName");
|
||||||
|
fail("createAppRoleSecret() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.lookupAppRoleSecret("roleName", "secretID");
|
||||||
|
fail("lookupAppRoleSecret() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.listAppRoles();
|
||||||
|
fail("listAppRoles() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.listAppRoleSecrets("roleName");
|
||||||
|
fail("listAppRoleSecrets() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.read("key");
|
||||||
|
fail("read() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.list("path");
|
||||||
|
fail("list() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.renew("leaseID");
|
||||||
|
fail("renew() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.lookupToken("token");
|
||||||
|
fail("lookupToken() succeeded on invalid instance");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertParseError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertParseError(Exception e) {
|
||||||
|
assertThat("Unexpected type of exception", e, instanceOf(InvalidResponseException.class));
|
||||||
|
assertThat("Unexpected exception message", e.getMessage(), is("Unable to parse response"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test requests that expect an empty response with code 204, but receive a 200 body.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void nonEmpty204ResponseTest() throws IOException {
|
||||||
|
HTTPVaultConnector connector = new HTTPVaultConnector("https://127.0.0.1", null, 0, 250);
|
||||||
|
// Mock authorization.
|
||||||
|
setPrivate(connector, "authorized", true);
|
||||||
|
// Mock response.
|
||||||
|
initHttpMock();
|
||||||
|
mockResponse(200, "{}", ContentType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
// Now test the methods expecting a 204.
|
||||||
|
try {
|
||||||
|
connector.registerAppId("appID", "policy", "displayName");
|
||||||
|
fail("registerAppId() with 200 response succeeded");
|
||||||
|
} catch (VaultConnectorException e) {
|
||||||
|
assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.registerUserId("appID", "userID");
|
||||||
|
fail("registerUserId() with 200 response succeeded");
|
||||||
|
} catch (VaultConnectorException e) {
|
||||||
|
assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.createAppRole("appID", Collections.singletonList("policy"));
|
||||||
|
fail("createAppRole() with 200 response succeeded");
|
||||||
|
} catch (VaultConnectorException e) {
|
||||||
|
assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.deleteAppRole("roleName");
|
||||||
|
fail("deleteAppRole() with 200 response succeeded");
|
||||||
|
} catch (VaultConnectorException e) {
|
||||||
|
assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.setAppRoleID("roleName", "roleID");
|
||||||
|
fail("setAppRoleID() with 200 response succeeded");
|
||||||
|
} catch (VaultConnectorException e) {
|
||||||
|
assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.destroyAppRoleSecret("roleName", "secretID");
|
||||||
|
fail("destroyAppRoleSecret() with 200 response succeeded");
|
||||||
|
} catch (VaultConnectorException e) {
|
||||||
|
assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.destroyAppRoleSecret("roleName", "secretUD");
|
||||||
|
fail("destroyAppRoleSecret() with 200 response succeeded");
|
||||||
|
} catch (VaultConnectorException e) {
|
||||||
|
assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.delete("key");
|
||||||
|
fail("delete() with 200 response succeeded");
|
||||||
|
} catch (VaultConnectorException e) {
|
||||||
|
assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
connector.revoke("leaseID");
|
||||||
|
fail("destroyAppRoleSecret() with 200 response succeeded");
|
||||||
|
} catch (VaultConnectorException e) {
|
||||||
|
assertThat("Unexpected exception type", e, instanceOf(InvalidResponseException.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getPrivate(Object target, String fieldName) {
|
||||||
|
try {
|
||||||
|
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;
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPrivate(Object target, String fieldName, Object value) {
|
||||||
|
try {
|
||||||
|
Field field = target.getClass().getDeclaredField(fieldName);
|
||||||
|
boolean accessible =field.isAccessible();
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(target, value);
|
||||||
|
field.setAccessible(accessible);
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
|
// Should not occur, to be taken care of in test code.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initHttpMock() {
|
||||||
|
mockStatic(HttpClientBuilder.class);
|
||||||
|
when(HttpClientBuilder.create()).thenReturn(httpMockBuilder);
|
||||||
|
when(httpMockBuilder.setSSLContext(null)).thenReturn(httpMockBuilder);
|
||||||
|
when(httpMockBuilder.build()).thenReturn(httpMock);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mockResponse(int status, String body, ContentType type) throws IOException {
|
||||||
|
when(httpMock.execute(any())).thenReturn(responseMock);
|
||||||
|
when(responseMock.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), status, ""));
|
||||||
|
when(responseMock.getEntity()).thenReturn(new StringEntity(body, type));
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -16,21 +16,19 @@
|
|||||||
|
|
||||||
package de.stklcode.jvault.connector;
|
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.*;
|
||||||
import de.stklcode.jvault.connector.model.response.*;
|
import de.stklcode.jvault.connector.model.response.*;
|
||||||
import de.stklcode.jvault.connector.factory.HTTPVaultConnectorFactory;
|
import de.stklcode.jvault.connector.factory.HTTPVaultConnectorFactory;
|
||||||
import de.stklcode.jvault.connector.test.Credentials;
|
import de.stklcode.jvault.connector.test.Credentials;
|
||||||
import de.stklcode.jvault.connector.test.VaultConfiguration;
|
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 de.stklcode.jvault.connector.factory.VaultConnectorFactory;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
import org.junit.rules.TemporaryFolder;
|
import org.junit.rules.TemporaryFolder;
|
||||||
import org.junit.rules.TestName;
|
import org.junit.rules.TestName;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -50,21 +48,24 @@ import static org.junit.Assume.*;
|
|||||||
* @since 0.1
|
* @since 0.1
|
||||||
*/
|
*/
|
||||||
public class HTTPVaultConnectorTest {
|
public class HTTPVaultConnectorTest {
|
||||||
private static String KEY = "81011a8061e5c028bd0d9503eeba40bd9054b9af0408d080cb24f57405c27a61";
|
private static final String VAULT_VERISON = "0.8.3"; // the vault version this test is supposed to run against
|
||||||
private static String TOKEN_ROOT = "d1bd50e2-587b-6e68-d80b-a9a507625cb7";
|
private static final String KEY = "81011a8061e5c028bd0d9503eeba40bd9054b9af0408d080cb24f57405c27a61";
|
||||||
private static String USER_VALID = "validUser";
|
private static final String TOKEN_ROOT = "d1bd50e2-587b-6e68-d80b-a9a507625cb7";
|
||||||
private static String PASS_VALID = "validPass";
|
private static final String USER_VALID = "validUser";
|
||||||
private static String APP_ID = "152AEA38-85FB-47A8-9CBD-612D645BFACA";
|
private static final String PASS_VALID = "validPass";
|
||||||
private static String USER_ID = "5ADF8218-D7FB-4089-9E38-287465DBF37E";
|
private static final String APP_ID = "152AEA38-85FB-47A8-9CBD-612D645BFACA";
|
||||||
private static String APPROLE_ROLE_NAME = "testrole1"; // role with secret ID
|
private static final String USER_ID = "5ADF8218-D7FB-4089-9E38-287465DBF37E";
|
||||||
private static String APPROLE_ROLE = "627b6400-90c3-a239-49a9-af65a448ca10";
|
private static final String APPROLE_ROLE_NAME = "testrole1"; // role with secret ID
|
||||||
private static String APPROLE_SECRET = "5e8b0e99-d906-27f5-f043-ccb9bb53b5e8";
|
private static final String APPROLE_ROLE = "627b6400-90c3-a239-49a9-af65a448ca10";
|
||||||
private static String APPROLE_ROLE2 = "35b7bf43-9644-588a-e68f-2e8313bb23b7"; // role with CIDR subnet
|
private static final String APPROLE_SECRET = "5e8b0e99-d906-27f5-f043-ccb9bb53b5e8";
|
||||||
private static String SECRET_PATH = "userstore";
|
private static final String APPROLE_SECRET_ACCESSOR = "071e2e9d-742a-fc3c-3fd3-1f4004b0420a";
|
||||||
private static String SECRET_KEY = "foo";
|
private static final String APPROLE_ROLE2_NAME = "testrole2"; // role with CIDR subnet
|
||||||
private static String SECRET_VALUE = "bar";
|
private static final String APPROLE_ROLE2 = "35b7bf43-9644-588a-e68f-2e8313bb23b7";
|
||||||
private static String SECRET_KEY_JSON = "json";
|
private static final String SECRET_PATH = "userstore";
|
||||||
private static String SECRET_KEY_COMPLEX = "complex";
|
private static final String SECRET_KEY = "foo";
|
||||||
|
private static final String SECRET_VALUE = "bar";
|
||||||
|
private static final String SECRET_KEY_JSON = "json";
|
||||||
|
private static final String SECRET_KEY_COMPLEX = "complex";
|
||||||
|
|
||||||
private Process vaultProcess;
|
private Process vaultProcess;
|
||||||
private VaultConnector connector;
|
private VaultConnector connector;
|
||||||
@ -113,6 +114,70 @@ public class HTTPVaultConnectorTest {
|
|||||||
vaultProcess.destroy();
|
vaultProcess.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test sealing and unsealing Vault.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void sealTest() throws VaultConnectorException {
|
||||||
|
SealResponse sealStatus = connector.sealStatus();
|
||||||
|
assumeFalse(sealStatus.isSealed());
|
||||||
|
|
||||||
|
/* Unauthorized sealing should fail */
|
||||||
|
try {
|
||||||
|
connector.seal();
|
||||||
|
fail("Unauthorized sealing succeeded");
|
||||||
|
} catch (VaultConnectorException e) {
|
||||||
|
assertThat("Vault sealed, although sealing failed", sealStatus.isSealed(), is(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Root user should be able to seal */
|
||||||
|
authRoot();
|
||||||
|
assumeTrue(connector.isAuthorized());
|
||||||
|
try {
|
||||||
|
connector.seal();
|
||||||
|
sealStatus = connector.sealStatus();
|
||||||
|
assertThat("Vault not sealed", sealStatus.isSealed(), is(true));
|
||||||
|
sealStatus = connector.unseal(KEY);
|
||||||
|
assertThat("Vault not unsealed", sealStatus.isSealed(), is(false));
|
||||||
|
} catch (VaultConnectorException e) {
|
||||||
|
fail("Sealing failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test health status
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void healthTest() {
|
||||||
|
HealthResponse res = null;
|
||||||
|
try {
|
||||||
|
res = connector.getHealth();
|
||||||
|
} catch (VaultConnectorException e) {
|
||||||
|
fail("Retrieving health status failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
assertThat("Health response should be set", res, is(notNullValue()));
|
||||||
|
assertThat("Unexpected version", res.getVersion(), is(VAULT_VERISON));
|
||||||
|
assertThat("Unexpected init status", res.isInitialized(), is(true));
|
||||||
|
assertThat("Unexpected seal status", res.isSealed(), is(false));
|
||||||
|
assertThat("Unexpected standby status", res.isStandby(), is(false));
|
||||||
|
|
||||||
|
// No seal vault and verify correct status.
|
||||||
|
authRoot();
|
||||||
|
try {
|
||||||
|
connector.seal();
|
||||||
|
assumeTrue(connector.sealStatus().isSealed());
|
||||||
|
connector.resetAuth(); // SHould work unauthenticated
|
||||||
|
} catch (VaultConnectorException e) {
|
||||||
|
fail("Unexpected exception on sealing: " + e.getMessage());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
res = connector.getHealth();
|
||||||
|
} catch (VaultConnectorException e) {
|
||||||
|
fail("Retrieving health status failed when sealed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
assertThat("Unexpected seal status", res.isSealed(), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test listing of authentication backends
|
* Test listing of authentication backends
|
||||||
*/
|
*/
|
||||||
@ -191,6 +256,23 @@ public class HTTPVaultConnectorTest {
|
|||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public void authAppIdTest() {
|
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();
|
authRoot();
|
||||||
assumeTrue(connector.isAuthorized());
|
assumeTrue(connector.isAuthorized());
|
||||||
|
|
||||||
@ -285,6 +367,65 @@ public class HTTPVaultConnectorTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void createAppRoleTest() {
|
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();
|
authRoot();
|
||||||
assumeTrue(connector.isAuthorized());
|
assumeTrue(connector.isAuthorized());
|
||||||
|
|
||||||
@ -310,15 +451,16 @@ public class HTTPVaultConnectorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Lookup role ID */
|
/* Lookup role ID */
|
||||||
|
String roleID = "";
|
||||||
try {
|
try {
|
||||||
String res = connector.getAppRoleID(roleName);
|
roleID = connector.getAppRoleID(roleName);
|
||||||
assertThat("Role ID lookup returned empty ID.", res, is(not(emptyString())));
|
assertThat("Role ID lookup returned empty ID.", roleID, is(not(emptyString())));
|
||||||
} catch (VaultConnectorException e) {
|
} catch (VaultConnectorException e) {
|
||||||
fail("Role ID lookup failed.");
|
fail("Role ID lookup failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set custom role ID */
|
/* Set custom role ID */
|
||||||
String roleID = "custom-role-id";
|
roleID = "custom-role-id";
|
||||||
try {
|
try {
|
||||||
connector.setAppRoleID(roleName, roleID);
|
connector.setAppRoleID(roleName, roleID);
|
||||||
} catch (VaultConnectorException e) {
|
} catch (VaultConnectorException e) {
|
||||||
@ -377,7 +519,8 @@ public class HTTPVaultConnectorTest {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
AppRoleResponse res = connector.lookupAppRole(roleName);
|
AppRoleResponse res = connector.lookupAppRole(roleName);
|
||||||
assertThat("Role lookuo returned wrong policy count", res.getRole().getPolicies(), hasSize(2));
|
// Note: As of Vault 0.8.3 default policy is not added automatically, so this test should return 1, not 2.
|
||||||
|
assertThat("Role lookuo returned wrong policy count (before Vault 0.8.3 is should be 2)", res.getRole().getPolicies(), hasSize(1));
|
||||||
assertThat("Role lookuo returned wrong policies", res.getRole().getPolicies(), hasItem("testpolicy"));
|
assertThat("Role lookuo returned wrong policies", res.getRole().getPolicies(), hasItem("testpolicy"));
|
||||||
} catch (VaultConnectorException e) {
|
} catch (VaultConnectorException e) {
|
||||||
fail("Creation of role by name failed.");
|
fail("Creation of role by name failed.");
|
||||||
@ -444,6 +587,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.
|
* Test reading of secrets.
|
||||||
*/
|
*/
|
||||||
@ -696,7 +884,7 @@ public class HTTPVaultConnectorTest {
|
|||||||
fail("Secret written to inaccessible path.");
|
fail("Secret written to inaccessible path.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Overwrite token */
|
/* Overwrite token should fail as of Vault 0.8.0 */
|
||||||
token = new TokenBuilder()
|
token = new TokenBuilder()
|
||||||
.withId("test-id2")
|
.withId("test-id2")
|
||||||
.withDisplayName("test name 3")
|
.withDisplayName("test name 3")
|
||||||
@ -707,19 +895,13 @@ public class HTTPVaultConnectorTest {
|
|||||||
.withTtl(1234)
|
.withTtl(1234)
|
||||||
.build();
|
.build();
|
||||||
try {
|
try {
|
||||||
AuthResponse res = connector.createToken(token);
|
connector.createToken(token);
|
||||||
assertThat("Invalid token ID returned.", res.getAuth().getClientToken(), is("test-id2"));
|
fail("Overwriting token should fail as of Vault 0.8.0");
|
||||||
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));
|
|
||||||
} catch (VaultConnectorException e) {
|
} 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 +926,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.
|
* Initialize Vault with resource datastore and generated configuration.
|
||||||
*
|
*
|
||||||
@ -776,8 +979,7 @@ public class HTTPVaultConnectorTest {
|
|||||||
bw = new BufferedWriter(new FileWriter(configFile));
|
bw = new BufferedWriter(new FileWriter(configFile));
|
||||||
bw.write(config.toString());
|
bw.write(config.toString());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
throw new IllegalStateException("Unable to generate config file.", e);
|
||||||
throw new IllegalStateException("Unable to generate config file.");
|
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
if (bw != null)
|
if (bw != null)
|
||||||
@ -791,8 +993,7 @@ public class HTTPVaultConnectorTest {
|
|||||||
try {
|
try {
|
||||||
vaultProcess = Runtime.getRuntime().exec("vault server -config " + configFile.toString());
|
vaultProcess = Runtime.getRuntime().exec("vault server -config " + configFile.toString());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
throw new IllegalStateException("Unable to start vault. Make sure vault binary is in your executable path.", e);
|
||||||
throw new IllegalStateException("Unable to start vault. Make sure vault binary is in your executable path.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* 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.model;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParseException;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.emptyString;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
import static org.hamcrest.junit.MatcherAssume.assumeThat;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JUnit Test for AppRoleSecret model.
|
||||||
|
*
|
||||||
|
* @author Stefan Kalscheuer
|
||||||
|
* @since 0.5.0
|
||||||
|
*/
|
||||||
|
public class AppRoleSecretTest {
|
||||||
|
|
||||||
|
private static final String TEST_ID = "abc123";
|
||||||
|
private static final Map<String, Object> TEST_META = new HashMap<>();
|
||||||
|
private static final List<String> TEST_CIDR = Arrays.asList("203.0.113.0/24", "198.51.100.0/24");
|
||||||
|
|
||||||
|
static {
|
||||||
|
TEST_META.put("foo", "bar");
|
||||||
|
TEST_META.put("number", 1337);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test constructors.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void constructorTest() {
|
||||||
|
/* Empty constructor */
|
||||||
|
AppRoleSecret secret = new AppRoleSecret();
|
||||||
|
assertThat(secret.getId(), is(nullValue()));
|
||||||
|
assertThat(secret.getAccessor(), is(nullValue()));
|
||||||
|
assertThat(secret.getMetadata(), is(nullValue()));
|
||||||
|
assertThat(secret.getCidrList(), is(nullValue()));
|
||||||
|
assertThat(secret.getCidrListString(), is(emptyString()));
|
||||||
|
assertThat(secret.getCreationTime(), is(nullValue()));
|
||||||
|
assertThat(secret.getExpirationTime(), is(nullValue()));
|
||||||
|
assertThat(secret.getLastUpdatedTime(), is(nullValue()));
|
||||||
|
assertThat(secret.getNumUses(), is(nullValue()));
|
||||||
|
assertThat(secret.getTtl(), is(nullValue()));
|
||||||
|
|
||||||
|
/* Constructor with ID */
|
||||||
|
secret = new AppRoleSecret(TEST_ID);
|
||||||
|
assertThat(secret.getId(), is(TEST_ID));
|
||||||
|
assertThat(secret.getAccessor(), is(nullValue()));
|
||||||
|
assertThat(secret.getMetadata(), is(nullValue()));
|
||||||
|
assertThat(secret.getCidrList(), is(nullValue()));
|
||||||
|
assertThat(secret.getCidrListString(), is(emptyString()));
|
||||||
|
assertThat(secret.getCreationTime(), is(nullValue()));
|
||||||
|
assertThat(secret.getExpirationTime(), is(nullValue()));
|
||||||
|
assertThat(secret.getLastUpdatedTime(), is(nullValue()));
|
||||||
|
assertThat(secret.getNumUses(), is(nullValue()));
|
||||||
|
assertThat(secret.getTtl(), is(nullValue()));
|
||||||
|
|
||||||
|
/* Constructor with Metadata and CIDR bindings */
|
||||||
|
secret = new AppRoleSecret(TEST_ID, TEST_META, TEST_CIDR);
|
||||||
|
assertThat(secret.getId(), is(TEST_ID));
|
||||||
|
assertThat(secret.getAccessor(), is(nullValue()));
|
||||||
|
assertThat(secret.getMetadata(), is(TEST_META));
|
||||||
|
assertThat(secret.getCidrList(), is(TEST_CIDR));
|
||||||
|
assertThat(secret.getCidrListString(), is(String.join(",", TEST_CIDR)));
|
||||||
|
assertThat(secret.getCreationTime(), is(nullValue()));
|
||||||
|
assertThat(secret.getExpirationTime(), is(nullValue()));
|
||||||
|
assertThat(secret.getLastUpdatedTime(), is(nullValue()));
|
||||||
|
assertThat(secret.getNumUses(), is(nullValue()));
|
||||||
|
assertThat(secret.getTtl(), is(nullValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test setter.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void setterTest() {
|
||||||
|
AppRoleSecret secret = new AppRoleSecret(TEST_ID);
|
||||||
|
assertThat(secret.getCidrList(), is(nullValue()));
|
||||||
|
assertThat(secret.getCidrListString(), is(emptyString()));
|
||||||
|
secret.setCidrList(TEST_CIDR);
|
||||||
|
assertThat(secret.getCidrList(), is(TEST_CIDR));
|
||||||
|
assertThat(secret.getCidrListString(), is(String.join(",", TEST_CIDR)));
|
||||||
|
secret.setCidrList(null);
|
||||||
|
assertThat(secret.getCidrList(), is(nullValue()));
|
||||||
|
assertThat(secret.getCidrListString(), is(emptyString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test JSON (de)serialization.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void jsonTest() throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
|
/* A simple roundtrip first. All set fields should be present afterwards. */
|
||||||
|
AppRoleSecret secret = new AppRoleSecret(TEST_ID, TEST_META, TEST_CIDR);
|
||||||
|
String secretJson = "";
|
||||||
|
try {
|
||||||
|
secretJson = mapper.writeValueAsString(secret);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail("Serialization failed");
|
||||||
|
}
|
||||||
|
/* CIDR list is comma-separated when used as input, but List otherwise, hence convert string to list */
|
||||||
|
secretJson = commaSeparatedToList(secretJson);
|
||||||
|
|
||||||
|
AppRoleSecret secret2;
|
||||||
|
try {
|
||||||
|
secret2 = mapper.readValue(secretJson, AppRoleSecret.class);
|
||||||
|
assertThat(secret.getId(), is(secret2.getId()));
|
||||||
|
assertThat(secret.getMetadata(), is(secret2.getMetadata()));
|
||||||
|
assertThat(secret.getCidrList(), is(secret2.getCidrList()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail("Deserialization failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test fields, that should not be written to JSON */
|
||||||
|
setPrivateField(secret, "accessor", "TEST_ACCESSOR");
|
||||||
|
assumeThat(secret.getAccessor(), is("TEST_ACCESSOR"));
|
||||||
|
setPrivateField(secret, "creationTime", "TEST_CREATION");
|
||||||
|
assumeThat(secret.getCreationTime(), is("TEST_CREATION"));
|
||||||
|
setPrivateField(secret, "expirationTime", "TEST_EXPIRATION");
|
||||||
|
assumeThat(secret.getExpirationTime(), is("TEST_EXPIRATION"));
|
||||||
|
setPrivateField(secret, "lastUpdatedTime", "TEST_UPDATETIME");
|
||||||
|
assumeThat(secret.getLastUpdatedTime(), is("TEST_UPDATETIME"));
|
||||||
|
setPrivateField(secret, "numUses", 678);
|
||||||
|
assumeThat(secret.getNumUses(), is(678));
|
||||||
|
setPrivateField(secret, "ttl", 12345);
|
||||||
|
assumeThat(secret.getTtl(), is(12345));
|
||||||
|
try {
|
||||||
|
secretJson = mapper.writeValueAsString(secret);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail("Serialization failed");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
secret2 = mapper.readValue(commaSeparatedToList(secretJson), AppRoleSecret.class);
|
||||||
|
assertThat(secret.getId(), is(secret2.getId()));
|
||||||
|
assertThat(secret.getMetadata(), is(secret2.getMetadata()));
|
||||||
|
assertThat(secret.getCidrList(), is(secret2.getCidrList()));
|
||||||
|
assertThat(secret2.getAccessor(), is(nullValue()));
|
||||||
|
assertThat(secret2.getCreationTime(), is(nullValue()));
|
||||||
|
assertThat(secret2.getExpirationTime(), is(nullValue()));
|
||||||
|
assertThat(secret2.getLastUpdatedTime(), is(nullValue()));
|
||||||
|
assertThat(secret2.getNumUses(), is(nullValue()));
|
||||||
|
assertThat(secret2.getTtl(), is(nullValue()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail("Deserialization failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Those fields should be deserialized from JSON though */
|
||||||
|
secretJson = "{\"secret_id\":\"abc123\",\"metadata\":{\"number\":1337,\"foo\":\"bar\"}," +
|
||||||
|
"\"cidr_list\":[\"203.0.113.0/24\",\"198.51.100.0/24\"],\"secret_id_accessor\":\"TEST_ACCESSOR\"," +
|
||||||
|
"\"creation_time\":\"TEST_CREATION\",\"expiration_time\":\"TEST_EXPIRATION\"," +
|
||||||
|
"\"last_updated_time\":\"TEST_LASTUPDATE\",\"secret_id_num_uses\":678,\"secret_id_ttl\":12345}";
|
||||||
|
try {
|
||||||
|
secret2 = mapper.readValue(secretJson, AppRoleSecret.class);
|
||||||
|
assertThat(secret2.getAccessor(), is("TEST_ACCESSOR"));
|
||||||
|
assertThat(secret2.getCreationTime(), is("TEST_CREATION"));
|
||||||
|
assertThat(secret2.getExpirationTime(), is("TEST_EXPIRATION"));
|
||||||
|
assertThat(secret2.getLastUpdatedTime(), is("TEST_LASTUPDATE"));
|
||||||
|
assertThat(secret2.getNumUses(), is(678));
|
||||||
|
assertThat(secret2.getTtl(), is(12345));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail("Deserialization failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setPrivateField(Object object, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
Field field = object.getClass().getDeclaredField(fieldName);
|
||||||
|
boolean accessible = field.isAccessible();
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(object, value);
|
||||||
|
field.setAccessible(accessible);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String commaSeparatedToList(String json) {
|
||||||
|
return json.replaceAll("\"cidr_list\":\"([^\"]*)\"", "\"cidr_list\":\\[$1\\]")
|
||||||
|
.replaceAll("(\\d+\\.\\d+\\.\\d+\\.\\d+/\\d+)", "\"$1\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -37,6 +37,7 @@ public class AuthBackendTest {
|
|||||||
assertThat(AuthBackend.forType("token"), is(AuthBackend.TOKEN));
|
assertThat(AuthBackend.forType("token"), is(AuthBackend.TOKEN));
|
||||||
assertThat(AuthBackend.forType("app-id"), is(AuthBackend.APPID));
|
assertThat(AuthBackend.forType("app-id"), is(AuthBackend.APPID));
|
||||||
assertThat(AuthBackend.forType("userpass"), is(AuthBackend.USERPASS));
|
assertThat(AuthBackend.forType("userpass"), is(AuthBackend.USERPASS));
|
||||||
|
assertThat(AuthBackend.forType("github"), is(AuthBackend.GITHUB));
|
||||||
assertThat(AuthBackend.forType(""), is(AuthBackend.UNKNOWN));
|
assertThat(AuthBackend.forType(""), is(AuthBackend.UNKNOWN));
|
||||||
assertThat(AuthBackend.forType("foobar"), is(AuthBackend.UNKNOWN));
|
assertThat(AuthBackend.forType("foobar"), is(AuthBackend.UNKNOWN));
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -45,7 +45,8 @@ public class TokenBuilderTest {
|
|||||||
private static final Integer NUM_USES = 4;
|
private static final Integer NUM_USES = 4;
|
||||||
private static final List<String> POLICIES = new ArrayList<>();
|
private static final List<String> POLICIES = new ArrayList<>();
|
||||||
private static final String POLICY = "policy";
|
private static final String POLICY = "policy";
|
||||||
private static final String POLICY_2 = "policy";
|
private static final String POLICY_2 = "policy2";
|
||||||
|
private static final String POLICY_3 = "policy3";
|
||||||
private static final Map<String, String> META = new HashMap<>();
|
private static final Map<String, String> META = new HashMap<>();
|
||||||
private static final String META_KEY = "key";
|
private static final String META_KEY = "key";
|
||||||
private static final String META_VALUE = "value";
|
private static final String META_VALUE = "value";
|
||||||
@ -138,11 +139,11 @@ public class TokenBuilderTest {
|
|||||||
assertThat(token.getPolicies(), hasSize(1));
|
assertThat(token.getPolicies(), hasSize(1));
|
||||||
assertThat(token.getPolicies(), contains(POLICY_2));
|
assertThat(token.getPolicies(), contains(POLICY_2));
|
||||||
token = new TokenBuilder()
|
token = new TokenBuilder()
|
||||||
.withPolicies(POLICIES)
|
.withPolicies(POLICY, POLICY_2)
|
||||||
.withPolicy(POLICY_2)
|
.withPolicy(POLICY_3)
|
||||||
.build();
|
.build();
|
||||||
assertThat(token.getPolicies(), hasSize(2));
|
assertThat(token.getPolicies(), hasSize(3));
|
||||||
assertThat(token.getPolicies(), contains(POLICY, POLICY_2));
|
assertThat(token.getPolicies(), contains(POLICY, POLICY_2, POLICY_3));
|
||||||
|
|
||||||
/* Add single metadata */
|
/* Add single metadata */
|
||||||
token = new TokenBuilder().withMeta(META_KEY_2, META_VALUE_2).build();
|
token = new TokenBuilder().withMeta(META_KEY_2, META_VALUE_2).build();
|
||||||
|
@ -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,56 @@
|
|||||||
|
package de.stklcode.jvault.connector.model.response;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JUnit Test for {@link AuthResponse} model.
|
||||||
|
*
|
||||||
|
* @author Stefan Kalscheuer
|
||||||
|
* @since 0.7.0
|
||||||
|
*/
|
||||||
|
public class HealthResponseTest {
|
||||||
|
private static final String CLUSTER_ID = "c9abceea-4f46-4dab-a688-5ce55f89e228";
|
||||||
|
private static final String CLUSTER_NAME = "vault-cluster-5515c810";
|
||||||
|
private static final String VERSION = "0.6.2";
|
||||||
|
private static final Long SERVER_TIME_UTC = 1469555798L;
|
||||||
|
private static final Boolean STANDBY = false;
|
||||||
|
private static final Boolean SEALED = false;
|
||||||
|
private static final Boolean INITIALIZED = true;
|
||||||
|
|
||||||
|
private static final String RES_JSON = "{\n" +
|
||||||
|
" \"cluster_id\": \"" + CLUSTER_ID + "\",\n" +
|
||||||
|
" \"cluster_name\": \"" + CLUSTER_NAME + "\",\n" +
|
||||||
|
" \"version\": \"" + VERSION + "\",\n" +
|
||||||
|
" \"server_time_utc\": " + SERVER_TIME_UTC + ",\n" +
|
||||||
|
" \"standby\": " + STANDBY + ",\n" +
|
||||||
|
" \"sealed\": " + SEALED + ",\n" +
|
||||||
|
" \"initialized\": " + INITIALIZED + "\n" +
|
||||||
|
"}";
|
||||||
|
/**
|
||||||
|
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void jsonRoundtrip() {
|
||||||
|
try {
|
||||||
|
HealthResponse res = new ObjectMapper().readValue(RES_JSON, HealthResponse.class);
|
||||||
|
assertThat("Parsed response is NULL", res, is(notNullValue()));
|
||||||
|
assertThat("Incorrect cluster ID", res.getClusterID(), is(CLUSTER_ID));
|
||||||
|
assertThat("Incorrect cluster name", res.getClusterName(), is(CLUSTER_NAME));
|
||||||
|
assertThat("Incorrect version", res.getVersion(), is(VERSION));
|
||||||
|
assertThat("Incorrect server time", res.getServerTimeUTC(), is(SERVER_TIME_UTC));
|
||||||
|
assertThat("Incorrect standby state", res.isStandby(), is(STANDBY));
|
||||||
|
assertThat("Incorrect seal state", res.isSealed(), is(SEALED));
|
||||||
|
assertThat("Incorrect initialization state", res.isInitialized(), is(INITIALIZED));
|
||||||
|
} catch (IOException e) {
|
||||||
|
fail("Health 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016 Stefan Kalscheuer
|
* Copyright 2016-2017 Stefan Kalscheuer
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
Reference in New Issue
Block a user