122 Commits

Author SHA1 Message Date
aa2619b1b0 Bump version to 0.7.1 2018-03-17 14:01:55 +01:00
88d49bc9f7 Added automatic module name for JPMS compatibility 2018-03-15 19:54:18 +01:00
27e7a2dffc Test against 0.9.5 2018-02-27 18:07:23 +01:00
41c15f285c Test against 0.9.4 2018-02-24 10:58:45 +01:00
5f419e3f9b Updated test dependencies
* JUnit 5.1.0
* Mockito 2.15.0
2018-02-20 19:25:44 +01:00
9362e245ee Minor test changes
Changed Thread.sleep() to TimeUnit.SECONDS.sleep()
2018-02-20 19:25:07 +01:00
b2082925d5 Copy Vault data directory to temp location before each test
To avoid the annoying clean before each test run (because Vault data has
been modified by previous run), the data is now copied from resource
directory to temporary location.
2018-02-04 20:04:47 +01:00
38a7d4952d Minor dependency updates
* httpcore 4.4.9
* httpclient 4.5.5
* jackon 2.9.4
2018-01-29 16:34:28 +01:00
23cea38da6 Test against 0.9.3 2018-01-29 16:30:51 +01:00
bf2da210ba Test against 0.9.2 2018-01-28 10:35:19 +01:00
91fb012acc Update copyright notice to 2018 2018-01-01 17:22:02 +01:00
61e1f3f745 Test against 0.9.1 2017-12-22 16:40:15 +01:00
50cd400ba3 Migrated tests to JUnit5 and removed PowerMock
* Unit tests are using JUnit Jupiter framework
 * Enabled support for legacy rules for now
 * Replaced PowerMock with custom ByteBuddy redefinition for the offline test
2017-11-26 18:17:13 +01:00
470dcb48ba Test framework migrated to Mockito/Powermock 2
This simple migration with the bare minimum of changes necessary solves
compatibility issues with Java 9 build environments.
2017-11-25 18:43:25 +01:00
736f23c19a Tested against 0.9.0 2017-11-16 20:34:52 +01:00
ed2b9d62a3 Preparations for 0.7.0 release 2017-10-03 17:39:03 +02:00
007b523295 Extracted nested try-blocks from response handling into new methods. 2017-10-03 17:29:11 +02:00
061c1e9743 Minor CleanUp
Reworked some JavaDoc comments and optimized imports.
2017-10-03 17:12:03 +02:00
6904ed6817 Added tests for parse exceptions. 2017-09-27 20:23:14 +02:00
1ed5d8d992 Added tests for unexpected 200 responses.
Some methods do expect code 204 (successful without result), those are now covered by tested.
2017-09-27 20:07:12 +02:00
f70fc084be Override toString() on ErrorResponse
Partially reverts last commit that added first error message to exception
without checking for presence of such.
2017-09-25 20:48:36 +02:00
4b14ab3f4b Offline tests with mocked Vault server
Added some tests that do not require an actual Vault server to test constructors and exceptional behavior.
2017-09-25 20:39:13 +02:00
29776f459e Fixed Exception class on invalid response during sealStatus() 2017-09-25 20:35:37 +02:00
4ca8aa56d2 Test constructors and exceptions on sealStatus 2017-09-24 13:23:13 +02:00
32ab9f4bb1 Updated dependencies 2017-09-24 11:39:26 +02:00
e002fc749a Adaptation to Vault 0.8 endpoints for renew and revoke leases (#11)
Breaking backwards compatibility with Vault 0.7 and below.
2017-09-24 11:08:00 +02:00
b9ad2d1551 Test against 0.8.3
Minor test adaptation, because default policy is no longer added to AppRole by default.
2017-09-23 14:46:41 +02:00
35a8c2e0fa Test constants made constant 2017-09-09 20:32:56 +02:00
89f7581d17 Test against 0.8.2 2017-09-08 19:21:41 +02:00
43511dc20b AppRole path generation with pre-formatted String 2017-08-29 09:04:04 +02:00
05b44759c0 Bundled common error messages in static inner class 2017-08-29 08:56:30 +02:00
ba17286ab3 Add Slack notification to Travis 2017-08-29 08:25:31 +02:00
51e505313a Removed deprecated method listAppRoleSecretss (#14)
Has been deprecated because of a typo in the method name in v0.6.2.
As of 0.7 it is now removed. Please use listAppRoleSecrets() instead.
2017-08-29 08:18:10 +02:00
a1784245a3 Refactored (un)seal methods to throw Exception instead of catching it (#12) 2017-08-28 19:24:52 +02:00
df7de5dd73 Health status query and response model implemented (#15) 2017-08-28 17:50:24 +02:00
23419e94f1 Preparations for 0.6.2 release 2017-08-19 12:27:20 +02:00
5b34cfcc27 Refactored extraction of auth backends
Changed iteration over keys ot iteration over entries.
Implemented unit test as part of this process.
2017-08-19 12:16:57 +02:00
b1c78b50d2 Added unit tests for response classes with embedded functionality
AppRoleResponse, AuthResponse, SecretResponse, TokenResponse
2017-08-19 11:28:04 +02:00
238ac8bd10 Do not print stacktrace in response models (#13) 2017-08-18 21:09:40 +02:00
c8a2e0784f Do not print stacktrace on PUT request (#13) 2017-08-18 20:58:57 +02:00
23f98f190b Fix typo in method name listAppRoleSecrets (#14) 2017-08-18 20:45:47 +02:00
745ab7a24c More connector unit tests
Listing of AppRole roles and secrets, seal-unseal roundtrip, closing
2017-08-18 20:27:06 +02:00
71f68f088f Unit tests for custom exceptions
... for the sake of coverage.
2017-08-18 18:28:36 +02:00
52a1abfb87 Fields of InvalidResposneException made final
Deprecated pseudo-builder methods withStatusCode() and withResponse() in
favor of additional constructor arguments to enforce fixed state.
2017-08-18 17:47:55 +02:00
4bf9df5f73 Quality Gate badge in ReadMe 2017-08-18 17:07:22 +02:00
8ae4dccdd6 Throw more speaking Exception when parsing body failed
Removed the fall-through behavior in code 200 exception.
2017-08-18 17:01:30 +02:00
7ac550230f Prevent potential NPE on SecretResponse getter 2017-08-18 16:58:33 +02:00
c1d519826c Add SonarCloud to Travis 2017-08-18 13:57:10 +02:00
a727ed960b Test against Vault 0.8.1 2017-08-16 19:41:38 +02:00
c685ec82a0 Test against Vault 0.8.0 2017-08-11 16:16:05 +02:00
934628f382 Test against Vault 0.8.0-rc1 2017-08-04 08:46:33 +02:00
ce90f9fba2 Readme 0.6.1 2017-08-04 08:37:03 +02:00
6b25113b9f Bump version to 0.6.1 2017-08-02 17:50:20 +02:00
63dc329857 Revert Travis test to Vault 0.7,3
Partially reverts e9663ef (commented out), because fixes should be released before 0.8 compatibility is finally required.
2017-08-02 17:46:56 +02:00
42094101a3 Code style
A number of style corrections in main source files.
Trimmed lines to 120 characters, added some spaces and line breaks.
Removed unused imports
2017-08-02 17:46:56 +02:00
259747afae JavaDoc fixes
Added various JavaDoc blocks for public methods in model classes and some minor style corrections.
2017-08-02 17:46:56 +02:00
d7365dcaf1 Fix typo in TokenData.getCreationTtl()
The method getCreatinTtl() has been renamed to getCreatoinTtl(),
2017-08-02 17:46:56 +02:00
c24d1cae0b Fix CredentialsPassword model 2017-08-02 17:46:56 +02:00
af7b99587f Model classes and various method parameters declared final.
As the model classes are not designed for inheritance, they are now explicitly declared final.
Same for various input parameters, as thes should be immutable in most methods.
2017-08-02 17:46:55 +02:00
13c2cce162 Bump Jackson to 2.9.0 2017-07-31 20:46:15 +02:00
e9663ef794 Fix token creation test for compatibiltiy with Vault 0.8.0 (#10)
As of Vault 0.8.0 specifying the same token ID twice is prohibited. Adapted the unit test to match this behavior.
2017-07-31 20:38:54 +02:00
3fd74a7fd2 Jackson dependency Update
Updated Jackson libraries to 2.9.0.pr4 to evaluate compatibility with upcoming release
2017-07-18 11:12:56 +02:00
21943896c7 Test against 0.7.3 2017-06-08 21:18:50 +02:00
3794f4aac6 Preparations for 0.6.0 release 2017-05-12 12:15:35 +02:00
f805a9c751 Test against 0.7.2 2017-05-09 19:32:00 +02:00
767c2cce91 ReadMe and dependency updates 2017-04-30 13:31:54 +02:00
ed703f6e53 Implement AutoCloseable 2017-04-13 19:49:47 +02:00
e767c07a61 #8 Initialization from environment variables 2017-04-13 19:46:01 +02:00
c1f6ee891b #9 Number of retries and custom timeout 2017-04-10 13:22:54 +02:00
5d46e75068 Prevent SecretResponse from raising NPE in get() 2017-04-10 12:30:36 +02:00
7a67080aa0 TlsException cleanup 2017-04-07 15:47:13 +02:00
81c28f10c1 Travis trusty environment 2017-03-19 12:57:10 +01:00
b99edb86ac .gitignore in repo 2017-03-19 12:40:13 +01:00
594b80f62b Typo fix 2017-03-19 12:13:52 +01:00
4bd614a633 Dependencies updated, Release 0.5.0 2017-03-18 14:39:49 +01:00
0f6bccff02 PNG logo 2017-03-18 14:35:00 +01:00
fca6e496d8 SecretResponse.getValue() deprecated 2017-03-18 14:28:48 +01:00
0f5540913a Logo and ReadMe updates 2017-03-18 14:28:48 +01:00
8129017ad0 #7 Convenience methods for SQL credentials 2017-03-18 14:19:40 +01:00
c0ad451134 Test against vault 0.7.0 2017-03-18 13:49:37 +01:00
5f3e285a8a Added "local" attribute for AuthMethod response (0.7.0 compatibility) 2017-03-18 13:48:47 +01:00
107244cb81 Minor fixed and test coverage 2017-02-10 11:16:31 +01:00
e877d377c0 Dependencies updated 2017-02-10 09:58:09 +01:00
a565411b22 UnitTest against 0.6.5 2017-02-10 09:54:23 +01:00
6f13af5c91 More usage examples 2017-01-09 12:48:49 +01:00
ce2de2df81 TokenBuilder with policies as vararg 2017-01-09 12:42:12 +01:00
d7e4e7e5be Writing of complex data 2017-01-09 12:41:49 +01:00
2f312d3937 Read/write/list arbitrary keys 2017-01-08 12:45:07 +01:00
2f5b6d1523 Travis 2017-01-07 21:09:29 +01:00
69874bdceb ReadMe updated 2017-01-07 19:18:37 +01:00
8ab9c23605 Copyright updated 2017-01-07 19:18:37 +01:00
324bff7e58 Additional information in POM 2016-12-30 10:16:12 +01:00
b036b73e11 Typos 2016-12-27 17:49:51 +01:00
17145e53be Minor JavaDoc corrections 2016-12-24 12:43:58 +01:00
e988833eb9 Preparations for 0.4.1 release 2016-12-24 12:24:32 +01:00
ea3b6d50cb Fix #6 Factory Null-tolerant for trusted certificate 2016-12-21 20:30:28 +01:00
3f7f88e14a Tested against 0.6.3 2016-12-14 09:08:05 +01:00
3396693120 Test stacktraces for revealing any secret information 2016-12-04 10:38:30 +01:00
ca51fed145 Unimplemented initialization method removed 2016-12-04 10:18:31 +01:00
9c216dd805 ReadMe updated 2016-12-04 10:12:35 +01:00
b98b7ab95c Dependencies updated 2016-12-04 09:52:04 +01:00
ecf398c9d0 Removed unnecessary boolean results from API 2016-11-13 18:05:36 +01:00
a80805a044 typo fix 2016-11-06 16:48:48 +01:00
2b2b86023e v0.4.0 2016-11-06 16:21:04 +01:00
3df2293741 Support for complex secrets added 2016-11-06 16:06:13 +01:00
c1a964b0d1 Lease renewal implemented 2016-11-06 15:22:50 +01:00
d2b31122b6 #2 Option to provide trusted CA certificate 2016-11-06 13:02:40 +01:00
4adefc2cda Changelog and dependency update 2016-11-06 10:51:32 +01:00
3271e5e513 Test corrections 2016-11-05 18:15:28 +01:00
40742b00de #5 Role and Secret creation implemented and tested 2016-11-05 18:01:19 +01:00
c7b4c46ad2 Test coverage increased 2016-10-24 15:53:30 +02:00
9618a50646 #4 token creation implemented 2016-10-21 18:08:26 +02:00
53a459eda1 Token metamodel implemented 2016-10-17 16:40:26 +02:00
e99809cd46 v0.4.0-SNAPSHOT 2016-10-16 18:30:25 +02:00
fc493a2e73 Secret deletion implemented and tested 2016-10-16 18:24:43 +02:00
048e4d12b4 #3 Secret revocation implemented 2016-10-15 18:38:26 +02:00
c3ad6b6edd License information in source code 2016-10-10 15:25:35 +02:00
7069eabbff Merge branch 'develop' 2016-10-07 17:03:48 +02:00
ffd97a696a Preparation for v0.3.0 2016-10-07 17:02:47 +02:00
ca529027f7 Tested against Vault 0.6.2; changelog added to repo 2016-10-06 20:18:07 +02:00
40f60cee03 v0.3.0-SNAPSHOT 2016-09-27 21:17:00 +02:00
aacbed836a #1 Retrieval of JSON objects 2016-09-27 21:13:29 +02:00
83 changed files with 7055 additions and 475 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/target/
/*.iml
/.idea/
/*.project
*~

29
.travis.yml Normal file
View File

@ -0,0 +1,29 @@
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.9.5/vault_0.9.5_linux_amd64.zip
- wget -q -O - https://releases.hashicorp.com/vault/0.9.5/vault_0.9.5_SHA256SUMS | grep linux_amd64 | sha256sum -c
- unzip vault_0.9.5_linux_amd64.zip
- rm vault_0.9.5_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="

67
CHANGELOG.md Normal file
View File

@ -0,0 +1,67 @@
## 0.7.1 [2018-03-17]
* [improvement] Added automatic module name for JPMS compatibility
* [dependencies] Minor dependency updates
* [test] Tested against Vault 0.9.5
## 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]
* [fix] Factory Null-tolerant for trusted certificate (#6)
* [test] StackTraces tested for secret leaks
* [test] Tested against Vault 0.6.4
## 0.4.0 [2016-11-06]
* [feature] Option to provide a trusted CA certificate (#2)
* [feature] Deletion, revocation and renewal of secrets (#3)
* [feature] Token creation (#4)
* [feature] AppRole auth backend supported (#5)
* [improvement] Support for complex secrets
* [deprecation] App-ID backend marked as deprecated
## 0.3.0 [2016-10-07]
* [feature] Retrieval of JSON objects (#1)
* [test] Tested against Vault 0.6.2
## 0.2.0 [2016-09-01]
* Dependecies updated and CommonsIO removed
* [fix] Fixed auth backend detection for Vault 0.6.1
* [test] Tested against Vault 0.6.1
## 0.1.1 [2016-06-20]
* [fix] Check for "permission denied" without status code 400 instead of 403
* [test] Tested against Vault 0.6.0
## 0.1.0 [2016-03-29]
* First release

116
README.md
View File

@ -1,58 +1,132 @@
Java Vault Connector
=========
# Java Vault Connector
[![Build Status](https://travis-ci.org/stklcode/jvaultconnector.svg?branch=master)](https://travis-ci.org/stklcode/jvaultconnector)
[![Quality Gate](https://sonarcloud.io/api/badges/gate?key=de.stklcode.jvault%3Aconnector)](https://sonarcloud.io/dashboard?id=de.stklcode.jvault%3Aconnector)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/stklcode/jvaultconnector/blob/master/LICENSE.txt)
[![Maven Central](https://img.shields.io/maven-central/v/de.stklcode.jvault/connector.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.stklcode.jvault%22%20AND%20a%3A%22connector%22)
![Logo](https://raw.githubusercontent.com/stklcode/jvaultconnector/master/assets/logo.png)
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
* Authorization methods:
* Ability to provide or enforce custom CA certificate
* Optional initialization from environment variables
* Authorization methods
* Token
* Username/Password
* AppID (register and authenticate)
* AppID (register and authenticate) [_deprecated_]
* AppRole (register and authenticate)
* Tokens
* Creation and lookup of tokens
* TokenBuilder for speaking creation of complex configuraitons
* Secrets
* Read secrets
* Write secrets
* List secrets
* Delete secrets
* Renew/revoke leases
* Raw secret content or JSON decoding
* SQL secret handling
* Connector Factory with builder pattern
* Tested against Vault 0.6.1
* Tested against Vault 0.9.5
**Usage Example**
## Maven Artifact
```xml
<dependency>
<groupId>de.stklcode.jvault</groupId>
<artifactId>connector</artifactId>
<version>0.7.1</version>
</dependency>
```
## Usage Examples
### Initialization
```java
// Instanciate using builder pattern style factory
// Instantiate using builder pattern style factory (TLS enabled by default)
VaultConnector vault = VaultConnectorFactory.httpFactory()
.wiithHost("127.0.0.1")
.withHost("127.0.0.1")
.withPort(8200)
.withTLS()
.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");
// 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();
// 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**
```
<dependency>
<groupId>de.stklcode.jvault</groupId>
<artifactId>connector</artifactId>
<version>0.2.0</version>
</dependency>
### Token and role creation
```java
// Create token using TokenBuilder
Token token = new TokenBuilder().withId("token id")
.withDisplayName("new test token")
.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)
[JavaDoc API](http://jvault.stklcode.de/apidocs/)
**Planned features:**
## Planned features
* Creation and modification of policies
* Implement more authentication methods
**License**
## License
The project is licensed under [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0).

BIN
assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

12
assets/logo.svg Normal file
View 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

111
pom.xml
View File

@ -2,60 +2,147 @@
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>
<name>jVaultConnector</name>
<groupId>de.stklcode.jvault</groupId>
<artifactId>connector</artifactId>
<version>0.2.0</version>
<version>0.7.1</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>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</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>
<configuration>
<archive>
<manifestEntries>
<Automatic-Module-Name>de.stklcode.jvault.connector</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</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.19.1</version>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</pluginManagement>
</build>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.5</version>
<version>4.4.9</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
<version>4.5.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.1</version>
<version>2.9.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.1</version>
<version>2.9.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-migrationsupport</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-junit</artifactId>
<version>2.0.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-rules</artifactId>
<version>1.17.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.15.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>2.15.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,27 +1,43 @@
/*
* Copyright 2016-2018 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.VaultConnectorException;
import de.stklcode.jvault.connector.model.AuthBackend;
import de.stklcode.jvault.connector.model.response.SealResponse;
import de.stklcode.jvault.connector.model.response.SecretResponse;
import de.stklcode.jvault.connector.model.response.TokenResponse;
import de.stklcode.jvault.connector.model.response.AuthResponse;
import de.stklcode.jvault.connector.model.*;
import de.stklcode.jvault.connector.model.response.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Vault Connector interface.
* Provides methods to connect with Vault backend and handle secrets.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public interface VaultConnector {
public interface VaultConnector extends AutoCloseable {
/**
* Verify that vault connection is initialized.
* @return TRUE if correctly initialized
* Default sub-path for Vault secrets.
*/
boolean init();
String PATH_SECRET = "secret";
/**
* Reset authorization information.
@ -30,126 +46,589 @@ public interface VaultConnector {
/**
* Retrieve status of vault seal.
* @return Seal status
*
* @return Seal status
* @throws VaultConnectorException on error
*/
SealResponse sealStatus();
SealResponse sealStatus() throws VaultConnectorException;
/**
* Seal vault.
* @return TRUE on success
*
* @throws VaultConnectorException on error
*/
boolean seal();
void seal() throws VaultConnectorException;
/**
* Unseal vault.
* @param key A single master share key
* @param reset Discard previously provided keys (optional)
* @return TRUE on success
*
* @param key A single master share key
* @param reset Discard previously provided keys (optional)
* @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.
* @param key A single master share key
* @return TRUE on success
*
* @param key A single master share key
* @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);
}
/**
* Query server health information.
*
* @return Health information.
* @throws VaultConnectorException on error
* @since 0.7.0
*/
HealthResponse getHealth() throws VaultConnectorException;
/**
* Get all availale authentication backends.
* @return List of backends
* @throws VaultConnectorException on error
*
* @return List of backends
* @throws VaultConnectorException on error
*/
List<AuthBackend> getAuthBackends() throws VaultConnectorException;
/**
* Authorize to Vault using token.
* @param token The token
* @return Token response
* @throws VaultConnectorException on error
*
* @param token The token
* @return Token response
* @throws VaultConnectorException on error
*/
TokenResponse authToken(final String token) throws VaultConnectorException;
/**
* Authorize to Vault using username and password.
* @param username The username
* @param password The password
* @return Authorization result
* @throws VaultConnectorException on error
*
* @param username The username
* @param password The password
* @return Authorization result
* @throws VaultConnectorException on error
*/
AuthResponse authUserPass(final String username, final String password) throws VaultConnectorException;
/**
* Authorize to Vault using AppID method.
* @param appID The App ID
* @param userID The User ID
* @return TRUE on success
* @throws VaultConnectorException on error
*
* @param appID The App ID
* @param userID The User ID
* @return The {@link AuthResponse}
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. Consider using {@link #authAppRole} instead.
*/
@Deprecated
AuthResponse authAppId(final String appID, final String userID) throws VaultConnectorException;
/**
* Register new App-ID with policy.
* @param appID The unique App-ID
* @param policy The policy to associate with
* @param displayName Arbitrary name to display
* @return TRUE on success
* @throws VaultConnectorException on error
* Authorize to Vault using AppRole method without secret ID.
*
* @param roleID The role ID
* @return The {@link AuthResponse}
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean registerAppId(final String appID, final String policy, final String displayName) throws VaultConnectorException;
default AuthResponse authAppRole(final String roleID) throws VaultConnectorException {
return authAppRole(roleID, null);
}
/**
* Register User-ID with App-ID
* @param appID The App-ID
* @param userID The User-ID
* @return TRUE on success
* @throws VaultConnectorException on error
* Authorize to Vault using AppRole method.
*
* @param roleID The role ID
* @param secretID The secret ID
* @return The {@link AuthResponse}
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AuthResponse authAppRole(final String roleID, final String secretID) throws VaultConnectorException;
/**
* Register new App-ID with policy.
*
* @param appID The unique App-ID
* @param policy The policy to associate with
* @param displayName Arbitrary name to display
* @return {@code true} on success
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. Consider using {@link #createAppRole} instead.
*/
@Deprecated
boolean registerAppId(final String appID, final String policy, final String displayName)
throws VaultConnectorException;
/**
* Register a new AppRole role from given metamodel.
*
* @param role The role
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean createAppRole(final AppRole role) throws VaultConnectorException;
/**
* Register new AppRole role with default policy.
*
* @param roleName The role name
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName) throws VaultConnectorException {
return createAppRole(roleName, new ArrayList<>());
}
/**
* Register new AppRole role with policies.
*
* @param roleName The role name
* @param policies The policies to associate with
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName, final List<String> policies) throws VaultConnectorException {
return createAppRole(roleName, policies, null);
}
/**
* Register new AppRole role with default policy and custom ID.
*
* @param roleName The role name
* @param roleID A custom role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName, final String roleID) throws VaultConnectorException {
return createAppRole(roleName, new ArrayList<>(), roleID);
}
/**
* Register new AppRole role with policies and custom ID.
*
* @param roleName The role name
* @param policies The policies to associate with
* @param roleID A custom role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
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());
}
/**
* Delete AppRole role from Vault.
*
* @param roleName The role anme
* @return {@code true} on succevss
* @throws VaultConnectorException on error
*/
boolean deleteAppRole(final String roleName) throws VaultConnectorException;
/**
* Lookup an AppRole role.
*
* @param roleName The role name
* @return Result of the lookup
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleResponse lookupAppRole(final String roleName) throws VaultConnectorException;
/**
* Retrieve ID for an AppRole role.
*
* @param roleName The role name
* @return The role ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
String getAppRoleID(final String roleName) throws VaultConnectorException;
/**
* Set custom ID for an AppRole role.
*
* @param roleName The role name
* @param roleID The role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean setAppRoleID(final String roleName, final String roleID) throws VaultConnectorException;
/**
* Register new random generated AppRole secret.
*
* @param roleName The role name
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default AppRoleSecretResponse createAppRoleSecret(final String roleName) throws VaultConnectorException {
return createAppRoleSecret(roleName, new AppRoleSecret());
}
/**
* Register new AppRole secret with custom ID.
*
* @param roleName The role name
* @param secretID A custom secret ID
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default AppRoleSecretResponse createAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException {
return createAppRoleSecret(roleName, new AppRoleSecret(secretID));
}
/**
* Register new AppRole secret with custom ID.
*
* @param roleName The role name
* @param secret The secret meta object
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleSecretResponse createAppRoleSecret(final String roleName, final AppRoleSecret secret)
throws VaultConnectorException;
/**
* Lookup an AppRole secret.
*
* @param roleName The role name
* @param secretID The secret ID
* @return Result of the lookup
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleSecretResponse lookupAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException;
/**
* Destroy an AppRole secret.
*
* @param roleName The role name
* @param secretID The secret meta object
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean destroyAppRoleSecret(final String roleName, final String secretID) throws VaultConnectorException;
/**
* List existing (accessible) AppRole roles.
*
* @return List of roles
* @throws VaultConnectorException on error
*/
List<String> listAppRoles() throws VaultConnectorException;
/**
* List existing (accessible) secret IDs for AppRole role.
*
* @param roleName The role name
* @return List of roles
* @throws VaultConnectorException on error
*/
List<String> listAppRoleSecrets(final String roleName) throws VaultConnectorException;
/**
* Register User-ID with App-ID.
*
* @param appID The App-ID
* @param userID The User-ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole.
* Consider using {@link #createAppRoleSecret} instead.
*/
@Deprecated
boolean registerUserId(final String appID, final String userID) throws VaultConnectorException;
/**
* Register new App-ID and User-ID at once.
* @param appID The App-ID
* @param policy The policy to associate with
* @param displayName Arbitrary name to display
* @param userID The User-ID
* @return TRUE on success
* @throws VaultConnectorException on error
*
* @param appID The App-ID
* @param policy The policy to associate with
* @param displayName Arbitrary name to display
* @param userID The User-ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole.
*/
default boolean registerAppUserId(final String appID, final String policy, final String displayName, final String userID) throws VaultConnectorException {
@Deprecated
default boolean registerAppUserId(final String appID,
final String policy,
final String displayName,
final String userID) throws VaultConnectorException {
return registerAppId(appID, policy, userID) && registerUserId(appID, userID);
}
/**
* Get authorization status
* @return TRUE, if successfully authorized
* Get authorization status.
*
* @return TRUE, if successfully authorized
*/
boolean isAuthorized();
/**
* Retrieve secret form Vault.
* @param key Secret identifier
* @return Secret response
* @throws VaultConnectorException on error
* Retrieve any nodes content from Vault.
*
* @param key Secret identifier
* @return Secret response
* @throws VaultConnectorException on error
* @since 0.5.0
*/
SecretResponse readSecret(final String key) throws VaultConnectorException;
SecretResponse read(final String key) throws VaultConnectorException;
/**
* Retrieve secret from Vault.
* Prefix "secret/" is automatically added to key.
*
* @param key Secret identifier
* @return Secret response
* @throws VaultConnectorException on error
*/
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.
* @param path Root path to search
* @return List of secret keys
* @throws VaultConnectorException on error
* Prefix "secret/" is automatically added to path.
*
* @param path Root path to search
* @return List of secret keys
* @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.
* Prefix "secret/" is automatically added to path.
*
* @param key Secret path
* @param value Secret value
* @return TRUE on success
* @throws VaultConnectorException on error
* @throws VaultConnectorException on error
*/
boolean 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.
* Prefix "secret/" is automatically added to path.
*
* @param key Secret path
* @throws VaultConnectorException on error
*/
default void deleteSecret(final String key) throws VaultConnectorException {
delete(PATH_SECRET + "/" + key);
}
/**
* Revoke given lease immediately.
*
* @param leaseID the lease ID
* @throws VaultConnectorException on error
*/
void revoke(final String leaseID) throws VaultConnectorException;
/**
* Renew lease with given ID.
*
* @param leaseID the lase ID
* @return Renewed lease
* @throws VaultConnectorException on error
*/
default SecretResponse renew(final String leaseID) throws VaultConnectorException {
return renew(leaseID, null);
}
/**
* Renew lease with given ID.
*
* @param leaseID the lase ID
* @param increment number of seconds to extend lease time
* @return Renewed lease
* @throws VaultConnectorException on error
*/
SecretResponse renew(final String leaseID, final Integer increment) throws VaultConnectorException;
/**
* Create a new token.
*
* @param token the token
* @return the result response
* @throws VaultConnectorException on error
*/
AuthResponse createToken(final Token token) throws VaultConnectorException;
/**
* Create a new token.
*
* @param token the token
* @param orphan create orphan token
* @return the result response
* @throws VaultConnectorException on error
*/
AuthResponse createToken(final Token token, boolean orphan) throws VaultConnectorException;
/**
* Create a new token for specific role.
*
* @param token the token
* @param role the role name
* @return the result response
* @throws VaultConnectorException on error
*/
AuthResponse createToken(final Token token, final String role) throws VaultConnectorException;
/**
* Lookup token information.
*
* @param token the token
* @return the result response
* @throws VaultConnectorException on error
*/
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);
}
}

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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;
/**

View File

@ -1,24 +1,59 @@
/*
* Copyright 2016-2018 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;
/**
* Exception thrown on problems with connection to Vault backend.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public class ConnectionException extends VaultConnectorException {
/**
* Constructs a new empty exception.
*/
public ConnectionException() {
}
public ConnectionException(String message) {
/**
* Constructs a new exception with the specified detail message.
*
* @param message the detail message
*/
public ConnectionException(final String message) {
super(message);
}
public ConnectionException(Throwable cause) {
/**
* Constructs a new exception with the specified cause.
*
* @param cause the cause
*/
public ConnectionException(final Throwable cause) {
super(cause);
}
public ConnectionException(String message, Throwable cause) {
/**
* Constructs a new exception with the specified detail message and cause.
*
* @param message the detail message
* @param cause the cause
*/
public ConnectionException(final String message, final Throwable cause) {
super(message, cause);
}
}

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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;
/**
@ -7,18 +23,37 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public class InvalidRequestException extends VaultConnectorException {
/**
* Constructs a new empty exception.
*/
public InvalidRequestException() {
}
public InvalidRequestException(String message) {
/**
* Constructs a new exception with the specified detail message.
*
* @param message the detail message
*/
public InvalidRequestException(final String message) {
super(message);
}
public InvalidRequestException(Throwable cause) {
/**
* Constructs a new exception with the specified cause.
*
* @param cause the cause
*/
public InvalidRequestException(final Throwable cause) {
super(cause);
}
public InvalidRequestException(String message, Throwable cause) {
/**
* Constructs a new exception with the specified detail message and cause.
*
* @param message the detail message
* @param cause the cause
*/
public InvalidRequestException(final String message, final Throwable cause) {
super(message, cause);
}
}

View File

@ -1,45 +1,179 @@
/*
* Copyright 2016-2018 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;
/**
* Exception thrown when response from vault returned with erroneous status code or payload could not be parsed
* to entity class.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public class InvalidResponseException extends VaultConnectorException {
private Integer statusCode;
private String response;
public final class InvalidResponseException extends VaultConnectorException {
private final Integer statusCode;
private final String response;
/**
* Constructs a new empty exception.
*/
public InvalidResponseException() {
this.statusCode = null;
this.response = null;
}
public InvalidResponseException(String message) {
/**
* Constructs a new exception with the specified detail message.
*
* @param message The detail message
*/
public InvalidResponseException(final String message) {
super(message);
this.statusCode = null;
this.response = null;
}
public InvalidResponseException(Throwable cause) {
/**
* Constructs a new exception with the specified cause.
*
* @param cause The cause
*/
public InvalidResponseException(final Throwable cause) {
super(cause);
this.statusCode = null;
this.response = null;
}
public InvalidResponseException(String message, Throwable cause) {
/**
* Constructs a new exception with the specified detail message and cause.
*
* @param message The detail message
* @param cause The cause
*/
public InvalidResponseException(final String message, final Throwable cause) {
super(message, cause);
this.statusCode = null;
this.response = null;
}
public InvalidResponseException withStatusCode(Integer statusCode) {
/**
* Constructs a new exception with the specified detail message and status code.
* <p>
* The HTTP status code can be retrieved by {@link #getStatusCode()} later.
*
* @param message The detail message
* @param statusCode Status code of the HTTP response
* @since 0.6.2
*/
public InvalidResponseException(final String message, final Integer statusCode) {
super(message);
this.statusCode = statusCode;
return this;
this.response = null;
}
public InvalidResponseException withResponse(String response) {
/**
* Constructs a new exception with the specified detail message, cause and status code.
* <p>
* The HTTP status code can be retrieved by {@link #getStatusCode()} later.
*
* @param message The detail message
* @param statusCode Status code of the HTTP response
* @param cause The cause
* @since 0.6.2
*/
public InvalidResponseException(final String message, final Integer statusCode, final Throwable cause) {
this(message, statusCode, null, cause);
}
/**
* Constructs a new exception with the specified detail message, cause and status code.
* <p>
* The HTTP status code can be retrieved by {@link #getStatusCode()} later.
*
* @param message The detail message
* @param statusCode Status code of the HTTP response
* @param response HTTP response string
* @since 0.6.2
*/
public InvalidResponseException(final String message,
final Integer statusCode,
final String response) {
super(message);
this.statusCode = statusCode;
this.response = response;
return this;
}
/**
* Constructs a new exception with the specified detail message, cause and status code.
* <p>
* The HTTP status code can be retrieved by {@link #getStatusCode()} later.
*
* @param message The detail message
* @param statusCode Status code of the HTTP response
* @param response HTTP response string
* @param cause The cause
* @since 0.6.2
*/
public InvalidResponseException(final String message,
final Integer statusCode,
final String response,
final Throwable cause) {
super(message, cause);
this.statusCode = statusCode;
this.response = response;
}
/**
* Specify the HTTP status code. Can be retrieved by {@link #getStatusCode()} later.
*
* @param statusCode The status code
* @return self
* @deprecated as of 0.6.2, use constructor with status code argument instead
*/
@Deprecated
public InvalidResponseException withStatusCode(final Integer statusCode) {
return new InvalidResponseException(getMessage(), statusCode, getResponse(), getCause());
}
/**
* Specify the response string. Can be retrieved by {@link #getResponse()} later.
*
* @param response Response text
* @return self
* @deprecated use constructor with response argument instead
*/
@Deprecated
public InvalidResponseException withResponse(final String response) {
return new InvalidResponseException(getMessage(), getStatusCode(), response, getCause());
}
/**
* Retrieve the HTTP status code.
*
* @return The status code or {@code null} if none specified.
*/
public Integer getStatusCode() {
return statusCode;
}
/**
* Retrieve the response text.
*
* @return The response text or {@code null} if none specified.
*/
public String getResponse() {
return response;
}

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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;
/**
@ -7,19 +23,38 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public class PermissionDeniedException extends VaultConnectorException {
/**
* Constructs a new empty exception.
*/
public PermissionDeniedException() {
super("Permission denied");
}
public PermissionDeniedException(String message) {
/**
* Constructs a new exception with the specified detail message.
*
* @param message the detail message
*/
public PermissionDeniedException(final String message) {
super(message);
}
public PermissionDeniedException(Throwable cause) {
/**
* Constructs a new exception with the specified cause.
*
* @param cause the cause
*/
public PermissionDeniedException(final Throwable cause) {
super(cause);
}
public PermissionDeniedException(String message, Throwable cause) {
/**
* Constructs a new exception with the specified detail message and cause.
*
* @param message the detail message
* @param cause the cause
*/
public PermissionDeniedException(final String message, final Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2016-2018 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;
/**
* Exception thrown on errors with TLS connection.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
public class TlsException extends VaultConnectorException {
/**
* Constructs a new empty exception.
*/
public TlsException() {
}
/**
* Constructs a new exception with the specified detail message.
*
* @param message the detail message
*/
public TlsException(final String message) {
super(message);
}
/**
* Constructs a new exception with the specified cause.
*
* @param cause the cause
*/
public TlsException(final Throwable cause) {
super(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);
}
}

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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;
/**
@ -7,18 +23,37 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public abstract class VaultConnectorException extends Exception {
/**
* Constructs a new empty exception.
*/
public VaultConnectorException() {
}
public VaultConnectorException(String message) {
/**
* Constructs a new exception with the specified detail message.
*
* @param message the detail message
*/
public VaultConnectorException(final String message) {
super(message);
}
public VaultConnectorException(Throwable cause) {
/**
* Constructs a new exception with the specified cause.
*
* @param cause the cause
*/
public VaultConnectorException(final Throwable cause) {
super(cause);
}
public VaultConnectorException(String message, Throwable cause) {
/**
* Constructs a new exception with the specified detail message and cause.
*
* @param message the detail message
* @param cause the cause
*/
public VaultConnectorException(final String message, final Throwable cause) {
super(message, cause);
}
}

View File

@ -1,23 +1,67 @@
/*
* Copyright 2016-2018 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.ConnectionException;
import de.stklcode.jvault.connector.exception.TlsException;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
/**
* Vault Connector Factory implementation for HTTP Vault connectors.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
public final class HTTPVaultConnectorFactory extends VaultConnectorFactory {
private static final String ENV_VAULT_ADDR = "VAULT_ADDR";
private static final String ENV_VAULT_CACERT = "VAULT_CACERT";
private static final String ENV_VAULT_TOKEN = "VAULT_TOKEN";
private static final String ENV_VAULT_MAX_RETRIES = "VAULT_MAX_RETRIES";
public static final String DEFAULT_HOST = "127.0.0.1";
public static final Integer DEFAULT_PORT = 8200;
public static final boolean DEFAULT_TLS = true;
public static final String DEFAULT_PREFIX = "/v1/";
public static final int DEFAULT_NUMBER_OF_RETRIES = 0;
private String host;
private Integer port;
private boolean tls;
private String prefix;
private SSLContext sslContext;
private int numberOfRetries;
private Integer timeout;
private String token;
/**
* Default empty constructor.
@ -28,49 +72,55 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
port = DEFAULT_PORT;
tls = DEFAULT_TLS;
prefix = DEFAULT_PREFIX;
numberOfRetries = DEFAULT_NUMBER_OF_RETRIES;
}
/**
* Set hostname (default: 127.0.0.1)
* @param host Hostname or IP address
* @return self
* Set hostname (default: 127.0.0.1).
*
* @param host Hostname or IP address
* @return self
*/
public HTTPVaultConnectorFactory withHost(String host) {
public HTTPVaultConnectorFactory withHost(final String host) {
this.host = host;
return this;
}
/**
* Set port (default: 8200)
* @param port Vault TCP port
* @return self
* Set port (default: 8200).
*
* @param port Vault TCP port
* @return self
*/
public HTTPVaultConnectorFactory withPort(Integer port) {
public HTTPVaultConnectorFactory withPort(final Integer port) {
this.port = port;
return this;
}
/**
* Set TLS usage (default: TRUE)
* @param useTLS use TLS or not
* @return self
* Set TLS usage (default: TRUE).
*
* @param useTLS use TLS or not
* @return self
*/
public HTTPVaultConnectorFactory withTLS(boolean useTLS) {
public HTTPVaultConnectorFactory withTLS(final boolean useTLS) {
this.tls = useTLS;
return this;
}
/**
* Convenience Method for TLS usage (enabled by default)
* @return self
* Convenience Method for TLS usage (enabled by default).
*
* @return self
*/
public HTTPVaultConnectorFactory withTLS() {
return withTLS(true);
}
/**
* Convenience Method for NOT using TLS
* @return self
* Convenience Method for NOT using TLS.
*
* @return self
*/
public HTTPVaultConnectorFactory withoutTLS() {
return withTLS(false);
@ -78,16 +128,185 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
/**
* Set API prefix. Default is "/v1/" and changes should not be necessary for current state of development.
* @param prefix Vault API prefix (default: "/v1/"
* @return self
*
* @param prefix Vault API prefix (default: "/v1/"
* @return self
*/
public HTTPVaultConnectorFactory withPrefix(String prefix) {
public HTTPVaultConnectorFactory withPrefix(final String prefix) {
this.prefix = prefix;
return this;
}
/**
* Add a trusted CA certifiate for HTTPS connections.
*
* @param cert path to certificate file
* @return self
* @throws VaultConnectorException on error
* @since 0.4.0
*/
public HTTPVaultConnectorFactory withTrustedCA(final Path cert) throws VaultConnectorException {
if (cert != null)
return withSslContext(createSslContext(cert));
return this;
}
/**
* Add a custom SSL context.
* Overwrites certificates set by {@link #withTrustedCA}.
*
* @param sslContext the SSL context
* @return self
* @since 0.4.0
*/
public HTTPVaultConnectorFactory withSslContext(final SSLContext sslContext) {
this.sslContext = sslContext;
return this;
}
/**
* Set token for automatic authentication, using {@link #buildAndAuth()}.
*
* @param token Vault token
* @return self
* @since 0.6.0
*/
public HTTPVaultConnectorFactory withToken(final String token) {
this.token = token;
return this;
}
/**
* Build connector based on the {@code }VAULT_ADDR} and {@code VAULT_CACERT} (optional) environment variables.
*
* @return self
* @throws VaultConnectorException if Vault address from environment variables is malformed
* @since 0.6.0
*/
public HTTPVaultConnectorFactory fromEnv() throws VaultConnectorException {
/* Parse URL from environment variable */
if (System.getenv(ENV_VAULT_ADDR) != null && !System.getenv(ENV_VAULT_ADDR).trim().isEmpty()) {
try {
URL url = new URL(System.getenv(ENV_VAULT_ADDR));
this.host = url.getHost();
this.port = url.getPort();
this.tls = url.getProtocol().equals("https");
} catch (MalformedURLException e) {
throw new ConnectionException("URL provided in environment variable malformed", e);
}
}
/* Read number of retries */
if (System.getenv(ENV_VAULT_MAX_RETRIES) != null) {
try {
numberOfRetries = Integer.parseInt(System.getenv(ENV_VAULT_MAX_RETRIES));
} catch (NumberFormatException ignored) {
/* 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
public HTTPVaultConnector build() {
return new HTTPVaultConnector(host, tls, port, prefix);
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;
}
/**
* Create SSL Context trusting only provided certificate.
*
* @param trustedCert Path to trusted CA certificate
* @return SSL context
* @throws TlsException on errors
* @since 0.4.0
*/
private SSLContext createSslContext(final Path trustedCert) throws TlsException {
try {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, createTrustManager(trustedCert), new SecureRandom());
return context;
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new TlsException("Unable to intialize SSLContext", e);
}
}
/**
* Create a custom TrustManager for given CA certificate file.
*
* @param trustedCert Path to trusted CA certificate
* @return TrustManger
* @throws TlsException on error
* @since 0.4.0
*/
private TrustManager[] createTrustManager(final Path trustedCert) throws TlsException {
try {
/* Create Keystore with trusted certificate */
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("trustedCert", certificateFromFile(trustedCert));
/* Initialize TrustManager */
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
return tmf.getTrustManagers();
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
throw new TlsException("Unable to initialize TrustManager", e);
}
}
/**
* Read given certificate file to X.509 certificate.
*
* @param certFile Path to certificate file
* @return X.509 Certificate object
* @throws TlsException on error
* @since 0.4.0
*/
private X509Certificate certificateFromFile(final Path certFile) throws TlsException {
try (InputStream is = Files.newInputStream(certFile)) {
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
} catch (IOException | CertificateException e) {
throw new TlsException("Unable to read certificate.", e);
}
}
}

View File

@ -1,18 +1,36 @@
/*
* Copyright 2016-2018 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.VaultConnector;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
/**
* Abstract Vault Connector Factory interface.
* Provides builder pattern style factory for Vault connectors.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public abstract class VaultConnectorFactory {
/**
* Get Factory implementation for HTTP Vault Connector
* @return HTTP Connector Factory
* Get Factory implementation for HTTP Vault Connector.
*
* @return HTTP Connector Factory
*/
public static HTTPVaultConnectorFactory httpFactory() {
return new HTTPVaultConnectorFactory();
@ -20,7 +38,17 @@ public abstract class VaultConnectorFactory {
/**
* Build command, produces connector after initialization.
* @return Vault Connector instance.
*
* @return Vault Connector instance.
*/
public abstract VaultConnector build();
/**
* Build connector and authenticate with token set in factory or from environment.
*
* @return Authenticated Vault connector instance.
* @throws VaultConnectorException if authentication failed
* @since 0.6.0
*/
public abstract VaultConnector buildAndAuth() throws VaultConnectorException;
}

View File

@ -0,0 +1,209 @@
/*
* Copyright 2016-2018 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.annotation.*;
import java.util.List;
/**
* Vault AppRole role metamodel.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRole {
@JsonProperty("role_name")
private String name;
@JsonProperty("role_id")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String id;
@JsonProperty("bind_secret_id")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean bindSecretId;
private List<String> boundCidrList;
private List<String> policies;
@JsonProperty("secret_id_num_uses")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer secretIdNumUses;
@JsonProperty("secret_id_ttl")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer secretIdTtl;
@JsonProperty("token_ttl")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer tokenTtl;
@JsonProperty("token_max_ttl")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer tokenMaxTtl;
@JsonProperty("period")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer period;
/**
* Construct empty {@link AppRole} object.
*/
public AppRole() {
}
/**
* Construct complete {@link AppRole} object.
*
* @param name Role name (required)
* @param id Role ID (optional)
* @param bindSecretId Bind secret ID (optional)
* @param boundCidrList Whitelist of subnets in CIDR notation (optional)
* @param policies List of policies (optional)
* @param secretIdNumUses Maximum number of uses per secret (optional)
* @param secretIdTtl Maximum TTL in seconds for secrets (optional)
* @param tokenTtl Token TTL in seconds (optional)
* @param tokenMaxTtl Maximum token TTL in seconds, including renewals (optional)
* @param period Duration in seconds, if set the token is a periodic token (optional)
*/
public AppRole(final String name, final String id, final Boolean bindSecretId, final List<String> boundCidrList,
final List<String> policies, final Integer secretIdNumUses, final Integer secretIdTtl,
final Integer tokenTtl, final Integer tokenMaxTtl, final Integer period) {
this.name = name;
this.id = id;
this.bindSecretId = bindSecretId;
this.boundCidrList = boundCidrList;
this.policies = policies;
this.secretIdNumUses = secretIdNumUses;
this.secretIdTtl = secretIdTtl;
this.tokenTtl = tokenTtl;
this.tokenMaxTtl = tokenMaxTtl;
this.period = period;
}
/**
* @return the role name
*/
public String getName() {
return name;
}
/**
* @return the role ID
*/
public String getId() {
return id;
}
/**
* @return bind secret ID
*/
public Boolean getBindSecretId() {
return bindSecretId;
}
/**
* @return list of bound CIDR subnets
*/
public List<String> getBoundCidrList() {
return boundCidrList;
}
/**
* @param boundCidrList list of subnets in CIDR notation to bind role to
*/
@JsonSetter("bound_cidr_list")
public void setBoundCidrList(final List<String> boundCidrList) {
this.boundCidrList = boundCidrList;
}
/**
* @return list of subnets in CIDR notation as comma-separated {@link String}
*/
@JsonGetter("bound_cidr_list")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public String getBoundCidrListString() {
if (boundCidrList == null || boundCidrList.isEmpty())
return "";
return String.join(",", boundCidrList);
}
/**
* @return list of policies
*/
public List<String> getPolicies() {
return policies;
}
/**
* @param policies list of policies
*/
@JsonSetter("policies")
public void setPolicies(final List<String> policies) {
this.policies = policies;
}
/**
* @return list of policies as comma-separated {@link String}
*/
@JsonGetter("policies")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public String getPoliciesString() {
if (policies == null || policies.isEmpty())
return "";
return String.join(",", policies);
}
/**
* @return maximum number of uses per secret
*/
public Integer getSecretIdNumUses() {
return secretIdNumUses;
}
/**
* @return maximum TTL in seconds for secrets
*/
public Integer getSecretIdTtl() {
return secretIdTtl;
}
/**
* @return token TTL in seconds
*/
public Integer getTokenTtl() {
return tokenTtl;
}
/**
* @return maximum token TTL in seconds, including renewals
*/
public Integer getTokenMaxTtl() {
return tokenMaxTtl;
}
/**
* @return duration in seconds, if specified
*/
public Integer getPeriod() {
return period;
}
}

View File

@ -0,0 +1,214 @@
/*
* Copyright 2016-2018 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 java.util.ArrayList;
import java.util.List;
/**
* A builder for vault AppRole roles..
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
public final class AppRoleBuilder {
private String name;
private String id;
private Boolean bindSecretId;
private List<String> boundCidrList;
private List<String> policies;
private Integer secretIdNumUses;
private Integer secretIdTtl;
private Integer tokenTtl;
private Integer tokenMaxTtl;
private Integer period;
/**
* Construct {@link AppRoleBuilder} with only the role name set.
*
* @param name Role name
*/
public AppRoleBuilder(final String name) {
this.name = name;
}
/**
* Add custom role ID. (optional)
*
* @param id the ID
* @return self
*/
public AppRoleBuilder withId(final String id) {
this.id = id;
return this;
}
/**
* Set if role is bound to secret ID.
*
* @param bindSecretId the display name
* @return self
*/
public AppRoleBuilder withBindSecretID(final Boolean bindSecretId) {
this.bindSecretId = bindSecretId;
return this;
}
/**
* Bind role to secret ID.
* Convenience method for {@link #withBindSecretID(Boolean)}
*
* @return self
*/
public AppRoleBuilder withBindSecretID() {
return withBindSecretID(true);
}
/**
* Do not bind role to secret ID.
* Convenience method for {@link #withBindSecretID(Boolean)}
*
* @return self
*/
public AppRoleBuilder withoutBindSecretID() {
return withBindSecretID(false);
}
/**
* Set bound CIDR blocks.
*
* @param boundCidrList List of CIDR blocks which can perform login
* @return self
*/
public AppRoleBuilder withBoundCidrList(final List<String> boundCidrList) {
this.boundCidrList = boundCidrList;
return this;
}
/**
* Add a CIDR block to list of bound blocks.
*
* @param cidrBlock the CIDR block
* @return self
*/
public AppRoleBuilder withCidrBlock(final String cidrBlock) {
if (boundCidrList == null)
boundCidrList = new ArrayList<>();
boundCidrList.add(cidrBlock);
return this;
}
/**
* Add given policies.
*
* @param policies the policies
* @return self
*/
public AppRoleBuilder withPolicies(final List<String> policies) {
if (this.policies == null)
this.policies = new ArrayList<>();
this.policies.addAll(policies);
return this;
}
/**
* Add a single policy.
*
* @param policy the policy
* @return self
*/
public AppRoleBuilder withPolicy(final String policy) {
if (this.policies == null)
this.policies = new ArrayList<>();
policies.add(policy);
return this;
}
/**
* Set number of uses for sectet IDs.
*
* @param secredIdNumUses the number of uses
* @return self
*/
public AppRoleBuilder withSecretIdNumUses(final Integer secredIdNumUses) {
this.secretIdNumUses = secredIdNumUses;
return this;
}
/**
* Set default sectet ID TTL in seconds.
*
* @param secredIdTtl the TTL
* @return self
*/
public AppRoleBuilder withSecretIdTtl(final Integer secredIdTtl) {
this.secretIdTtl = secredIdTtl;
return this;
}
/**
* Set default token TTL in seconds.
*
* @param tokenTtl the TTL
* @return self
*/
public AppRoleBuilder withTokenTtl(final Integer tokenTtl) {
this.tokenTtl = tokenTtl;
return this;
}
/**
* Set maximum token TTL in seconds.
*
* @param tokenMaxTtl the TTL
* @return self
*/
public AppRoleBuilder withTokenMaxTtl(final Integer tokenMaxTtl) {
this.tokenMaxTtl = tokenMaxTtl;
return this;
}
/**
* Set renewal period for generated token in seconds.
*
* @param period period in seconds
* @return self
*/
public AppRoleBuilder withPeriod(final Integer period) {
this.period = period;
return this;
}
/**
* Build the AppRole role based on given parameters.
*
* @return the role
*/
public AppRole build() {
return new AppRole(name,
id,
bindSecretId,
boundCidrList,
policies,
secretIdNumUses,
secretIdTtl,
tokenTtl,
tokenMaxTtl,
period);
}
}

View File

@ -0,0 +1,168 @@
/*
* Copyright 2016-2018 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.annotation.*;
import java.util.List;
import java.util.Map;
/**
* Vault AppRole role metamodel.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRoleSecret {
@JsonProperty("secret_id")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String id;
@JsonProperty(value = "secret_id_accessor", access = JsonProperty.Access.WRITE_ONLY)
private String accessor;
@JsonProperty("metadata")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private Map<String, Object> metadata;
private List<String> cidrList;
@JsonProperty(value = "creation_time", access = JsonProperty.Access.WRITE_ONLY)
private String creationTime;
@JsonProperty(value = "expiration_time", access = JsonProperty.Access.WRITE_ONLY)
private String expirationTime;
@JsonProperty(value = "last_updated_time", access = JsonProperty.Access.WRITE_ONLY)
private String lastUpdatedTime;
@JsonProperty(value = "secret_id_num_uses", access = JsonProperty.Access.WRITE_ONLY)
private Integer numUses;
@JsonProperty(value = "secret_id_ttl", access = JsonProperty.Access.WRITE_ONLY)
private Integer ttl;
/**
* Construct empty {@link AppRoleSecret} object.
*/
public AppRoleSecret() {
}
/**
* Construct {@link AppRoleSecret} with secret ID.
*
* @param id Secret ID
*/
public AppRoleSecret(final String id) {
this.id = id;
}
/**
* Construct {@link AppRoleSecret} with ID and metadata.
*
* @param id Secret ID
* @param metadata Secret metadata
* @param cidrList List of subnets in CIDR notation, the role is bound to
*/
public AppRoleSecret(final String id, final Map<String, Object> metadata, final List<String> cidrList) {
this.id = id;
this.metadata = metadata;
this.cidrList = cidrList;
}
/**
* @return Secret ID
*/
public String getId() {
return id;
}
/**
* @return Secret accessor
*/
public String getAccessor() {
return accessor;
}
/**
* @return Secret metadata
*/
public Map<String, Object> getMetadata() {
return metadata;
}
/**
* @return List of bound subnets in CIDR notation
*/
public List<String> getCidrList() {
return cidrList;
}
/**
* @param cidrList List of subnets in CIDR notation
*/
@JsonSetter("cidr_list")
public void setCidrList(final List<String> cidrList) {
this.cidrList = cidrList;
}
/**
* @return List of bound subnets in CIDR notation as comma-separated {@link String}
*/
@JsonGetter("cidr_list")
public String getCidrListString() {
if (cidrList == null || cidrList.isEmpty())
return "";
return String.join(",", cidrList);
}
/**
* @return Creation time
*/
public String getCreationTime() {
return creationTime;
}
/**
* @return Expiration time
*/
public String getExpirationTime() {
return expirationTime;
}
/**
* @return Time of last update
*/
public String getLastUpdatedTime() {
return lastUpdatedTime;
}
/**
* @return Number of uses
*/
public Integer getNumUses() {
return numUses;
}
/**
* @return Time-to-live
*/
public Integer getTtl() {
return ttl;
}
}

View File

@ -1,24 +1,53 @@
/*
* Copyright 2016-2018 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;
/**
* Currently supported authentication backends.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public enum AuthBackend {
TOKEN("token"),
APPID("app-id"),
APPROLE("approle"),
USERPASS("userpass"),
GITHUB("github"), // Not supported yet.
UNKNOWN("");
private final String type;
AuthBackend(String type) {
/**
* Construct {@link AuthBackend} of given type.
*
* @param type Backend type
*/
AuthBackend(final String type) {
this.type = type;
}
public static AuthBackend forType(String type) {
/**
* Retrieve {@link AuthBackend} value for given type string.
*
* @param type Type string
* @return Auth backend value
*/
public static AuthBackend forType(final String type) {
for (AuthBackend v : values())
if (v.type.equalsIgnoreCase(type))
return v;

View File

@ -0,0 +1,165 @@
/*
* Copyright 2016-2018 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.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import java.util.Map;
/**
* Vault Token metamodel.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class Token {
@JsonProperty("id")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String id;
@JsonProperty("display_name")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String displayName;
@JsonProperty("no_parent")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean noParent;
@JsonProperty("no_default_policy")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean noDefaultPolicy;
@JsonProperty("ttl")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer ttl;
@JsonProperty("num_uses")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer numUses;
@JsonProperty("policies")
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<String> policies;
@JsonProperty("meta")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Map<String, String> meta;
@JsonProperty("renewable")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean renewable;
/**
* Construct complete {@link Token} object.
*
* @param id Token ID (optional)
* @param displayName Token display name (optional)
* @param noParent Token has no parent (optional)
* @param noDefaultPolicy Do not add default policy (optional)
* @param ttl Token TTL in seconds (optional)
* @param numUses Number of uses (optional)
* @param policies List of policies (optional)
* @param meta Metadata (optional)
* @param renewable Is the token renewable (optional)
*/
public Token(final String id,
final String displayName,
final Boolean noParent,
final Boolean noDefaultPolicy,
final Integer ttl,
final Integer numUses,
final List<String> policies,
final Map<String, String> meta,
final Boolean renewable) {
this.id = id;
this.displayName = displayName;
this.ttl = ttl;
this.numUses = numUses;
this.noParent = noParent;
this.noDefaultPolicy = noDefaultPolicy;
this.policies = policies;
this.meta = meta;
this.renewable = renewable;
}
/**
* @return Token ID
*/
public String getId() {
return id;
}
/**
* @return Token display name
*/
public String getDisplayName() {
return displayName;
}
/**
* @return Token has no parent
*/
public Boolean getNoParent() {
return noParent;
}
/**
* @return Token has no default policy
*/
public Boolean getNoDefaultPolicy() {
return noDefaultPolicy;
}
/**
* @return Time-to-live in seconds
*/
public Integer getTtl() {
return ttl;
}
/**
* @return Number of uses
*/
public Integer getNumUses() {
return numUses;
}
/**
* @return List of policies
*/
public List<String> getPolicies() {
return policies;
}
/**
* @return Metadata
*/
public Map<String, String> getMeta() {
return meta;
}
/**
* @return Token is renewable
*/
public Boolean isRenewable() {
return renewable;
}
}

View File

@ -0,0 +1,255 @@
/*
* Copyright 2016-2018 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 java.util.*;
/**
* A builder for vault tokens.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
public final class TokenBuilder {
private String id;
private String displayName;
private Boolean noParent;
private Boolean noDefaultPolicy;
private Integer ttl;
private Integer numUses;
private List<String> policies;
private Map<String, String> meta;
private Boolean renewable;
/**
* Add token ID. (optional)
*
* @param id the ID
* @return self
*/
public TokenBuilder withId(final String id) {
this.id = id;
return this;
}
/**
* Add display name.
*
* @param displayName the display name
* @return self
*/
public TokenBuilder withDisplayName(final String displayName) {
this.displayName = displayName;
return this;
}
/**
* Set desired time to live.
*
* @param ttl the ttl
* @return self
*/
public TokenBuilder withTtl(final Integer ttl) {
this.ttl = ttl;
return this;
}
/**
* Set desired number of uses.
*
* @param numUses the number of uses
* @return self
*/
public TokenBuilder withNumUses(final Integer numUses) {
this.numUses = numUses;
return this;
}
/**
* Set TRUE if the token should be created without parent.
*
* @param noParent if TRUE, token is created as orphan
* @return self
*/
public TokenBuilder withNoParent(final boolean noParent) {
this.noParent = noParent;
return this;
}
/**
* Create token without parent.
* Convenience method for withNoParent()
*
* @return self
*/
public TokenBuilder asOrphan() {
return withNoParent(true);
}
/**
* Create token with parent.
* Convenience method for withNoParent()
*
* @return self
*/
public TokenBuilder withParent() {
return withNoParent(false);
}
/**
* Set TRUE if the default policy should not be part of this token.
*
* @param noDefaultPolicy if TRUE, default policy is not attached
* @return self
*/
public TokenBuilder withNoDefaultPolicy(final boolean noDefaultPolicy) {
this.noDefaultPolicy = noDefaultPolicy;
return this;
}
/**
* Attach default policy to token.
* Convenience method for withNoDefaultPolicy()
*
* @return self
*/
public TokenBuilder withDefaultPolicy() {
return withNoDefaultPolicy(false);
}
/**
* Do not attach default policy to token.
* Convenience method for withNoDefaultPolicy()
*
* @return self
*/
public TokenBuilder withoutDefaultPolicy() {
return withNoDefaultPolicy(true);
}
/**
* 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
* @return self
*/
public TokenBuilder withPolicies(final List<String> policies) {
if (this.policies == null)
this.policies = new ArrayList<>();
this.policies.addAll(policies);
return this;
}
/**
* Add a single policy.
*
* @param policy the policy
* @return self
*/
public TokenBuilder withPolicy(final String policy) {
if (this.policies == null)
this.policies = new ArrayList<>();
policies.add(policy);
return this;
}
/**
* Add meta data.
*
* @param meta the metadata
* @return self
*/
public TokenBuilder withMeta(final Map<String, String> meta) {
if (this.meta == null)
this.meta = new HashMap<>();
this.meta.putAll(meta);
return this;
}
/**
* Add meta data.
*
* @param key the key
* @param value the value
* @return self
*/
public TokenBuilder withMeta(final String key, final String value) {
if (this.meta == null)
this.meta = new HashMap<>();
this.meta.put(key, value);
return this;
}
/**
* Set if token is renewable.
*
* @param renewable TRUE, if renewable
* @return self
*/
public TokenBuilder withRenewable(final Boolean renewable) {
this.renewable = renewable;
return this;
}
/**
* Set token to be renewable.
* Convenience method for withRenewable()
*
* @return self
*/
public TokenBuilder renewable() {
return withRenewable(true);
}
/**
* Set token to be not renewable.
* Convenience method for withRenewable()
*
* @return self
*/
public TokenBuilder notRenewable() {
return withRenewable(false);
}
/**
* Build the token based on given parameters.
*
* @return the token
*/
public Token build() {
return new Token(id,
displayName,
noParent,
noDefaultPolicy,
ttl,
numUses,
policies,
meta,
renewable);
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2016-2018 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.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.AppRole;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Vault response for AppRole lookup.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRoleResponse extends VaultDataResponse {
private AppRole role;
@Override
public void setData(final Map<String, Object> data) throws InvalidResponseException {
ObjectMapper mapper = new ObjectMapper();
try {
/* null empty strings on list objects */
Map<String, Object> filteredData = new HashMap<>();
data.forEach((k, v) -> {
if (!(v instanceof String && ((String) v).isEmpty())) filteredData.put(k, v);
});
this.role = mapper.readValue(mapper.writeValueAsString(filteredData), AppRole.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
/**
* @return The role
*/
public AppRole getRole() {
return role;
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2016-2018 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.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.AppRoleSecret;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Vault response for AppRole lookup.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRoleSecretResponse extends VaultDataResponse {
private AppRoleSecret secret;
@Override
public void setData(final Map<String, Object> data) throws InvalidResponseException {
ObjectMapper mapper = new ObjectMapper();
try {
/* null empty strings on list objects */
Map<String, Object> filteredData = new HashMap<>();
data.forEach((k, v) -> {
if (!(v instanceof String && ((String) v).isEmpty())) filteredData.put(k, v);
});
this.secret = mapper.readValue(mapper.writeValueAsString(filteredData), AppRoleSecret.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
/**
* @return The secret
*/
public AppRoleSecret getSecret() {
return secret;
}
}

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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;
@ -16,25 +32,32 @@ import java.util.Map;
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class AuthMethodsResponse extends VaultDataResponse {
public final class AuthMethodsResponse extends VaultDataResponse {
private Map<String, AuthMethod> supportedMethods;
/**
* Construct empty {@link AuthMethodsResponse} object.
*/
public AuthMethodsResponse() {
this.supportedMethods = new HashMap<>();
}
@Override
public void setData(Map<String, Object> data) throws InvalidResponseException {
public void setData(final Map<String, Object> data) throws InvalidResponseException {
ObjectMapper mapper = new ObjectMapper();
for (String path : data.keySet()) {
for (Map.Entry<String, Object> entry : data.entrySet()) {
try {
this.supportedMethods.put(path, mapper.readValue(mapper.writeValueAsString(data.get(path)), AuthMethod.class));
this.supportedMethods.put(entry.getKey(),
mapper.readValue(mapper.writeValueAsString(entry.getValue()), AuthMethod.class));
} catch (IOException e) {
throw new InvalidResponseException();
}
}
}
/**
* @return Supported authentication methods
*/
public Map<String, AuthMethod> getSupportedMethods() {
return supportedMethods;
}

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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;
@ -12,35 +28,46 @@ import java.util.Map;
/**
* Vault response for authentication providing auth info in {@link AuthData} field.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class AuthResponse extends VaultDataResponse {
public final class AuthResponse extends VaultDataResponse {
private Map<String, Object> data;
private AuthData auth;
/**
* Set authentication data. The input will be mapped to the {@link AuthData} model.
*
* @param auth Raw authentication data
* @throws InvalidResponseException on mapping errors
*/
@JsonProperty("auth")
public void setAuth(Map<String, Object> auth) throws InvalidResponseException {
public void setAuth(final Map<String, Object> auth) throws InvalidResponseException {
ObjectMapper mapper = new ObjectMapper();
try {
this.auth = mapper.readValue(mapper.writeValueAsString(auth), AuthData.class);
} catch (IOException e) {
e.printStackTrace();
throw new InvalidResponseException();
throw new InvalidResponseException("Failed deserializing response", e);
}
}
@Override
public void setData(Map<String, Object> data) {
public void setData(final Map<String, Object> data) {
this.data = data;
}
/**
* @return Raw data
*/
public Map<String, Object> getData() {
return data;
}
/**
* @return Authentication data
*/
public AuthData getAuth() {
return auth;
}

View File

@ -0,0 +1,49 @@
/*
* Copyright 2016-2018 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;
}
}

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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;
@ -12,11 +28,23 @@ import java.util.List;
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorResponse implements VaultResponse {
public final class ErrorResponse implements VaultResponse {
@JsonProperty("errors")
private List<String> errors;
public List<String > getErrors() {
/**
* @return List of errors
*/
public List<String> getErrors() {
return errors;
}
}
@Override
public String toString() {
if (errors == null || errors.isEmpty()) {
return "error response";
} else {
return errors.get(0);
}
}
}

View File

@ -0,0 +1,99 @@
/*
* Copyright 2016-2018 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;
}
}

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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;
@ -10,11 +26,14 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class HelpResponse implements VaultResponse {
public final class HelpResponse implements VaultResponse {
@JsonProperty("help")
private String help;
/**
* @return Help text
*/
public String getHelp() {
return help;
}
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2016-2018 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 java.util.Map;
/**
* Simple Vault data response.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class RawDataResponse extends VaultDataResponse {
private Map<String, Object> data;
@Override
public void setData(final Map<String, Object> data) {
this.data = data;
}
/**
* @return Raw data {@link Map}
*/
public Map<String, Object> getData() {
return data;
}
}

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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;
@ -10,7 +26,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SealResponse implements VaultResponse {
public final class SealResponse implements VaultResponse {
@JsonProperty("sealed")
private boolean sealed;
@ -23,18 +39,30 @@ public class SealResponse implements VaultResponse {
@JsonProperty("progress")
private Integer progress;
/**
* @return Seal status
*/
public boolean isSealed() {
return sealed;
}
/**
* @return Required threshold of secret shares
*/
public Integer getThreshold() {
return threshold;
}
/**
* @return Number of secret shares
*/
public Integer getNumberOfShares() {
return numberOfShares;
}
/**
* @return Current unseal progress (remaining required shares)
*/
public Integer getProgress() {
return progress;
}

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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;
@ -10,23 +26,31 @@ import java.util.Map;
/**
* Vault response for secret list request.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SecretListResponse extends VaultDataResponse {
public final class SecretListResponse extends VaultDataResponse {
private List<String> keys;
/**
* Set data. Extracts list of keys from raw response data.
*
* @param data Raw data
* @throws InvalidResponseException on parsing errors
*/
@JsonProperty("data")
public void setData(Map<String, Object> data) throws InvalidResponseException {
public void setData(final Map<String, Object> data) throws InvalidResponseException {
try {
this.keys = (List<String>)data.get("keys");
}
catch (ClassCastException e) {
this.keys = (List<String>) data.get("keys");
} catch (ClassCastException e) {
throw new InvalidResponseException("Keys could not be parsed from data.", e);
}
}
/**
* @return List of secret keys
*/
public List<String> getKeys() {
return keys;
}

View File

@ -1,30 +1,117 @@
/*
* Copyright 2016-2018 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.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Vault response for secret request.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SecretResponse extends VaultDataResponse {
private String value;
private Map<String, Object> data;
@Override
public void setData(Map<String, Object> data) throws InvalidResponseException {
try {
this.value = (String) data.get("value");
} catch (ClassCastException e) {
throw new InvalidResponseException("Value could not be parsed", e);
}
public final void setData(final Map<String, Object> data) throws InvalidResponseException {
this.data = data;
}
public String getValue() {
return value;
/**
* Get complete data object.
*
* @return data map
* @since 0.4.0
*/
public final Map<String, Object> getData() {
if (data == null)
return new HashMap<>();
return data;
}
}
/**
* Get a single value for given key.
*
* @param key the key
* @return the value or {@code null} if absent
* @since 0.4.0
*/
public final Object get(final String key) {
if (data == null)
return null;
return getData().get(key);
}
/**
* Get data element for key "value".
* Method for backwards compatibility in case of simple secrets.
*
* @return the value
* @deprecated Deprecated artifact, will be removed at latest at v1.0.0
*/
@Deprecated
public final String getValue() {
Object value = get("value");
if (value == null)
return null;
return value.toString();
}
/**
* Get response parsed as JSON.
*
* @param type Class to parse response
* @param <T> Class to parse response
* @return Parsed object
* @throws InvalidResponseException on parsing error
* @since 0.3
* @deprecated Deprecated artifact, will be removed at latest at v1.0.0
*/
@Deprecated
public final <T> T getValue(final Class<T> type) throws InvalidResponseException {
return get("value", type);
}
/**
* Get response parsed as JSON.
*
* @param key the key
* @param type Class to parse response
* @param <T> Class to parse response
* @return Parsed object or {@code null} if absent
* @throws InvalidResponseException on parsing error
* @since 0.4.0
*/
public final <T> T get(final String key, final Class<T> type) throws InvalidResponseException {
try {
Object rawValue = get(key);
if (rawValue == null)
return null;
return new ObjectMapper().readValue(rawValue.toString(), type);
} catch (IOException e) {
throw new InvalidResponseException("Unable to parse response payload: " + e.getMessage());
}
}
}

View File

@ -1,5 +1,20 @@
package de.stklcode.jvault.connector.model.response;
/*
* Copyright 2016-2018 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;
@ -13,27 +28,35 @@ import java.util.Map;
/**
* Vault response from token lookup providing Token information in {@link TokenData} field.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class TokenResponse extends VaultDataResponse {
public final class TokenResponse extends VaultDataResponse {
private TokenData data;
@JsonProperty("auth")
private Boolean auth;
/**
* Set data. Parses response data map to {@link TokenData}.
*
* @param data Raw response data
* @throws InvalidResponseException on parsing errors
*/
@Override
public void setData(Map<String, Object> data) throws InvalidResponseException {
public void setData(final Map<String, Object> data) throws InvalidResponseException {
ObjectMapper mapper = new ObjectMapper();
try {
this.data = mapper.readValue(mapper.writeValueAsString(data), TokenData.class);
} catch (IOException e) {
e.printStackTrace();
throw new InvalidResponseException();
throw new InvalidResponseException("Failed deserializing response", e);
}
}
/**
* @return Token data
*/
public TokenData getData() {
return data;
}

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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.JsonProperty;
@ -9,8 +25,8 @@ import java.util.Map;
/**
* Abstract Vault response with default payload fields.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public abstract class VaultDataResponse implements VaultResponse {
@JsonProperty("lease_id")
@ -25,22 +41,40 @@ public abstract class VaultDataResponse implements VaultResponse {
@JsonProperty("warnings")
private List<String> warnings;
/**
* Set data. To be implemented in the specific subclasses, as data can be of arbitrary structure.
*
* @param data Raw response data
* @throws InvalidResponseException on parsing errors
*/
@JsonProperty("data")
public abstract void setData(Map<String, Object> data) throws InvalidResponseException;
public abstract void setData(final Map<String, Object> data) throws InvalidResponseException;
public String getLeaseId() {
/**
* @return Lease ID
*/
public final String getLeaseId() {
return leaseId;
}
public boolean isRenewable() {
/**
* @return Lease is renewable
*/
public final boolean isRenewable() {
return renewable;
}
public Integer getLeaseDuration() {
/**
* @return Lease duration
*/
public final Integer getLeaseDuration() {
return leaseDuration;
}
public List<String> getWarnings() {
/**
* @return List of warnings
*/
public final List<String> getWarnings() {
return warnings;
}
}

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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;
/**

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@ -13,7 +29,7 @@ import java.util.Map;
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class AuthData {
public final class AuthData {
@JsonProperty("client_token")
private String clientToken;
@ -32,27 +48,45 @@ public class AuthData {
@JsonProperty("renewable")
private boolean renewable;
/**
* @return Client token
*/
public String getClientToken() {
return clientToken;
}
/**
* @return Token accessor
*/
public String getAccessor() {
return accessor;
}
/**
* @return List of policies
*/
public List<String> getPolicies() {
return policies;
}
/**
* @return Metadata
*/
public Map<String, Object> getMetadata() {
return metadata;
}
/**
* @return Lease duration
*/
public Integer getLeaseDuration() {
return leaseDuration;
}
/**
* @return Lease is renewable
*/
public boolean isRenewable() {
return renewable;
}
}
}

View File

@ -1,5 +1,22 @@
/*
* Copyright 2016-2018 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.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import de.stklcode.jvault.connector.model.AuthBackend;
@ -12,7 +29,8 @@ import java.util.Map;
* @author Stefan Kalscheuer
* @since 0.1
*/
public class AuthMethod {
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthMethod {
private AuthBackend type;
private String rawType;
@ -22,25 +40,50 @@ public class AuthMethod {
@JsonProperty("config")
private Map<String, String> config;
@JsonProperty("local")
private boolean local;
/**
* @param type Backend type, passed to {@link AuthBackend#forType(String)}
*/
@JsonSetter("type")
public void setType(String type) {
public void setType(final String type) {
this.rawType = type;
this.type = AuthBackend.forType(type);
}
/**
* @return Backend type
*/
public AuthBackend getType() {
return type;
}
/**
* @return Raw backend type string
*/
public String getRawType() {
return rawType;
}
/**
* @return Description
*/
public String getDescription() {
return description;
}
/**
* @return Configuration data
*/
public Map<String, String> getConfig() {
return config;
}
/**
* @return Is local backend
*/
public boolean isLocal() {
return local;
}
}

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@ -10,7 +26,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class TokenData {
public final class TokenData {
@JsonProperty("accessor")
private String accessor;
@ -18,7 +34,7 @@ public class TokenData {
private Integer creationTime;
@JsonProperty("creation_ttl")
private Integer creatinTtl;
private Integer creationTtl;
@JsonProperty("display_name")
private String name;
@ -44,47 +60,80 @@ public class TokenData {
@JsonProperty("ttl")
private Integer ttl;
/**
* @return Token accessor
*/
public String getAccessor() {
return accessor;
}
/**
* @return Creation time
*/
public Integer getCreationTime() {
return creationTime;
}
public Integer getCreatinTtl() {
return creatinTtl;
/**
* @return Creation TTL (in seconds)
*/
public Integer getCreationTtl() {
return creationTtl;
}
/**
* @return Token name
*/
public String getName() {
return name;
}
/**
* @return Token ID
*/
public String getId() {
return id;
}
/**
* @return Number of uses
*/
public Integer getNumUses() {
return numUses;
}
/**
* @return Token is orphan
*/
public boolean isOrphan() {
return orphan;
}
/**
* @return Token path
*/
public String getPath() {
return path;
}
/**
* @return Token role
*/
public String getRole() {
return role;
}
/**
* @return Token TTL (in seconds)
*/
public Integer getTtl() {
return ttl;
}
/**
* @return Metadata
*/
public String getMeta() {
return meta;
}
}
}

View File

@ -0,0 +1,483 @@
/*
* Copyright 2016-2018 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 net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
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.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.lang.reflect.Field;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import static net.bytebuddy.implementation.MethodDelegation.to;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
/**
* 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
*/
public class HTTPVaultConnectorOfflineTest {
private static final String INVALID_URL = "foo:/\\1nv4l1d_UrL";
private static HttpClientBuilder httpMockBuilder = mock(HttpClientBuilder.class);
private static CloseableHttpClient httpMock = mock(CloseableHttpClient.class);
private CloseableHttpResponse responseMock = mock(CloseableHttpResponse.class);
@BeforeAll
public static void initByteBuddy() {
// Install ByteBuddy Agent.
ByteBuddyAgent.install();
}
/**
* Helper method for redefinition of {@link HttpClientBuilder#create()} from {@link #initHttpMock()}.
*
* @return Mocked HTTP client builder.
*/
public static HttpClientBuilder create() {
return httpMockBuilder;
}
@BeforeEach
public void initHttpMock() {
// Redefine static method to return Mock on HttpClientBuilder creation.
new ByteBuddy().redefine(HttpClientBuilder.class)
.method(named("create"))
.intercept(to(HTTPVaultConnectorOfflineTest.class))
.make()
.load(HttpClientBuilder.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
// Ignore SSL context settings.
when(httpMockBuilder.setSSLContext(null)).thenReturn(httpMockBuilder);
// Re-initialize HTTP mock to ensure fresh (empty) results.
httpMock = mock(CloseableHttpClient.class);
// Mock actual client creation.
when(httpMockBuilder.build()).thenReturn(httpMock);
}
/**
* 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.
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).
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).
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.
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.
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 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));
}
}

View File

@ -0,0 +1,160 @@
/*
* Copyright 2016-2018 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.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.Is.is;
/**
* 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));
}
}

View File

@ -0,0 +1,129 @@
/*
* Copyright 2016-2018 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.contrib.java.lang.system.EnvironmentVariables;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.migrationsupport.rules.EnableRuleMigrationSupport;
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.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.fail;
/**
* JUnit test for HTTP Vault connector factory
*
* @author Stefan Kalscheuer
* @since 0.6.0
*/
@EnableRuleMigrationSupport
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;
}
}

View File

@ -0,0 +1,149 @@
/*
* Copyright 2016-2018 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.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
/**
* JUnit Test for AppRole Builder.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
public class AppRoleBuilderTest {
private static final String NAME = "TestRole";
private static final String ID = "test-id";
private static final Boolean BIND_SECRET_ID = true;
private static final List<String> BOUND_CIDR_LIST = new ArrayList<>();
private static final String CIDR_1 = "192.168.1.0/24";
private static final String CIDR_2 = "172.16.0.0/16";
private static final List<String> POLICIES = new ArrayList<>();
private static final String POLICY = "policy";
private static final String POLICY_2 = "policy2";
private static final Integer SECRET_ID_NUM_USES = 10;
private static final Integer SECRET_ID_TTL = 7200;
private static final Integer TOKEN_TTL = 4800;
private static final Integer TOKEN_MAX_TTL = 9600;
private static final Integer PERIOD = 1234;
private static final String JSON_MIN = "{\"role_name\":\"" + NAME + "\"}";
private static final String JSON_FULL = String.format("{\"role_name\":\"%s\",\"role_id\":\"%s\",\"bind_secret_id\":%s,\"bound_cidr_list\":\"%s\",\"policies\":\"%s\",\"secret_id_num_uses\":%d,\"secret_id_ttl\":%d,\"token_ttl\":%d,\"token_max_ttl\":%d,\"period\":%d}",
NAME, ID, BIND_SECRET_ID, CIDR_1, POLICY, SECRET_ID_NUM_USES, SECRET_ID_TTL, TOKEN_TTL, TOKEN_MAX_TTL, PERIOD);
@BeforeAll
public static void init() {
BOUND_CIDR_LIST.add(CIDR_1);
POLICIES.add(POLICY);
}
/**
* Build role with only a name.
*/
@Test
public void buildDefaultTest() throws JsonProcessingException {
AppRole role = new AppRoleBuilder(NAME).build();
assertThat(role.getId(), is(nullValue()));
assertThat(role.getBindSecretId(), is(nullValue()));
assertThat(role.getBoundCidrList(), is(nullValue()));
assertThat(role.getPolicies(), is(nullValue()));
assertThat(role.getSecretIdNumUses(), is(nullValue()));
assertThat(role.getSecretIdTtl(), is(nullValue()));
assertThat(role.getTokenTtl(), is(nullValue()));
assertThat(role.getTokenMaxTtl(), is(nullValue()));
assertThat(role.getPeriod(), is(nullValue()));
/* optional fields should be ignored, so JSON string should only contain role_name */
assertThat(new ObjectMapper().writeValueAsString(role), is(JSON_MIN));
}
/**
* Build token without all parameters set.
*/
@Test
public void buildFullTest() throws JsonProcessingException {
AppRole role = new AppRoleBuilder(NAME)
.withId(ID)
.withBindSecretID(BIND_SECRET_ID)
.withBoundCidrList(BOUND_CIDR_LIST)
.withPolicies(POLICIES)
.withSecretIdNumUses(SECRET_ID_NUM_USES)
.withSecretIdTtl(SECRET_ID_TTL)
.withTokenTtl(TOKEN_TTL)
.withTokenMaxTtl(TOKEN_MAX_TTL)
.withPeriod(PERIOD)
.build();
assertThat(role.getName(), is(NAME));
assertThat(role.getId(), is(ID));
assertThat(role.getBindSecretId(), is(BIND_SECRET_ID));
assertThat(role.getBoundCidrList(), is(BOUND_CIDR_LIST));
assertThat(role.getPolicies(), is(POLICIES));
assertThat(role.getSecretIdNumUses(), is(SECRET_ID_NUM_USES));
assertThat(role.getSecretIdTtl(), is(SECRET_ID_TTL));
assertThat(role.getTokenTtl(), is(TOKEN_TTL));
assertThat(role.getTokenMaxTtl(), is(TOKEN_MAX_TTL));
assertThat(role.getPeriod(), is(PERIOD));
/* Verify that all parameters are included in JSON string */
assertThat(new ObjectMapper().writeValueAsString(role), is(JSON_FULL));
}
/**
* Test convenience methods
*/
@Test
public void convenienceMethodsTest() {
/* bind_secret_id */
AppRole role = new AppRoleBuilder(NAME).build();
assertThat(role.getBindSecretId(), is(nullValue()));
role = new AppRoleBuilder(NAME).withBindSecretID().build();
assertThat(role.getBindSecretId(), is(true));
role = new AppRoleBuilder(NAME).withoutBindSecretID().build();
assertThat(role.getBindSecretId(), is(false));
/* Add single CIDR subnet */
role = new AppRoleBuilder(NAME).withCidrBlock(CIDR_2).build();
assertThat(role.getBoundCidrList(), hasSize(1));
assertThat(role.getBoundCidrList(), contains(CIDR_2));
role = new AppRoleBuilder(NAME)
.withBoundCidrList(BOUND_CIDR_LIST)
.withCidrBlock(CIDR_2)
.build();
assertThat(role.getBoundCidrList(), hasSize(2));
assertThat(role.getBoundCidrList(), contains(CIDR_1, CIDR_2));
/* Add single policy */
role = new AppRoleBuilder(NAME).withPolicy(POLICY_2).build();
assertThat(role.getPolicies(), hasSize(1));
assertThat(role.getPolicies(), contains(POLICY_2));
role = new AppRoleBuilder(NAME)
.withPolicies(POLICIES)
.withPolicy(POLICY_2)
.build();
assertThat(role.getPolicies(), hasSize(2));
assertThat(role.getPolicies(), contains(POLICY, POLICY_2));
}
}

View File

@ -0,0 +1,212 @@
/*
* Copyright 2016-2018 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.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.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.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.junit.MatcherAssume.assumeThat;
import static org.junit.jupiter.api.Assertions.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\"");
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2016-2018 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 org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
/**
* JUnit Test for AuthBackend model.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
public class AuthBackendTest {
/**
* Test forType() method.
*/
@Test
public void forTypeTest() {
assertThat(AuthBackend.forType("token"), is(AuthBackend.TOKEN));
assertThat(AuthBackend.forType("app-id"), is(AuthBackend.APPID));
assertThat(AuthBackend.forType("userpass"), is(AuthBackend.USERPASS));
assertThat(AuthBackend.forType("github"), is(AuthBackend.GITHUB));
assertThat(AuthBackend.forType(""), is(AuthBackend.UNKNOWN));
assertThat(AuthBackend.forType("foobar"), is(AuthBackend.UNKNOWN));
}
}

View File

@ -0,0 +1,161 @@
/*
* Copyright 2016-2018 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.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
/**
* JUnit Test for Token Builder.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
public class TokenBuilderTest {
private static final String ID = "test-id";
private static final String DISPLAY_NAME = "display-name";
private static final Boolean NO_PARENT = false;
private static final Boolean NO_DEFAULT_POLICY = false;
private static final Integer TTL = 123;
private static final Integer NUM_USES = 4;
private static final List<String> POLICIES = new ArrayList<>();
private static final String POLICY = "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 String META_KEY = "key";
private static final String META_VALUE = "value";
private static final String META_KEY_2 = "key2";
private static final String META_VALUE_2 = "value2";
private static final Boolean RENEWABLE = true;
private static final String JSON_FULL = "{\"id\":\"test-id\",\"display_name\":\"display-name\",\"no_parent\":false,\"no_default_policy\":false,\"ttl\":123,\"num_uses\":4,\"policies\":[\"policy\"],\"meta\":{\"key\":\"value\"},\"renewable\":true}";
@BeforeAll
public static void init() {
POLICIES.add(POLICY);
META.put(META_KEY, META_VALUE);
}
/**
* Build token without any parameters.
*/
@Test
public void buildDefaultTest() throws JsonProcessingException {
Token token = new TokenBuilder().build();
assertThat(token.getId(), is(nullValue()));
assertThat(token.getDisplayName(), is(nullValue()));
assertThat(token.getNoParent(), is(nullValue()));
assertThat(token.getNoDefaultPolicy(), is(nullValue()));
assertThat(token.getTtl(), is(nullValue()));
assertThat(token.getNumUses(), is(nullValue()));
assertThat(token.getPolicies(), is(nullValue()));
assertThat(token.getMeta(), is(nullValue()));
assertThat(token.isRenewable(), is(nullValue()));
/* optional fields should be ignored, so JSON string should be empty */
assertThat(new ObjectMapper().writeValueAsString(token), is("{}"));
}
/**
* Build token without all parameters set.
*/
@Test
public void buildFullTest() throws JsonProcessingException {
Token token = new TokenBuilder()
.withId(ID)
.withDisplayName(DISPLAY_NAME)
.withNoParent(NO_PARENT)
.withNoDefaultPolicy(NO_DEFAULT_POLICY)
.withTtl(TTL)
.withNumUses(NUM_USES)
.withPolicies(POLICIES)
.withMeta(META)
.withRenewable(RENEWABLE)
.build();
assertThat(token.getId(), is(ID));
assertThat(token.getDisplayName(), is(DISPLAY_NAME));
assertThat(token.getNoParent(), is(NO_PARENT));
assertThat(token.getNoDefaultPolicy(), is(NO_DEFAULT_POLICY));
assertThat(token.getTtl(), is(TTL));
assertThat(token.getNumUses(), is(NUM_USES));
assertThat(token.getPolicies(), is(POLICIES));
assertThat(token.getMeta(), is(META));
assertThat(token.isRenewable(), is(RENEWABLE));
/* Verify that all parameters are included in JSON string */
assertThat(new ObjectMapper().writeValueAsString(token), is(JSON_FULL));
}
/**
* Test convenience methods
*/
@Test
public void convenienceMethodsTest() {
/* Parent */
Token token = new TokenBuilder().asOrphan().build();
assertThat(token.getNoParent(), is(true));
token = new TokenBuilder().withParent().build();
assertThat(token.getNoParent(), is(false));
/* Default policy */
token = new TokenBuilder().withDefaultPolicy().build();
assertThat(token.getNoDefaultPolicy(), is(false));
token = new TokenBuilder().withoutDefaultPolicy().build();
assertThat(token.getNoDefaultPolicy(), is(true));
/* Renewability */
token = new TokenBuilder().renewable().build();
assertThat(token.isRenewable(), is(true));
token = new TokenBuilder().notRenewable().build();
assertThat(token.isRenewable(), is(false));
/* Add single policy */
token = new TokenBuilder().withPolicy(POLICY_2).build();
assertThat(token.getPolicies(), hasSize(1));
assertThat(token.getPolicies(), contains(POLICY_2));
token = new TokenBuilder()
.withPolicies(POLICY, POLICY_2)
.withPolicy(POLICY_3)
.build();
assertThat(token.getPolicies(), hasSize(3));
assertThat(token.getPolicies(), contains(POLICY, POLICY_2, POLICY_3));
/* Add single metadata */
token = new TokenBuilder().withMeta(META_KEY_2, META_VALUE_2).build();
assertThat(token.getMeta().size(), is(1));
assertThat(token.getMeta().keySet(), contains(META_KEY_2));
assertThat(token.getMeta().get(META_KEY_2), is(META_VALUE_2));
token = new TokenBuilder()
.withMeta(META)
.withMeta(META_KEY_2, META_VALUE_2)
.build();
assertThat(token.getMeta().size(), is(2));
assertThat(token.getMeta().get(META_KEY), is(META_VALUE));
assertThat(token.getMeta().get(META_KEY_2), is(META_VALUE_2));
}
}

View File

@ -0,0 +1,117 @@
/*
* Copyright 2016-2018 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.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.AppRole;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.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());
}
}
}

View File

@ -0,0 +1,128 @@
/*
* Copyright 2016-2018 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.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.AuthBackend;
import de.stklcode.jvault.connector.model.response.embedded.AuthMethod;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.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 {
}
}

View File

@ -0,0 +1,113 @@
/*
* Copyright 2016-2018 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.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.AuthData;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.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());
}
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright 2016-2018 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.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.jupiter.api.Assertions.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());
}
}
}

View File

@ -0,0 +1,133 @@
/*
* Copyright 2016-2018 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.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.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());
}
}
}

View File

@ -0,0 +1,123 @@
/*
* Copyright 2016-2018 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.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.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());
}
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2016-2018 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.test;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Simple credentials class for JSON testing.
*
* @author Stefan Kalscheuer
* @since 0.1
*/
public class Credentials {
@JsonProperty("username")
private String username;
@JsonProperty("password")
private String password;
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}

View File

@ -1,3 +1,19 @@
/*
* Copyright 2016-2018 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.test;
import java.nio.file.Path;
@ -6,8 +22,8 @@ import java.nio.file.Paths;
/**
* Vault configuration String using builder pattern.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public class VaultConfiguration {
private String host;
@ -15,6 +31,8 @@ public class VaultConfiguration {
private boolean disableTLS;
private boolean disableMlock;
private Path dataLocation;
private String certFile;
private String keyFile;
public VaultConfiguration() {
this.disableTLS = true;
@ -36,6 +54,16 @@ public class VaultConfiguration {
return this;
}
public VaultConfiguration withCert(String certFile) {
this.certFile = certFile;
return this;
}
public VaultConfiguration withKey(String keyFile) {
this.keyFile = keyFile;
return this;
}
public VaultConfiguration disableMlock() {
this.disableMlock = true;
return this;
@ -64,12 +92,14 @@ public class VaultConfiguration {
@Override
public String toString() {
return "backend \"file\" {\n" +
return "backend \"file\" {\n" +
" path = \"" + dataLocation + "\"\n" +
"}\n" +
"listener \"tcp\" {\n" +
" address = \"" + host + ":" + port + "\"\n" +
((disableTLS) ? " tls_disable = 1\n" : "") +
((certFile != null) ? " tls_cert_file = \"" + certFile + "\"\n" : "") +
((keyFile != null) ? " tls_key_file = \"" + keyFile + "\"\n" : "") +
"}\n" +
((disableMlock) ? "disable_mlock = true" : "");
}

View File

@ -0,0 +1 @@
{"Key":"auth/ac4e0527-a7b2-1b40-1148-dc0dfaf01990/salt","Value":"AAAAAQKDLmmb/XlhfVJ45oKGyYwneS9s3tcQUenB8bTcxuDmAMUWnwG8oNNJFs0mSCF9Yv1KOq3Twxj4qPp05viFnP0z"}

View File

@ -0,0 +1 @@
{"Key":"auth/ac4e0527-a7b2-1b40-1148-dc0dfaf01990/accessor/da42ddc9a483efd8ddeae4ab38428f73d42ad7f6320705f333555fed8593cbe2","Value":"AAAAAQLCu78fbRRgGWG++5XDCfaO/8NTg7LMAJL7aCsrn6c1WHJ5yrAAmWmSs1euhNd7yKUd0lQ0aknCKdPAZFBlAsqgOdnN8JLFe/H9lISaWdU6lRIfgTH9whEXWT0VK25FcS4r5yVe3Qoxg0DfT8FhjuzOa70="}

View File

@ -0,0 +1 @@
{"Key":"auth/ac4e0527-a7b2-1b40-1148-dc0dfaf01990/accessor/e83aed0dd0b867f09aa1dbc88b965eafba6030458d6555712e82c479cee3d2d7","Value":"AAAAAQL7t56z9Fr92ztubIfZPPkV3X1Aljnn95Y/tDXOxn8vjbjf21Fhyj3UnLwWyzK/9ip/6+x2DJBXikBOvXoCqKLXGegZ4JN9Z9UMiQ88aE9Z978r13E/rNbhIUa/PhT5NGwCbOl6vtK2hL06BHxKb+4+goM="}

View File

@ -0,0 +1 @@
{"Key":"auth/ac4e0527-a7b2-1b40-1148-dc0dfaf01990/accessor/e96c348451147331101ad48e157e8056ca1b039ee63a6aafd2d66446c94bcad8","Value":"AAAAAQIcvMn5QMtwELRDXZD9nNf7y/8O6z7u0NUZqyJrBb2OYDRvGpSuPS3CIareSxl8y5F4xtadvhyhunCGBUd289H9foMjfGbVVsM1mbM5i6FDTW0sFOPmXX44mQV29PVNMO+fcLuSWb0+qU4erqylpcvdLW8="}

View File

@ -0,0 +1 @@
{"Key":"auth/ac4e0527-a7b2-1b40-1148-dc0dfaf01990/role/testrole1","Value":"AAAAAQLyV03lH8m3IYxoZKLf+/suZ+2wwKAyIHqrR3QeJZK+68wslLXy0XZ35bPrdc3jzAFhTizqILlgTBHVccdM/pydtTtbsvGHQlWstLaC79GUTM32gS/jwSrbwfa9j0q/Yrdo2LSa9IM5lw2tmYy+xR9c3ZKcm+VADZMZy3+6UmbQ1t0lniZ4uuVmqu2gl3y0732UtdMSxJepPWMjfvVq5+tynhgvEZNGgZCPc9lsV1fcBVFswtBUeATNnSJPmTnxQflXyhitPOpEM+5L+gnEsSNsyinRjv5cSbIHCP5yDzvpiWtwZ5Q0psVRSh/WJppBHcovwbJsTLK/tZ1wtFl1OgU9NLONEpgDJYiDyU0ACeFJ7r+DhjIDrQkr+WITnfBBwI+65wpOPYboqGgd4qZy84PE2s/VhWS5hjpxgpM="}

View File

@ -0,0 +1 @@
{"Key":"auth/ac4e0527-a7b2-1b40-1148-dc0dfaf01990/role/testrole2","Value":"AAAAAQIA7g8ifdb9dcRQtIagNGpu2Miv6Dy4jBif1J9OZd26AgFDL6eZTrDr3FfmUQQUs/izDlfI9FDB+UJZO6P2B6vkTchwSg0JdOD8lHjtuoCSDKrIPmzallXHFGwnMnzFY80JzNlzUEfbzciExXthpUjlvBoMlHydZPtAn3pL2NkJdwW1dDRARGB9RoWguqYVgCMkOVdpLFYMVSN1nyHvlt2sm3IdwsXxlE9kH1HGiIEKWYX1U0l8uM0NJTZPFo8Km09u9sz/yzS9B+cyIKXaom7h7S53yRyGP7rFZObl3INMloJyJn7+XxpqiZYAiK31tToZ9k4Y3Eez1ZyCj+oujM6MDwnnzlAkOm3nptIySOk9+iEehr6rG5fpt3WTVSEC3f+1Q+4S"}

View File

@ -0,0 +1 @@
{"Key":"auth/ac4e0527-a7b2-1b40-1148-dc0dfaf01990/role_id/b2b271423a16ba322c3f87616230f8ced5e89bc8d1a32f0ce91c3d3b5f264a8a","Value":"AAAAAQJhm8OnoLuGdSqb3GhF36ALFfIdoRHQ0SMaC1CAuhlfgzuPcyZFMgHr7IL1UepjItfW"}

View File

@ -0,0 +1 @@
{"Key":"auth/ac4e0527-a7b2-1b40-1148-dc0dfaf01990/role_id/fb5542bdc4127acea06e585384296c607d18d139be530ac52f850b703b22bcb4","Value":"AAAAAQJMBpriwrK36PPIVHKh4hNEU66EXyp5npyEF3JxUD0BTQW/vQC6hrnDnSF9F59Xh1Ut"}

View File

@ -0,0 +1 @@
{"Key":"auth/ac4e0527-a7b2-1b40-1148-dc0dfaf01990/secret_id/7ec357dbed8f1b49bb2302aff1f08c57c2f03e03b842b7714ed13a5f9fbe970d/941884199542458348fa08c650246e293eb2bf743350861d73b8fc2978ae5c3a","Value":"AAAAAQLESOciqLucvh8+6PvJKIAQV+P4dPm8q8lweJm5KKH5/Ffh7rtp3btSJhUj2ey5SZummV1mF2rABJ7VROSSjOTbb698VpdXPUeK/qDlyAiT3f2vP16dCbsr1K8Pd0XRdRyrw6osnUwuLgNa9L4pBAoprPn5UwflZVAmwNPWMH3B6Ieo5aZrStP3xuDfU+tjvljaEQALwQAqqo0LTBVU2idw96g/TO75VjbcnptiJOeTPqctJKmh/tdaf1F7x2vOyu5IkhBX3PO4Qn+5F4am66q7HQfB773ga8ZSUoSkph7nahF6JtmHKJ+A972iK9NFx/69jOe1ylwwzzlG4aP1bsrYjGgCIk3CNrvUmK7iO0X9AbzOEgz2d27/VbmGh/bb29z8Oc6Tiw2Qo/tiQtNUreamE5q0UN9XTVC/wdUd5ZdG7RftT6Zv3imPIuAwHJ+GTNSI4HCwc5as/HXMA2xrUdYeuj0rdJejYtyEBQ=="}

View File

@ -1 +1 @@
{"Key":"core/audit","Value":"AAAAAQJ+0lfxYOKIXzquksd3Il4zfW4ja6BdScu7mCAijGDph63S5yWH92olwI2SQA=="}
{"Key":"core/audit","Value":"AAAAAQI4CkDWnI49wp9iDaEMhEgTyBBtXOuIcrn7m4qifUOwQ6reTf3BKc5IQXuhxN5h51KVeinMklz3Ld0Qgw=="}

View File

@ -1 +1 @@
{"Key":"core/auth","Value":"AAAAAQJeg+aK83bfYUPm5KV/+Y1Cf8fVX8Oq7cFiYE3PN4Tcl2j9YD7c+fijkopFzPLxh/EBRVzGTjBBkWBDTLC4EKn2lU8A+NJK6frGOu5Vjc4+WipBUcsGGcfosvxrZk8ZrTt09PRo7CnAFzmH4CgIVuEFv3NZyjXX08EMakxmH6R4S8Ti3cmit5Kr1TKSGnHeMfO6lBnAobAfNlfgNDM90yAxaQUT9gR27TabSKsVvkIY/0oxIcVFQ1RuF7xcdAOJ82wlWkcfT+rMhSS6roGt9Njx9t0PQNjv2eomh/leuhTUzfu4oAbtJJO3IPuC/KkJZpKinjJaGlA5Kx5m7W09DHieyI0GXmjJXH9oCj0z9w6eKDNZmjC1xeFylBvkvnkAKA6QmUmZjoq+m81/UC/C/ShJYxDFxaHwCPgF92qSrT1VTrz5lYAyyjJmrnbyuUXfgG6d4dbDxT/DVddHtIzHbBBT0xxjNM/+WxOSdRYZXKsfm8ovGaFWJr9AyFfEnyS0E9FJvkEXp68eNdacgdM3Ow5Zchm2/I9F4wN577ZwK9oGO2kjkDv4pwKQJ6uDYXeJDZxeMO2rXk/9sY8rAV20loOnqryfO3IE876H97KyE1LEzrky7mVw3YL/CDlZCO5Sf2IHTmwKylTRlsnUO1I5bviFD3a3EdeIGeDuNbWIqiju2fpMQX4l2gUuY4pysBM28AwbTe3zp348PePFpTcGE0/YwsW/aJit3VOc6xNX9WU="}
{"Key":"core/auth","Value":"AAAAAQKy/0yKRpmA5LiZxPlXV+5jBS7lsbsXcACqT/BmXs0nsEP0oHLb4423GWadgYKg1+Vow5qNcLgc6JufLVkEz4dnAcTU1plaCYhRxSGrO/rlAIsKTgwFkKYnV2YRmiSjxKT8hnWw1SHmxappAhZYDMvVVrE9BYGmrCXSmeopjIPLYWgO7UB9/jda7bzMQx9mDVDRUBhRRi4vXUYgo3Dwm1Dznh2yv20ts7O5BVBtpncXB/RovRRhvh2bn/H+RfE0NuZRhQnZ9S6ATF3kGmJX33OiTmBqHBaS8cvPPSZHWmEcXnM8bHEjYxUNZB6+RattgGYVfGtujKWHfwfwJ96VlfIXbQCoZ7bIa1czNa+xhuoOKvaV70crYT4drFnnu4RoV3+HqZl7qsmS8o4MJINoCO6All6GfK7lsRivVzPIZ9M4H6towxfBvEcDvTDHZlL5pOVp7yPP2PSTs0wHM/e9Gg2x9j7nNSDw2KWKTMrxvxHb53dZ3TaaTB388oylLoaNUTG3PlnKAwB4yMp7OpapWH1qX0oo1k3M+XzOX3krHD9UImCTN5DnNZ7jKf8MJ/0aoDi37lNLvQ+0dEXrhsnsRodb2mnCVbp0UhQpPp+Y3yLnB9zBYVAD8Dnt0hOgsxz3WcFOwNX2zeT7OgGnZlTP+NtKKVfXHYjh18JS7mypA7hkh1scBBLqwMyXpzWkKwnBrJYMM1Le1ht2erJvJ4hmLdISidQ8K7ULcS2Gjht+W83ITqC2fO4NIL8QwP9gk6QyIdC8BSHy0mOlZTkT0m5rnVnvl8CV2BbX0lUKTFSmEz6Z0L4nS0/obBRIrWgKgDw3jqnq6vcvmIH4xaOTfRWUeNMQiFnXEsj6tZvRSdpYmAv9jDbdWEBCA2gFkA8wxZ+MSgRIZE8ETUt//5gcvbLncBadS+d7DcqicXUje6jHCQbPg/j9zK38/cKGIszbqVavb89tf0PEQDJB4HOPiPs5kij3T8GtxgFW1DiT23TvtubQF0XsMnv9N3avwTeJoVtBwMTrO1mIam5EHqmvtftnTQycPg9MURmw54fpUevv/Og="}

View File

@ -1 +1 @@
{"Key":"core/mounts","Value":"AAAAAQLyZ1sJsIcAqhtCBFotH08os+J6UEjDnte1gzUp8md8RNH2LFTBe+8iwqSjgpJCyQPYXxDb7l5S4YG8ypUAk5yZA/CaC5y2idWXBrvzihCdDgOv+xLB17mGRuIJdPSdG2TlPY/HJBkadAPOzzD+qFHJKOeH+YOVwBQQP8GA9uLm3DZNHOSej59Y8wN7R9hJX1aXBnkqFhpLdARXqrlSI8SiWz3TNA2vmm4cCzxGcmKEUF3m6peBr47TTnZtcciGI0vd7yIbMeblF93HcrNMcQnKB4ItR8a+yO4WZHg/Y1iWn0JQB0y0FSYg+OFFolsMQpQDDd+YTUpj8zJ2pmlRZ9n19WBHD2VbkzkCyR214+NzCpOfCUsguYdGR34trwU6/4W5ApxtY/+T35vQ+esztU2HgQqJES6s8708Nn589Kvzg/+etbvhfq/DmWOcwZOtb2X/EQHaDmHWzsWqQ26Ux32WiAjedVwoba6vT23MIgUBjdHIKuTlrV6JqNVeuevfmfpBW8y/EhcAm6e2s8jTkdoaSPvq2NaBT9HF6FWJNXhVxAXQlOp7ibx5nk7l312umi2hbZ0+2Ad2wTGCVsECa26ZqXzBbU3uNni4sNdqbTq0i7unpqEQnyfTGcHkxe1uIbT2sK/AydtaOV8IDN4Z0HUBX9tj2UpQr8LX+JW9wX3MIXxQVfogyi/AmQRiDYuPeJyvvTTininGOHLSQyl/jRO/A3SdrTmppcwyNmTS1tzpwDawCP9yLWcw0/QVYgd8wMgmVjKsGuxJqWtEibnEnP9oU8Epi1Zy0OPXLUAT/06R9xtIMRReS2+VhBrFGmkD6eVL6EX0OOZ3yA6CxIft7cHQNishwIGL"}
{"Key":"core/mounts","Value":"AAAAAQKEEYCeXSTFocHW81rN1uI6MofozgPy2HnyOaonbuLKzaYM90H7UWfCymZ8sJ/3buSfv8/HNGkrjMHXnwyNbwTZrMt1+3LzSySfrNuq8naoLCbZK0Pn3vJElDnJAej44SBoKrmC04RAj7ROjxB5Eiqe4VJmj2KzjX8pnwKo2cFvetgNiW1a1W9zqqDZX4HRxTCfiS4RwLdkWrUjYvwjX4tQB+GYuixUEWWCsUXSAoIhHx/H7AkmJaJVyrHILjHAcSD8fgxCHwFwf7xaMgQhWqj+ofBYwilgtXkPc/vcmT1pZqw8RgHrfMKTl1gGmuXiiL9/tkWeMs4u9H9+nhLFYy6V2EDFDKPc+zvHg/c4lRUvN0AnX1A050ZJKucYDLq8IxRuBQL4ZZ0syyIVxoA2iJYgIy8dZXHg232LQg5Gicc+sqHKMAJxknkEwl2QBPhcAyGobent4UaAx9b+7LGXhg=="}

View File

@ -0,0 +1 @@
{"Key":"core/cluster/local/info","Value":"AAAAAQLM3HpjYNukfnGPRBV4yhHkaDqTMag0rk3fDmRcUt5pzDH0yh/2ZRuF7czOYsfV6146nxmUfekMrH457GtCMPIppE4x0WkikQRxiA5fSw9lYT8yeErVL1o7ETNo3AHPib2ldxBdX8ik3jY="}

View File

@ -0,0 +1 @@
{"Key":"logical/b85d867d-74d1-7d84-7a97-4597d813a5fb/userstore/complex","Value":"AAAAAQJGyPQ1TFtwJLO5tbYDvnXDxbK0GVxef0qXs4h2ddHTdWFvk+WJWsTw2l+Igr5v5KY5HOQz/apI6Vo2LmwY"}

View File

@ -0,0 +1 @@
{"Key":"logical/b85d867d-74d1-7d84-7a97-4597d813a5fb/userstore/json","Value":"AAAAAQIow6Rc/bPZhf5PDQ3jK/diX99iQZM01NA62tkT0BaKE4UfmSYuYDVUCIrWUOKsVyvD48phL3hEHfgNrJzVsVIk296Br/y7/es9z5zOxe9VATSSJy3CI54AtA=="}

View File

@ -0,0 +1 @@
{"Key":"sys/expire/id/auth/userpass/login/validUser/dadddf1d8c65ecfb20c4361929d1e7f6b72e39ae","Value":"AAAAAQLS9Dgic+3ywWAIR7I3J+9PmdEt81fce3eOTNpcT/TRNDkzD5NY3WEQjBLM7UzxGMg7M88IeGi6L7Rd+ZmoKjL0zogptwvKYggG4P0z+fCQW+/WgpIYEB1187wsF7wh7GQtXTXKE9F/dtKFvfi+3KsZ/0//tXcs9fUqPuJFJSUelcMaIeb2emle4p+kjs0pDuSNzovIGvRToLW4f5TbqVy0ve0zo8r/7IwKlrxo7E2uY0xzJX6IjygIACFm7GjRZgy2rkl0v9Be0T31k/zDWsEPINXu2a+vsYqjZTkRWevrK2ZE8IQBlJcFER5bcnsZiA89wm0VTcwBbYlWJ32IM9AJw/75DGMQ1wbdyJ8PUWvdhyl9i9HahtHWKCo9oH8qTiBjbmkrCECCaUeV1TgpqcqyglxBkgn6Qlb5kgNEHeXxCPy8GarT2gHlmPNaWunnxqE71WuVLZ4+PBlCjmksyXQtdqmDIRE1oSHeuohBQ2dA0B/rDmhLwXBssA+/eQDONLm639VrLJR4IRaNo04PEdxz8pec8W5fG5+Ea3Z171nl3FseZO78i3Wj7Y2KvYFA1XWNlrucxWg0jRI1hDlUHXqLh7nqctdudkI8NrkwbAE6W6a9imMUnTd3yIHN05ke9ihlJrVvAaBbgav4ssz3tnYC/s3TmozGic2TdXGxi9ewMKhdfntXi1VQEJ52i2QmWsnDAUoISHFaK+azNFt7sD5tCKmSIdpS4IL9g6RMH/sVAzuB0ZT+83jYY+jP9L4SajQs4ncWkrMQmJ0fxGs62x6lBxk1LtI2qzV1J57+1QZxFoQc6OQINec3VoQ1t7aFpqYYDk9GKEA/hk8vM5vhwc058RPpjYM8l+3PCPOilMh+FgqOs++8HBTarMTp"}

View File

@ -0,0 +1 @@
{"Key":"sys/policy/response-wrapping","Value":"AAAAAQI0PU/pu6EEHcT4HwfZjzScyW8DLBzmGDanjLuWqGEtlLcKgRLZh7/c/CRWwbRXy2d3GUB1Bo3YVzpUuDDlNY3NaipcORS3zzCHep5uO/DFUJ3DPSlde8j1BrmSpQDHerAsJYXYEManr93puObYs1cEfP9Mt8WdC/IPhgecSw32tVGBz0SSP2qaXGwdJQva6xroMWqmwMVU/lsVi/qcV459xXiTYU/8Kp6Xbqx0p0SRR0yVdM+yNiMtYtnzoxWdptbSYLTG1mhumA=="}

View File

@ -0,0 +1 @@
{"Key":"sys/token/accessor/f36b16467afa41b83f8d2f467ce86b0a848aebbf","Value":"AAAAAQKCq6Zqg/q7n6Oi/FfipknrqzI7vYVD9IB+FUuZR56CWUngRRLOs4kLU78vNboCenbYQ3kDYtnxOvUD4xOjNktUzvXoqV0sF0N1p50Mc+MBsR1kzRbbk3nhxocW6lvOmnwLwnE7TtQdEMiU4sHeCoitFgWXfITl2YVxNnY5SXbq4ZSHAVlF"}

View File

@ -1 +1 @@
{"Key":"sys/token/id/05b3023411dd89a9a27282d57d027f5312be4adc","Value":"AAAAAQIUAO6ILG2gwWjc+J2kp4n03Rp6ycNYAWBYEM0ygocB7DmIT531H5cLbqFVJF5Zw+OQie0HOVLX/zcAPWtxkTOIRXH9FIUT14T9k1IzoxEOYSrbI6ig8bFffe4cd9b0qj9UKgwakQ1GG8vfeSXZnJjVBCSsvWL46s/IGh+SEmirNTiGSE3iy8p3+zunl2s/mUP08i/We03LcLTsCBfSsHVa/CongLNKgSq4oF23LFxv3De+9j8+IQ9HKA0pAatTaCjHdU1TsAiBGsKUhujGW5oQuygkUYVIBFqFqwDOytpdcxiP/A2LAut6qvQjvfT7s7C/Cvke9ypOQAr7iSmUlAhKcXPPEN21NdBmFq4K4w=="}
{"Key":"sys/token/id/05b3023411dd89a9a27282d57d027f5312be4adc","Value":"AAAAAQKiu1H1ntud1j4D5e/ZkrSbjuiQgzXK2/b+chRAVynYtfOSrY4pz4BYwZ31OU/VFdsL66Em2FLgGQDVWi6IdM9d3ao7i+EkRf842PAgKrX99coubFB4QBVHqyKhMwfDUmzflirVgSKy4IgKDVKkR08Z6ETHOGBs4Rc9c97pwYsXJP9OE8dSass3jXVLADKCe+MWJeqv1iKTAQSWlWxa75VNXNYiTYcVQ9LYS3egvDeMOqHWBICnoQGnjaHV9Yz/GmCT5YvqwZL+ZOYvy/DwlyFfr6XIWsrbpVOELWU+SPJCvVriE8E67mbDqthh0I1Du3FoE2AJl+5bIEXQIMlezWTLJN7DdnEnTCWssOdEE6LBz8Ue3o2yFe82HS8mucJECOLIjGuEm0aLAXrKzC7RlFOvkl7q0BNu+AQbg5tAe4PUBrFf+cdMdQ81FxNOOAmrjByhnnLCT8ASEd4Ugv3N1PafZtiZQ4ks8U0ppvqdFWgjnlw="}

View File

@ -0,0 +1 @@
{"Key":"sys/token/id/dadddf1d8c65ecfb20c4361929d1e7f6b72e39ae","Value":"AAAAAQLf0+mzTh9i2njHeuHQTkC0cDkZGbSHljPETXi4PtH7V1bwuJHi7LLiS3TQNDLl9M/jR6eVK/V374Q+qKdi6sZjVvRKErpbuZhX6YjYy/YNCKs9RJcU21wgXM0emBH6cvrVkzWz7y9UdrTR86e4PU8GrqkbtKUWZ08EcB+jt3mlzkOK+3lRBj9mmDC1McsZ4ALw8Y13Mq6a8xSeSxX4ZJLq4MYfI2GtR3JiEdYdx8gS5YlbbgxTjwxEOUC1mxwDHw+rsguh9eOD6RZaUTvL3MIvQsggoYU9kecvP9jvMnOfhRwd8pT93ilE+MWRylKI8ZOc7K1TMU+qw7Eho5KRKCuR7AXpWrc23SIkkMTDqmaLZiwyM5+fGR1R0c/KpsrzYo5X+TU3SMghlmrQyTHEEU6RGmAOC7RWfFrV1144T390hE9zhbY1zMRmtgBY9qsueXvK3pVaQT83/PswVGR8jliThzXjCsy12BwThBNlZVpEKZK8oI3HRqMk2jpkSpG2cAYiWNnZV9fbipNa92ovGeHHOTM9ZdPpX8apxS47CnMbuwdkNPmCvu+wtRBuGsbmmEwy+F8czMRJuAHu"}

View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDfzCCAmegAwIBAgIJAIsdtmg40qeTMA0GCSqGSIb3DQEBDQUAMFYxCzAJBgNV
BAYTAkRFMQowCAYDVQQIDAEgMREwDwYDVQQKDAhzdGtsY29kZTENMAsGA1UECwwE
VGVzdDEZMBcGA1UEAwwQc3RrbGNvZGUgVGVzdCBDQTAeFw0xNjExMDYxMDM4MDda
Fw00NjEwMzAxMDM4MDdaMFYxCzAJBgNVBAYTAkRFMQowCAYDVQQIDAEgMREwDwYD
VQQKDAhzdGtsY29kZTENMAsGA1UECwwEVGVzdDEZMBcGA1UEAwwQc3RrbGNvZGUg
VGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKIVAIDK++4v
mH8/V9fELi3X3Ychgz2WP+dDbXrHsIdkQnmT9sdCfZuLH/0V98XwWQAFHlSfc9GB
4NEID31y/f76AcKhuAx4aLebMBp6L4eJssahhxLoKzodFZm9WVIj6g6kXl6Auc9z
v9d+DH70PHGtf/ORqnkiuraY5hTzUK7pMrRkL/BFuZyMOtsDsaBWuImZTuf8s2aF
URLbD1cnFKn3LbeydlAipA12EXgZ1KhmY8X8BOrDRQlHTIjRjCs0kV3Jc8thi2xt
N+Yo/Zm8HqP/fmuszeID0WWgRpmE8RTg8WuoDAJAb600xKEK11qpXkUT3vHiot5N
np6HoQXm0HUCAwEAAaNQME4wHQYDVR0OBBYEFFiwMeDNFusyU90UELnglsankCkd
MB8GA1UdIwQYMBaAFFiwMeDNFusyU90UELnglsankCkdMAwGA1UdEwQFMAMBAf8w
DQYJKoZIhvcNAQENBQADggEBAEwk8fDIo1Wc3EpJKNKjsCZbaiyC8GiiYfuKQVmq
82jAacf7MUw8EgpuboDwEbDSIhCeEyM/t8mgttcT/DP0vD3qMhpkNLQcuSK0NFza
XvnoPqHMZhxerc7QBMeEKYFRjUd8iPiT3D8rYPdWq8klQnLIPyws2/uyijIXo9k3
oiPMBUO+WAe3tLwO9EV6Ff9q5BmlVufngPT1R4wTNR6mZQ3yy8CWPOsk3CBCyleT
8maCnFjhJ9fBz74WVgAO7QE72VTwsu9MZ+DawsHt8oKaNU1dfIXfqMHKh3KItn1N
cIIlhpnIUtxoWEawH6NbtCoQpTRBSZ8EoBhP4z9jC2+A7i0=
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAs+l54Lm03sacNzjlj5V2gUJPJvDQsAKi/O313vbsv4FLxFX8
QnGYFKouFAtVW4MTpEN6ciFP6ucwb6YxtoOKIxZ4nqmMDz4R3Q2Spep7Q9I9kISX
LMvs92qE1phSqhi6dfH+ZTTPl9HlpWmSWhDReBqfSK1QPJVB1QUrmZA4yCxSfpD6
sx0R28sPLuzR/lTiPB2aFst6aM9wG8ZMrl7KYO37W6QH/0p3CfvPdB42b8q5txTG
l9Ia++eTcZE69ESyA9LLaPWLfjzGCCW/FbF/zd3WvV8oH7IXqrOfW532Sy6Ui2Id
8DmtoNHTulFFKypDe5sF0aFWpkoJsqvaDj/I9wIDAQABAoIBAHXCDBQbeVeXiAhd
JWSl37sbO9OxK+cI0sXau2QFG1D9wCnyXfrffzuHaEGWaXhMgz6xLCQnybdnOzzY
+xELaA8vViQDtbkEV4zopWQT5jquEb3WC1023RPUlL4hVXogVWt9yZVUy8wDhtyO
DU0GVRTX2Aop5qrAxyY3DCKnU4Mw5pZW6tVrALh2W+c/7tlB3mp89uzgRVLsOyP1
KoCiIWkb83DT73rTTYg2NOL+69Pp0idtADEE8tuo/3pgcZhAVI9jtisnWg7MsSWu
rKkNCS3vOcxAKG9kw3znJfVVH7ZF1LaDVx9LP4inEwVQfg9aImhkjquIgGT0iDgK
e62Zx4ECgYEA2YWsXSjRFrscataSM+w71tH4GlE0FAJx5FW+F4YeTfnn+k7FaXuE
562737GqsadOXkNiVVgfxsB6snR2WWjxJKuPHGJWncl7yR/MdRmradQGsQYe/xTa
AMouZIHp7BWPV/TG6s3x2ezx2GvMhGUnJ43QvTipuJFSDFObgROvz+MCgYEA07yn
4PnKXmnIZbhXz9wkvmDpbfPcCrapFmtRXBTK7fbwEA+YPl3xPjkvDX8cQDTsze7h
R+o0jMG0VPwmjfECHva5GWemcN5AFMPfuGqik0jacXa81oti0H5L67Z/ffeFxYnD
UXukXFInDLT0c8/k1Ex4shwfjiaat030olweBt0CgYEAu5+6ogx/9bxlcZ4tM84z
e0NXXtPmONA3Dv4KXl4YK6hAuT5St36MkA3iPLwSAPTP+yziV70Qg64o517fapXD
Up8MbS5Big5t0Hi2Mdd3bGwvbWhbOijxNbcvNxB8BmA+aV7AaW5Ei3X+0W+CVDyv
/kUr5NtIQeRPQkSnoDmr74MCgYEAyrnqksEXPWZS9PGXQfEpTQ5E8X12xNs28bw2
3c8arNSt7PLBdZVEkar2nhmB1wfVYybAk7ZuMgaUvnneADEtMrBPcT+IYLCq8jbI
US3oEtTCMbjZ/SDfr3f9AOZvExCXCBdq5u1W5P3TXZs0Il5+XbYKKZ47qELWB4Og
IoPITBECgYBvA3+4YL006l/Hkyf21aDiqh3kUAhuPVSXd5ef9EvE2fxMR225jTks
URCwYxi/Njg5B2FtuXZjq/eqis/piNtqr3nwZcpiOiwr8J/jwwBXPbtIcE5Nxjzx
ag6bkbXe6mpxvHDtroAw84sC0h77ztyJ4Lq/khiEjq+XTPn1iEJ+DQ==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDVzCCAj8CCQDn4qCNgPQBezANBgkqhkiG9w0BAQ0FADBWMQswCQYDVQQGEwJE
RTEKMAgGA1UECAwBIDERMA8GA1UECgwIc3RrbGNvZGUxDTALBgNVBAsMBFRlc3Qx
GTAXBgNVBAMMEHN0a2xjb2RlIFRlc3QgQ0EwHhcNMTYxMTA2MTA0MTQ4WhcNNDEx
MDMxMTA0MTQ4WjCBhDELMAkGA1UEBhMCREUxCjAIBgNVBAgMASAxETAPBgNVBAoM
CHN0a2xjb2RlMQ0wCwYDVQQLDARUZXN0MSMwIQYDVQQDDBpzdGtsY29kZSBWYXVs
dCBUZXN0IENsaWVudDEiMCAGCSqGSIb3DQEJARYTbm9yZXBseUBzdGtsY29kZS5k
ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALPpeeC5tN7GnDc45Y+V
doFCTybw0LACovzt9d727L+BS8RV/EJxmBSqLhQLVVuDE6RDenIhT+rnMG+mMbaD
iiMWeJ6pjA8+Ed0NkqXqe0PSPZCElyzL7PdqhNaYUqoYunXx/mU0z5fR5aVpkloQ
0Xgan0itUDyVQdUFK5mQOMgsUn6Q+rMdEdvLDy7s0f5U4jwdmhbLemjPcBvGTK5e
ymDt+1ukB/9Kdwn7z3QeNm/KubcUxpfSGvvnk3GROvREsgPSy2j1i348xgglvxWx
f83d1r1fKB+yF6qzn1ud9ksulItiHfA5raDR07pRRSsqQ3ubBdGhVqZKCbKr2g4/
yPcCAwEAATANBgkqhkiG9w0BAQ0FAAOCAQEAaW0XEGs8PpHV9dfDD3QERoDpuqsj
IkTSO6+e1Ah/Uak6nDPSkAHwS53Avz2SElM3kGa9DVniXOVxC9OjM/E74vncv71w
/MLiIS3aXbTgiUmDhuTutBrL9Q3HJGOfO6gqEyQakPfW1NFUFleJKvWKNX0S4eeZ
2nXt7da7xaxR6r0L6nwRrWT85ys/jdDgfF0SnmQRmddQttsmRCJ3DXq0z2EeXbO3
J8XFF+Y+SyV0CB7bjHx0BXZPaISUMAqnifRqDyw/4G/9iLqFN2Lc0Lxp74w6D/8z
OSiHwFvjG1dwEkwnPL9V5vD4/BgeClre4FWqD6wqS3UwLdq6DzEaSNKHJw==
-----END CERTIFICATE-----

View File

@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEA3WItNwzszD4/ok3uydlOa7WCprOX4+4Lui8EscR4d7axWv31
A8Vp8GyxASi1MyCIxMeldD/uCzh4EInvuxhfFHr0BjYqHMj4kSf8u5Qo4b7n6A2K
rfiVH9qsoz1Cvl4ocLRGKH0JqcWORcKFVWhAhSDKjdu13ckgQxUWC4lNRzjIfMlI
F8BLHTivZO/RTcVBlm/ukpVxG8aeaSyD0vGnoiqhkq6L9K8NRQ7H65lwALHtYeOB
jEdIJxbMHi+G6Imm4eO88pneC7TIshPYSEMmIhpYYhXIMhyN2V31/ER7gOs4b+Sd
ymInjRRH8zTYITIq1wcqbtTIWVqoYqLYAkiLzFVJgEDhOJaCToUv8SU2+bkjhS96
e0h/01shcNKBNNO1z7g/gKG0ywwTgSijAENQxW5VmYV5n7ITyZF0mGR35dPszLG+
uEpFTt959+WK/VgAUoeYk5gbr025hnD1MMByXkRUMnk2n8Y4ksZ083dtoyeEpgxz
gT+kSAvDcjm1x/7GpAqUr5dKaJxmEUKflk+y7swhRJfp8KDgvrW8MhKsHsAEOynI
3sehnqb49VZKfYwPgs9gGCDVLnS05CROPy3sPgYEh/N13PMdZq8UOcENnTye3NlA
l3nXx0fm6wDwdVclVQq8P4mqGVpHmV0EJcNm9VtVohRZRgPYD7fjTVv5nVcCAwEA
AQKCAgBo7xgvd9jmFrti2z3MP0yEkUyUZ5wfVb4JSjAXcuEHHXmDf8ybNP+6Dkr4
GauJyGoLm/Y42/ShLOr8K+WN8UdgFceFCjd73Wa0pxeMcfXOywZxX7nULHfC2Yvq
9CamxUq14T1AA8SIzDNbrZA1o2yxrZFVHEdgEO1R3rTMUxBmKewd+epKF8OC3lOE
rIexLUahX/zdTiiG2eZMQ+VYH2Mt4rcjJ8j++dp4WUE500jbi3rRY10MeN0iahPm
WvC/WD/Z4nC1LWmqcs6OWgmyduGkWIh8NYbm+dHirj7ijDNeMCBYKS0BuPS2Ul6o
UOwBEB5uPd9HGWS9tdMKrdVlf62DE1IBQT1/Dl5gO6FpPZv+DPDirXjs90thEaUQ
rgeGP/FiLwyYppr31rPKVSWZ3at7cxifHsiTBFQDGVOaId1BykBzqiEzi4SYgrSu
Bd5hzH/nwjjfmx6MPo/mp/YEIIF1abwUghgwvFeo/NbLIof9/Tj77E3wHuOTdff7
xPcM7a+9nqgquJ0OyiqB5qJLnBjqUF1X1jDOR2qS5+Y4E0nVE1bHI30yr/nl3TJT
uVK3Ea+y5tMjydX7lzdRUmzuF+dRGrMiwAS9A85oI+oe+BS6LLjD1bLWAPK6kuIf
jf9pxtAqOFnfOBF/bVPbS1xBVV224aErZwvNO+66+bkvsvdPgQKCAQEA8kudmJo3
EDkK5rTLeeBfke2aLNxkIVSQtGAVh2F2Ra8+HQ5wpoWtm5Rc64G8kviuSZDgyG7Y
x/tLPkXpb7kM1m1j6pxIw4163sSZNyKX2qtQZQP62tmxi2sGYwrB3aj7IXtQ7HjI
NiEuZS1P9kP5djSBwtM7YDVu1nDc63vQPEOKwpfySxDf8ABSUscsrdl1lzKN+TOu
+9uEO8V0RsQETiVkpirGXhrdz0wYViOGqwHNZNwQz99W2mjIrpO8bG94ctw6HJ5x
x6P1U2L2GdHwIs9mDO4aUmWOKQ3+bGJ/J4G0Vwx13TR/DUDDPDTuUZhWSsstoB6F
ekxKOyFtAtnFWQKCAQEA6efC/CYKEDrFe0MAfmXeDT5cKCrC9erpRukogMm9CvaH
2GIdmhuMDbS7mkmOB3UW9SJ0HKQLtArZ2wFtk3CxPUxEGbPkk4HMsMKubwOpG751
bSPo8PX7JUwEklPRqKhf0DoCEUjtessRqy/4ea/jiOhLiY+wPc/gLxjQzFMBR8fm
mHArMahMa9fEuqwn+xRLcSDAWSb1CLJ4GV6ULupXhI/3l20gJiz6AobyZbHfTnBd
nJJQQgvAa0QxAQy4HjQ+AmjedcyQnNfR27TuuCVwkQz4ffG9zHV9kuiYUqJ3nkBD
3tYHoWCkRAiLorEuM4M67L3Fi0+durImmJxZ86syLwKCAQAL4PMoAR+D9xf2uZRk
NEDbOafeXSu3iprRjQhhK8ENp4rHB+cz8sfRIdPwY9rn5bM9vhGXIgAUxdgphGnu
ZUcg2BoW7XSPycblVwQf9N03BkEZwrkws42FxUh54JQilt9BA/eysDU4miXZJgCO
lUSMrARUleCKVfRKJRxfmyFZYwJRifuB/KDN9mYS0tr45vlh4UOenQ8OH/P6rjKG
KaQAZMrrbpttD6oiOJvU1UcL6Tm1oShd2Jg8evijvnB1bH2eO/fJYWc4n2wum2Jv
X6CDRGG/bojx0zLGBn6bt7R+Lli2D9FTd/hmoO8xa3Lnoy1P22gwOm7W0Riuj3P1
uNF5AoIBAAlt8Gxd1DYHSILJlrGBxcve4bQ01Rs41yKmr51RhK92dM+CVRMrXSAI
Uy/LG1CtpblIJEorStV9Qn8Ttakl998yveQTXnmb1/agQovzJ9QYf39g3TkpkXBV
ejGz81XLQ+GPFRpBSGGU4id2jZvKPW/9fV4UTtSPFsiPRYuXJQwRwPgQPY2I7VvD
nQixfAMhNFFhMp/ldCdfmnvbVjn19IVBkIeoPI2Nbp6/dfInk4sD+KIhO98NvjoU
y6zxKFL/ZCiQtbcmAgZwpOMojh8aU0llrnbVUgN2ERPlEI70QcI9cP8AvdoBnV2o
wohSgDxPZAa7N8V/9inamLe6Rd4O3r0CggEBAJAWIm87f+tAI81UYG3ndDXFfy/m
uODIRjnXyaPNj+B2+xJ0ygnmrSZo/7lZUCcU2ixCqx3HMwkWhOciOrpQ2i2yrY66
db1/F/4RYanCpMp1b3OQxLk4VluketpCsZTR8ZJNKbBx5kCwFO6CYfvgeo7xO5b0
2x3mt/QX+Ch9l+84TamClUdQsN0toMLQT821gLes7zgw2Rn3gWoN335dvKtVtyRC
pZpLDm44vd+85piF2VOdr7r6RsmAylpKRvleyD3Q7kDI2PpIlb16zPt6BA5VjSjo
U9UWQ4g4V0wum1KJiKYmumartgP9TGoql6zVAJxlcRdB3l2IaFPdizu7K1E=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIEMTCCAxkCCQDn4qCNgPQBejANBgkqhkiG9w0BAQ0FADBWMQswCQYDVQQGEwJE
RTEKMAgGA1UECAwBIDERMA8GA1UECgwIc3RrbGNvZGUxDTALBgNVBAsMBFRlc3Qx
GTAXBgNVBAMMEHN0a2xjb2RlIFRlc3QgQ0EwHhcNMTYxMTA2MTAzODQxWhcNNDEx
MDMxMTAzODQxWjBfMQswCQYDVQQGEwJERTEKMAgGA1UECAwBIDERMA8GA1UECgwI
c3RrbGNvZGUxHTAbBgNVBAsMFFZhdWx0IENvbm5lY3RvciBUZXN0MRIwEAYDVQQD
DAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDdYi03
DOzMPj+iTe7J2U5rtYKms5fj7gu6LwSxxHh3trFa/fUDxWnwbLEBKLUzIIjEx6V0
P+4LOHgQie+7GF8UevQGNiocyPiRJ/y7lCjhvufoDYqt+JUf2qyjPUK+XihwtEYo
fQmpxY5FwoVVaECFIMqN27XdySBDFRYLiU1HOMh8yUgXwEsdOK9k79FNxUGWb+6S
lXEbxp5pLIPS8aeiKqGSrov0rw1FDsfrmXAAse1h44GMR0gnFsweL4boiabh47zy
md4LtMiyE9hIQyYiGlhiFcgyHI3ZXfX8RHuA6zhv5J3KYieNFEfzNNghMirXBypu
1MhZWqhiotgCSIvMVUmAQOE4loJOhS/xJTb5uSOFL3p7SH/TWyFw0oE007XPuD+A
obTLDBOBKKMAQ1DFblWZhXmfshPJkXSYZHfl0+zMsb64SkVO33n35Yr9WABSh5iT
mBuvTbmGcPUwwHJeRFQyeTafxjiSxnTzd22jJ4SmDHOBP6RIC8NyObXH/sakCpSv
l0ponGYRQp+WT7LuzCFEl+nwoOC+tbwyEqwewAQ7Kcjex6Gepvj1Vkp9jA+Cz2AY
INUudLTkJE4/Lew+BgSH83Xc8x1mrxQ5wQ2dPJ7c2UCXedfHR+brAPB1VyVVCrw/
iaoZWkeZXQQlw2b1W1WiFFlGA9gPt+NNW/mdVwIDAQABMA0GCSqGSIb3DQEBDQUA
A4IBAQA4nrZlyoN/iyRDWZqudXyedMRVUquekzvkcPndInAaW2ukOl+LMGdN7C5n
wjglyg5DV0aDNy+Mpy/rInC4kZ5UDKfHjYg4Q9x6kdZOch9gJ6Qvq7hhP8hLUcta
pi/m3+k+PP/X6V1oSLxTl/Ja6peDvK1eo5imAbyEPz0kQNHZ88BxEAWGaQgNbItM
SC7xmrO78o832d07KF8fJL+o35KV0EuHKMnvr2TLv09kL61EKRRiEMxb6x/90Jw8
Rys/FnZh+N0Xdk8sfpq6itGnaDqZSBw0EPhBDXcX9bNpztm8JIIZv101H208BfYG
GyJ1DYEp2FfyLgVcY9hNi6P0tmzn
-----END CERTIFICATE-----