Compare commits
496 Commits
Author | SHA1 | Date | |
---|---|---|---|
80abbda46f | |||
a8e85b88d1 | |||
91baed4fe5 | |||
2ea261d36a | |||
43da0f5109 | |||
cc5ca13aeb | |||
71842eb758 | |||
e9aeda9a55 | |||
d51af06e29 | |||
7b2b137d53 | |||
ee2543e3ad | |||
dad35023eb | |||
0127cf30be | |||
90f8bb7f20 | |||
ff6d2140cf | |||
076cd8b607 | |||
2e0d092cae | |||
d329af2c67 | |||
f50f5c5de7 | |||
c8a6015f3f | |||
835372eb3b | |||
11ece9974f | |||
0d0fbb5461 | |||
6c9a1fc10e | |||
7e05f4937d | |||
fd9045d7cd | |||
e938f81954 | |||
e5dd207c8c | |||
92d5750c1d | |||
2011a83fd9 | |||
d3da00372c | |||
d90dfc8ba7 | |||
8bf0f9c45f | |||
4fcfa6938e | |||
26cfceb581 | |||
ccf820d524 | |||
5a9d6d9183 | |||
a1dd2b20fb | |||
b0c6ea2d19 | |||
9b6aa91e52 | |||
01812bf492 | |||
e6ef19f1a1 | |||
d4066c1829 | |||
498e46d94d | |||
658f005433 | |||
c8a8f4cbbf | |||
0964c8c41a | |||
ae00b29b4d | |||
10395007bc | |||
91bd6cd572 | |||
8a7ef2d455 | |||
4588703f5c | |||
8a4ebeaad8 | |||
e2c3dd1c35 | |||
b2f7c61654 | |||
8ae024fc36 | |||
c6a9cc2b1a | |||
610464327d | |||
077d670609 | |||
d099995409 | |||
b751b58f11 | |||
59af162c7d | |||
d6b9a805b3 | |||
e585777340 | |||
44f0953998 | |||
318186d9e0 | |||
15ee202167 | |||
defbce0782 | |||
1a18e6b73b | |||
5f1f94f59c | |||
e0711e6108 | |||
a3393ae0cb | |||
8ec160a436 | |||
69da6b9f14 | |||
936928a4fb | |||
a75621d67e | |||
8cb27ed4d1 | |||
7d5996244b | |||
20983e5089 | |||
56fb92178c | |||
4258489dba | |||
e49216f611 | |||
dd5adf897a | |||
d04067db7e | |||
703cc0d87b | |||
c35760d0ab | |||
2f5b25d847 | |||
7681e9e2af | |||
4c4a38cb0b | |||
fe309746fe | |||
df251f1f2c | |||
a008fa2b69 | |||
156156cdef | |||
7bcd57691c | |||
531111cb2b | |||
151b58dc82 | |||
65fb01617d | |||
097cb5415a | |||
2dff8930b7 | |||
d82554974c | |||
8352d04c52 | |||
56d5345fcb | |||
52876ef3a4 | |||
62f2249a4d | |||
10965b01d6 | |||
0f302af3e7 | |||
02ae647002 | |||
1d9e1458be | |||
683052a804 | |||
cc290f4def | |||
2722a125e5 | |||
5e5143168e | |||
08e8c9f090 | |||
c06cb9b0fb | |||
505d420fd6 | |||
be23129441 | |||
199dfd30ca | |||
b72298f2a8 | |||
226b6ad6c4 | |||
d81fc4e5af | |||
1195b447a2 | |||
f3e1f01e38 | |||
622b13f508 | |||
0f0b008f2f | |||
34322b389c | |||
7e5d193d1b | |||
7a813cdda3 | |||
d9dbdad75b | |||
c97308fb4f | |||
fea27910bb | |||
4d79ef6634 | |||
402567a0db | |||
00422ea00c | |||
01e1c6e8c7 | |||
e322a74818 | |||
f9fe57230f | |||
e0c33b51e4 | |||
5e6dcc64cd | |||
70b7338f3e | |||
489e450dc8 | |||
909eab762c | |||
abba4dff93 | |||
712fab04e1 | |||
39ac32a2f6 | |||
31e20385d4 | |||
30996e9fc9 | |||
81decd1a4c | |||
adedc277fa | |||
0c56813121 | |||
2412a291f6 | |||
b5ed7704e3 | |||
a1626aa1c7 | |||
3fb8454711 | |||
ecf18881b9 | |||
69287f7196 | |||
4b1b4399e1 | |||
9ce819b1d0 | |||
64e55eddd8 | |||
feb6e147fe | |||
b0d2b038eb | |||
f3cc16f44a | |||
4f3cb4b330 | |||
021421a54c | |||
18cb89ace4 | |||
85aa5c3c30 | |||
912b9ec61b | |||
bd0c5b08fe | |||
5f3a36e2c5 | |||
deb03cc2b0 | |||
f6180c4f90 | |||
dc4b62496a | |||
dbb21f85bf | |||
61dcfc79d3 | |||
63e7af552f | |||
5e2d37797e | |||
b4a822bf10 | |||
4045b1a4fd | |||
6a73bc39d3 | |||
75561a0540 | |||
fdda685f6f | |||
6e19e8514f | |||
1c31b7a5fe | |||
f918f85d20 | |||
7f153df136 | |||
7793b4fc77 | |||
7701f9f768 | |||
c60580481b | |||
bbceee35f2 | |||
3a920fe960 | |||
eed61c4569 | |||
1cd1b63f8d | |||
e81dd87fe1 | |||
f6037e31bb | |||
74092bba9a | |||
3c11fe912b | |||
53d954ea12 | |||
71564e87e8 | |||
e578591a49 | |||
de17f48be2 | |||
ce24de7347 | |||
f783286909 | |||
9ef709e3eb | |||
ce28b8eb60 | |||
587c6cde0a | |||
dab42816a7 | |||
9346619237 | |||
df466a4dd2 | |||
258a852f5c | |||
5f9950e048 | |||
e2c439379e | |||
ce33d37396 | |||
bdf4fc4b83 | |||
0f3ebc0bde | |||
ec4fbc5d3f | |||
4e2b8857e9 | |||
3485839553 | |||
36102326db | |||
60d94fc5bb | |||
8dfcf02a0a | |||
c45dbf014e | |||
f7d6f9384d | |||
50d485fab8 | |||
5b508374d9 | |||
fbc61e065f | |||
56a52cb22a | |||
c43ec190ca | |||
639d0e3c5b | |||
8e97f3c1dd | |||
c04d940a80 | |||
76a5ea4fe9 | |||
2b0f458da3 | |||
63278c09c8 | |||
600f3d0d0f | |||
1a19eaa87d | |||
a2dde38348 | |||
dfb6d0a37c | |||
b46b59e4a0 | |||
79ec536876 | |||
00d4e9acef | |||
48eccedad0 | |||
ec4c4ac868 | |||
90835aea92 | |||
32eed75de8 | |||
c8ca5c4091 | |||
4ba81492d5 | |||
84b9877ca9 | |||
b5c9a3b35b | |||
9d7f501b1a | |||
aab76273a5 | |||
4fb63f0977 | |||
1d5db0c365 | |||
9f80a7dada | |||
46461f482a | |||
be7aa865d8 | |||
fa7036921a | |||
e0cbe34881 | |||
dcb8d6067a | |||
fc9e429bd1 | |||
94d1d2c80b | |||
edb9194153 | |||
c0708bd288 | |||
f54ba38cf5 | |||
8f10bbfed7 | |||
a4a0e13904 | |||
df696e9f17 | |||
83a05fcd40 | |||
d564ba9365 | |||
071eeda423 | |||
4788fa7272 | |||
21d544c2c7 | |||
a944fce6c5 | |||
9710d59821 | |||
30d426303e | |||
ca9da6bd0f | |||
9fedb3f88b | |||
596a097707 | |||
d51421cb14 | |||
ffea9bfbfe | |||
ffdc0f6a27 | |||
9b5c537e55 | |||
a9f1eb63c2 | |||
fd749b19e5 | |||
0cca2de1aa | |||
8b278f67fe | |||
8f3462b22a | |||
a394cb7f0d | |||
50d0b2fe56 | |||
e2bb09d50f | |||
4a2b40a4cf | |||
bed9c868f6 | |||
7a45af8856 | |||
4bafcec012 | |||
4ca150a0cb | |||
efb0aba7cd | |||
17f1ee79db | |||
d8b9c2b373 | |||
04d530a5ed | |||
b134b5a605 | |||
f8ff93fa6c | |||
5bd6a90f25 | |||
92cfc3a597 | |||
3f47da6134 | |||
3446d1590e | |||
a24ddf65a5 | |||
d6f422e0ec | |||
fbaa560551 | |||
42c2869675 | |||
eabc458176 | |||
dee7ec0b23 | |||
ab33325b8e | |||
e4cf8a1dde | |||
22a48d4a90 | |||
7020d3701c | |||
51e54d9870 | |||
b103d6e804 | |||
1aade2882b | |||
7909a6772d | |||
5f391286e5 | |||
068f961454 | |||
ad2986195d | |||
487070bcd2 | |||
646379a69a | |||
5e143e9f36 | |||
19f9a97422 | |||
aca5443bdd | |||
e59073cf00 | |||
7032bd4b2b | |||
263669362f | |||
3b2a3dd70a | |||
d1876c88aa | |||
c2bd54ca22 | |||
493bed55f0 | |||
e41a61f33b | |||
e3f2193df2 | |||
068a87d915 | |||
04e92626bd | |||
c8aeb1396d | |||
12083df14b | |||
2e0d79424f | |||
9caeac4cba | |||
c1ec929147 | |||
96fd377db2 | |||
46cb33fd7d | |||
384cc77de2 | |||
2ca4473481 | |||
b6d36fbc5c | |||
c869a640a9 | |||
874341ddf7 | |||
c111a6aff0 | |||
13793dc9ce | |||
44858edb76 | |||
8287be48b9 | |||
51d118786a | |||
0193bebf0b | |||
493e22e46b | |||
6b1211d90f | |||
ee9a6530d3 | |||
3db73a913a | |||
ce9cd9bbf1 | |||
9e50190c02 | |||
4dea8a1c5f | |||
47e7a3f4b0 | |||
a5a708895e | |||
810073cb3b | |||
bc1223e1a3 | |||
4d46f2c6d1 | |||
d2aaea1938 | |||
e996ff157a | |||
065f662b95 | |||
44c1a685a6 | |||
b02d06f1dd | |||
23fbc7a6d3 | |||
1a18f9f6b7 | |||
0c23f47bd5 | |||
aa2619b1b0 | |||
88d49bc9f7 | |||
27e7a2dffc | |||
41c15f285c | |||
5f419e3f9b | |||
9362e245ee | |||
b2082925d5 | |||
38a7d4952d | |||
23cea38da6 | |||
bf2da210ba | |||
91fb012acc | |||
61e1f3f745 | |||
50cd400ba3 | |||
470dcb48ba | |||
736f23c19a | |||
ed2b9d62a3 | |||
007b523295 | |||
061c1e9743 | |||
6904ed6817 | |||
1ed5d8d992 | |||
f70fc084be | |||
4b14ab3f4b | |||
29776f459e | |||
4ca8aa56d2 | |||
32ab9f4bb1 | |||
e002fc749a | |||
b9ad2d1551 | |||
35a8c2e0fa | |||
89f7581d17 | |||
43511dc20b | |||
05b44759c0 | |||
ba17286ab3 | |||
51e505313a | |||
a1784245a3 | |||
df7de5dd73 | |||
23419e94f1 | |||
5b34cfcc27 | |||
b1c78b50d2 | |||
238ac8bd10 | |||
c8a2e0784f | |||
23f98f190b | |||
745ab7a24c | |||
71f68f088f | |||
52a1abfb87 | |||
4bf9df5f73 | |||
8ae4dccdd6 | |||
7ac550230f | |||
c1d519826c | |||
a727ed960b | |||
c685ec82a0 | |||
934628f382 | |||
ce90f9fba2 | |||
6b25113b9f | |||
63dc329857 | |||
42094101a3 | |||
259747afae | |||
d7365dcaf1 | |||
c24d1cae0b | |||
af7b99587f | |||
13c2cce162 | |||
e9663ef794 | |||
3fd74a7fd2 | |||
21943896c7 | |||
3794f4aac6 | |||
f805a9c751 | |||
767c2cce91 | |||
ed703f6e53 | |||
e767c07a61 | |||
c1f6ee891b | |||
5d46e75068 | |||
7a67080aa0 | |||
81c28f10c1 | |||
b99edb86ac | |||
594b80f62b | |||
4bd614a633 | |||
0f6bccff02 | |||
fca6e496d8 | |||
0f5540913a | |||
8129017ad0 | |||
c0ad451134 | |||
5f3e285a8a | |||
107244cb81 | |||
e877d377c0 | |||
a565411b22 | |||
6f13af5c91 | |||
ce2de2df81 | |||
d7e4e7e5be | |||
2f312d3937 | |||
2f5b6d1523 | |||
69874bdceb | |||
8ab9c23605 | |||
324bff7e58 | |||
b036b73e11 | |||
17145e53be | |||
e988833eb9 | |||
ea3b6d50cb | |||
3f7f88e14a | |||
3396693120 | |||
ca51fed145 | |||
9c216dd805 | |||
b98b7ab95c | |||
ecf398c9d0 | |||
a80805a044 | |||
2b2b86023e | |||
3df2293741 | |||
c1a964b0d1 | |||
d2b31122b6 | |||
4adefc2cda | |||
3271e5e513 | |||
40742b00de | |||
c7b4c46ad2 | |||
9618a50646 | |||
53a459eda1 | |||
e99809cd46 | |||
fc493a2e73 | |||
048e4d12b4 | |||
c3ad6b6edd | |||
7069eabbff | |||
ffd97a696a | |||
ca529027f7 | |||
40f60cee03 | |||
aacbed836a |
14
.editorconfig
Normal file
14
.editorconfig
Normal file
@ -0,0 +1,14 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
max_line_length = 120
|
||||
tab_width = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{*.yaml,*.yml}]
|
||||
indent_size = 2
|
56
.github/workflows/ci-it.yml
vendored
Normal file
56
.github/workflows/ci-it.yml
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
pull_request:
|
||||
branches:
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
build-with-it:
|
||||
if: github.ref_name == 'main' || github.base_ref == 'main' || startsWith(github.ref_name, 'release/')
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
jdk: [ 11, 17, 21 ]
|
||||
vault: [ '1.2.0', '1.19.0' ]
|
||||
include:
|
||||
- jdk: 21
|
||||
vault: '1.19.0'
|
||||
analysis: true
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: ${{ matrix.jdk }}
|
||||
distribution: 'temurin'
|
||||
- name: Compile
|
||||
run: ./mvnw -B clean compile
|
||||
- name: Set up Vault
|
||||
run: |
|
||||
wget -q "https://releases.hashicorp.com/vault/${{ matrix.vault }}/vault_${{ matrix.vault }}_linux_amd64.zip"
|
||||
wget -q -O - "https://releases.hashicorp.com/vault/${{ matrix.vault }}/vault_${{ matrix.vault }}_SHA256SUMS" | grep linux_amd64 | sha256sum -c
|
||||
tmp="$(mktemp -d)"
|
||||
unzip "vault_${{ matrix.vault }}_linux_amd64.zip" -d "$tmp"
|
||||
rm "vault_${{ matrix.vault }}_linux_amd64.zip"
|
||||
sudo mv "$tmp/vault" /usr/bin/vault
|
||||
rm -rf "$tmp"
|
||||
- name: Test (Unit & Integration)
|
||||
env:
|
||||
VAULT_VERSION: ${{ matrix.vault }}
|
||||
run: ./mvnw -B -P coverage -P integration-test verify
|
||||
- name: Analysis
|
||||
if: matrix.analysis && env.SONAR_TOKEN != ''
|
||||
run: >
|
||||
./mvnw -B sonar:sonar
|
||||
-Dsonar.host.url=https://sonarcloud.io
|
||||
-Dsonar.organization=stklcode-github
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
44
.github/workflows/ci.yml
vendored
Normal file
44
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
- '!main'
|
||||
pull_request:
|
||||
branches:
|
||||
- '**'
|
||||
- '!main'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
jdk: [ 11, 17, 21 ]
|
||||
include:
|
||||
- jdk: 21
|
||||
analysis: true
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: ${{ matrix.jdk }}
|
||||
distribution: 'temurin'
|
||||
- name: Compile
|
||||
run: ./mvnw -B clean compile
|
||||
- name: Test (Unit)
|
||||
run: ./mvnw -B -P coverage verify
|
||||
- name: Analysis
|
||||
if: matrix.analysis && env.SONAR_TOKEN != ''
|
||||
run: >
|
||||
./mvnw -B sonar:sonar
|
||||
-Dsonar.host.url=https://sonarcloud.io
|
||||
-Dsonar.organization=stklcode-github
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
.idea
|
||||
*.iml
|
||||
|
||||
.bin
|
||||
|
||||
*~
|
2
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
2
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar
|
453
CHANGELOG.md
Normal file
453
CHANGELOG.md
Normal file
@ -0,0 +1,453 @@
|
||||
## 1.5.0 (2025-04-13)
|
||||
|
||||
### Deprecations
|
||||
* `read...Credentials()` methods for specific database mounts (#92)
|
||||
|
||||
### Features
|
||||
* Support Vault transit API (#89)
|
||||
* Support PEM certificate string from `VAULT_CACERT` environment variable (#93)
|
||||
|
||||
### Improvements
|
||||
* Replace deprecated `java.net.URL` usage with `java.net.URI` (#94)
|
||||
|
||||
### Fix
|
||||
* Fix initialization from environment without explicit port
|
||||
|
||||
### Dependencies
|
||||
* Updated Jackson to 2.18.3 (#90)
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.2 to 1.19
|
||||
|
||||
|
||||
## 1.4.0 (2024-12-07)
|
||||
|
||||
### Removal
|
||||
* Remove deprecated `get...TimeString()` on model classes (#77)
|
||||
* Drop support for deprecated `App-ID` auth backend (#61) (#78)
|
||||
|
||||
### Fix
|
||||
* Add jackson-annotations requirement to module-info (#84)
|
||||
|
||||
### Dependencies
|
||||
* Updated Jackson to 2.18.2 (#85)
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.2 to 1.18
|
||||
|
||||
|
||||
## 1.3.1 (2024-10-03)
|
||||
|
||||
### Dependencies
|
||||
* Updated Jackson to 2.18.0 (#80)
|
||||
|
||||
### Fix
|
||||
* Remove `Automatic-Module-Name` from JAR manifest (#79)
|
||||
|
||||
|
||||
## 1.3.0 (2024-06-29)
|
||||
|
||||
### Improvements
|
||||
* Simplify JSON parsing in error handler
|
||||
* Add new fields from Vault 1.16 and 1.17 to `HealthResponse`
|
||||
* `echo_duration_ms`
|
||||
* `clock_skew_ms`
|
||||
* `replication_primary_canary_age_ms`
|
||||
* `enterprise`
|
||||
* Add missing `num_uses` field to `AuthData`
|
||||
* Add `mount_type` attribute to common response model
|
||||
* Add `auth` attribute to common response model
|
||||
* Add `custom_metadata`, `cas_required` and `delete_version_after` fields for KVv2 metadata
|
||||
* Generate and attach CycloneDX SBOM
|
||||
|
||||
### Fix
|
||||
* Rename `enable_local_secret_id` to `local_secret_ids` in `AppRole` model
|
||||
|
||||
### Dependencies
|
||||
* Updated Jackson to 2.17.1
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.2 to 1.17
|
||||
|
||||
|
||||
## 1.2.0 (2023-12-11)
|
||||
|
||||
### Deprecations
|
||||
* `get...TimeString()` methods on various model classes are now deprecated
|
||||
|
||||
### Improvements
|
||||
* Parse timestamps as `ZonedDateTime` instead of `String` representation
|
||||
* Remove redundant `java.base` requirement from _module-info.java_ (#69)
|
||||
* Close Java HTTP Client when running on Java 21 or later (#70)
|
||||
* Add MFA requirements tu `AuthResponse` (#71)
|
||||
* Extend `AuthMethod` data model (#72)
|
||||
|
||||
### Dependencies
|
||||
* Updated Jackson to 2.16.0
|
||||
|
||||
|
||||
## 1.1.5 (2023-08-19)
|
||||
|
||||
### Fix
|
||||
* Fixed JSON type conversion in `SecretResponse#get(String, Class)` (#67)
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.2 to 1.15
|
||||
|
||||
|
||||
## 1.1.4 (2023-06-15)
|
||||
|
||||
### Fix
|
||||
* Use `[+-]XX:XX` notation for timezone in date/time parsing
|
||||
|
||||
### Improvements
|
||||
* Use explicit UTF-8 encoding for parsing responses
|
||||
|
||||
### Dependencies
|
||||
* Updated Jackson to 2.15.2
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.2.0 to 1.13.3
|
||||
|
||||
|
||||
## 1.1.3 (2023-01-31)
|
||||
|
||||
### Deprecations
|
||||
* AppID components (deprecated since 0.4) are marked for removal with the next major release
|
||||
|
||||
### Dependencies
|
||||
* Updated Jackson to 2.14.2
|
||||
|
||||
### Improvements
|
||||
* Minor internal refactoring
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.2.0 to 1.12.2
|
||||
|
||||
|
||||
## 1.1.2 (2022-10-26)
|
||||
|
||||
### Dependencies
|
||||
* Updated Jackson to 2.13.4.2
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.2.0 to 1.12.0
|
||||
* Disable AppID tests for Vault 1.12 and above (auth method removed)
|
||||
* Tested with Java 19
|
||||
|
||||
|
||||
## 1.1.1 (2022-08-29)
|
||||
|
||||
### Dependencies
|
||||
* Updated Jackson to 2.13.3
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.11.2
|
||||
* Tested with Java 18
|
||||
|
||||
|
||||
## 1.1.0 (2022-04-24)
|
||||
|
||||
### Fix
|
||||
* Use `replication_performance_mode` instead of `replication_perf_mode` in health response.
|
||||
|
||||
### Improvements
|
||||
* Add `migration`, `recovery_seal` and `storage_type` fields to `SealReponse` model
|
||||
* Add support for `wrap_info` in data response models
|
||||
* Dependency updates
|
||||
* Model and response classes implement `Serializable` (#57)
|
||||
* Split `SercretResponse` into `PlainSecretResponse` and `MetaSecretResponse` subclasses (common API unchanged)
|
||||
* Add missing fields to `AuthMethod` model
|
||||
* Add support for (dis)allowed policy glob patterns in `TokenRole`
|
||||
* Add request ID to data response models
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.10.1
|
||||
|
||||
|
||||
## 1.0.1 (2021-11-21)
|
||||
|
||||
### Fix
|
||||
* Make `HTTPVaultConnectorBuilder#withPort(Integer)` null-safe (#56)
|
||||
* Make system-lambda dependency test-only (#58)
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.9.0
|
||||
|
||||
## 1.0.0 (2021-10-02)
|
||||
|
||||
### Breaking
|
||||
* Requires Java 11 or later
|
||||
* Builder invocation has changed, use `HTTPVaultConnector.builder()....build()`
|
||||
|
||||
### Removal
|
||||
* Remove deprecated `VaultConnectorFactory` in favor of `VaultConnectorBuilder` with identical API
|
||||
* Remove deprecated `AppRoleBuilder` and `TokenBuilder` in favor of `AppRole.Builder` and `Token.Builder`
|
||||
* Remove deprecated `Period`, `Policy` and `Policies` methods from `AppRole` in favor of `Token`-prefixed versions
|
||||
* Remove deprecated `SecretResponse#getValue()` method, use `get("value")` instead
|
||||
* Remove deprecated convenience methods for interaction with "secret" mount
|
||||
|
||||
### Improvements
|
||||
* Use pre-sized map objects for fixed-size payloads
|
||||
* Remove Apache HTTP Client dependency in favor of Java 11 HTTP
|
||||
* Introduce Java module descriptor
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.8.3
|
||||
|
||||
|
||||
## 0.9.5 (2021-07-28)
|
||||
|
||||
### Deprecations
|
||||
* Deprecate ` {read,write,delete}Secret()` convenience methods. Use `{read,write,delete}("secret/...")` instead (#52)
|
||||
* Deprecated builder invocation `VaultConnectorBuilder.http()` in favor of `HTTPVaultConnector.builder()` (#51)
|
||||
* Deprecated `de.stklcode.jvault.connector.builder.HTTPVaultConnectorBuilder` in favor of `de.stklcode.jvault.connector.HTTPVaultConnectorBuilder` (only package changed) (#51)
|
||||
|
||||
Old builders will be removed in 1.0
|
||||
|
||||
### Improvements
|
||||
* Minor dependency updates
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.8.0
|
||||
|
||||
## 0.9.4 (2021-06-06)
|
||||
|
||||
### Deprecations
|
||||
* `AppRole.Builder#wit0hTokenPeriod()` is deprecated in favor of `#withTokenPeriod()` (#49)
|
||||
|
||||
### Improvements
|
||||
* Minor dependency updates
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.7.2
|
||||
|
||||
## 0.9.3 (2021-04-02)
|
||||
|
||||
### Improvements
|
||||
* Use pre-sized map objects for fixed-size payloads
|
||||
* Minor dependency updates
|
||||
* Unit test adjustments for JDK 16 build environments
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.7.0
|
||||
|
||||
## 0.9.2 (2021-01-24)
|
||||
|
||||
### Fixes
|
||||
* Only initialize custom trust managers, if CA certificate is actually provided (#43)
|
||||
|
||||
### Improvements
|
||||
* Minor dependency updates
|
||||
|
||||
## 0.9.1 (2021-01-03)
|
||||
|
||||
### Improvements
|
||||
* Dependency updates
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.6.1
|
||||
|
||||
## 0.9.0 (2020-04-29)
|
||||
|
||||
### Fixes
|
||||
* Correctly parse Map field for token metadata (#34)
|
||||
* Correctly map token policies on token lookup (#35)
|
||||
|
||||
### Features
|
||||
* Support for token types (#26)
|
||||
* Support for token role handling (#27) (#37)
|
||||
|
||||
### Improvements
|
||||
* Added `entity_id`, `token_policies`, `token_type` and `orphan` flags to auth response
|
||||
* Added `entity_id`, `expire_time`, `explicit_max_ttl`, `issue_time`, `renewable` and `type` flags to token data
|
||||
* Added `explicit_max_ttl`, `period` and `entity_alias` flags to _Token_ model (#41)
|
||||
* Added `enable_local_secret_ids`, `token_bound_cidrs`, `token_explicit_max_ttl`, `token_no_default_policy`,
|
||||
`token_num_uses`, `token_period` and `token_type` flags to _AppRole_ model
|
||||
* Minor dependency updates
|
||||
|
||||
### Deprecations
|
||||
* `AppRole#getPolicies()` and `#setPolicies()` are deprecated in favor of `#getTokenPolicies()` and `#setTokenPolicies()`
|
||||
* `AppRole#getPeriod()` is deprecated in favor of `#getTokenPeriod()`
|
||||
* `AppRoleBuilder` and `TokenBuilder` in favor of `AppRole.Builder` and `Token.Builder`
|
||||
* All-arg constructors of `AppRole` and `Token` in favor of `.builder()....build()` introduced in 0.8
|
||||
|
||||
### Removals
|
||||
* Deprecated methods `AppRole#getBoundCidrList()`, `#setBoundCidrList()` and `getBoundCidrListString()` have been removed.
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.4.0
|
||||
|
||||
|
||||
## 0.8.2 (2019-10-20)
|
||||
|
||||
### Fixes
|
||||
* Fixed token lookup (#31)
|
||||
|
||||
### Improvements
|
||||
* Updated dependencies
|
||||
|
||||
## 0.8.1 (2019-08-16)
|
||||
### Fixes
|
||||
* Removed compile dependency to JUnit library (#30)
|
||||
|
||||
### Improvements
|
||||
* Updated dependencies
|
||||
|
||||
### Test
|
||||
* Tested against Vault 1.2.2
|
||||
|
||||
## 0.8.0 (2019-03-24)
|
||||
### Breaking
|
||||
* Moved Maven artifact to `de.stklcode.jvault:jvault-connector` (#28)
|
||||
* Removed support for `HTTPVaultConnectorFactory#withSslContext()` in favor of `#withTrustedCA()` due to
|
||||
|
||||
### Features
|
||||
* Support for KV version 2 secret engine (#16)
|
||||
* Ability to pass custom mount point to KV v2 read/write methods (#25)
|
||||
|
||||
### Improvements
|
||||
* refactoring of the internal SSL handling (#17)
|
||||
* `VaultConnector` extends `java.io.Serializable` (#19)
|
||||
* Added missing flags to `SealResponse` (#20)
|
||||
* Added replication flags to `HealthResponse` (#21)
|
||||
* Enforce TLS 1.2 by default with option to override (#22)
|
||||
* Build environment and tests now compatible with Java 10
|
||||
* Updated dependencies to fix vulnerabilities (i.e. CVE-2018-7489)
|
||||
* New static method `Token.builder()` to get token builder instance
|
||||
* New static method `AppRole.builder()` to get AppRole builder instance
|
||||
|
||||
### Deprecation
|
||||
* `VaultConnectorFactory` is deprecated in favor of `VaultConnectorBuilder` with identical API (#18)
|
||||
* `AppRoleBuilder#withBoundCidrList(List)` is deprecated in favor of `AppRoleBuilder#withSecretIdBoundCidrs(List)` (#24)
|
||||
|
||||
|
||||
## 0.7.1 (2018-03-17)
|
||||
### Improvements
|
||||
* Added automatic module name for JPMS compatibility
|
||||
* Minor dependency updates
|
||||
|
||||
### Test
|
||||
* Tested against Vault 0.9.5
|
||||
|
||||
|
||||
## 0.7.0 (2017-10-03)
|
||||
### Features
|
||||
* Retrieval of health status via `getHealth()` (#15)
|
||||
|
||||
### Improvements
|
||||
* `seal()`, `unseal()` are now `void` and throw Exception on error (#12)
|
||||
* Adaptation to Vault 0.8 endpoints for `renew` and `revoke`, **breaking** 0.7 compatibility (#11)
|
||||
|
||||
### Removed
|
||||
* Removed deprecated `listAppRoleSecretss()` (use `listAppRoleSecrets()`) (#14)
|
||||
|
||||
### Test
|
||||
* Tested against Vault 0.8.3
|
||||
|
||||
|
||||
## 0.6.2 [2017-08-19]
|
||||
### Fixes
|
||||
* Prevent potential NPE on SecretResponse getter
|
||||
* Removed stack traces on PUT request and response deserialization (#13)
|
||||
|
||||
### Improvements
|
||||
* 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)
|
||||
### Fixes
|
||||
* `TokenModel.getPassword()` returned username instead of password
|
||||
* `TokenModel.getUsername()` and `getPassword()` could produce NPE in multithreaded environments
|
||||
* `TokenData.getCreatinTtl()` renamed to `getCreationTtl()` (typo fix)
|
||||
|
||||
### Test
|
||||
* Tested against Vault 0.7.3
|
||||
|
||||
|
||||
## 0.6.0 (2017-05-12)
|
||||
### Features
|
||||
* Initialization from environment variables using `fromEnv()` in factory (#8)
|
||||
* Automatic authentication with `buildAndAuth()`
|
||||
* Custom timeout and number of retries (#9)
|
||||
* Connector implements `AutoCloseable`
|
||||
|
||||
### Fixes
|
||||
* `SecretResponse` does not throw NPE on `get(key)` and `getData()`
|
||||
|
||||
### Test
|
||||
* Tested against Vault 0.7.2
|
||||
|
||||
|
||||
## 0.5.0 (2017-03-18)
|
||||
### Features
|
||||
* Convenience methods for DB credentials (#7)
|
||||
|
||||
### Fixes
|
||||
* Minor bugfix in TokenBuilder
|
||||
|
||||
### Deprecation
|
||||
* `SecretResponse.getValue()` deprecated
|
||||
|
||||
### Test
|
||||
* Tested against Vault 0.7.0
|
||||
|
||||
|
||||
## 0.4.1 [2016-12-24]
|
||||
### Fixes
|
||||
* Factory Null-tolerant for trusted certificate (#6)
|
||||
|
||||
### Test
|
||||
* StackTraces tested for secret leaks
|
||||
* Tested against Vault 0.6.4
|
||||
|
||||
|
||||
## 0.4.0 (2016-11-06)
|
||||
### Features
|
||||
* Option to provide a trusted CA certificate (#2)
|
||||
* Deletion, revocation and renewal of secrets (#3)
|
||||
* Token creation (#4)
|
||||
* AppRole auth backend supported (#5)
|
||||
|
||||
### Improvements
|
||||
* Support for complex secrets
|
||||
|
||||
### Deprecation
|
||||
* App-ID backend marked as deprecated
|
||||
|
||||
|
||||
## 0.3.0 (2016-10-07)
|
||||
### Features
|
||||
* Retrieval of JSON objects (#1)
|
||||
|
||||
### Test
|
||||
* Tested against Vault 0.6.2
|
||||
|
||||
|
||||
## 0.2.0 (2016-09-01)
|
||||
### Improvements
|
||||
* Dependecies updated and CommonsIO removed
|
||||
|
||||
### Fixes
|
||||
* Fixed auth backend detection for Vault 0.6.1
|
||||
|
||||
### Test
|
||||
* Tested against Vault 0.6.1
|
||||
|
||||
|
||||
## 0.1.1 (2016-06-20)
|
||||
### Fixes
|
||||
* 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
|
112
CONTRIBUTING.md
Normal file
112
CONTRIBUTING.md
Normal file
@ -0,0 +1,112 @@
|
||||
# How to contribute
|
||||
|
||||
As for all great Open Source projects, contributions in form of bug reports and code are welcome and important to keep the project alive.
|
||||
|
||||
In general, this project follows the [GitHub Flow](https://guides.github.com/introduction/flow/).
|
||||
Fork the project, commit your changes to your branch, open a pull request and it will probably be merged.
|
||||
However, to ensure maintainability and quality of the code, there are some guidelines you might be more or less familiar with.
|
||||
For that purpose, this document describes the important points.
|
||||
|
||||
## Opening an Issue
|
||||
|
||||
If you experience any issues with the library or the code, don't hesitate to file an issue.
|
||||
|
||||
### Bug Reports
|
||||
|
||||
Think you found a bug?
|
||||
Please clearly state what happens and describe your environment to help tracking down the issue.
|
||||
|
||||
* Which version of the connector are you running?
|
||||
* Which version of Java (architecture and OS if relevant)?
|
||||
* Which version of Vault?
|
||||
|
||||
### Feature Requests
|
||||
|
||||
Missing a feature or like to have certain functionality enhanced?
|
||||
No problem, please open an issue and describe what and why you think this change is required.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
If you want to contribute your code to solve an issue or implement a desired feature yourself, you might open a pull request.
|
||||
If the changes introduce new functionality or affect major parts of existing code, please consider opening an issue for discussion first.
|
||||
|
||||
Extending or adapting JUnit test cases would be nice (no hard criterion though).
|
||||
|
||||
The `main` branch also be target for most pull requests.
|
||||
However, if it features new functionality you might want to target the `develop` branch instead (see next section for details on branches).
|
||||
|
||||
### Branches
|
||||
|
||||
The `main` branch represents the current, more or less stable state of development.
|
||||
Please ensure your initial code is up to date with it at the time you start development.
|
||||
|
||||
In addition, this project features a `develop` branch, which holds bleeding edge developments, not necessarily considered stable or even compatible.
|
||||
Do not expect this code to run smoothly, but you might have a look into the history to see if some work on an issue has already been started there.
|
||||
|
||||
For fixes and features, there might be additional branches, likely prefixed by `fix/` or `feature/` followed by an issue number (if applicable) and/or a title.
|
||||
Feel free to adapt this naming scheme to your forks.
|
||||
|
||||
### Merge Requirements
|
||||
|
||||
To be merged into the main branch, your code has to pass the automated continuous integration tests, to ensure compatibility.
|
||||
In addition, your code has to be approved by a project member.
|
||||
|
||||
#### What if my code fails the tests?
|
||||
|
||||
Don't worry, you can submit your PR anyway.
|
||||
The reviewing process might help you to solve remaining issues.
|
||||
|
||||
### Commit messages
|
||||
|
||||
Please use speaking titles and messages for your commits, to ensure a transparent history.
|
||||
If your patch fixes an issue, reference the ID in the first line.
|
||||
If you feel like you have to _briefly_ explain your changes, do it (for long explanations and discussion, consider opening an issue or describe in the PR).
|
||||
|
||||
**Example commit:**
|
||||
```text
|
||||
Fix nasty bug from #1337
|
||||
|
||||
This example commit fixes the issue that some people write non-speaking commit messages like 'done magic'.
|
||||
A short description is helpful sometimes.
|
||||
```
|
||||
|
||||
You might sign your work, although that's no must.
|
||||
|
||||
### When will it be merged?
|
||||
|
||||
Short answer: When it makes sense.
|
||||
|
||||
Bugfixes should be merged in time - assuming they pass the above criteria.
|
||||
New features might be assigned to a certain milestone and as a result of this be scheduled according to the planned release cycle.
|
||||
|
||||
## Compatibility
|
||||
|
||||
To ensure usability for a wide range of users, please take note on the software requirements stated in the `README`.
|
||||
This includes especially Java versions and a minimum version of _Vault_.
|
||||
|
||||
If you are unsure if your code matches these versions, the test will probably tell you.
|
||||
|
||||
In case you think, your change is more important than maintaining backwards compatibility, please start a discussion to see,
|
||||
if we might increase the minimum version or find a workaround for legacy systems.
|
||||
|
||||
## Build Environment
|
||||
|
||||
All you need to start off - besides your favorite IDE and a JDK of course - is [Maven](https://maven.apache.org/).
|
||||
|
||||
## Unit Tests
|
||||
|
||||
The code is tested by JUnit tests.
|
||||
For standalone testing against mocked APIs the _Maven_ profile `offline-test` should be used.
|
||||
Otherwise, there is a test suite that requires an actual _Vault_ binary in the executable path to start a real server instance.
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
Automated tests are run using [GitHub Actions](https://github.com/features/actions) for every commit including pull requests.
|
||||
Tests usually run against the minimal supported version, all supported LTS versions and the latest version of Java.
|
||||
|
||||
There is an automated code quality analysis pushing results to [SonarCloud](https://sonarcloud.io/dashboard?id=de.stklcode.jvault%3Ajvault-connector).
|
||||
|
||||
## Still Open Questions?
|
||||
|
||||
If anything is still left unanswered and you're unsure if you got it right, don't hesitate to contact a team member.
|
||||
In any case you might submit your request/issue anyway, we won't refuse good code only for formal reasons.
|
125
README.md
125
README.md
@ -1,58 +1,127 @@
|
||||
Java Vault Connector
|
||||
=========
|
||||
# Java Vault Connector
|
||||
|
||||
[](https://github.com/stklcode/jvaultconnector/actions/workflows/ci.yml)
|
||||
[](https://sonarcloud.io/summary/new_code?id=de.stklcode.jvault%3Ajvault-connector)
|
||||
[](https://github.com/stklcode/jvaultconnector/blob/main/LICENSE.txt)
|
||||
[](https://central.sonatype.com/artifact/de.stklcode.jvault/jvault-connector)
|
||||
|
||||

|
||||
|
||||
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)
|
||||
* AppRole (register and authenticate)
|
||||
* Tokens
|
||||
* Creation and lookup of tokens and token roles
|
||||
* TokenBuilder for speaking creation of complex configurations
|
||||
* Secrets
|
||||
* Read secrets
|
||||
* Write secrets
|
||||
* List secrets
|
||||
* Delete secrets
|
||||
* Renew/revoke leases
|
||||
* Raw secret content or JSON decoding
|
||||
* KV v1 and v2 support
|
||||
* Database secret handling
|
||||
* Transit API support
|
||||
* Connector Factory with builder pattern
|
||||
* Tested against Vault 0.6.1
|
||||
* Tested against Vault 1.2 to 1.19
|
||||
|
||||
**Usage Example**
|
||||
|
||||
## Maven Artifact
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>de.stklcode.jvault</groupId>
|
||||
<artifactId>jvault-connector</artifactId>
|
||||
<version>1.5.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Initialization
|
||||
|
||||
```java
|
||||
// Instanciate using builder pattern style factory
|
||||
VaultConnector vault = VaultConnectorFactory.httpFactory()
|
||||
.wiithHost("127.0.0.1")
|
||||
// Instantiate using builder pattern style factory (TLS enabled by default)
|
||||
VaultConnector vault = HTTPVaultConnector.builder()
|
||||
.withHost("127.0.0.1")
|
||||
.withPort(8200)
|
||||
.withTLS()
|
||||
.build();
|
||||
|
||||
//authenticate with token
|
||||
// Instantiate with custom SSL context
|
||||
VaultConnector vault = HTTPVaultConnector.builder("https://example.com:8200/v1/")
|
||||
.withTrustedCA(Paths.get("/path/to/CA.pem"))
|
||||
.build();
|
||||
|
||||
// Initialization from environment variables
|
||||
VaultConnector vault = HTTPVaultConnector.builder()
|
||||
.fromEnv()
|
||||
.build();
|
||||
```
|
||||
|
||||
### Authentication
|
||||
|
||||
```java
|
||||
// Authenticate with token.
|
||||
vault.authToken("01234567-89ab-cdef-0123-456789abcdef");
|
||||
|
||||
// retrieve secret
|
||||
String secret = vault.readSecret("some/secret/key").getValue();
|
||||
// Authenticate with username and password.
|
||||
vault.authUserPass("username", "p4ssw0rd");
|
||||
|
||||
// Authenticate with AppRole (secret - 2nd argument - is optional).
|
||||
vault.authAppRole("01234567-89ab-cdef-0123-456789abcdef", "fedcba98-7654-3210-fedc-ba9876543210");
|
||||
```
|
||||
|
||||
**Maven Artifact**
|
||||
```
|
||||
<dependency>
|
||||
<groupId>de.stklcode.jvault</groupId>
|
||||
<artifactId>connector</artifactId>
|
||||
<version>0.2.0</version>
|
||||
</dependency>
|
||||
### Secret read & write
|
||||
|
||||
```java
|
||||
// Retrieve secret (prefix "secret/" assumed, use read() to read arbitrary paths)
|
||||
String secret = vault.read("secret/some/key").get("value", String.class);
|
||||
|
||||
// Complex secret.
|
||||
Map<String, Object> secretData = vault.read("secret/another/key").getData();
|
||||
|
||||
// Write simple secret.
|
||||
vault.write("secret/new/key", "secret value");
|
||||
|
||||
// Write complex data.
|
||||
Map<String, Object> map = ...;
|
||||
vault.write("path/to/write", map);
|
||||
|
||||
// Delete secret.
|
||||
vault.delete("path/to/delete");
|
||||
```
|
||||
|
||||
**Links**
|
||||
### Token and role creation
|
||||
|
||||
[Project Page](http://jvault.stklcode.de)
|
||||
```java
|
||||
// Create token using TokenBuilder
|
||||
Token token = Token.builder()
|
||||
.withId("token id")
|
||||
.withDisplayName("new test token")
|
||||
.withPolicies("pol1", "pol2")
|
||||
.build();
|
||||
vault.createToken(token);
|
||||
|
||||
[JavaDoc API](http://jvault.stklcode.de/apidocs/)
|
||||
// Create AppRole credentials
|
||||
vault.createAppRole("testrole", policyList);
|
||||
AppRoleSecretResponse secret = vault.createAppRoleSecret("testrole");
|
||||
```
|
||||
|
||||
**Planned features:**
|
||||
## Links
|
||||
|
||||
* Creation and modification of policies
|
||||
* Implement more authentication methods
|
||||
[Project Page](https://jvault.stklcode.de)
|
||||
|
||||
**License**
|
||||
[JavaDoc API](https://jvault.stklcode.de/apidocs/)
|
||||
|
||||
The project is licensed under [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0).
|
||||
## License
|
||||
|
||||
The project is licensed under [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
|
||||
|
BIN
assets/logo.png
Normal file
BIN
assets/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
12
assets/logo.svg
Normal file
12
assets/logo.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128">
|
||||
<path d="M4,12 l60,104 l60,-104 z" stroke="none" fill="#000000" />
|
||||
<rect x="74" y="20" width="8" height="8" stroke="none" fill="#00abe0" />
|
||||
<rect x="74" y="34" width="8" height="8" stroke="none" fill="#00abe0" />
|
||||
<rect x="74" y="48" width="8" height="8" stroke="none" fill="#00abe0" />
|
||||
<rect x="74" y="62" width="8" height="8" stroke="none" fill="#00abe0" />
|
||||
<rect x="68" y="74" width="8" height="8" stroke="none" fill="#00abe0" />
|
||||
<rect x="54" y="74" width="8" height="8" stroke="none" fill="#00abe0" />
|
||||
<rect x="48" y="62" width="8" height="8" stroke="none" fill="#00abe0" />
|
||||
</svg>
|
After Width: | Height: | Size: 837 B |
332
mvnw
vendored
Executable file
332
mvnw
vendored
Executable file
@ -0,0 +1,332 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------------
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Apache Maven Wrapper startup batch script, version 3.3.2
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
# e.g. to debug Maven itself, use
|
||||
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if [ -z "$MAVEN_SKIP_RC" ]; then
|
||||
|
||||
if [ -f /usr/local/etc/mavenrc ]; then
|
||||
. /usr/local/etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f /etc/mavenrc ]; then
|
||||
. /etc/mavenrc
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.mavenrc" ]; then
|
||||
. "$HOME/.mavenrc"
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# OS specific support. $var _must_ be set to either true or false.
|
||||
cygwin=false
|
||||
darwin=false
|
||||
mingw=false
|
||||
case "$(uname)" in
|
||||
CYGWIN*) cygwin=true ;;
|
||||
MINGW*) mingw=true ;;
|
||||
Darwin*)
|
||||
darwin=true
|
||||
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
|
||||
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -x "/usr/libexec/java_home" ]; then
|
||||
JAVA_HOME="$(/usr/libexec/java_home)"
|
||||
export JAVA_HOME
|
||||
else
|
||||
JAVA_HOME="/Library/Java/Home"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
if [ -r /etc/gentoo-release ]; then
|
||||
JAVA_HOME=$(java-config --jre-home)
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin; then
|
||||
[ -n "$JAVA_HOME" ] \
|
||||
&& JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] \
|
||||
&& CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
|
||||
fi
|
||||
|
||||
# For Mingw, ensure paths are in UNIX format before anything is touched
|
||||
if $mingw; then
|
||||
[ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] \
|
||||
&& JAVA_HOME="$(
|
||||
cd "$JAVA_HOME" || (
|
||||
echo "cannot cd into $JAVA_HOME." >&2
|
||||
exit 1
|
||||
)
|
||||
pwd
|
||||
)"
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
javaExecutable="$(which javac)"
|
||||
if [ -n "$javaExecutable" ] && ! [ "$(expr "$javaExecutable" : '\([^ ]*\)')" = "no" ]; then
|
||||
# readlink(1) is not available as standard on Solaris 10.
|
||||
readLink=$(which readlink)
|
||||
if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
|
||||
if $darwin; then
|
||||
javaHome="$(dirname "$javaExecutable")"
|
||||
javaExecutable="$(cd "$javaHome" && pwd -P)/javac"
|
||||
else
|
||||
javaExecutable="$(readlink -f "$javaExecutable")"
|
||||
fi
|
||||
javaHome="$(dirname "$javaExecutable")"
|
||||
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
|
||||
JAVA_HOME="$javaHome"
|
||||
export JAVA_HOME
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$JAVACMD" ]; then
|
||||
if [ -n "$JAVA_HOME" ]; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
else
|
||||
JAVACMD="$(
|
||||
\unset -f command 2>/dev/null
|
||||
\command -v java
|
||||
)"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVACMD" ]; then
|
||||
echo "Error: JAVA_HOME is not defined correctly." >&2
|
||||
echo " We cannot execute $JAVACMD" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$JAVA_HOME" ]; then
|
||||
echo "Warning: JAVA_HOME environment variable is not set." >&2
|
||||
fi
|
||||
|
||||
# traverses directory structure from process work directory to filesystem root
|
||||
# first directory with .mvn subdirectory is considered project base directory
|
||||
find_maven_basedir() {
|
||||
if [ -z "$1" ]; then
|
||||
echo "Path not specified to find_maven_basedir" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
basedir="$1"
|
||||
wdir="$1"
|
||||
while [ "$wdir" != '/' ]; do
|
||||
if [ -d "$wdir"/.mvn ]; then
|
||||
basedir=$wdir
|
||||
break
|
||||
fi
|
||||
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
|
||||
if [ -d "${wdir}" ]; then
|
||||
wdir=$(
|
||||
cd "$wdir/.." || exit 1
|
||||
pwd
|
||||
)
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
printf '%s' "$(
|
||||
cd "$basedir" || exit 1
|
||||
pwd
|
||||
)"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
# Remove \r in case we run on Windows within Git Bash
|
||||
# and check out the repository with auto CRLF management
|
||||
# enabled. Otherwise, we may read lines that are delimited with
|
||||
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
|
||||
# splitting rules.
|
||||
tr -s '\r\n' ' ' <"$1"
|
||||
fi
|
||||
}
|
||||
|
||||
log() {
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
printf '%s\n' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
export MAVEN_PROJECTBASEDIR
|
||||
log "$MAVEN_PROJECTBASEDIR"
|
||||
|
||||
##########################################################################################
|
||||
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
# This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
##########################################################################################
|
||||
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if [ -r "$wrapperJarPath" ]; then
|
||||
log "Found $wrapperJarPath"
|
||||
else
|
||||
log "Couldn't find $wrapperJarPath, downloading it ..."
|
||||
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
|
||||
else
|
||||
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
|
||||
fi
|
||||
while IFS="=" read -r key value; do
|
||||
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
|
||||
safeValue=$(echo "$value" | tr -d '\r')
|
||||
case "$key" in wrapperUrl)
|
||||
wrapperUrl="$safeValue"
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
log "Downloading from: $wrapperUrl"
|
||||
|
||||
if $cygwin; then
|
||||
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
|
||||
fi
|
||||
|
||||
if command -v wget >/dev/null; then
|
||||
log "Found wget ... using wget"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
else
|
||||
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl >/dev/null; then
|
||||
log "Found curl ... using curl"
|
||||
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
else
|
||||
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
else
|
||||
log "Falling back to using Java to download"
|
||||
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaSource=$(cygpath --path --windows "$javaSource")
|
||||
javaClass=$(cygpath --path --windows "$javaClass")
|
||||
fi
|
||||
if [ -e "$javaSource" ]; then
|
||||
if [ ! -e "$javaClass" ]; then
|
||||
log " - Compiling MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/javac" "$javaSource")
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
log " - Running MavenWrapperDownloader.java ..."
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
|
||||
wrapperSha256Sum=""
|
||||
while IFS="=" read -r key value; do
|
||||
case "$key" in wrapperSha256Sum)
|
||||
wrapperSha256Sum=$value
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ -n "$wrapperSha256Sum" ]; then
|
||||
wrapperSha256Result=false
|
||||
if command -v sha256sum >/dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c >/dev/null 2>&1; then
|
||||
wrapperSha256Result=true
|
||||
fi
|
||||
elif command -v shasum >/dev/null; then
|
||||
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c >/dev/null 2>&1; then
|
||||
wrapperSha256Result=true
|
||||
fi
|
||||
else
|
||||
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
|
||||
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ $wrapperSha256Result = false ]; then
|
||||
echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
|
||||
echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
|
||||
echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin; then
|
||||
[ -n "$JAVA_HOME" ] \
|
||||
&& JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
|
||||
[ -n "$CLASSPATH" ] \
|
||||
&& CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
|
||||
[ -n "$MAVEN_PROJECTBASEDIR" ] \
|
||||
&& MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
|
||||
# Provide a "standardized" way to retrieve the CLI args that will
|
||||
# work with both Windows and non-Windows executions.
|
||||
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
|
||||
export MAVEN_CMD_LINE_ARGS
|
||||
|
||||
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
# shellcheck disable=SC2086 # safe args
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
$MAVEN_DEBUG_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
206
mvnw.cmd
vendored
Normal file
206
mvnw.cmd
vendored
Normal file
@ -0,0 +1,206 @@
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||
@REM or more contributor license agreements. See the NOTICE file
|
||||
@REM distributed with this work for additional information
|
||||
@REM regarding copyright ownership. The ASF licenses this file
|
||||
@REM to you under the Apache License, Version 2.0 (the
|
||||
@REM "License"); you may not use this file except in compliance
|
||||
@REM with the License. You may obtain a copy of the License at
|
||||
@REM
|
||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
@REM
|
||||
@REM Unless required by applicable law or agreed to in writing,
|
||||
@REM software distributed under the License is distributed on an
|
||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@REM KIND, either express or implied. See the License for the
|
||||
@REM specific language governing permissions and limitations
|
||||
@REM under the License.
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM ----------------------------------------------------------------------------
|
||||
@REM Apache Maven Wrapper startup batch script, version 3.3.2
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
|
||||
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
|
||||
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
|
||||
@REM e.g. to debug Maven itself, use
|
||||
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
|
||||
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
|
||||
@REM ----------------------------------------------------------------------------
|
||||
|
||||
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
|
||||
@echo off
|
||||
@REM set title of command window
|
||||
title %0
|
||||
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
|
||||
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
|
||||
|
||||
@REM set %HOME% to equivalent of $HOME
|
||||
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
|
||||
|
||||
@REM Execute a user defined script before this one
|
||||
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
|
||||
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
|
||||
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
|
||||
:skipRcPre
|
||||
|
||||
@setlocal
|
||||
|
||||
set ERROR_CODE=0
|
||||
|
||||
@REM To isolate internal variables from possible post scripts, we use another setlocal
|
||||
@setlocal
|
||||
|
||||
@REM ==== START VALIDATION ====
|
||||
if not "%JAVA_HOME%" == "" goto OkJHome
|
||||
|
||||
echo. >&2
|
||||
echo Error: JAVA_HOME not found in your environment. >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo. >&2
|
||||
goto error
|
||||
|
||||
:OkJHome
|
||||
if exist "%JAVA_HOME%\bin\java.exe" goto init
|
||||
|
||||
echo. >&2
|
||||
echo Error: JAVA_HOME is set to an invalid directory. >&2
|
||||
echo JAVA_HOME = "%JAVA_HOME%" >&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the >&2
|
||||
echo location of your Java installation. >&2
|
||||
echo. >&2
|
||||
goto error
|
||||
|
||||
@REM ==== END VALIDATION ====
|
||||
|
||||
:init
|
||||
|
||||
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
|
||||
@REM Fallback to current working directory if not found.
|
||||
|
||||
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
|
||||
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
|
||||
|
||||
set EXEC_DIR=%CD%
|
||||
set WDIR=%EXEC_DIR%
|
||||
:findBaseDir
|
||||
IF EXIST "%WDIR%"\.mvn goto baseDirFound
|
||||
cd ..
|
||||
IF "%WDIR%"=="%CD%" goto baseDirNotFound
|
||||
set WDIR=%CD%
|
||||
goto findBaseDir
|
||||
|
||||
:baseDirFound
|
||||
set MAVEN_PROJECTBASEDIR=%WDIR%
|
||||
cd "%EXEC_DIR%"
|
||||
goto endDetectBaseDir
|
||||
|
||||
:baseDirNotFound
|
||||
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
|
||||
cd "%EXEC_DIR%"
|
||||
|
||||
:endDetectBaseDir
|
||||
|
||||
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
|
||||
|
||||
@setlocal EnableExtensions EnableDelayedExpansion
|
||||
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
|
||||
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
|
||||
|
||||
:endReadAdditionalConfig
|
||||
|
||||
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
|
||||
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
|
||||
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
|
||||
|
||||
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
|
||||
|
||||
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
|
||||
)
|
||||
|
||||
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
|
||||
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
|
||||
if exist %WRAPPER_JAR% (
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Found %WRAPPER_JAR%
|
||||
)
|
||||
) else (
|
||||
if not "%MVNW_REPOURL%" == "" (
|
||||
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %WRAPPER_URL%
|
||||
)
|
||||
|
||||
powershell -Command "&{"^
|
||||
"$webclient = new-object System.Net.WebClient;"^
|
||||
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
|
||||
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
|
||||
"}"^
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
|
||||
SET WRAPPER_SHA_256_SUM=""
|
||||
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
|
||||
)
|
||||
IF NOT %WRAPPER_SHA_256_SUM%=="" (
|
||||
powershell -Command "&{"^
|
||||
"Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash;"^
|
||||
"$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
|
||||
"If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
|
||||
" Write-Error 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
|
||||
" Write-Error 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
|
||||
" Write-Error 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
|
||||
" exit 1;"^
|
||||
"}"^
|
||||
"}"
|
||||
if ERRORLEVEL 1 goto error
|
||||
)
|
||||
|
||||
@REM Provide a "standardized" way to retrieve the CLI args that will
|
||||
@REM work with both Windows and non-Windows executions.
|
||||
set MAVEN_CMD_LINE_ARGS=%*
|
||||
|
||||
%MAVEN_JAVA_EXE% ^
|
||||
%JVM_CONFIG_MAVEN_PROPS% ^
|
||||
%MAVEN_OPTS% ^
|
||||
%MAVEN_DEBUG_OPTS% ^
|
||||
-classpath %WRAPPER_JAR% ^
|
||||
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
|
||||
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
|
||||
if ERRORLEVEL 1 goto error
|
||||
goto end
|
||||
|
||||
:error
|
||||
set ERROR_CODE=1
|
||||
|
||||
:end
|
||||
@endlocal & set ERROR_CODE=%ERROR_CODE%
|
||||
|
||||
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
|
||||
@REM check for post script, once with legacy .bat ending and once with .cmd ending
|
||||
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
|
||||
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
|
||||
:skipRcPost
|
||||
|
||||
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
|
||||
if "%MAVEN_BATCH_PAUSE%"=="on" pause
|
||||
|
||||
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
|
||||
|
||||
cmd /C exit /B %ERROR_CODE%
|
445
pom.xml
445
pom.xml
@ -2,60 +2,419 @@
|
||||
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>
|
||||
<artifactId>jvault-connector</artifactId>
|
||||
<version>1.5.1-SNAPSHOT</version>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>jVaultConnector</name>
|
||||
<description>Connector artifact for Hashicorp's Vault secret management</description>
|
||||
<url>https://jvault.stklcode.de</url>
|
||||
<inceptionYear>2016</inceptionYear>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>Apache License 2.0</name>
|
||||
<url>https://www.apache.org/licenses/LICENSE-2.0.html</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Stefan Kalscheuer</name>
|
||||
<email>stefan@stklcode.de</email>
|
||||
<timezone>Europe/Berlin</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git://github.com/stklcode/jvaultconnector.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:stklcode/jvaultconnector.git</developerConnection>
|
||||
<url>https://github.com/stklcode/jvaultconnector</url>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
|
||||
<issueManagement>
|
||||
<system>GitHub Issues</system>
|
||||
<url>https://github.com/stklcode/jvaultconnector/issues</url>
|
||||
</issueManagement>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<argLine></argLine>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.18.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<version>2.18.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.12.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>5.17.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.stefanbirkner</groupId>
|
||||
<artifactId>system-lambda</artifactId>
|
||||
<version>1.2.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wiremock</groupId>
|
||||
<artifactId>wiremock</artifactId>
|
||||
<version>3.13.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.19.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>nl.jqno.equalsverifier</groupId>
|
||||
<artifactId>equalsverifier</artifactId>
|
||||
<version>3.19.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<version>4.3.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>3.14.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<release>11</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>3.1.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>3.5.3</version>
|
||||
<configuration>
|
||||
<argLine>
|
||||
@{argLine}
|
||||
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.test=com.fasterxml.jackson.databind
|
||||
</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>3.1.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.4.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.5.3</version>
|
||||
<configuration>
|
||||
<argLine>
|
||||
@{argLine}
|
||||
--add-opens java.base/java.util=ALL-UNNAMED
|
||||
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector=ALL-UNNAMED
|
||||
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.exception=ALL-UNNAMED
|
||||
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.model=ALL-UNNAMED
|
||||
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.model.response=ALL-UNNAMED
|
||||
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.model.response.embedded=ALL-UNNAMED
|
||||
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.test=com.fasterxml.jackson.databind
|
||||
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.test=com.fasterxml.jackson.datatype.jsr310
|
||||
</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.cyclonedx</groupId>
|
||||
<artifactId>cyclonedx-maven-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.13</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.sonarsource.scanner.maven</groupId>
|
||||
<artifactId>sonar-maven-plugin</artifactId>
|
||||
<version>5.1.0.4751</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce-versions</id>
|
||||
<goals>
|
||||
<goal>enforce</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<requireMavenVersion>
|
||||
<version>[3.6.3,)</version>
|
||||
</requireMavenVersion>
|
||||
<requireJavaVersion>
|
||||
<version>[11,)</version>
|
||||
</requireJavaVersion>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>sources</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>javadoc</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.11.2</version>
|
||||
<configuration>
|
||||
<source>11</source>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>sbom</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.cyclonedx</groupId>
|
||||
<artifactId>cyclonedx-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>makeBom</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<skipNotDeployed>false</skipNotDeployed>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>sign</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>3.2.7</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<keyname>${gpg.keyname}</keyname>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>coverage</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>default-report</id>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>integration-test</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>dependency-check</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>12.1.1</version>
|
||||
<configuration>
|
||||
<nvdApiKey>${env.NVD_API_KEY}</nvdApiKey>
|
||||
<nvdDatafeedUrl>${env.NVD_DATAFEED_URL}</nvdDatafeedUrl>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>central</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.sonatype.central</groupId>
|
||||
<artifactId>central-publishing-maven-plugin</artifactId>
|
||||
<version>0.7.0</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<publishingServerId>central</publishingServerId>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<packaging>jar</packaging>
|
||||
</profile>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpcore</artifactId>
|
||||
<version>4.4.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.8.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.8.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-junit</artifactId>
|
||||
<version>2.0.0.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<profile>
|
||||
<id>local</id>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>stklcode</id>
|
||||
<url>${dist.repo.local}</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>stklcode</id>
|
||||
<url>${dist.repo.local.snapshot}</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,442 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.ConnectionException;
|
||||
import de.stklcode.jvault.connector.exception.TlsException;
|
||||
import de.stklcode.jvault.connector.exception.VaultConnectorException;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* Vault Connector Builder implementation for HTTP Vault connectors.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.8.0
|
||||
* @since 0.9.5 Package {@link de.stklcode.jvault.connector}
|
||||
*/
|
||||
public final class HTTPVaultConnectorBuilder {
|
||||
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_TLS_VERSION = "TLSv1.2";
|
||||
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 tlsVersion;
|
||||
private String prefix;
|
||||
private X509Certificate trustedCA;
|
||||
private int numberOfRetries;
|
||||
private Integer timeout;
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* Default empty constructor.
|
||||
* Initializes factory with default values.
|
||||
*/
|
||||
HTTPVaultConnectorBuilder() {
|
||||
host = DEFAULT_HOST;
|
||||
port = DEFAULT_PORT;
|
||||
tls = DEFAULT_TLS;
|
||||
tlsVersion = DEFAULT_TLS_VERSION;
|
||||
prefix = DEFAULT_PREFIX;
|
||||
numberOfRetries = DEFAULT_NUMBER_OF_RETRIES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set base URL, e.g. "protocol://host:port/prefix".
|
||||
*
|
||||
* @param baseURL Base URL
|
||||
* @return self
|
||||
* @throws URISyntaxException Invalid URI syntax.
|
||||
* @since 1.0
|
||||
*/
|
||||
public HTTPVaultConnectorBuilder withBaseURL(final String baseURL) throws URISyntaxException {
|
||||
return withBaseURL(new URI(baseURL));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set base URL, e.g. "protocol://host:port/prefix".
|
||||
*
|
||||
* @param baseURL Base URL
|
||||
* @return self
|
||||
* @since 1.0
|
||||
*/
|
||||
public HTTPVaultConnectorBuilder withBaseURL(final URI baseURL) {
|
||||
String path = baseURL.getPath();
|
||||
if (path == null || path.isBlank()) {
|
||||
path = DEFAULT_PREFIX;
|
||||
}
|
||||
return withTLS(!("http".equalsIgnoreCase(baseURL.getScheme())))
|
||||
.withHost(baseURL.getHost())
|
||||
.withPort(baseURL.getPort())
|
||||
.withPrefix(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set hostname (default: 127.0.0.1).
|
||||
*
|
||||
* @param host Hostname or IP address
|
||||
* @return self
|
||||
*/
|
||||
public HTTPVaultConnectorBuilder withHost(final String host) {
|
||||
this.host = host;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hostname.
|
||||
*
|
||||
* @return Hostname or IP address
|
||||
*/
|
||||
String getHost() {
|
||||
return this.host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set port (default: 8200).
|
||||
* A value of {@code null} or {@code -1} indicates that no port is specified, i.e. the protocol default is used.
|
||||
* Otherwise, a valid port number between 1 and 65535 is expected.
|
||||
*
|
||||
* @param port Vault TCP port
|
||||
* @return self
|
||||
*/
|
||||
public HTTPVaultConnectorBuilder withPort(final Integer port) {
|
||||
if (port == null || port < 0) {
|
||||
this.port = null;
|
||||
} else if (port < 1 || port > 65535) {
|
||||
throw new IllegalArgumentException("Port number " + port + " out of range");
|
||||
} else {
|
||||
this.port = port;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set port..
|
||||
*
|
||||
* @return Vault TCP port
|
||||
*/
|
||||
Integer getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set TLS usage (default: TRUE).
|
||||
*
|
||||
* @param useTLS use TLS or not
|
||||
* @return self
|
||||
*/
|
||||
public HTTPVaultConnectorBuilder withTLS(final boolean useTLS) {
|
||||
this.tls = useTLS;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get TLS usage flag.
|
||||
*
|
||||
* @return use TLS or not
|
||||
*/
|
||||
boolean isWithTLS() {
|
||||
return this.tls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get TLS version.
|
||||
*
|
||||
* @return TLS version.
|
||||
*/
|
||||
String getTlsVersion() {
|
||||
return this.tlsVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set TLS usage (default: TRUE).
|
||||
*
|
||||
* @param useTLS Use TLS or not.
|
||||
* @param version Supported TLS version ({@code TLSv1.2}, {@code TLSv1.1}, {@code TLSv1.0}, {@code TLS}).
|
||||
* @return self
|
||||
* @since 0.8 Added version parameter (#22).
|
||||
*/
|
||||
public HTTPVaultConnectorBuilder withTLS(final boolean useTLS, final String version) {
|
||||
this.tls = useTLS;
|
||||
this.tlsVersion = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience Method for TLS usage (enabled by default).
|
||||
*
|
||||
* @param version Supported TLS version ({@code TLSv1.2}, {@code TLSv1.1}, {@code TLSv1.0}, {@code TLS}).
|
||||
* @return self
|
||||
* @since 0.8 Added version parameter (#22).
|
||||
*/
|
||||
public HTTPVaultConnectorBuilder withTLS(final String version) {
|
||||
return withTLS(true, version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience Method for TLS usage (enabled by default).
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public HTTPVaultConnectorBuilder withTLS() {
|
||||
return withTLS(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience Method for NOT using TLS.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public HTTPVaultConnectorBuilder withoutTLS() {
|
||||
return withTLS(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public HTTPVaultConnectorBuilder withPrefix(final String prefix) {
|
||||
this.prefix = prefix;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get API prefix.
|
||||
*
|
||||
* @return Vault API prefix.
|
||||
*/
|
||||
String getPrefix() {
|
||||
return this.prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a trusted CA certificate for HTTPS connections.
|
||||
*
|
||||
* @param cert path to certificate file
|
||||
* @return self
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.4.0
|
||||
*/
|
||||
public HTTPVaultConnectorBuilder withTrustedCA(final Path cert) throws VaultConnectorException {
|
||||
if (cert != null) {
|
||||
return withTrustedCA(certificateFromFile(cert));
|
||||
} else {
|
||||
this.trustedCA = null;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a trusted CA certificate for HTTPS connections.
|
||||
*
|
||||
* @param cert path to certificate file
|
||||
* @return self
|
||||
* @since 0.8.0
|
||||
*/
|
||||
public HTTPVaultConnectorBuilder withTrustedCA(final X509Certificate cert) {
|
||||
this.trustedCA = cert;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the trusted CA certificate for HTTPS connections.
|
||||
*
|
||||
* @return path to certificate file, if specified.
|
||||
*/
|
||||
X509Certificate getTrustedCA() {
|
||||
return this.trustedCA;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set token for automatic authentication, using {@link #buildAndAuth()}.
|
||||
*
|
||||
* @param token Vault token
|
||||
* @return self
|
||||
* @since 0.6.0
|
||||
*/
|
||||
public HTTPVaultConnectorBuilder 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 HTTPVaultConnectorBuilder fromEnv() throws VaultConnectorException {
|
||||
/* Parse URL from environment variable */
|
||||
if (System.getenv(ENV_VAULT_ADDR) != null && !System.getenv(ENV_VAULT_ADDR).isBlank()) {
|
||||
try {
|
||||
withBaseURL(System.getenv(ENV_VAULT_ADDR));
|
||||
} catch (URISyntaxException e) {
|
||||
throw new ConnectionException("URL provided in environment variable malformed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read number of retries */
|
||||
if (System.getenv(ENV_VAULT_MAX_RETRIES) != null) {
|
||||
try {
|
||||
withNumberOfRetries(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).isBlank()) {
|
||||
X509Certificate cert = certificateFromString(System.getenv(ENV_VAULT_CACERT));
|
||||
if (cert == null) {
|
||||
cert = certificateFromFile(Paths.get(System.getenv(ENV_VAULT_CACERT)));
|
||||
}
|
||||
return withTrustedCA(cert);
|
||||
}
|
||||
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 HTTPVaultConnectorBuilder withNumberOfRetries(final int numberOfRetries) {
|
||||
this.numberOfRetries = numberOfRetries;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of retries to attempt on 5xx errors.
|
||||
*
|
||||
* @return The number of retries to attempt on 5xx errors (default: 0)
|
||||
*/
|
||||
int getNumberOfRetries() {
|
||||
return this.numberOfRetries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a custom timeout for the HTTP connection.
|
||||
*
|
||||
* @param milliseconds Timeout value in milliseconds.
|
||||
* @return self
|
||||
* @since 0.6.0
|
||||
*/
|
||||
public HTTPVaultConnectorBuilder withTimeout(final int milliseconds) {
|
||||
this.timeout = milliseconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom timeout for the HTTP connection.
|
||||
*
|
||||
* @return Timeout value in milliseconds.
|
||||
*/
|
||||
Integer getTimeout() {
|
||||
return this.timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build command, produces connector after initialization.
|
||||
*
|
||||
* @return Vault Connector instance.
|
||||
*/
|
||||
public HTTPVaultConnector build() {
|
||||
return new HTTPVaultConnector(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 HTTPVaultConnector buildAndAuth() throws VaultConnectorException {
|
||||
if (token == null) {
|
||||
throw new ConnectionException("No vault token provided, unable to authenticate.");
|
||||
}
|
||||
HTTPVaultConnector con = build();
|
||||
con.authToken(token);
|
||||
return con;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read given certificate file to X.509 certificate.
|
||||
*
|
||||
* @param cert Certificate string (optionally PEM)
|
||||
* @return X.509 Certificate object if parseable, else {@code null}
|
||||
* @throws TlsException on error
|
||||
* @since 1.5.0
|
||||
*/
|
||||
private X509Certificate certificateFromString(final String cert) throws TlsException {
|
||||
// Check if PEM header is present in given string
|
||||
if (cert.contains("-BEGIN ") && cert.contains("-END")) {
|
||||
try (var is = new ByteArrayInputStream(cert.getBytes(StandardCharsets.UTF_8))) {
|
||||
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
|
||||
} catch (IOException | CertificateException e) {
|
||||
throw new TlsException("Unable to read certificate.", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Not am PEM string, skip
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (var is = Files.newInputStream(certFile)) {
|
||||
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
|
||||
} catch (IOException | CertificateException e) {
|
||||
throw new TlsException("Unable to read certificate.", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +1,27 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.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.List;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Vault Connector interface.
|
||||
@ -16,12 +30,7 @@ import java.util.List;
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
*/
|
||||
public interface VaultConnector {
|
||||
/**
|
||||
* Verify that vault connection is initialized.
|
||||
* @return TRUE if correctly initialized
|
||||
*/
|
||||
boolean init();
|
||||
public interface VaultConnector extends AutoCloseable, Serializable {
|
||||
|
||||
/**
|
||||
* Reset authorization information.
|
||||
@ -30,35 +39,52 @@ public interface VaultConnector {
|
||||
|
||||
/**
|
||||
* Retrieve status of vault seal.
|
||||
*
|
||||
* @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
|
||||
* @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
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all availale authentication backends.
|
||||
* Query server health information.
|
||||
*
|
||||
* @return Health information.
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.7.0
|
||||
*/
|
||||
HealthResponse getHealth() throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Get all available authentication backends.
|
||||
*
|
||||
* @return List of backends
|
||||
* @throws VaultConnectorException on error
|
||||
*/
|
||||
@ -66,6 +92,7 @@ public interface VaultConnector {
|
||||
|
||||
/**
|
||||
* Authorize to Vault using token.
|
||||
*
|
||||
* @param token The token
|
||||
* @return Token response
|
||||
* @throws VaultConnectorException on error
|
||||
@ -74,6 +101,7 @@ public interface VaultConnector {
|
||||
|
||||
/**
|
||||
* Authorize to Vault using username and password.
|
||||
*
|
||||
* @param username The username
|
||||
* @param password The password
|
||||
* @return Authorization result
|
||||
@ -82,74 +110,710 @@ public interface VaultConnector {
|
||||
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
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
boolean registerAppId(final String appID, final String policy, final String displayName) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Register User-ID with App-ID
|
||||
* @param appID The App-ID
|
||||
* @param userID The User-ID
|
||||
* @return TRUE on success
|
||||
* @throws VaultConnectorException on error
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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);
|
||||
default AuthResponse authAppRole(final String roleID) throws VaultConnectorException {
|
||||
return authAppRole(roleID, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authorization status
|
||||
* 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 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(AppRole.builder(roleName).withTokenPolicies(policies).withId(roleID).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete AppRole role from Vault.
|
||||
*
|
||||
* @param roleName The role name
|
||||
* @return {@code true} on success
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* Get authorization status.
|
||||
*
|
||||
* @return TRUE, if successfully authorized
|
||||
*/
|
||||
boolean isAuthorized();
|
||||
|
||||
/**
|
||||
* Retrieve secret form Vault.
|
||||
* Retrieve any nodes content from Vault.
|
||||
*
|
||||
* @param key Secret identifier
|
||||
* @return Secret response
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.5.0
|
||||
*/
|
||||
SecretResponse readSecret(final String key) throws VaultConnectorException;
|
||||
SecretResponse read(final String key) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* List available secrets from Vault.
|
||||
* @param path Root path to search
|
||||
* @return List of secret keys
|
||||
* Retrieve the latest secret data for specific version from Vault.
|
||||
* <br>
|
||||
* Path {@code <mount>/data/<key>} is read here.
|
||||
* Only available for KV v2 secrets.
|
||||
*
|
||||
* @param mount Secret store mount point (without leading or trailing slash).
|
||||
* @param key Secret identifier
|
||||
* @return Secret response
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.8
|
||||
*/
|
||||
List<String> listSecrets(final String path) throws VaultConnectorException;
|
||||
default SecretResponse readSecretData(final String mount, final String key) throws VaultConnectorException {
|
||||
return readSecretVersion(mount, key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write secret to Vault.
|
||||
* <br>
|
||||
* Path {@code <mount>/data/<key>} is written here.
|
||||
* Only available for KV v2 secrets.
|
||||
*
|
||||
* @param mount Secret store mount point (without leading or trailing slash).
|
||||
* @param key Secret identifier
|
||||
* @param data Secret content. Value must be be JSON serializable.
|
||||
* @return Metadata for the created/updated secret.
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.8
|
||||
*/
|
||||
default SecretVersionResponse writeSecretData(final String mount,
|
||||
final String key,
|
||||
final Map<String, Object> data) throws VaultConnectorException {
|
||||
return writeSecretData(mount, key, data, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write secret to Vault.
|
||||
* <br>
|
||||
* Path {@code <mount>/data/<key>} is written here.
|
||||
* Only available for KV v2 secrets.
|
||||
*
|
||||
* @param mount Secret store mount point (without leading or trailing slash).
|
||||
* @param key Secret identifier
|
||||
* @param data Secret content. Value must be be JSON serializable.
|
||||
* @param cas Use Check-And-Set operation, i.e. only allow writing if current version matches this value.
|
||||
* @return Metadata for the created/updated secret.
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.8
|
||||
*/
|
||||
SecretVersionResponse writeSecretData(final String mount,
|
||||
final String key,
|
||||
final Map<String, Object> data,
|
||||
final Integer cas) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Retrieve secret data from Vault.
|
||||
* <br>
|
||||
* Path {@code <mount>/data/<key>} is read here.
|
||||
* Only available for KV v2 secrets.
|
||||
*
|
||||
* @param mount Secret store mount point (without leading or trailing slash).
|
||||
* @param key Secret identifier
|
||||
* @param version Version to read. If {@code null} or zero, the latest version will be returned.
|
||||
* @return Secret response.
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.8
|
||||
*/
|
||||
SecretResponse readSecretVersion(final String mount, final String key, final Integer version)
|
||||
throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Retrieve secret metadata from Vault.
|
||||
* <br>
|
||||
* Path {@code <mount>/metadata/<key>} is read here.
|
||||
* Only available for KV v2 secrets.
|
||||
*
|
||||
* @param mount Secret store mount point (without leading or trailing slash).
|
||||
* @param key Secret identifier
|
||||
* @return Metadata response
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.8
|
||||
*/
|
||||
MetadataResponse readSecretMetadata(final String mount, final String key) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Update secret metadata.
|
||||
* <br>
|
||||
* Path {@code <mount>/metadata/<key>} is written here.
|
||||
* Only available for KV v2 secrets.
|
||||
*
|
||||
* @param mount Secret store mount point (without leading or trailing slash).
|
||||
* @param key Secret identifier
|
||||
* @param maxVersions Maximum number of versions (fallback to backend default if {@code null})
|
||||
* @param casRequired Specify if Check-And-Set is required for this secret.
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.8
|
||||
*/
|
||||
void updateSecretMetadata(final String mount,
|
||||
final String key,
|
||||
final Integer maxVersions,
|
||||
final boolean casRequired) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Write simple value to Vault.
|
||||
*
|
||||
* @param key Secret path
|
||||
* @param value Secret value
|
||||
* @return TRUE on success
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.5.0
|
||||
*/
|
||||
default void write(final String key, final String value) throws VaultConnectorException {
|
||||
write(key, Collections.singletonMap("value", value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
default void write(final String key, final Map<String, Object> data) throws VaultConnectorException {
|
||||
write(key, data, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write value to Vault.
|
||||
*
|
||||
* @param key Secret path
|
||||
* @param data Secret content. Value must be be JSON serializable.
|
||||
* @param options Secret options (optional).
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.8 {@code options} parameter added
|
||||
*/
|
||||
void write(final String key, final Map<String, Object> data, final Map<String, Object> options)
|
||||
throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Delete key from Vault.
|
||||
*
|
||||
* @param key Secret path
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.5.0
|
||||
*/
|
||||
void delete(final String key) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Delete latest version of a secret from Vault.
|
||||
* <br>
|
||||
* Only available for KV v2 stores.
|
||||
*
|
||||
* @param mount Secret store mount point (without leading or trailing slash).
|
||||
* @param key Secret path.
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.8
|
||||
*/
|
||||
void deleteLatestSecretVersion(final String mount, final String key) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Delete latest version of a secret from Vault.
|
||||
* <br>
|
||||
* Prefix {@code secret/} is automatically added to path.
|
||||
* Only available for KV v2 stores.
|
||||
*
|
||||
* @param mount Secret store mount point (without leading or trailing slash).
|
||||
* @param key Secret path.
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.8
|
||||
*/
|
||||
void deleteAllSecretVersions(final String mount, final String key) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Delete secret versions from Vault.
|
||||
* <br>
|
||||
* Only available for KV v2 stores.
|
||||
*
|
||||
* @param mount Secret store mount point (without leading or trailing slash).
|
||||
* @param key Secret path.
|
||||
* @param versions Versions of the secret to delete.
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.8
|
||||
*/
|
||||
void deleteSecretVersions(final String mount, final String key, final int... versions)
|
||||
throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Undelete (restore) secret versions from Vault.
|
||||
* Only available for KV v2 stores.
|
||||
*
|
||||
* @param mount Secret store mount point (without leading or trailing slash).
|
||||
* @param key Secret path.
|
||||
* @param versions Versions of the secret to undelete.
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.8
|
||||
*/
|
||||
void undeleteSecretVersions(final String mount, final String key, final int... versions)
|
||||
throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Destroy secret versions from Vault.
|
||||
* Only available for KV v2 stores.
|
||||
*
|
||||
* @param mount Secret store mount point (without leading or trailing slash).
|
||||
* @param key Secret path.
|
||||
* @param versions Versions of the secret to destroy.
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.8
|
||||
*/
|
||||
void destroySecretVersions(final String mount, final String key, final int... versions)
|
||||
throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Revoke given lease immediately.
|
||||
*
|
||||
* @param leaseID the lease ID
|
||||
* @throws VaultConnectorException on error
|
||||
*/
|
||||
boolean writeSecret(final String key, final String value) throws VaultConnectorException;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Create a new or update an existing token role.
|
||||
*
|
||||
* @param role the role entity (name must be set)
|
||||
* @return {@code true} on success
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.9
|
||||
*/
|
||||
default boolean createOrUpdateTokenRole(final TokenRole role) throws VaultConnectorException {
|
||||
return createOrUpdateTokenRole(role.getName(), role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new or update an existing token role.
|
||||
*
|
||||
* @param name the role name (overrides name possibly set in role entity)
|
||||
* @param role the role entity
|
||||
* @return {@code true} on success
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.9
|
||||
*/
|
||||
boolean createOrUpdateTokenRole(final String name, final TokenRole role) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Lookup token information.
|
||||
*
|
||||
* @param name the role name
|
||||
* @return the result response
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.9
|
||||
*/
|
||||
TokenRoleResponse readTokenRole(final String name) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* List available token roles from Vault.
|
||||
*
|
||||
* @return List of token roles
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.9
|
||||
*/
|
||||
List<String> listTokenRoles() throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Delete a token role.
|
||||
*
|
||||
* @param name the role name to delete
|
||||
* @return {@code true} on success
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.9
|
||||
*/
|
||||
boolean deleteTokenRole(final String name) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Encrypt plaintext via transit engine from Vault.
|
||||
*
|
||||
* @param keyName Transit key name
|
||||
* @param plaintext Text to encrypt (Base64 encoded)
|
||||
* @return Transit response
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 1.5.0
|
||||
*/
|
||||
TransitResponse transitEncrypt(final String keyName, final String plaintext) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Encrypt plaintext via transit engine from Vault.
|
||||
*
|
||||
* @param keyName Transit key name
|
||||
* @param plaintext Binary data to encrypt
|
||||
* @return Transit response
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 1.5.0
|
||||
*/
|
||||
default TransitResponse transitEncrypt(final String keyName, final byte[] plaintext)
|
||||
throws VaultConnectorException {
|
||||
return transitEncrypt(keyName, Base64.getEncoder().encodeToString(plaintext));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt ciphertext via transit engine from Vault.
|
||||
*
|
||||
* @param keyName Transit key name
|
||||
* @param ciphertext Text to decrypt
|
||||
* @return Transit response
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 1.5.0
|
||||
*/
|
||||
TransitResponse transitDecrypt(final String keyName, final String ciphertext) throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Hash data in hex format via transit engine from Vault.
|
||||
*
|
||||
* @param algorithm Specifies the hash algorithm to use
|
||||
* @param input Data to hash
|
||||
* @return Transit response
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 1.5.0
|
||||
*/
|
||||
default TransitResponse transitHash(final String algorithm, final String input) throws VaultConnectorException {
|
||||
return transitHash(algorithm, input, "hex");
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash data via transit engine from Vault.
|
||||
*
|
||||
* @param algorithm Specifies the hash algorithm to use
|
||||
* @param input Data to hash (Base64 encoded)
|
||||
* @param format Specifies the output encoding (hex/base64)
|
||||
* @return Transit response
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 1.5.0
|
||||
*/
|
||||
TransitResponse transitHash(final String algorithm, final String input, final String format)
|
||||
throws VaultConnectorException;
|
||||
|
||||
/**
|
||||
* Hash data via transit engine from Vault.
|
||||
*
|
||||
* @param algorithm Specifies the hash algorithm to use
|
||||
* @param input Data to hash
|
||||
* @return Transit response
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 1.5.0
|
||||
*/
|
||||
default TransitResponse transitHash(final String algorithm, final byte[] input, final String format)
|
||||
throws VaultConnectorException {
|
||||
return transitHash(algorithm, Base64.getEncoder().encodeToString(input), format);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @deprecated use {@link #readDbCredentials(String, String)} your MySQL mountpoint
|
||||
*/
|
||||
@Deprecated(since = "1.5.0", forRemoval = true)
|
||||
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
|
||||
* @deprecated use {@link #readDbCredentials(String, String)} your PostgreSQL mountpoint
|
||||
*/
|
||||
@Deprecated(since = "1.5.0", forRemoval = true)
|
||||
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
|
||||
* @deprecated use {@link #readDbCredentials(String, String)} your MSSQL mountpoint
|
||||
*/
|
||||
@Deprecated(since = "1.5.0", forRemoval = true)
|
||||
default CredentialsResponse readMsSqlCredentials(final String role) throws VaultConnectorException {
|
||||
return readDbCredentials(role, "mssql");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read credentials for MongoDB backend at default mount point.
|
||||
*
|
||||
* @param role the role name
|
||||
* @return the credentials response
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.5.0
|
||||
* @deprecated use {@link #readDbCredentials(String, String)} your MongoDB mountpoint
|
||||
*/
|
||||
@Deprecated(since = "1.5.0", forRemoval = true)
|
||||
default CredentialsResponse readMongoDbCredentials(final String role) throws VaultConnectorException {
|
||||
return readDbCredentials(role, "mongodb");
|
||||
}
|
||||
|
||||
/**
|
||||
* Read credentials for database backends.
|
||||
*
|
||||
* @param role the role name
|
||||
* @param mount mount point of the database backend
|
||||
* @return the credentials response
|
||||
* @throws VaultConnectorException on error
|
||||
* @since 0.5.0
|
||||
*/
|
||||
default CredentialsResponse readDbCredentials(final String role, final String mount)
|
||||
throws VaultConnectorException {
|
||||
return (CredentialsResponse) read(mount + "/creds/" + role);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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,4 +23,5 @@ package de.stklcode.jvault.connector.exception;
|
||||
* @since 0.1
|
||||
*/
|
||||
public class AuthorizationRequiredException extends VaultConnectorException {
|
||||
private static final long serialVersionUID = 2629577936657393880L;
|
||||
}
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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,39 @@ package de.stklcode.jvault.connector.exception;
|
||||
* @since 0.1
|
||||
*/
|
||||
public class ConnectionException extends VaultConnectorException {
|
||||
private static final long serialVersionUID = 3005430116002990418L;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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,39 @@ package de.stklcode.jvault.connector.exception;
|
||||
* @since 0.1
|
||||
*/
|
||||
public class InvalidRequestException extends VaultConnectorException {
|
||||
private static final long serialVersionUID = -6712239648281809159L;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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,39 +23,135 @@ package de.stklcode.jvault.connector.exception;
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
*/
|
||||
public class InvalidResponseException extends VaultConnectorException {
|
||||
private Integer statusCode;
|
||||
private String response;
|
||||
public final class InvalidResponseException extends VaultConnectorException {
|
||||
private static final long serialVersionUID = 2003151038614163479L;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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,40 @@ package de.stklcode.jvault.connector.exception;
|
||||
* @since 0.1
|
||||
*/
|
||||
public class PermissionDeniedException extends VaultConnectorException {
|
||||
private static final long serialVersionUID = -7149134015090750776L;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 {
|
||||
private static final long serialVersionUID = -5139276834988258086L;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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,39 @@ package de.stklcode.jvault.connector.exception;
|
||||
* @since 0.1
|
||||
*/
|
||||
public abstract class VaultConnectorException extends Exception {
|
||||
public VaultConnectorException() {
|
||||
private static final long serialVersionUID = -2612477894310906036L;
|
||||
|
||||
/**
|
||||
* Constructs a new empty exception.
|
||||
*/
|
||||
protected VaultConnectorException() {
|
||||
}
|
||||
|
||||
public VaultConnectorException(String message) {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message.
|
||||
*
|
||||
* @param message the detail message
|
||||
*/
|
||||
protected VaultConnectorException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public VaultConnectorException(Throwable cause) {
|
||||
/**
|
||||
* Constructs a new exception with the specified cause.
|
||||
*
|
||||
* @param cause the cause
|
||||
*/
|
||||
protected 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
|
||||
*/
|
||||
protected VaultConnectorException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Some custom exceptions for error handling.
|
||||
*/
|
||||
package de.stklcode.jvault.connector.exception;
|
@ -1,93 +0,0 @@
|
||||
package de.stklcode.jvault.connector.factory;
|
||||
|
||||
import de.stklcode.jvault.connector.HTTPVaultConnector;
|
||||
|
||||
/**
|
||||
* Vault Connector Factory implementation for HTTP Vault connectors.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
*/
|
||||
public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
|
||||
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/";
|
||||
|
||||
private String host;
|
||||
private Integer port;
|
||||
private boolean tls;
|
||||
private String prefix;
|
||||
|
||||
/**
|
||||
* Default empty constructor.
|
||||
* Initializes factory with default values.
|
||||
*/
|
||||
public HTTPVaultConnectorFactory() {
|
||||
host = DEFAULT_HOST;
|
||||
port = DEFAULT_PORT;
|
||||
tls = DEFAULT_TLS;
|
||||
prefix = DEFAULT_PREFIX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set hostname (default: 127.0.0.1)
|
||||
* @param host Hostname or IP address
|
||||
* @return self
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withHost(String host) {
|
||||
this.host = host;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set port (default: 8200)
|
||||
* @param port Vault TCP port
|
||||
* @return self
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withPort(Integer port) {
|
||||
this.port = port;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set TLS usage (default: TRUE)
|
||||
* @param useTLS use TLS or not
|
||||
* @return self
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withTLS(boolean useTLS) {
|
||||
this.tls = useTLS;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience Method for TLS usage (enabled by default)
|
||||
* @return self
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withTLS() {
|
||||
return withTLS(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience Method for NOT using TLS
|
||||
* @return self
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withoutTLS() {
|
||||
return withTLS(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public HTTPVaultConnectorFactory withPrefix(String prefix) {
|
||||
this.prefix = prefix;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HTTPVaultConnector build() {
|
||||
return new HTTPVaultConnector(host, tls, port, prefix);
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package de.stklcode.jvault.connector.factory;
|
||||
|
||||
import de.stklcode.jvault.connector.VaultConnector;
|
||||
|
||||
/**
|
||||
* Abstract Vault Connector Factory interface.
|
||||
* Provides builder pattern style factory for Vault connectors.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
*/
|
||||
public abstract class VaultConnectorFactory {
|
||||
/**
|
||||
* Get Factory implementation for HTTP Vault Connector
|
||||
* @return HTTP Connector Factory
|
||||
*/
|
||||
public static HTTPVaultConnectorFactory httpFactory() {
|
||||
return new HTTPVaultConnectorFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build command, produces connector after initialization.
|
||||
* @return Vault Connector instance.
|
||||
*/
|
||||
public abstract VaultConnector build();
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.internal;
|
||||
|
||||
/**
|
||||
* Utility class to bundle common error messages.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.8 Extracted from static inner class.
|
||||
*/
|
||||
final class Error {
|
||||
static final String READ_RESPONSE = "Unable to read response";
|
||||
static final String PARSE_RESPONSE = "Unable to parse response";
|
||||
static final String UNEXPECTED_RESPONSE = "Received response where none was expected";
|
||||
static final String URI_FORMAT = "Invalid URI format";
|
||||
static final String RESPONSE_CODE = "Invalid response code";
|
||||
static final String INIT_SSL_CONTEXT = "Unable to initialize SSLContext";
|
||||
static final String CONNECTION = "Unable to connect to Vault server";
|
||||
|
||||
/**
|
||||
* Constructor hidden, this class should not be instantiated.
|
||||
*/
|
||||
private Error() {
|
||||
}
|
||||
}
|
@ -0,0 +1,450 @@
|
||||
package de.stklcode.jvault.connector.internal;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import de.stklcode.jvault.connector.exception.*;
|
||||
import de.stklcode.jvault.connector.model.response.ErrorResponse;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.io.*;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* Helper class to bundle Vault HTTP requests.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.8 Extracted methods from {@link de.stklcode.jvault.connector.HTTPVaultConnector}.
|
||||
*/
|
||||
public final class RequestHelper implements Serializable {
|
||||
private static final String HEADER_VAULT_TOKEN = "X-Vault-Token";
|
||||
|
||||
private final String baseURL; // Base URL of Vault.
|
||||
private final Integer timeout; // Timeout in milliseconds.
|
||||
private final int retries; // Number of retries on 5xx errors.
|
||||
private final String tlsVersion; // TLS version (#22).
|
||||
private final X509Certificate trustedCaCert; // Trusted CA certificate.
|
||||
private final JsonMapper jsonMapper;
|
||||
|
||||
/**
|
||||
* Constructor of the request helper.
|
||||
*
|
||||
* @param baseURL The URL
|
||||
* @param retries Number of retries on 5xx errors
|
||||
* @param timeout Timeout for HTTP requests (milliseconds)
|
||||
* @param tlsVersion TLS Version.
|
||||
* @param trustedCaCert Trusted CA certificate
|
||||
*/
|
||||
public RequestHelper(final String baseURL,
|
||||
final int retries,
|
||||
final Integer timeout,
|
||||
final String tlsVersion,
|
||||
final X509Certificate trustedCaCert) {
|
||||
this.baseURL = baseURL + (baseURL.endsWith("/") ? "" : "/");
|
||||
this.retries = retries;
|
||||
this.timeout = timeout;
|
||||
this.tlsVersion = tlsVersion;
|
||||
this.trustedCaCert = trustedCaCert;
|
||||
this.jsonMapper = JsonMapper.builder()
|
||||
.addModule(new JavaTimeModule())
|
||||
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
||||
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute HTTP request using POST method.
|
||||
*
|
||||
* @param path URL path (relative to base).
|
||||
* @param payload Map of payload values (will be converted to JSON).
|
||||
* @param token Vault token (may be {@code null}).
|
||||
* @return HTTP response
|
||||
* @throws VaultConnectorException on connection error
|
||||
* @since 0.8 Added {@code token} parameter.
|
||||
*/
|
||||
public String post(final String path, final Object payload, final String token) throws VaultConnectorException {
|
||||
// Initialize POST.
|
||||
var req = HttpRequest.newBuilder(URI.create(baseURL + path));
|
||||
|
||||
// Generate JSON from payload.
|
||||
try {
|
||||
req.POST(HttpRequest.BodyPublishers.ofString(jsonMapper.writeValueAsString(payload), UTF_8));
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new InvalidRequestException(Error.PARSE_RESPONSE, e);
|
||||
}
|
||||
|
||||
req.setHeader("Content-Type", "application/json; charset=utf-8");
|
||||
|
||||
// Set X-Vault-Token header.
|
||||
if (token != null) {
|
||||
req.setHeader(HEADER_VAULT_TOKEN, token);
|
||||
}
|
||||
|
||||
return request(req, retries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute HTTP request using POST method and parse JSON result.
|
||||
*
|
||||
* @param path URL path (relative to base).
|
||||
* @param payload Map of payload values (will be converted to JSON).
|
||||
* @param token Vault token (may be {@code null}).
|
||||
* @param target Target class.
|
||||
* @param <T> Target type.
|
||||
* @return HTTP response
|
||||
* @throws VaultConnectorException on connection error
|
||||
* @since 0.8
|
||||
*/
|
||||
public <T> T post(final String path, final Object payload, final String token, final Class<T> target)
|
||||
throws VaultConnectorException {
|
||||
try {
|
||||
String response = post(path, payload, token);
|
||||
return jsonMapper.readValue(response, target);
|
||||
} catch (IOException e) {
|
||||
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute HTTP request using POST method and expect empty (204) response.
|
||||
*
|
||||
* @param path URL path (relative to base).
|
||||
* @param payload Map of payload values (will be converted to JSON).
|
||||
* @param token Vault token (may be {@code null}).
|
||||
* @throws VaultConnectorException on connection error
|
||||
* @since 0.8
|
||||
*/
|
||||
public void postWithoutResponse(final String path, final Object payload, final String token)
|
||||
throws VaultConnectorException {
|
||||
if (!post(path, payload, token).isEmpty()) {
|
||||
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute HTTP request using PUT method.
|
||||
*
|
||||
* @param path URL path (relative to base).
|
||||
* @param payload Map of payload values (will be converted to JSON).
|
||||
* @param token Vault token (may be {@code null}).
|
||||
* @return HTTP response
|
||||
* @throws VaultConnectorException on connection error
|
||||
* @since 0.8 Added {@code token} parameter.
|
||||
*/
|
||||
public String put(final String path, final Map<String, String> payload, final String token)
|
||||
throws VaultConnectorException {
|
||||
// Initialize PUT.
|
||||
var req = HttpRequest.newBuilder(URI.create(baseURL + path));
|
||||
|
||||
// Generate JSON from payload.
|
||||
try {
|
||||
req.PUT(HttpRequest.BodyPublishers.ofString(jsonMapper.writeValueAsString(payload), UTF_8));
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new InvalidRequestException("Payload serialization failed", e);
|
||||
}
|
||||
|
||||
req.setHeader("Content-Type", "application/json; charset=utf-8");
|
||||
|
||||
// Set X-Vault-Token header.
|
||||
if (token != null) {
|
||||
req.setHeader(HEADER_VAULT_TOKEN, token);
|
||||
}
|
||||
|
||||
return request(req, retries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute HTTP request using PUT method and parse JSON result.
|
||||
*
|
||||
* @param path URL path (relative to base).
|
||||
* @param payload Map of payload values (will be converted to JSON).
|
||||
* @param token Vault token (may be {@code null}).
|
||||
* @param target Target class.
|
||||
* @param <T> Target type.
|
||||
* @return HTTP response
|
||||
* @throws VaultConnectorException on connection error
|
||||
* @since 0.8
|
||||
*/
|
||||
public <T> T put(final String path, final Map<String, String> payload, final String token, final Class<T> target)
|
||||
throws VaultConnectorException {
|
||||
try {
|
||||
String response = put(path, payload, token);
|
||||
return jsonMapper.readValue(response, target);
|
||||
} catch (IOException e) {
|
||||
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute HTTP request using PUT method and expect empty (204) response.
|
||||
*
|
||||
* @param path URL path (relative to base).
|
||||
* @param payload Map of payload values (will be converted to JSON).
|
||||
* @param token Vault token (may be {@code null}).
|
||||
* @throws VaultConnectorException on connection error
|
||||
* @since 0.8
|
||||
*/
|
||||
public void putWithoutResponse(final String path, final Map<String, String> payload, final String token)
|
||||
throws VaultConnectorException {
|
||||
if (!put(path, payload, token).isEmpty()) {
|
||||
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute HTTP request using DELETE method.
|
||||
*
|
||||
* @param path URL path (relative to base).
|
||||
* @param token Vault token (may be {@code null}).
|
||||
* @return HTTP response
|
||||
* @throws VaultConnectorException on connection error
|
||||
* @since 0.8 Added {@code token} parameter.
|
||||
*/
|
||||
public String delete(final String path, final String token) throws VaultConnectorException {
|
||||
// Initialize DELETE.
|
||||
HttpRequest.Builder req = HttpRequest.newBuilder(URI.create(baseURL + path)).DELETE();
|
||||
|
||||
// Set X-Vault-Token header.
|
||||
if (token != null) {
|
||||
req.setHeader(HEADER_VAULT_TOKEN, token);
|
||||
}
|
||||
|
||||
return request(req, retries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute HTTP request using DELETE method and expect empty (204) response.
|
||||
*
|
||||
* @param path URL path (relative to base).
|
||||
* @param token Vault token (may be {@code null}).
|
||||
* @throws VaultConnectorException on connection error
|
||||
* @since 0.8
|
||||
*/
|
||||
public void deleteWithoutResponse(final String path, final String token) throws VaultConnectorException {
|
||||
if (!delete(path, token).isEmpty()) {
|
||||
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute HTTP request using GET method.
|
||||
*
|
||||
* @param path URL path (relative to base).
|
||||
* @param payload Map of payload values (will be converted to JSON).
|
||||
* @param token Vault token (may be {@code null}).
|
||||
* @return HTTP response
|
||||
* @throws VaultConnectorException on connection error
|
||||
* @since 0.8 Added {@code token} parameter.
|
||||
*/
|
||||
public String get(final String path, final Map<String, String> payload, final String token)
|
||||
throws VaultConnectorException {
|
||||
// Add parameters to URI.
|
||||
var uriBuilder = new StringBuilder(baseURL + path);
|
||||
|
||||
if (!payload.isEmpty()) {
|
||||
uriBuilder.append("?").append(
|
||||
payload.entrySet().stream().map(par ->
|
||||
URLEncoder.encode(par.getKey(), UTF_8) + "=" + URLEncoder.encode(par.getValue(), UTF_8)
|
||||
).collect(Collectors.joining("&"))
|
||||
);
|
||||
}
|
||||
|
||||
// Initialize GET.
|
||||
try {
|
||||
var req = HttpRequest.newBuilder(new URI(uriBuilder.toString()));
|
||||
|
||||
// Set X-Vault-Token header.
|
||||
if (token != null) {
|
||||
req.setHeader(HEADER_VAULT_TOKEN, token);
|
||||
}
|
||||
|
||||
return request(req, retries);
|
||||
} catch (URISyntaxException e) {
|
||||
/* this should never occur and may leak sensible information */
|
||||
throw new InvalidRequestException(Error.URI_FORMAT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute HTTP request using GET method and parse JSON result to target class.
|
||||
*
|
||||
* @param path URL path (relative to base).
|
||||
* @param payload Map of payload values (will be converted to JSON).
|
||||
* @param token Vault token (may be {@code null}).
|
||||
* @param target Target class.
|
||||
* @param <T> Target type.
|
||||
* @return HTTP response
|
||||
* @throws VaultConnectorException on connection error
|
||||
* @since 0.8
|
||||
*/
|
||||
public <T> T get(final String path, final Map<String, String> payload, final String token, final Class<T> target)
|
||||
throws VaultConnectorException {
|
||||
try {
|
||||
String response = get(path, payload, token);
|
||||
return jsonMapper.readValue(response, target);
|
||||
} catch (IOException e) {
|
||||
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute prepared HTTP request and return result.
|
||||
*
|
||||
* @param requestBuilder Prepared request.
|
||||
* @param retries Number of retries.
|
||||
* @return HTTP response
|
||||
* @throws VaultConnectorException on connection error
|
||||
*/
|
||||
private String request(final HttpRequest.Builder requestBuilder, final int retries) throws VaultConnectorException {
|
||||
// Set JSON Header.
|
||||
requestBuilder.setHeader("accept", "application/json");
|
||||
|
||||
var clientBuilder = HttpClient.newBuilder();
|
||||
|
||||
// Set custom timeout, if defined.
|
||||
if (this.timeout != null) {
|
||||
clientBuilder.connectTimeout(Duration.ofMillis(timeout));
|
||||
}
|
||||
|
||||
// Set custom SSL context.
|
||||
clientBuilder.sslContext(createSSLContext());
|
||||
|
||||
HttpClient client = clientBuilder.build();
|
||||
|
||||
// Execute request.
|
||||
try {
|
||||
HttpResponse<InputStream> response = client.sendAsync(
|
||||
requestBuilder.build(),
|
||||
HttpResponse.BodyHandlers.ofInputStream()
|
||||
).join();
|
||||
|
||||
/* Check if response is valid */
|
||||
if (response == null) {
|
||||
throw new InvalidResponseException("Response unavailable");
|
||||
}
|
||||
|
||||
switch (response.statusCode()) {
|
||||
case 200:
|
||||
return handleResult(response);
|
||||
case 204:
|
||||
return "";
|
||||
case 403:
|
||||
throw new PermissionDeniedException();
|
||||
default:
|
||||
if (response.statusCode() >= 500 && response.statusCode() < 600 && retries > 0) {
|
||||
// Retry on 5xx errors.
|
||||
return request(requestBuilder, retries - 1);
|
||||
} else {
|
||||
// Fail on different error code and/or no retries left.
|
||||
handleError(response);
|
||||
|
||||
// Throw exception without details, if response entity is empty.
|
||||
throw new InvalidResponseException(Error.RESPONSE_CODE, response.statusCode());
|
||||
}
|
||||
}
|
||||
} catch (CompletionException e) {
|
||||
throw new ConnectionException(Error.CONNECTION, e.getCause());
|
||||
} finally {
|
||||
if (client instanceof AutoCloseable) {
|
||||
// Close the client, which is supported since JDK21.
|
||||
try {
|
||||
((AutoCloseable) client).close();
|
||||
} catch (Exception ignored) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a custom SSL context from trusted CA certificate.
|
||||
*
|
||||
* @return The context.
|
||||
* @throws TlsException An error occurred during initialization of the SSL context.
|
||||
* @since 0.8.0
|
||||
* @since 0.10 Generate {@link SSLContext} instead of Apache {@code SSLConnectionSocketFactory}
|
||||
*/
|
||||
private SSLContext createSSLContext() throws TlsException {
|
||||
try {
|
||||
// Create context.
|
||||
var sslContext = SSLContext.getInstance(tlsVersion);
|
||||
|
||||
if (trustedCaCert != null) {
|
||||
// Create Keystore with trusted certificate.
|
||||
var keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
keyStore.load(null, null);
|
||||
keyStore.setCertificateEntry("trustedCert", trustedCaCert);
|
||||
|
||||
// Initialize TrustManager.
|
||||
var tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init(keyStore);
|
||||
sslContext.init(null, tmf.getTrustManagers(), null);
|
||||
} else {
|
||||
sslContext.init(null, null, null);
|
||||
}
|
||||
|
||||
return sslContext;
|
||||
} catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException |
|
||||
KeyManagementException e) {
|
||||
throw new TlsException(Error.INIT_SSL_CONTEXT, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle successful result.
|
||||
*
|
||||
* @param response The raw HTTP response (assuming status code 200)
|
||||
* @return Complete response body as String
|
||||
* @throws InvalidResponseException on reading errors
|
||||
*/
|
||||
private String handleResult(final HttpResponse<InputStream> response) throws InvalidResponseException {
|
||||
try (var reader = new BufferedReader(new InputStreamReader(response.body(), UTF_8))) {
|
||||
return reader.lines().collect(Collectors.joining("\n"));
|
||||
} catch (IOException ignored) {
|
||||
throw new InvalidResponseException(Error.READ_RESPONSE, 200);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle unsuccessful response. Throw detailed exception if possible.
|
||||
*
|
||||
* @param response The raw HTTP response (assuming status code 5xx)
|
||||
* @throws VaultConnectorException Expected exception with details to throw
|
||||
*/
|
||||
private void handleError(final HttpResponse<InputStream> response) throws VaultConnectorException {
|
||||
try (var body = response.body()) {
|
||||
if (body != null) {
|
||||
try (var reader = new BufferedReader(new InputStreamReader(body, UTF_8))) {
|
||||
ErrorResponse er = jsonMapper.readValue(reader, ErrorResponse.class);
|
||||
/* Check for "permission denied" response */
|
||||
if (!er.getErrors().isEmpty() && er.getErrors().get(0).equals("permission denied")) {
|
||||
throw new PermissionDeniedException();
|
||||
}
|
||||
throw new InvalidResponseException(Error.RESPONSE_CODE, response.statusCode(), er.toString());
|
||||
}
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
// Exception ignored.
|
||||
}
|
||||
}
|
||||
}
|
661
src/main/java/de/stklcode/jvault/connector/model/AppRole.java
Normal file
661
src/main/java/de/stklcode/jvault/connector/model/AppRole.java
Normal file
@ -0,0 +1,661 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault AppRole role metamodel.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
* @since 1.1 implements {@link Serializable}
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class AppRole implements Serializable {
|
||||
private static final long serialVersionUID = 693228837510483448L;
|
||||
|
||||
@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> secretIdBoundCidrs;
|
||||
|
||||
@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("local_secret_ids")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Boolean localSecretIds;
|
||||
|
||||
@JsonProperty("token_ttl")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Integer tokenTtl;
|
||||
|
||||
@JsonProperty("token_max_ttl")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Integer tokenMaxTtl;
|
||||
|
||||
private List<String> tokenPolicies;
|
||||
|
||||
@JsonProperty("token_bound_cidrs")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private List<String> tokenBoundCidrs;
|
||||
|
||||
@JsonProperty("token_explicit_max_ttl")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Integer tokenExplicitMaxTtl;
|
||||
|
||||
@JsonProperty("token_no_default_policy")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Boolean tokenNoDefaultPolicy;
|
||||
|
||||
@JsonProperty("token_num_uses")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Integer tokenNumUses;
|
||||
|
||||
@JsonProperty("token_period")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Integer tokenPeriod;
|
||||
|
||||
@JsonProperty("token_type")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private String tokenType;
|
||||
|
||||
/**
|
||||
* Construct empty {@link AppRole} object.
|
||||
*/
|
||||
public AppRole() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct {@link AppRole} object from {@link AppRole.Builder}.
|
||||
*
|
||||
* @param builder AppRole builder.
|
||||
*/
|
||||
public AppRole(final Builder builder) {
|
||||
this.name = builder.name;
|
||||
this.id = builder.id;
|
||||
this.bindSecretId = builder.bindSecretId;
|
||||
this.secretIdBoundCidrs = builder.secretIdBoundCidrs;
|
||||
this.secretIdNumUses = builder.secretIdNumUses;
|
||||
this.secretIdTtl = builder.secretIdTtl;
|
||||
this.localSecretIds = builder.localSecretIds;
|
||||
this.tokenTtl = builder.tokenTtl;
|
||||
this.tokenMaxTtl = builder.tokenMaxTtl;
|
||||
this.tokenPolicies = builder.tokenPolicies;
|
||||
this.tokenBoundCidrs = builder.tokenBoundCidrs;
|
||||
this.tokenExplicitMaxTtl = builder.tokenExplicitMaxTtl;
|
||||
this.tokenNoDefaultPolicy = builder.tokenNoDefaultPolicy;
|
||||
this.tokenNumUses = builder.tokenNumUses;
|
||||
this.tokenPeriod = builder.tokenPeriod;
|
||||
this.tokenType = builder.tokenType != null ? builder.tokenType.value() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link Builder} instance.
|
||||
*
|
||||
* @param name Role name.
|
||||
* @return AppRole Builder.
|
||||
* @since 0.8
|
||||
*/
|
||||
public static Builder builder(final String name) {
|
||||
return new Builder(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 of associated tokens
|
||||
* @since 0.9
|
||||
*/
|
||||
public List<String> getTokenBoundCidrs() {
|
||||
return tokenBoundCidrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param boundCidrList list of subnets in CIDR notation to bind role to
|
||||
* @since 0.9
|
||||
*/
|
||||
@JsonSetter("token_bound_cidrs")
|
||||
public void setBoundCidrs(final List<String> boundCidrList) {
|
||||
this.tokenBoundCidrs = boundCidrList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of subnets in CIDR notation as comma-separated {@link String}
|
||||
* @since 0.9
|
||||
*/
|
||||
@JsonGetter("token_bound_cidrs")
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public String getTokenBoundCidrsString() {
|
||||
if (tokenBoundCidrs == null || tokenBoundCidrs.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return String.join(",", tokenBoundCidrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of bound CIDR subnets
|
||||
* @since 0.8 replaces {@code getBoundCidrList()}
|
||||
*/
|
||||
public List<String> getSecretIdBoundCidrs() {
|
||||
return secretIdBoundCidrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param secretIdBoundCidrs List of subnets in CIDR notation to bind secrets of this role to.
|
||||
* @since 0.8 replaces {@code setBoundCidrList(List)}
|
||||
*/
|
||||
@JsonSetter("secret_id_bound_cidrs")
|
||||
public void setSecretIdBoundCidrs(final List<String> secretIdBoundCidrs) {
|
||||
this.secretIdBoundCidrs = secretIdBoundCidrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of subnets in CIDR notation as comma-separated {@link String}
|
||||
* @since 0.8 replaces {@code getBoundCidrListString()} ()}
|
||||
*/
|
||||
@JsonGetter("secret_id_bound_cidrs")
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public String getSecretIdBoundCidrsString() {
|
||||
if (secretIdBoundCidrs == null || secretIdBoundCidrs.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return String.join(",", secretIdBoundCidrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of token policies
|
||||
* @since 0.9
|
||||
*/
|
||||
public List<String> getTokenPolicies() {
|
||||
return tokenPolicies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tokenPolicies list of token policies
|
||||
* @since 0.9
|
||||
*/
|
||||
@JsonSetter("token_policies")
|
||||
public void setTokenPolicies(final List<String> tokenPolicies) {
|
||||
this.tokenPolicies = tokenPolicies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list of policies as comma-separated {@link String}
|
||||
* @since 0.9
|
||||
*/
|
||||
@JsonGetter("token_policies")
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public String getTokenPoliciesString() {
|
||||
if (tokenPolicies == null || tokenPolicies.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
return String.join(",", tokenPolicies);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 Enable local secret IDs?
|
||||
* @since 0.9
|
||||
* @since 1.3 renamed to {@code getLocalSecretIds()}
|
||||
*/
|
||||
public Boolean getLocalSecretIds() {
|
||||
return localSecretIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return token TTL in seconds
|
||||
*/
|
||||
public Integer getTokenTtl() {
|
||||
return tokenTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return maximum token TTL in seconds, including renewals
|
||||
*/
|
||||
public Integer getTokenMaxTtl() {
|
||||
return tokenMaxTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return explicit maximum token TTL in seconds, including renewals
|
||||
* @since 0.9
|
||||
*/
|
||||
public Integer getTokenExplicitMaxTtl() {
|
||||
return tokenExplicitMaxTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return enable default policy for token?
|
||||
* @since 0.9
|
||||
*/
|
||||
public Boolean getTokenNoDefaultPolicy() {
|
||||
return tokenNoDefaultPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of uses for token
|
||||
* @since 0.9
|
||||
*/
|
||||
public Integer getTokenNumUses() {
|
||||
return tokenNumUses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return duration in seconds, if specified
|
||||
* @since 0.9
|
||||
*/
|
||||
public Integer getTokenPeriod() {
|
||||
return tokenPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return duration in seconds, if specified
|
||||
* @since 0.9
|
||||
*/
|
||||
public String getTokenType() {
|
||||
return tokenType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
AppRole appRole = (AppRole) o;
|
||||
return Objects.equals(name, appRole.name) &&
|
||||
Objects.equals(id, appRole.id) &&
|
||||
Objects.equals(bindSecretId, appRole.bindSecretId) &&
|
||||
Objects.equals(secretIdBoundCidrs, appRole.secretIdBoundCidrs) &&
|
||||
Objects.equals(secretIdNumUses, appRole.secretIdNumUses) &&
|
||||
Objects.equals(secretIdTtl, appRole.secretIdTtl) &&
|
||||
Objects.equals(localSecretIds, appRole.localSecretIds) &&
|
||||
Objects.equals(tokenTtl, appRole.tokenTtl) &&
|
||||
Objects.equals(tokenMaxTtl, appRole.tokenMaxTtl) &&
|
||||
Objects.equals(tokenPolicies, appRole.tokenPolicies) &&
|
||||
Objects.equals(tokenBoundCidrs, appRole.tokenBoundCidrs) &&
|
||||
Objects.equals(tokenExplicitMaxTtl, appRole.tokenExplicitMaxTtl) &&
|
||||
Objects.equals(tokenNoDefaultPolicy, appRole.tokenNoDefaultPolicy) &&
|
||||
Objects.equals(tokenNumUses, appRole.tokenNumUses) &&
|
||||
Objects.equals(tokenPeriod, appRole.tokenPeriod) &&
|
||||
Objects.equals(tokenType, appRole.tokenType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, id, bindSecretId, secretIdBoundCidrs, secretIdNumUses, secretIdTtl,
|
||||
localSecretIds, tokenTtl, tokenMaxTtl, tokenPolicies, tokenBoundCidrs, tokenExplicitMaxTtl,
|
||||
tokenNoDefaultPolicy, tokenNumUses, tokenPeriod, tokenType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A builder for vault AppRole roles..
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
* @since 0.9 Moved into subclass of {@link AppRole}.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private String name;
|
||||
private String id;
|
||||
private Boolean bindSecretId;
|
||||
private List<String> secretIdBoundCidrs;
|
||||
private List<String> tokenPolicies;
|
||||
private Integer secretIdNumUses;
|
||||
private Integer secretIdTtl;
|
||||
private Boolean localSecretIds;
|
||||
private Integer tokenTtl;
|
||||
private Integer tokenMaxTtl;
|
||||
private List<String> tokenBoundCidrs;
|
||||
private Integer tokenExplicitMaxTtl;
|
||||
private Boolean tokenNoDefaultPolicy;
|
||||
private Integer tokenNumUses;
|
||||
private Integer tokenPeriod;
|
||||
private Token.Type tokenType;
|
||||
|
||||
/**
|
||||
* Construct {@link Builder} with only the role name set.
|
||||
*
|
||||
* @param name Role name
|
||||
*/
|
||||
public Builder(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add role name.
|
||||
*
|
||||
* @param name Role name
|
||||
* @return self
|
||||
*/
|
||||
public Builder withName(final String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom role ID. (optional)
|
||||
*
|
||||
* @param id the ID
|
||||
* @return self
|
||||
*/
|
||||
public Builder 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 Builder withBindSecretID(final Boolean bindSecretId) {
|
||||
this.bindSecretId = bindSecretId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind role to secret ID.
|
||||
* Convenience method for {@link #withBindSecretID(Boolean)}
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public Builder withBindSecretID() {
|
||||
return withBindSecretID(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not bind role to secret ID.
|
||||
* Convenience method for {@link #withBindSecretID(Boolean)}
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public Builder withoutBindSecretID() {
|
||||
return withBindSecretID(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set bound CIDR blocks.
|
||||
*
|
||||
* @param secretIdBoundCidrs List of CIDR blocks which can perform login
|
||||
* @return self
|
||||
* @since 0.8 replaces {@code withBoundCidrList(List)}
|
||||
*/
|
||||
public Builder withSecretIdBoundCidrs(final List<String> secretIdBoundCidrs) {
|
||||
if (this.secretIdBoundCidrs == null) {
|
||||
this.secretIdBoundCidrs = new ArrayList<>();
|
||||
}
|
||||
this.secretIdBoundCidrs.addAll(secretIdBoundCidrs);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a CIDR block to list of bound blocks for secret.
|
||||
*
|
||||
* @param secretBoundCidr the CIDR block
|
||||
* @return self
|
||||
* @since 0.9
|
||||
*/
|
||||
public Builder withSecretBoundCidr(final String secretBoundCidr) {
|
||||
if (secretIdBoundCidrs == null) {
|
||||
secretIdBoundCidrs = new ArrayList<>();
|
||||
}
|
||||
secretIdBoundCidrs.add(secretBoundCidr);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given policies.
|
||||
*
|
||||
* @param tokenPolicies the token policies
|
||||
* @return self
|
||||
* @since 0.9
|
||||
*/
|
||||
public Builder withTokenPolicies(final List<String> tokenPolicies) {
|
||||
if (this.tokenPolicies == null) {
|
||||
this.tokenPolicies = new ArrayList<>();
|
||||
}
|
||||
this.tokenPolicies.addAll(tokenPolicies);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single policy.
|
||||
*
|
||||
* @param tokenPolicy the token policy
|
||||
* @return self
|
||||
* @since 0.9
|
||||
*/
|
||||
public Builder withTokenPolicy(final String tokenPolicy) {
|
||||
if (this.tokenPolicies == null) {
|
||||
this.tokenPolicies = new ArrayList<>();
|
||||
}
|
||||
tokenPolicies.add(tokenPolicy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set number of uses for sectet IDs.
|
||||
*
|
||||
* @param secretIdNumUses the number of uses
|
||||
* @return self
|
||||
*/
|
||||
public Builder withSecretIdNumUses(final Integer secretIdNumUses) {
|
||||
this.secretIdNumUses = secretIdNumUses;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default sectet ID TTL in seconds.
|
||||
*
|
||||
* @param secretIdTtl the TTL
|
||||
* @return self
|
||||
*/
|
||||
public Builder withSecretIdTtl(final Integer secretIdTtl) {
|
||||
this.secretIdTtl = secretIdTtl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable local secret IDs.
|
||||
*
|
||||
* @param localSecretIds Enable local secret IDs?
|
||||
* @return self
|
||||
* @since 0.9
|
||||
* @since 1.3 renamed to {@code withLocalSecretIds()}
|
||||
*/
|
||||
public Builder withLocalSecretIds(final Boolean localSecretIds) {
|
||||
this.localSecretIds = localSecretIds;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default token TTL in seconds.
|
||||
*
|
||||
* @param tokenTtl the TTL
|
||||
* @return self
|
||||
*/
|
||||
public Builder withTokenTtl(final Integer tokenTtl) {
|
||||
this.tokenTtl = tokenTtl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set maximum token TTL in seconds.
|
||||
*
|
||||
* @param tokenMaxTtl the TTL
|
||||
* @return self
|
||||
*/
|
||||
public Builder withTokenMaxTtl(final Integer tokenMaxTtl) {
|
||||
this.tokenMaxTtl = tokenMaxTtl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set bound CIDR blocks for associated tokens.
|
||||
*
|
||||
* @param tokenBoundCidrs List of CIDR blocks which can perform login
|
||||
* @return self
|
||||
* @since 0.9
|
||||
*/
|
||||
public Builder withTokenBoundCidrs(final List<String> tokenBoundCidrs) {
|
||||
if (this.tokenBoundCidrs == null) {
|
||||
this.tokenBoundCidrs = new ArrayList<>();
|
||||
}
|
||||
this.tokenBoundCidrs.addAll(tokenBoundCidrs);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a CIDR block to list of bound blocks for token.
|
||||
*
|
||||
* @param tokenBoundCidr the CIDR block
|
||||
* @return self
|
||||
* @since 0.9
|
||||
*/
|
||||
public Builder withTokenBoundCidr(final String tokenBoundCidr) {
|
||||
if (tokenBoundCidrs == null) {
|
||||
tokenBoundCidrs = new ArrayList<>();
|
||||
}
|
||||
tokenBoundCidrs.add(tokenBoundCidr);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set explicit maximum token TTL in seconds.
|
||||
*
|
||||
* @param tokenExplicitMaxTtl the TTL
|
||||
* @return self
|
||||
*/
|
||||
public Builder withTokenExplicitMaxTtl(final Integer tokenExplicitMaxTtl) {
|
||||
this.tokenExplicitMaxTtl = tokenExplicitMaxTtl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable default policy for generated token.
|
||||
*
|
||||
* @param tokenNoDefaultPolicy Enable default policy for token?
|
||||
* @return self
|
||||
* @since 0.9
|
||||
*/
|
||||
public Builder withTokenNoDefaultPolicy(final Boolean tokenNoDefaultPolicy) {
|
||||
this.tokenNoDefaultPolicy = tokenNoDefaultPolicy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set number of uses for generated tokens.
|
||||
*
|
||||
* @param tokenNumUses number of uses for tokens
|
||||
* @return self
|
||||
* @since 0.9
|
||||
*/
|
||||
public Builder withTokenNumUses(final Integer tokenNumUses) {
|
||||
this.tokenNumUses = tokenNumUses;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set renewal period for generated token in seconds.
|
||||
*
|
||||
* @param tokenPeriod period in seconds
|
||||
* @return self
|
||||
* @since 0.9
|
||||
*/
|
||||
public Builder withTokenPeriod(final Integer tokenPeriod) {
|
||||
this.tokenPeriod = tokenPeriod;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set type of generated token.
|
||||
*
|
||||
* @param tokenType token type
|
||||
* @return self
|
||||
* @since 0.9
|
||||
*/
|
||||
public Builder withTokenType(final Token.Type tokenType) {
|
||||
this.tokenType = tokenType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the AppRole role based on given parameters.
|
||||
*
|
||||
* @return the role
|
||||
*/
|
||||
public AppRole build() {
|
||||
return new AppRole(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault AppRole role metamodel.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
* @since 1.1 implements {@link Serializable}
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class AppRoleSecret implements Serializable {
|
||||
private static final long serialVersionUID = -3401074170145792641L;
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
AppRoleSecret that = (AppRoleSecret) o;
|
||||
return Objects.equals(id, that.id) &&
|
||||
Objects.equals(accessor, that.accessor) &&
|
||||
Objects.equals(metadata, that.metadata) &&
|
||||
Objects.equals(cidrList, that.cidrList) &&
|
||||
Objects.equals(creationTime, that.creationTime) &&
|
||||
Objects.equals(expirationTime, that.expirationTime) &&
|
||||
Objects.equals(lastUpdatedTime, that.lastUpdatedTime) &&
|
||||
Objects.equals(numUses, that.numUses) &&
|
||||
Objects.equals(ttl, that.ttl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, accessor, metadata, cidrList, creationTime, expirationTime, lastUpdatedTime, numUses,
|
||||
ttl);
|
||||
}
|
||||
}
|
@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
|
||||
/**
|
||||
@ -8,20 +24,34 @@ package de.stklcode.jvault.connector.model;
|
||||
*/
|
||||
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) {
|
||||
for (AuthBackend v : values())
|
||||
if (v.type.equalsIgnoreCase(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;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
554
src/main/java/de/stklcode/jvault/connector/model/Token.java
Normal file
554
src/main/java/de/stklcode/jvault/connector/model/Token.java
Normal file
@ -0,0 +1,554 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Vault Token metamodel.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
* @since 1.1 implements {@link Serializable}
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class Token implements Serializable {
|
||||
private static final long serialVersionUID = 5208508683665365287L;
|
||||
|
||||
@JsonProperty("id")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private String id;
|
||||
|
||||
@JsonProperty("type")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private String type;
|
||||
|
||||
@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("explicit_max_ttl")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Integer explicitMaxTtl;
|
||||
|
||||
@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;
|
||||
|
||||
@JsonProperty("period")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Integer period;
|
||||
|
||||
@JsonProperty("entity_alias")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private String entityAlias;
|
||||
|
||||
/**
|
||||
* Construct empty {@link Token} object.
|
||||
*/
|
||||
public Token() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct {@link Token} object from {@link Builder}.
|
||||
*
|
||||
* @param builder Token builder.
|
||||
*/
|
||||
public Token(final Builder builder) {
|
||||
this.id = builder.id;
|
||||
this.type = builder.type != null ? builder.type.value() : null;
|
||||
this.displayName = builder.displayName;
|
||||
this.noParent = builder.noParent;
|
||||
this.noDefaultPolicy = builder.noDefaultPolicy;
|
||||
this.ttl = builder.ttl;
|
||||
this.explicitMaxTtl = builder.explicitMaxTtl;
|
||||
this.numUses = builder.numUses;
|
||||
this.policies = builder.policies;
|
||||
this.meta = builder.meta;
|
||||
this.renewable = builder.renewable;
|
||||
this.period = builder.period;
|
||||
this.entityAlias = builder.entityAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link Builder} instance.
|
||||
*
|
||||
* @return Token Builder.
|
||||
* @since 0.8
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token ID
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token type
|
||||
* @since 0.9
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 Explicit maximum time-to-live in seconds
|
||||
* @since 0.9
|
||||
*/
|
||||
public Integer getExplicitMaxTtl() {
|
||||
return explicitMaxTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token period.
|
||||
* @since 0.9
|
||||
*/
|
||||
public Integer getPeriod() {
|
||||
return period;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token entity alias.
|
||||
* @since 0.9
|
||||
*/
|
||||
public String getEntityAlias() {
|
||||
return entityAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Token token = (Token) o;
|
||||
return Objects.equals(id, token.id) &&
|
||||
Objects.equals(type, token.type) &&
|
||||
Objects.equals(displayName, token.displayName) &&
|
||||
Objects.equals(noParent, token.noParent) &&
|
||||
Objects.equals(noDefaultPolicy, token.noDefaultPolicy) &&
|
||||
Objects.equals(ttl, token.ttl) &&
|
||||
Objects.equals(explicitMaxTtl, token.explicitMaxTtl) &&
|
||||
Objects.equals(numUses, token.numUses) &&
|
||||
Objects.equals(policies, token.policies) &&
|
||||
Objects.equals(meta, token.meta) &&
|
||||
Objects.equals(renewable, token.renewable) &&
|
||||
Objects.equals(period, token.period) &&
|
||||
Objects.equals(entityAlias, token.entityAlias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, type, displayName, noParent, noDefaultPolicy, ttl, explicitMaxTtl, numUses, policies,
|
||||
meta, renewable, period, entityAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constants for token types.
|
||||
*/
|
||||
public enum Type {
|
||||
DEFAULT("default"),
|
||||
BATCH("batch"),
|
||||
SERVICE("service"),
|
||||
DEFAULT_SERVICE("default-service"),
|
||||
DEFAULT_BATCH("default-batch");
|
||||
|
||||
private final String value;
|
||||
|
||||
Type(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A builder for vault tokens.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
* @since 0.9 Moved into subclass of {@link Token}.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private String id;
|
||||
private Type type;
|
||||
private String displayName;
|
||||
private Boolean noParent;
|
||||
private Boolean noDefaultPolicy;
|
||||
private Integer ttl;
|
||||
private Integer explicitMaxTtl;
|
||||
private Integer numUses;
|
||||
private List<String> policies;
|
||||
private Map<String, String> meta;
|
||||
private Boolean renewable;
|
||||
private Integer period;
|
||||
private String entityAlias;
|
||||
|
||||
/**
|
||||
* Add token ID. (optional)
|
||||
*
|
||||
* @param id the ID
|
||||
* @return self
|
||||
*/
|
||||
public Builder withId(final String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify token type.
|
||||
*
|
||||
* @param type the type
|
||||
* @return self
|
||||
* @since 0.9
|
||||
*/
|
||||
public Builder withType(final Token.Type type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add display name.
|
||||
*
|
||||
* @param displayName the display name
|
||||
* @return self
|
||||
*/
|
||||
public Builder withDisplayName(final String displayName) {
|
||||
this.displayName = displayName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set desired time to live.
|
||||
*
|
||||
* @param ttl the ttl
|
||||
* @return self
|
||||
*/
|
||||
public Builder withTtl(final Integer ttl) {
|
||||
this.ttl = ttl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set desired explicit maximum time to live.
|
||||
*
|
||||
* @param explicitMaxTtl the explicit max. TTL
|
||||
* @return self
|
||||
*/
|
||||
public Builder withExplicitMaxTtl(final Integer explicitMaxTtl) {
|
||||
this.explicitMaxTtl = explicitMaxTtl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set desired number of uses.
|
||||
*
|
||||
* @param numUses the number of uses
|
||||
* @return self
|
||||
*/
|
||||
public Builder 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 Builder withNoParent(final boolean noParent) {
|
||||
this.noParent = noParent;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create token without parent.
|
||||
* Convenience method for withNoParent()
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public Builder asOrphan() {
|
||||
return withNoParent(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create token with parent.
|
||||
* Convenience method for withNoParent()
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public Builder 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 Builder withNoDefaultPolicy(final boolean noDefaultPolicy) {
|
||||
this.noDefaultPolicy = noDefaultPolicy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach default policy to token.
|
||||
* Convenience method for withNoDefaultPolicy()
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public Builder withDefaultPolicy() {
|
||||
return withNoDefaultPolicy(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not attach default policy to token.
|
||||
* Convenience method for withNoDefaultPolicy()
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public Builder withoutDefaultPolicy() {
|
||||
return withNoDefaultPolicy(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given policies.
|
||||
*
|
||||
* @param policies the policies
|
||||
* @return self
|
||||
* @since 0.5.0
|
||||
*/
|
||||
public Builder withPolicies(final String... policies) {
|
||||
return withPolicies(Arrays.asList(policies));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add given policies.
|
||||
*
|
||||
* @param policies the policies
|
||||
* @return self
|
||||
*/
|
||||
public Builder 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 Builder 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 Builder 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 Builder 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 Builder withRenewable(final Boolean renewable) {
|
||||
this.renewable = renewable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set token to be renewable.
|
||||
* Convenience method for withRenewable()
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public Builder renewable() {
|
||||
return withRenewable(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set token to be not renewable.
|
||||
* Convenience method for withRenewable()
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public Builder notRenewable() {
|
||||
return withRenewable(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set token period (former lease time).
|
||||
*
|
||||
* @param period Period in seconds.
|
||||
* @return self
|
||||
*/
|
||||
public Builder withPeriod(final Integer period) {
|
||||
this.period = period;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set entity alias for token.
|
||||
* Only works in combination with an associated token role.
|
||||
*
|
||||
* @param entityAlias Entity alias.
|
||||
* @return self
|
||||
*/
|
||||
public Builder withEntityAlias(final String entityAlias) {
|
||||
this.entityAlias = entityAlias;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the token based on given parameters.
|
||||
*
|
||||
* @return the token
|
||||
*/
|
||||
public Token build() {
|
||||
return new Token(this);
|
||||
}
|
||||
}
|
||||
}
|
598
src/main/java/de/stklcode/jvault/connector/model/TokenRole.java
Normal file
598
src/main/java/de/stklcode/jvault/connector/model/TokenRole.java
Normal file
@ -0,0 +1,598 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault Token Role metamodel.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.9
|
||||
* @since 1.1 implements {@link Serializable}
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class TokenRole implements Serializable {
|
||||
private static final long serialVersionUID = -3505215215838576321L;
|
||||
|
||||
@JsonProperty("name")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private String name;
|
||||
|
||||
@JsonProperty("allowed_policies")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private List<String> allowedPolicies;
|
||||
|
||||
@JsonProperty("allowed_policies_glob")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private List<String> allowedPoliciesGlob;
|
||||
|
||||
@JsonProperty("disallowed_policies")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private List<String> disallowedPolicies;
|
||||
|
||||
@JsonProperty("disallowed_policies_glob")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private List<String> disallowedPoliciesGlob;
|
||||
|
||||
@JsonProperty("orphan")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Boolean orphan;
|
||||
|
||||
@JsonProperty("renewable")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Boolean renewable;
|
||||
|
||||
@JsonProperty("path_suffix")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private String pathSuffix;
|
||||
|
||||
@JsonProperty("allowed_entity_aliases")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private List<String> allowedEntityAliases;
|
||||
|
||||
@JsonProperty("token_bound_cidrs")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private List<String> tokenBoundCidrs;
|
||||
|
||||
@JsonProperty("token_explicit_max_ttl")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Integer tokenExplicitMaxTtl;
|
||||
|
||||
@JsonProperty("token_no_default_policy")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Boolean tokenNoDefaultPolicy;
|
||||
|
||||
@JsonProperty("token_num_uses")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Integer tokenNumUses;
|
||||
|
||||
@JsonProperty("token_period")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private Integer tokenPeriod;
|
||||
|
||||
@JsonProperty("token_type")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private String tokenType;
|
||||
|
||||
/**
|
||||
* Construct empty {@link TokenRole} object.
|
||||
*/
|
||||
public TokenRole() {
|
||||
}
|
||||
|
||||
public TokenRole(final Builder builder) {
|
||||
this.name = builder.name;
|
||||
this.allowedPolicies = builder.allowedPolicies;
|
||||
this.allowedPoliciesGlob = builder.allowedPoliciesGlob;
|
||||
this.disallowedPolicies = builder.disallowedPolicies;
|
||||
this.disallowedPoliciesGlob = builder.disallowedPoliciesGlob;
|
||||
this.orphan = builder.orphan;
|
||||
this.renewable = builder.renewable;
|
||||
this.pathSuffix = builder.pathSuffix;
|
||||
this.allowedEntityAliases = builder.allowedEntityAliases;
|
||||
this.tokenBoundCidrs = builder.tokenBoundCidrs;
|
||||
this.tokenExplicitMaxTtl = builder.tokenExplicitMaxTtl;
|
||||
this.tokenNoDefaultPolicy = builder.tokenNoDefaultPolicy;
|
||||
this.tokenNumUses = builder.tokenNumUses;
|
||||
this.tokenPeriod = builder.tokenPeriod;
|
||||
this.tokenType = builder.tokenType != null ? builder.tokenType.value() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link Builder} instance.
|
||||
*
|
||||
* @return Token Role Builder.
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token Role name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of allowed policies
|
||||
*/
|
||||
public List<String> getAllowedPolicies() {
|
||||
return allowedPolicies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of allowed policy glob patterns
|
||||
* @since 1.1
|
||||
*/
|
||||
public List<String> getAllowedPoliciesGlob() {
|
||||
return allowedPoliciesGlob;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of disallowed policies
|
||||
*/
|
||||
public List<String> getDisallowedPolicies() {
|
||||
return disallowedPolicies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of disallowed policy glob patterns
|
||||
* @since 1.1
|
||||
*/
|
||||
public List<String> getDisallowedPoliciesGlob() {
|
||||
return disallowedPoliciesGlob;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Is Token Role orphan?
|
||||
*/
|
||||
public Boolean getOrphan() {
|
||||
return orphan;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Is Token Role renewable?
|
||||
*/
|
||||
public Boolean getRenewable() {
|
||||
return renewable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Path suffix
|
||||
*/
|
||||
public String getPathSuffix() {
|
||||
return pathSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of allowed entity aliases
|
||||
*/
|
||||
public List<String> getAllowedEntityAliases() {
|
||||
return allowedEntityAliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token bound CIDR blocks
|
||||
*/
|
||||
public List<String> getTokenBoundCidrs() {
|
||||
return tokenBoundCidrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token explicit maximum TTL
|
||||
*/
|
||||
public Integer getTokenExplicitMaxTtl() {
|
||||
return tokenExplicitMaxTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token without default policy?
|
||||
*/
|
||||
public Boolean getTokenNoDefaultPolicy() {
|
||||
return tokenNoDefaultPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token number of uses
|
||||
*/
|
||||
public Integer getTokenNumUses() {
|
||||
return tokenNumUses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token period
|
||||
*/
|
||||
public Integer getTokenPeriod() {
|
||||
return tokenPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token type
|
||||
*/
|
||||
public String getTokenType() {
|
||||
return tokenType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TokenRole tokenRole = (TokenRole) o;
|
||||
return Objects.equals(name, tokenRole.name) &&
|
||||
Objects.equals(allowedPolicies, tokenRole.allowedPolicies) &&
|
||||
Objects.equals(allowedPoliciesGlob, tokenRole.allowedPoliciesGlob) &&
|
||||
Objects.equals(disallowedPolicies, tokenRole.disallowedPolicies) &&
|
||||
Objects.equals(disallowedPoliciesGlob, tokenRole.disallowedPoliciesGlob) &&
|
||||
Objects.equals(orphan, tokenRole.orphan) &&
|
||||
Objects.equals(renewable, tokenRole.renewable) &&
|
||||
Objects.equals(pathSuffix, tokenRole.pathSuffix) &&
|
||||
Objects.equals(allowedEntityAliases, tokenRole.allowedEntityAliases) &&
|
||||
Objects.equals(tokenBoundCidrs, tokenRole.tokenBoundCidrs) &&
|
||||
Objects.equals(tokenExplicitMaxTtl, tokenRole.tokenExplicitMaxTtl) &&
|
||||
Objects.equals(tokenNoDefaultPolicy, tokenRole.tokenNoDefaultPolicy) &&
|
||||
Objects.equals(tokenNumUses, tokenRole.tokenNumUses) &&
|
||||
Objects.equals(tokenPeriod, tokenRole.tokenPeriod) &&
|
||||
Objects.equals(tokenType, tokenRole.tokenType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, allowedPolicies, allowedPoliciesGlob, disallowedPolicies, disallowedPoliciesGlob,
|
||||
orphan, renewable, pathSuffix, allowedEntityAliases, tokenBoundCidrs, tokenExplicitMaxTtl,
|
||||
tokenNoDefaultPolicy, tokenNumUses, tokenPeriod, tokenType);
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for vault token roles.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.9
|
||||
*/
|
||||
public static final class Builder {
|
||||
private String name;
|
||||
private List<String> allowedPolicies;
|
||||
private List<String> allowedPoliciesGlob;
|
||||
private List<String> disallowedPolicies;
|
||||
private List<String> disallowedPoliciesGlob;
|
||||
private Boolean orphan;
|
||||
private Boolean renewable;
|
||||
private String pathSuffix;
|
||||
private List<String> allowedEntityAliases;
|
||||
private List<String> tokenBoundCidrs;
|
||||
private Integer tokenExplicitMaxTtl;
|
||||
private Boolean tokenNoDefaultPolicy;
|
||||
private Integer tokenNumUses;
|
||||
private Integer tokenPeriod;
|
||||
private Token.Type tokenType;
|
||||
|
||||
/**
|
||||
* Add token role name.
|
||||
*
|
||||
* @param name role name
|
||||
* @return self
|
||||
*/
|
||||
public Builder forName(final String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an allowed policy.
|
||||
*
|
||||
* @param allowedPolicy allowed policy to add
|
||||
* @return self
|
||||
*/
|
||||
public Builder withAllowedPolicy(final String allowedPolicy) {
|
||||
if (allowedPolicy != null) {
|
||||
if (this.allowedPolicies == null) {
|
||||
this.allowedPolicies = new ArrayList<>();
|
||||
}
|
||||
this.allowedPolicies.add(allowedPolicy);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add allowed policies.
|
||||
*
|
||||
* @param allowedPolicies list of allowed policies
|
||||
* @return self
|
||||
*/
|
||||
public Builder withAllowedPolicies(final List<String> allowedPolicies) {
|
||||
if (allowedPolicies != null) {
|
||||
if (this.allowedPolicies == null) {
|
||||
this.allowedPolicies = new ArrayList<>();
|
||||
}
|
||||
this.allowedPolicies.addAll(allowedPolicies);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an allowed policy glob pattern.
|
||||
*
|
||||
* @param allowedPolicyGlob allowed policy glob pattern to add
|
||||
* @return self
|
||||
* @since 1.1
|
||||
*/
|
||||
public Builder withAllowedPolicyGlob(final String allowedPolicyGlob) {
|
||||
if (allowedPolicyGlob != null) {
|
||||
if (this.allowedPoliciesGlob == null) {
|
||||
this.allowedPoliciesGlob = new ArrayList<>();
|
||||
}
|
||||
this.allowedPoliciesGlob.add(allowedPolicyGlob);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add allowed policy glob patterns.
|
||||
*
|
||||
* @param allowedPoliciesGlob list of allowed policy glob patterns
|
||||
* @return self
|
||||
* @since 1.1
|
||||
*/
|
||||
public Builder withAllowedPoliciesGlob(final List<String> allowedPoliciesGlob) {
|
||||
if (allowedPoliciesGlob != null) {
|
||||
if (this.allowedPoliciesGlob == null) {
|
||||
this.allowedPoliciesGlob = new ArrayList<>();
|
||||
}
|
||||
this.allowedPoliciesGlob.addAll(allowedPoliciesGlob);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a disallowed policy.
|
||||
*
|
||||
* @param disallowedPolicy disallowed policy to add
|
||||
* @return self
|
||||
*/
|
||||
public Builder withDisallowedPolicy(final String disallowedPolicy) {
|
||||
if (disallowedPolicy != null) {
|
||||
if (this.disallowedPolicies == null) {
|
||||
this.disallowedPolicies = new ArrayList<>();
|
||||
}
|
||||
this.disallowedPolicies.add(disallowedPolicy);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add disallowed policies.
|
||||
*
|
||||
* @param disallowedPolicies list of disallowed policies
|
||||
* @return self
|
||||
*/
|
||||
public Builder withDisallowedPolicies(final List<String> disallowedPolicies) {
|
||||
if (disallowedPolicies != null) {
|
||||
if (this.disallowedPolicies == null) {
|
||||
this.disallowedPolicies = new ArrayList<>();
|
||||
}
|
||||
this.disallowedPolicies.addAll(disallowedPolicies);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an allowed policy glob pattern.
|
||||
*
|
||||
* @param disallowedPolicyGlob disallowed policy glob pattern to add
|
||||
* @return self
|
||||
* @since 1.1
|
||||
*/
|
||||
public Builder withDisallowedPolicyGlob(final String disallowedPolicyGlob) {
|
||||
if (disallowedPolicyGlob != null) {
|
||||
if (this.disallowedPoliciesGlob == null) {
|
||||
this.disallowedPoliciesGlob = new ArrayList<>();
|
||||
}
|
||||
this.disallowedPoliciesGlob.add(disallowedPolicyGlob);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add disallowed policy glob patterns.
|
||||
*
|
||||
* @param disallowedPoliciesGlob list of disallowed policy glob patterns
|
||||
* @return self
|
||||
* @since 1.1
|
||||
*/
|
||||
public Builder withDisallowedPoliciesGlob(final List<String> disallowedPoliciesGlob) {
|
||||
if (disallowedPoliciesGlob != null) {
|
||||
if (this.disallowedPoliciesGlob == null) {
|
||||
this.disallowedPoliciesGlob = new ArrayList<>();
|
||||
}
|
||||
this.disallowedPoliciesGlob.addAll(disallowedPoliciesGlob);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set TRUE if the token role should be created orphan.
|
||||
*
|
||||
* @param orphan if TRUE, token role is created as orphan
|
||||
* @return self
|
||||
*/
|
||||
public Builder orphan(final Boolean orphan) {
|
||||
this.orphan = orphan;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set TRUE if the token role should be created renewable.
|
||||
*
|
||||
* @param renewable if TRUE, token role is created renewable
|
||||
* @return self
|
||||
*/
|
||||
public Builder renewable(final Boolean renewable) {
|
||||
this.renewable = renewable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set token role path suffix.
|
||||
*
|
||||
* @param pathSuffix path suffix to use
|
||||
* @return self
|
||||
*/
|
||||
public Builder withPathSuffix(final String pathSuffix) {
|
||||
this.pathSuffix = pathSuffix;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an allowed entity alias.
|
||||
*
|
||||
* @param allowedEntityAlias allowed entity alias to add
|
||||
* @return self
|
||||
*/
|
||||
public Builder withAllowedEntityAlias(final String allowedEntityAlias) {
|
||||
if (allowedEntityAlias != null) {
|
||||
if (this.allowedEntityAliases == null) {
|
||||
this.allowedEntityAliases = new ArrayList<>();
|
||||
}
|
||||
this.allowedEntityAliases.add(allowedEntityAlias);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add allowed entity aliases.
|
||||
*
|
||||
* @param allowedEntityAliases list of allowed entity aliases to add
|
||||
* @return self
|
||||
*/
|
||||
public Builder withAllowedEntityAliases(final List<String> allowedEntityAliases) {
|
||||
if (allowedEntityAliases != null) {
|
||||
if (this.allowedEntityAliases == null) {
|
||||
this.allowedEntityAliases = new ArrayList<>();
|
||||
}
|
||||
this.allowedEntityAliases.addAll(allowedEntityAliases);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single bound CIDR.
|
||||
*
|
||||
* @param tokenBoundCidr bound CIDR to add
|
||||
* @return self
|
||||
*/
|
||||
public Builder withTokenBoundCidr(final String tokenBoundCidr) {
|
||||
if (tokenBoundCidr != null) {
|
||||
if (this.tokenBoundCidrs == null) {
|
||||
this.tokenBoundCidrs = new ArrayList<>();
|
||||
}
|
||||
this.tokenBoundCidrs.add(tokenBoundCidr);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a list of bound CIDRs.
|
||||
*
|
||||
* @param tokenBoundCidrs list of bound CIDRs to add
|
||||
* @return self
|
||||
*/
|
||||
public Builder withTokenBoundCidrs(final List<String> tokenBoundCidrs) {
|
||||
if (tokenBoundCidrs != null) {
|
||||
if (this.tokenBoundCidrs == null) {
|
||||
this.tokenBoundCidrs = new ArrayList<>();
|
||||
}
|
||||
this.tokenBoundCidrs.addAll(tokenBoundCidrs);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set explicit max. TTL for token.
|
||||
*
|
||||
* @param tokenExplicitMaxTtl explicit maximum TTL
|
||||
* @return self
|
||||
*/
|
||||
public Builder withTokenExplicitMaxTtl(final Integer tokenExplicitMaxTtl) {
|
||||
this.tokenExplicitMaxTtl = tokenExplicitMaxTtl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set TRUE if the token role should be created renewable.
|
||||
*
|
||||
* @param tokenNoDefaultPolicy if TRUE, token is created without default policy.
|
||||
* @return self
|
||||
*/
|
||||
public Builder withTokenNoDefaultPolicy(final Boolean tokenNoDefaultPolicy) {
|
||||
this.tokenNoDefaultPolicy = tokenNoDefaultPolicy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set number of uses for tokens.
|
||||
*
|
||||
* @param tokenNumUses number of uses for associated tokens.
|
||||
* @return self
|
||||
*/
|
||||
public Builder withTokenNumUses(final Integer tokenNumUses) {
|
||||
this.tokenNumUses = tokenNumUses;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set token period.
|
||||
*
|
||||
* @param tokenPeriod token period
|
||||
* @return self
|
||||
*/
|
||||
public Builder withTokenPeriod(final Integer tokenPeriod) {
|
||||
this.tokenPeriod = tokenPeriod;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set token type.
|
||||
*
|
||||
* @param tokenType token type
|
||||
* @return self
|
||||
*/
|
||||
public Builder withTokenType(final Token.Type tokenType) {
|
||||
this.tokenType = tokenType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the token based on given parameters.
|
||||
*
|
||||
* @return the token
|
||||
*/
|
||||
public TokenRole build() {
|
||||
return new TokenRole(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Model classes for communication with the Vault API.
|
||||
*/
|
||||
package de.stklcode.jvault.connector.model;
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
import de.stklcode.jvault.connector.model.AppRole;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault response for AppRole lookup.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class AppRoleResponse extends VaultDataResponse {
|
||||
private static final long serialVersionUID = -6536422219633829177L;
|
||||
|
||||
@JsonProperty("data")
|
||||
private AppRole role;
|
||||
|
||||
/**
|
||||
* @return The role
|
||||
*/
|
||||
public AppRole getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
AppRoleResponse that = (AppRoleResponse) o;
|
||||
return Objects.equals(role, that.role);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), role);
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
import de.stklcode.jvault.connector.model.AppRoleSecret;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault response for AppRole lookup.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class AppRoleSecretResponse extends VaultDataResponse {
|
||||
private static final long serialVersionUID = -2484103304072370585L;
|
||||
|
||||
@JsonProperty("data")
|
||||
private AppRoleSecret secret;
|
||||
|
||||
/**
|
||||
* @return The secret
|
||||
*/
|
||||
public AppRoleSecret getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
AppRoleSecretResponse that = (AppRoleSecretResponse) o;
|
||||
return Objects.equals(secret, that.secret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), secret);
|
||||
}
|
||||
}
|
@ -1,13 +1,28 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.AuthMethod;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Authentication method response.
|
||||
@ -16,26 +31,39 @@ import java.util.Map;
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AuthMethodsResponse extends VaultDataResponse {
|
||||
public final class AuthMethodsResponse extends VaultDataResponse {
|
||||
private static final long serialVersionUID = -1802724129533405375L;
|
||||
|
||||
@JsonProperty("data")
|
||||
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 {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
for (String path : data.keySet()) {
|
||||
try {
|
||||
this.supportedMethods.put(path, mapper.readValue(mapper.writeValueAsString(data.get(path)), AuthMethod.class));
|
||||
} catch (IOException e) {
|
||||
throw new InvalidResponseException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Supported authentication methods
|
||||
*/
|
||||
public Map<String, AuthMethod> getSupportedMethods() {
|
||||
return supportedMethods;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
AuthMethodsResponse that = (AuthMethodsResponse) o;
|
||||
return Objects.equals(supportedMethods, that.supportedMethods);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), supportedMethods);
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,24 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.AuthData;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Vault response for authentication providing auth info in {@link AuthData} field.
|
||||
*
|
||||
@ -16,32 +26,6 @@ import java.util.Map;
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AuthResponse extends VaultDataResponse {
|
||||
private Map<String, Object> data;
|
||||
|
||||
private AuthData auth;
|
||||
|
||||
@JsonProperty("auth")
|
||||
public void setAuth(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();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setData(Map<String, Object> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Map<String, Object> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public AuthData getAuth() {
|
||||
return auth;
|
||||
}
|
||||
public final class AuthResponse extends VaultDataResponse {
|
||||
private static final long serialVersionUID = 1628851361067456715L;
|
||||
}
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 PlainSecretResponse {
|
||||
private static final long serialVersionUID = -1439692963299045425L;
|
||||
|
||||
/**
|
||||
* @return Username
|
||||
*/
|
||||
public String getUsername() {
|
||||
Object username = get("username");
|
||||
if (username != null) {
|
||||
return username.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Password
|
||||
*/
|
||||
public String getPassword() {
|
||||
Object password = get("password");
|
||||
if (password != null) {
|
||||
return password.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,9 +1,26 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault response in case of errors.
|
||||
@ -12,11 +29,41 @@ import java.util.List;
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class ErrorResponse implements VaultResponse {
|
||||
public final class ErrorResponse implements VaultResponse {
|
||||
private static final long serialVersionUID = -6227368087842549149L;
|
||||
|
||||
@JsonProperty("errors")
|
||||
private List<String> errors;
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ErrorResponse that = (ErrorResponse) o;
|
||||
return Objects.equals(errors, that.errors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(errors);
|
||||
}
|
||||
}
|
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault response for health query.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.7.0
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class HealthResponse implements VaultResponse {
|
||||
private static final long serialVersionUID = 8675155916902904516L;
|
||||
|
||||
@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;
|
||||
|
||||
@JsonProperty("replication_performance_mode")
|
||||
private String replicationPerfMode;
|
||||
|
||||
@JsonProperty("replication_dr_mode")
|
||||
private String replicationDrMode;
|
||||
|
||||
@JsonProperty("performance_standby")
|
||||
private Boolean performanceStandby;
|
||||
|
||||
@JsonProperty("echo_duration_ms")
|
||||
private Long echoDurationMs;
|
||||
|
||||
@JsonProperty("clock_skew_ms")
|
||||
private Long clockSkewMs;
|
||||
|
||||
@JsonProperty("replication_primary_canary_age_ms")
|
||||
private Long replicationPrimaryCanaryAgeMs;
|
||||
|
||||
@JsonProperty("enterprise")
|
||||
private Boolean enterprise;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Replication performance mode of the active node (since Vault 0.9.2).
|
||||
* @since 0.8 (#21)
|
||||
*/
|
||||
public String getReplicationPerfMode() {
|
||||
return replicationPerfMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Replication DR mode of the active node (since Vault 0.9.2).
|
||||
* @since 0.8 (#21)
|
||||
*/
|
||||
public String getReplicationDrMode() {
|
||||
return replicationDrMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Performance standby status.
|
||||
* @since 0.8 (#21)
|
||||
*/
|
||||
public Boolean isPerformanceStandby() {
|
||||
return performanceStandby;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Heartbeat echo duration in milliseconds (since Vault 1.16)
|
||||
* @since 1.3
|
||||
*/
|
||||
public Long getEchoDurationMs() {
|
||||
return echoDurationMs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Clock skew in milliseconds (since Vault 1.16)
|
||||
* @since 1.3
|
||||
*/
|
||||
public Long getClockSkewMs() {
|
||||
return clockSkewMs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Replication primary canary age in milliseconds (since Vault 1.17)
|
||||
* @since 1.3
|
||||
*/
|
||||
public Long getReplicationPrimaryCanaryAgeMs() {
|
||||
return replicationPrimaryCanaryAgeMs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Enterprise instance? (since Vault 1.17)
|
||||
* @since 1.3
|
||||
*/
|
||||
public Boolean isEnterprise() {
|
||||
return enterprise;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
HealthResponse that = (HealthResponse) o;
|
||||
return Objects.equals(clusterID, that.clusterID) &&
|
||||
Objects.equals(clusterName, that.clusterName) &&
|
||||
Objects.equals(version, that.version) &&
|
||||
Objects.equals(serverTimeUTC, that.serverTimeUTC) &&
|
||||
Objects.equals(standby, that.standby) &&
|
||||
Objects.equals(sealed, that.sealed) &&
|
||||
Objects.equals(initialized, that.initialized) &&
|
||||
Objects.equals(replicationPerfMode, that.replicationPerfMode) &&
|
||||
Objects.equals(replicationDrMode, that.replicationDrMode) &&
|
||||
Objects.equals(performanceStandby, that.performanceStandby) &&
|
||||
Objects.equals(echoDurationMs, that.echoDurationMs) &&
|
||||
Objects.equals(clockSkewMs, that.clockSkewMs) &&
|
||||
Objects.equals(replicationPrimaryCanaryAgeMs, that.replicationPrimaryCanaryAgeMs) &&
|
||||
Objects.equals(enterprise, that.enterprise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(clusterID, clusterName, version, serverTimeUTC, standby, sealed, initialized,
|
||||
replicationPerfMode, replicationDrMode, performanceStandby, echoDurationMs, clockSkewMs,
|
||||
replicationPrimaryCanaryAgeMs, enterprise);
|
||||
}
|
||||
}
|
@ -1,8 +1,26 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault response for help request.
|
||||
*
|
||||
@ -10,11 +28,32 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class HelpResponse implements VaultResponse {
|
||||
public final class HelpResponse implements VaultResponse {
|
||||
private static final long serialVersionUID = -1152070966642848490L;
|
||||
|
||||
@JsonProperty("help")
|
||||
private String help;
|
||||
|
||||
/**
|
||||
* @return Help text
|
||||
*/
|
||||
public String getHelp() {
|
||||
return help;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
HelpResponse that = (HelpResponse) o;
|
||||
return Objects.equals(help, that.help);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(help);
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.SecretWrapper;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault response for secret responses with metadata.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 1.1 abstract
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class MetaSecretResponse extends SecretResponse {
|
||||
private static final long serialVersionUID = -1076542846391240162L;
|
||||
|
||||
@JsonProperty("data")
|
||||
private SecretWrapper secret;
|
||||
|
||||
@Override
|
||||
public final Map<String, Serializable> getData() {
|
||||
if (secret != null) {
|
||||
return secret.getData();
|
||||
} else {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final VersionMetadata getMetadata() {
|
||||
if (secret != null) {
|
||||
return secret.getMetadata();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
MetaSecretResponse that = (MetaSecretResponse) o;
|
||||
return Objects.equals(secret, that.secret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), secret);
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.SecretMetadata;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
* Vault response for secret metadata (KV v2).
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.8
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class MetadataResponse extends VaultDataResponse {
|
||||
private static final long serialVersionUID = -3679762333630984679L;
|
||||
|
||||
@JsonProperty("data")
|
||||
private SecretMetadata metadata;
|
||||
|
||||
/**
|
||||
* Get the actual metadata.
|
||||
*
|
||||
* @return Metadata.
|
||||
*/
|
||||
public SecretMetadata getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
MetadataResponse that = (MetadataResponse) o;
|
||||
return Objects.equals(metadata, that.metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), metadata);
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault response for plain secret responses.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 1.1 abstract
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class PlainSecretResponse extends SecretResponse {
|
||||
private static final long serialVersionUID = 3010138542437913023L;
|
||||
|
||||
@JsonProperty("data")
|
||||
private Map<String, Serializable> data;
|
||||
|
||||
@Override
|
||||
public final Map<String, Serializable> getData() {
|
||||
return Objects.requireNonNullElseGet(data, Collections::emptyMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final VersionMetadata getMetadata() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
PlainSecretResponse that = (PlainSecretResponse) o;
|
||||
return Objects.equals(data, that.data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), data);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Simple Vault data response.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class RawDataResponse extends VaultDataResponse {
|
||||
private static final long serialVersionUID = -319727427792124071L;
|
||||
|
||||
@JsonProperty("data")
|
||||
private Map<String, Serializable> data;
|
||||
|
||||
/**
|
||||
* @return Raw data {@link Map}
|
||||
*/
|
||||
public Map<String, Serializable> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
RawDataResponse that = (RawDataResponse) o;
|
||||
return Objects.equals(data, that.data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), data);
|
||||
}
|
||||
}
|
@ -1,8 +1,27 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault response for seal status or unseal request.
|
||||
*
|
||||
@ -10,10 +29,18 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SealResponse implements VaultResponse {
|
||||
public final class SealResponse implements VaultResponse {
|
||||
private static final long serialVersionUID = -6000309255473305787L;
|
||||
|
||||
@JsonProperty("type")
|
||||
private String type;
|
||||
|
||||
@JsonProperty("sealed")
|
||||
private boolean sealed;
|
||||
|
||||
@JsonProperty("initialized")
|
||||
private boolean initialized;
|
||||
|
||||
@JsonProperty("t")
|
||||
private Integer threshold;
|
||||
|
||||
@ -23,19 +50,165 @@ public class SealResponse implements VaultResponse {
|
||||
@JsonProperty("progress")
|
||||
private Integer progress;
|
||||
|
||||
@JsonProperty("version")
|
||||
private String version;
|
||||
|
||||
@JsonProperty("build_date")
|
||||
private ZonedDateTime buildDate;
|
||||
|
||||
@JsonProperty("nonce")
|
||||
private String nonce;
|
||||
|
||||
@JsonProperty("cluster_name")
|
||||
private String clusterName;
|
||||
|
||||
@JsonProperty("cluster_id")
|
||||
private String clusterId;
|
||||
|
||||
@JsonProperty("migration")
|
||||
private Boolean migration;
|
||||
|
||||
@JsonProperty("recovery_seal")
|
||||
private Boolean recoverySeal;
|
||||
|
||||
@JsonProperty("storage_type")
|
||||
private String storageType;
|
||||
|
||||
/**
|
||||
* @return Seal type.
|
||||
* @since 0.8
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Seal status
|
||||
*/
|
||||
public boolean isSealed() {
|
||||
return sealed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vault initialization status (since Vault 0.11.2).
|
||||
* @since 0.8
|
||||
*/
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vault version.
|
||||
* @since 0.8
|
||||
*/
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vault build date.
|
||||
* @since 1.2
|
||||
*/
|
||||
public ZonedDateTime getBuildDate() {
|
||||
return buildDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A random nonce.
|
||||
* @since 0.8
|
||||
*/
|
||||
public String getNonce() {
|
||||
return nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vault cluster name (only if unsealed).
|
||||
* @since 0.8
|
||||
*/
|
||||
public String getClusterName() {
|
||||
return clusterName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Vault cluster ID (only if unsealed).
|
||||
* @since 0.8
|
||||
*/
|
||||
public String getClusterId() {
|
||||
return clusterId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Migration status (since Vault 1.4)
|
||||
* @since 1.1
|
||||
*/
|
||||
public Boolean getMigration() {
|
||||
return migration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Recovery seal status.
|
||||
* @since 1.1
|
||||
*/
|
||||
public Boolean getRecoverySeal() {
|
||||
return recoverySeal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Storage type (since Vault 1.3).
|
||||
* @since 1.1
|
||||
*/
|
||||
public String getStorageType() {
|
||||
return storageType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SealResponse that = (SealResponse) o;
|
||||
return sealed == that.sealed &&
|
||||
initialized == that.initialized &&
|
||||
Objects.equals(type, that.type) &&
|
||||
Objects.equals(threshold, that.threshold) &&
|
||||
Objects.equals(numberOfShares, that.numberOfShares) &&
|
||||
Objects.equals(progress, that.progress) &&
|
||||
Objects.equals(version, that.version) &&
|
||||
Objects.equals(buildDate, that.buildDate) &&
|
||||
Objects.equals(nonce, that.nonce) &&
|
||||
Objects.equals(clusterName, that.clusterName) &&
|
||||
Objects.equals(clusterId, that.clusterId) &&
|
||||
Objects.equals(migration, that.migration) &&
|
||||
Objects.equals(recoverySeal, that.recoverySeal) &&
|
||||
Objects.equals(storageType, that.storageType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(type, sealed, initialized, threshold, numberOfShares, progress, version, buildDate, nonce,
|
||||
clusterName, clusterId, migration, recoverySeal, storageType);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,28 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.SecretListWrapper;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault response for secret list request.
|
||||
@ -14,20 +31,35 @@ import java.util.Map;
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SecretListResponse extends VaultDataResponse {
|
||||
private List<String> keys;
|
||||
public final class SecretListResponse extends VaultDataResponse {
|
||||
|
||||
private static final long serialVersionUID = 8597121175002967213L;
|
||||
@JsonProperty("data")
|
||||
public void setData(Map<String, Object> data) throws InvalidResponseException {
|
||||
try {
|
||||
this.keys = (List<String>)data.get("keys");
|
||||
}
|
||||
catch (ClassCastException e) {
|
||||
throw new InvalidResponseException("Keys could not be parsed from data.", e);
|
||||
private SecretListWrapper data;
|
||||
|
||||
/**
|
||||
* @return List of secret keys
|
||||
*/
|
||||
public List<String> getKeys() {
|
||||
if (data == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Objects.requireNonNullElseGet(data.getKeys(), Collections::emptyList);
|
||||
}
|
||||
|
||||
public List<String> getKeys() {
|
||||
return keys;
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
SecretListResponse that = (SecretListResponse) o;
|
||||
return Objects.equals(data, that.data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), data);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,31 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -10,21 +33,72 @@ import java.util.Map;
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
* @since 1.1 abstract
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SecretResponse extends VaultDataResponse {
|
||||
private String value;
|
||||
public abstract class SecretResponse extends VaultDataResponse {
|
||||
private static final long serialVersionUID = 5198088815871692951L;
|
||||
|
||||
@Override
|
||||
public void setData(Map<String, Object> data) throws InvalidResponseException {
|
||||
/**
|
||||
* Get complete data object.
|
||||
*
|
||||
* @return data map
|
||||
* @since 0.4.0
|
||||
* @since 1.1 Serializable map value.
|
||||
*/
|
||||
public abstract Map<String, Serializable> getData();
|
||||
|
||||
/**
|
||||
* Get secret metadata. This is only available for KV v2 secrets.
|
||||
*
|
||||
* @return Metadata of the secret.
|
||||
* @since 0.8
|
||||
*/
|
||||
public abstract VersionMetadata getMetadata();
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
return getData().get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get response parsed as JSON.
|
||||
*
|
||||
* @param key the key
|
||||
* @param type Class to parse response
|
||||
* @param <C> Class to parse response
|
||||
* @return Parsed object or {@code null} if absent
|
||||
* @throws InvalidResponseException on parsing error
|
||||
* @since 0.4.0
|
||||
*/
|
||||
public final <C> C get(final String key, final Class<C> type) throws InvalidResponseException {
|
||||
try {
|
||||
this.value = (String) data.get("value");
|
||||
} catch (ClassCastException e) {
|
||||
throw new InvalidResponseException("Value could not be parsed", e);
|
||||
}
|
||||
}
|
||||
Object rawValue = get(key);
|
||||
if (rawValue == null) {
|
||||
return null;
|
||||
} else if (type.isInstance(rawValue)) {
|
||||
return type.cast(rawValue);
|
||||
} else {
|
||||
var om = JsonMapper.builder()
|
||||
.addModule(new JavaTimeModule())
|
||||
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
||||
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
|
||||
.build();
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
if (rawValue instanceof String) {
|
||||
return om.readValue((String) rawValue, type);
|
||||
} else {
|
||||
return om.readValue(om.writeValueAsString(rawValue), type);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new InvalidResponseException("Unable to parse response payload: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault response for a single secret version metadata, i.e. after update (KV v2).
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.8
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SecretVersionResponse extends VaultDataResponse {
|
||||
private static final long serialVersionUID = 2748635005258576174L;
|
||||
|
||||
@JsonProperty("data")
|
||||
private VersionMetadata metadata;
|
||||
|
||||
/**
|
||||
* Get the actual metadata.
|
||||
*
|
||||
* @return Metadata.
|
||||
*/
|
||||
public VersionMetadata getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
SecretVersionResponse that = (SecretVersionResponse) o;
|
||||
return Objects.equals(metadata, that.metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), metadata);
|
||||
}
|
||||
}
|
@ -1,14 +1,26 @@
|
||||
package de.stklcode.jvault.connector.model.response;
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault response from token lookup providing Token information in {@link TokenData} field.
|
||||
@ -17,24 +29,33 @@ import java.util.Map;
|
||||
* @since 0.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class TokenResponse extends VaultDataResponse {
|
||||
public final class TokenResponse extends VaultDataResponse {
|
||||
private static final long serialVersionUID = -4341114947980033457L;
|
||||
|
||||
@JsonProperty("data")
|
||||
private TokenData data;
|
||||
|
||||
@JsonProperty("auth")
|
||||
private Boolean auth;
|
||||
|
||||
@Override
|
||||
public void setData(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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token data
|
||||
*/
|
||||
public TokenData getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
TokenResponse that = (TokenResponse) o;
|
||||
return Objects.equals(data, that.data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), data);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
import de.stklcode.jvault.connector.model.TokenRole;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Vault response from token role lookup providing Token information in {@link TokenData} field.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.9
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class TokenRoleResponse extends VaultDataResponse {
|
||||
private static final long serialVersionUID = 5265363857731948626L;
|
||||
|
||||
@JsonProperty("data")
|
||||
private TokenRole data;
|
||||
|
||||
/**
|
||||
* @return TokenRole data
|
||||
*/
|
||||
public TokenRole getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
TokenRoleResponse that = (TokenRoleResponse) o;
|
||||
return Objects.equals(data, that.data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), data);
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.JsonSetter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Response entity for transit operations.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class TransitResponse extends VaultDataResponse {
|
||||
|
||||
private static final long serialVersionUID = 6873804240772242771L;
|
||||
|
||||
private String ciphertext;
|
||||
private String plaintext;
|
||||
private String sum;
|
||||
|
||||
@JsonSetter("data")
|
||||
private void setData(Map<String, String> data) {
|
||||
ciphertext = data.get("ciphertext");
|
||||
plaintext = data.get("plaintext");
|
||||
sum = data.get("sum");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ciphertext.
|
||||
* Populated after encryption.
|
||||
*
|
||||
* @return Ciphertext
|
||||
*/
|
||||
public String getCiphertext() {
|
||||
return ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plaintext.
|
||||
* Base64 encoded, populated after decryption.
|
||||
*
|
||||
* @return Plaintext
|
||||
*/
|
||||
public String getPlaintext() {
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hash sum.
|
||||
* Hex or Base64 string. Populated after hashing.
|
||||
*
|
||||
* @return Hash sum
|
||||
*/
|
||||
public String getSum() {
|
||||
return sum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
TransitResponse that = (TransitResponse) o;
|
||||
return Objects.equals(ciphertext, that.ciphertext) &&
|
||||
Objects.equals(plaintext, that.plaintext) &&
|
||||
Objects.equals(sum, that.sum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), ciphertext, plaintext, sum);
|
||||
}
|
||||
}
|
@ -1,10 +1,27 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.AuthData;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.WrapInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Abstract Vault response with default payload fields.
|
||||
@ -13,6 +30,11 @@ import java.util.Map;
|
||||
* @since 0.1
|
||||
*/
|
||||
public abstract class VaultDataResponse implements VaultResponse {
|
||||
private static final long serialVersionUID = 4787715235558510045L;
|
||||
|
||||
@JsonProperty("request_id")
|
||||
private String requestId;
|
||||
|
||||
@JsonProperty("lease_id")
|
||||
private String leaseId;
|
||||
|
||||
@ -25,22 +47,95 @@ public abstract class VaultDataResponse implements VaultResponse {
|
||||
@JsonProperty("warnings")
|
||||
private List<String> warnings;
|
||||
|
||||
@JsonProperty("data")
|
||||
public abstract void setData(Map<String, Object> data) throws InvalidResponseException;
|
||||
@JsonProperty("wrap_info")
|
||||
private WrapInfo wrapInfo;
|
||||
|
||||
public String getLeaseId() {
|
||||
@JsonProperty("auth")
|
||||
private AuthData auth;
|
||||
|
||||
@JsonProperty("mount_type")
|
||||
private String mountType;
|
||||
|
||||
/**
|
||||
* @return Request ID
|
||||
* @since 1.1
|
||||
*/
|
||||
public final String getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Wrapping information
|
||||
* @since 1.1
|
||||
*/
|
||||
public final WrapInfo getWrapInfo() {
|
||||
return wrapInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Authentication information for this response
|
||||
* @since 1.3
|
||||
*/
|
||||
public final AuthData getAuth() {
|
||||
return auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Information about the type of mount this secret is from (since Vault 1.17)
|
||||
* @since 1.3
|
||||
*/
|
||||
public final String getMountType() {
|
||||
return mountType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
VaultDataResponse that = (VaultDataResponse) o;
|
||||
return renewable == that.renewable &&
|
||||
Objects.equals(requestId, that.requestId) &&
|
||||
Objects.equals(leaseId, that.leaseId) &&
|
||||
Objects.equals(leaseDuration, that.leaseDuration) &&
|
||||
Objects.equals(warnings, that.warnings) &&
|
||||
Objects.equals(wrapInfo, that.wrapInfo) &&
|
||||
Objects.equals(auth, that.auth) &&
|
||||
Objects.equals(mountType, that.mountType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(requestId, leaseId, renewable, leaseDuration, warnings, wrapInfo, auth, mountType);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,29 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Marker interface for responses from Vault backend.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
* @since 1.1 extends {@link Serializable}
|
||||
*/
|
||||
public interface VaultResponse {
|
||||
public interface VaultResponse extends Serializable {
|
||||
}
|
||||
|
@ -1,19 +1,40 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Embedded authorization information inside Vault response.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
* @since 1.1 implements {@link Serializable}
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AuthData {
|
||||
public final class AuthData implements Serializable {
|
||||
private static final long serialVersionUID = 5969334512309655317L;
|
||||
|
||||
@JsonProperty("client_token")
|
||||
private String clientToken;
|
||||
|
||||
@ -23,6 +44,9 @@ public class AuthData {
|
||||
@JsonProperty("policies")
|
||||
private List<String> policies;
|
||||
|
||||
@JsonProperty("token_policies")
|
||||
private List<String> tokenPolicies;
|
||||
|
||||
@JsonProperty("metadata")
|
||||
private Map<String, Object> metadata;
|
||||
|
||||
@ -32,27 +56,137 @@ public class AuthData {
|
||||
@JsonProperty("renewable")
|
||||
private boolean renewable;
|
||||
|
||||
@JsonProperty("entity_id")
|
||||
private String entityId;
|
||||
|
||||
@JsonProperty("token_type")
|
||||
private String tokenType;
|
||||
|
||||
@JsonProperty("orphan")
|
||||
private boolean orphan;
|
||||
|
||||
@JsonProperty("num_uses")
|
||||
private Integer numUses;
|
||||
|
||||
@JsonProperty("mfa_requirement")
|
||||
private MfaRequirement mfaRequirement;
|
||||
|
||||
/**
|
||||
* @return Client token
|
||||
*/
|
||||
public String getClientToken() {
|
||||
return clientToken;
|
||||
}
|
||||
|
||||
public String getAccessor() {
|
||||
return accessor;
|
||||
/**
|
||||
* @return Token type
|
||||
* @since 0.9
|
||||
*/
|
||||
public String getTokenType() {
|
||||
return tokenType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of policies
|
||||
*/
|
||||
public List<String> getPolicies() {
|
||||
return policies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of policies associated with the token
|
||||
* @since 0.9
|
||||
*/
|
||||
public List<String> getTokenPolicies() {
|
||||
return tokenPolicies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Entity ID
|
||||
* @since 0.9
|
||||
*/
|
||||
public String getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token accessor
|
||||
*/
|
||||
public String getAccessor() {
|
||||
return accessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return allowed number of uses for the issued token
|
||||
* @since 1.3
|
||||
*/
|
||||
public Integer getNumUses() {
|
||||
return numUses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token is orphan
|
||||
* @since 0.9
|
||||
*/
|
||||
public boolean isOrphan() {
|
||||
return orphan;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return multi-factor requirement
|
||||
* @since 1.2
|
||||
*/
|
||||
public MfaRequirement getMfaRequirement() {
|
||||
return mfaRequirement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
AuthData authData = (AuthData) o;
|
||||
return renewable == authData.renewable &&
|
||||
orphan == authData.orphan &&
|
||||
Objects.equals(clientToken, authData.clientToken) &&
|
||||
Objects.equals(accessor, authData.accessor) &&
|
||||
Objects.equals(policies, authData.policies) &&
|
||||
Objects.equals(tokenPolicies, authData.tokenPolicies) &&
|
||||
Objects.equals(metadata, authData.metadata) &&
|
||||
Objects.equals(leaseDuration, authData.leaseDuration) &&
|
||||
Objects.equals(entityId, authData.entityId) &&
|
||||
Objects.equals(tokenType, authData.tokenType) &&
|
||||
Objects.equals(numUses, authData.numUses) &&
|
||||
Objects.equals(mfaRequirement, authData.mfaRequirement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(clientToken, accessor, policies, tokenPolicies, metadata, leaseDuration, renewable,
|
||||
entityId, tokenType, orphan, numUses, mfaRequirement);
|
||||
}
|
||||
}
|
@ -1,46 +1,225 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Embedded authentication method response.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
* @since 1.1 implements {@link Serializable}
|
||||
*/
|
||||
public class AuthMethod {
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class AuthMethod implements Serializable {
|
||||
private static final long serialVersionUID = -439987082190917691L;
|
||||
|
||||
private AuthBackend type;
|
||||
private String rawType;
|
||||
|
||||
@JsonProperty("accessor")
|
||||
private String accessor;
|
||||
|
||||
@JsonProperty("deprecation_status")
|
||||
private String deprecationStatus;
|
||||
|
||||
@JsonProperty("description")
|
||||
private String description;
|
||||
|
||||
@JsonProperty("config")
|
||||
private Map<String, String> config;
|
||||
private MountConfig config;
|
||||
|
||||
@JsonProperty("external_entropy_access")
|
||||
private boolean externalEntropyAccess;
|
||||
|
||||
@JsonProperty("local")
|
||||
private boolean local;
|
||||
|
||||
@JsonProperty("options")
|
||||
private Map<String, String> options;
|
||||
|
||||
@JsonProperty("plugin_version")
|
||||
private String pluginVersion;
|
||||
|
||||
@JsonProperty("running_plugin_version")
|
||||
private String runningPluginVersion;
|
||||
|
||||
@JsonProperty("running_sha256")
|
||||
private String runningSha256;
|
||||
|
||||
@JsonProperty("seal_wrap")
|
||||
private boolean sealWrap;
|
||||
|
||||
@JsonProperty("uuid")
|
||||
private String uuid;
|
||||
|
||||
/**
|
||||
* @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 Accessor
|
||||
* @since 1.1
|
||||
*/
|
||||
public String getAccessor() {
|
||||
return accessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Deprecation status
|
||||
* @since 1.2
|
||||
*/
|
||||
public String getDeprecationStatus() {
|
||||
return deprecationStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Description
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public Map<String, String> getConfig() {
|
||||
/**
|
||||
* @return Configuration data
|
||||
* @since 0.2
|
||||
* @since 1.2 Returns {@link MountConfig} instead of {@link Map}
|
||||
*/
|
||||
public MountConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Backend has access to external entropy source
|
||||
* @since 1.1
|
||||
*/
|
||||
public boolean isExternalEntropyAccess() {
|
||||
return externalEntropyAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Is local backend
|
||||
*/
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Options
|
||||
* @since 1.2
|
||||
*/
|
||||
public Map<String, String> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Plugin version
|
||||
* @since 1.2
|
||||
*/
|
||||
public String getPluginVersion() {
|
||||
return pluginVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Running plugin version
|
||||
* @since 1.2
|
||||
*/
|
||||
public String getRunningPluginVersion() {
|
||||
return runningPluginVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Running SHA256
|
||||
* @since 1.2
|
||||
*/
|
||||
public String getRunningSha256() {
|
||||
return runningSha256;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Seal wrapping enabled
|
||||
* @since 1.1
|
||||
*/
|
||||
public boolean isSealWrap() {
|
||||
return sealWrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Backend UUID
|
||||
* @since 1.1
|
||||
*/
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
AuthMethod that = (AuthMethod) o;
|
||||
return local == that.local &&
|
||||
type == that.type &&
|
||||
externalEntropyAccess == that.externalEntropyAccess &&
|
||||
sealWrap == that.sealWrap &&
|
||||
Objects.equals(rawType, that.rawType) &&
|
||||
Objects.equals(accessor, that.accessor) &&
|
||||
Objects.equals(deprecationStatus, that.deprecationStatus) &&
|
||||
Objects.equals(description, that.description) &&
|
||||
Objects.equals(config, that.config) &&
|
||||
Objects.equals(options, that.options) &&
|
||||
Objects.equals(pluginVersion, that.pluginVersion) &&
|
||||
Objects.equals(runningPluginVersion, that.runningPluginVersion) &&
|
||||
Objects.equals(runningSha256, that.runningSha256) &&
|
||||
Objects.equals(uuid, that.uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(type, rawType, accessor, deprecationStatus, description, config, externalEntropyAccess,
|
||||
local, options, pluginVersion, runningPluginVersion, runningSha256, sealWrap, uuid);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Embedded multi-factor-authentication (MFA) constraint "any".
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 1.2
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class MfaConstraintAny implements Serializable {
|
||||
private static final long serialVersionUID = 1226126781813149627L;
|
||||
|
||||
@JsonProperty("any")
|
||||
private List<MfaMethodId> any;
|
||||
|
||||
/**
|
||||
* @return List of "any" MFA methods
|
||||
*/
|
||||
public List<MfaMethodId> getAny() {
|
||||
return any;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
MfaConstraintAny mfaRequirement = (MfaConstraintAny) o;
|
||||
return Objects.equals(any, mfaRequirement.any);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(any);
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Embedded multi-factor-authentication (MFA) requirement.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 1.2
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class MfaMethodId implements Serializable {
|
||||
private static final long serialVersionUID = 691298070242998814L;
|
||||
|
||||
@JsonProperty("type")
|
||||
private String type;
|
||||
|
||||
@JsonProperty("id")
|
||||
private String id;
|
||||
|
||||
@JsonProperty("uses_passcode")
|
||||
private Boolean usesPasscode;
|
||||
|
||||
@JsonProperty("name")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* @return MFA method type
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MFA method id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MFA uses passcode id
|
||||
*/
|
||||
public Boolean getUsesPasscode() {
|
||||
return usesPasscode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MFA method name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
MfaMethodId mfaMethodId = (MfaMethodId) o;
|
||||
return Objects.equals(type, mfaMethodId.type) &&
|
||||
Objects.equals(id, mfaMethodId.id) &&
|
||||
Objects.equals(usesPasscode, mfaMethodId.usesPasscode) &&
|
||||
Objects.equals(name, mfaMethodId.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(type, id, usesPasscode, name);
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Embedded multi-factor-authentication (MFA) requirement.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 1.2
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class MfaRequirement implements Serializable {
|
||||
private static final long serialVersionUID = -2516941512455319638L;
|
||||
|
||||
@JsonProperty("mfa_request_id")
|
||||
private String mfaRequestId;
|
||||
|
||||
@JsonProperty("mfa_constraints")
|
||||
private Map<String, MfaConstraintAny> mfaConstraints;
|
||||
|
||||
/**
|
||||
* @return MFA request ID
|
||||
*/
|
||||
public String getMfaRequestId() {
|
||||
return mfaRequestId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MFA constraints
|
||||
*/
|
||||
public Map<String, MfaConstraintAny> getMfaConstraints() {
|
||||
return mfaConstraints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
MfaRequirement mfaRequirement = (MfaRequirement) o;
|
||||
return Objects.equals(mfaRequestId, mfaRequirement.mfaRequestId) &&
|
||||
Objects.equals(mfaConstraints, mfaRequirement.mfaConstraints);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mfaRequestId, mfaConstraints);
|
||||
}
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
package de.stklcode.jvault.connector.model.response.embedded;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Embedded mount config output.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 1.2
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class MountConfig implements Serializable {
|
||||
private static final long serialVersionUID = -8653909672663717792L;
|
||||
|
||||
@JsonProperty("default_lease_ttl")
|
||||
private Integer defaultLeaseTtl;
|
||||
|
||||
@JsonProperty("max_lease_ttl")
|
||||
private Integer maxLeaseTtl;
|
||||
|
||||
@JsonProperty("force_no_cache")
|
||||
private Boolean forceNoCache;
|
||||
|
||||
@JsonProperty("token_type")
|
||||
private String tokenType;
|
||||
|
||||
@JsonProperty("audit_non_hmac_request_keys")
|
||||
private List<String> auditNonHmacRequestKeys;
|
||||
|
||||
@JsonProperty("audit_non_hmac_response_keys")
|
||||
private List<String> auditNonHmacResponseKeys;
|
||||
|
||||
@JsonProperty("listing_visibility")
|
||||
private String listingVisibility;
|
||||
|
||||
@JsonProperty("passthrough_request_headers")
|
||||
private List<String> passthroughRequestHeaders;
|
||||
|
||||
@JsonProperty("allowed_response_headers")
|
||||
private List<String> allowedResponseHeaders;
|
||||
|
||||
@JsonProperty("allowed_managed_keys")
|
||||
private List<String> allowedManagedKeys;
|
||||
|
||||
@JsonProperty("delegated_auth_accessors")
|
||||
private List<String> delegatedAuthAccessors;
|
||||
|
||||
@JsonProperty("user_lockout_config")
|
||||
private UserLockoutConfig userLockoutConfig;
|
||||
|
||||
/**
|
||||
* @return Default lease TTL
|
||||
*/
|
||||
public Integer getDefaultLeaseTtl() {
|
||||
return defaultLeaseTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Maximum lease TTL
|
||||
*/
|
||||
public Integer getMaxLeaseTtl() {
|
||||
return maxLeaseTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Force no cache?
|
||||
*/
|
||||
public Boolean getForceNoCache() {
|
||||
return forceNoCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token type
|
||||
*/
|
||||
public String getTokenType() {
|
||||
return tokenType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Audit non HMAC request keys
|
||||
*/
|
||||
public List<String> getAuditNonHmacRequestKeys() {
|
||||
return auditNonHmacRequestKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Audit non HMAC response keys
|
||||
*/
|
||||
public List<String> getAuditNonHmacResponseKeys() {
|
||||
return auditNonHmacResponseKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Listing visibility
|
||||
*/
|
||||
public String getListingVisibility() {
|
||||
return listingVisibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Passthrough request headers
|
||||
*/
|
||||
public List<String> getPassthroughRequestHeaders() {
|
||||
return passthroughRequestHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Allowed response headers
|
||||
*/
|
||||
public List<String> getAllowedResponseHeaders() {
|
||||
return allowedResponseHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Allowed managed keys
|
||||
*/
|
||||
public List<String> getAllowedManagedKeys() {
|
||||
return allowedManagedKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Delegated auth accessors
|
||||
*/
|
||||
public List<String> getDelegatedAuthAccessors() {
|
||||
return delegatedAuthAccessors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User lockout config
|
||||
*/
|
||||
public UserLockoutConfig getUserLockoutConfig() {
|
||||
return userLockoutConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
MountConfig that = (MountConfig) o;
|
||||
return Objects.equals(defaultLeaseTtl, that.defaultLeaseTtl) &&
|
||||
Objects.equals(maxLeaseTtl, that.maxLeaseTtl) &&
|
||||
Objects.equals(forceNoCache, that.forceNoCache) &&
|
||||
Objects.equals(tokenType, that.tokenType) &&
|
||||
Objects.equals(auditNonHmacRequestKeys, that.auditNonHmacRequestKeys) &&
|
||||
Objects.equals(auditNonHmacResponseKeys, that.auditNonHmacResponseKeys) &&
|
||||
Objects.equals(listingVisibility, that.listingVisibility) &&
|
||||
Objects.equals(passthroughRequestHeaders, that.passthroughRequestHeaders) &&
|
||||
Objects.equals(allowedResponseHeaders, that.allowedResponseHeaders) &&
|
||||
Objects.equals(allowedManagedKeys, that.allowedManagedKeys) &&
|
||||
Objects.equals(delegatedAuthAccessors, that.delegatedAuthAccessors) &&
|
||||
Objects.equals(userLockoutConfig, that.userLockoutConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(defaultLeaseTtl, maxLeaseTtl, forceNoCache, tokenType, auditNonHmacRequestKeys,
|
||||
auditNonHmacResponseKeys, listingVisibility, passthroughRequestHeaders, allowedResponseHeaders,
|
||||
allowedManagedKeys, delegatedAuthAccessors, userLockoutConfig);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package de.stklcode.jvault.connector.model.response.embedded;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Wrapper object for secret key lists.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 1.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SecretListWrapper implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8777605197063766125L;
|
||||
@JsonProperty("keys")
|
||||
private List<String> keys;
|
||||
|
||||
public List<String> getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SecretListWrapper that = (SecretListWrapper) o;
|
||||
return Objects.equals(keys, that.keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(keys);
|
||||
}
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 java.io.Serializable;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Embedded metadata for Key-Value v2 secrets.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.8
|
||||
* @since 1.1 implements {@link Serializable}
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class SecretMetadata implements Serializable {
|
||||
private static final long serialVersionUID = -905059942871916214L;
|
||||
|
||||
@JsonProperty("created_time")
|
||||
private ZonedDateTime createdTime;
|
||||
|
||||
@JsonProperty("current_version")
|
||||
private Integer currentVersion;
|
||||
|
||||
@JsonProperty("max_versions")
|
||||
private Integer maxVersions;
|
||||
|
||||
@JsonProperty("oldest_version")
|
||||
private Integer oldestVersion;
|
||||
|
||||
@JsonProperty("updated_time")
|
||||
private ZonedDateTime updatedTime;
|
||||
|
||||
@JsonProperty("versions")
|
||||
private Map<Integer, VersionMetadata> versions;
|
||||
|
||||
@JsonProperty("cas_required")
|
||||
private Boolean casRequired;
|
||||
|
||||
@JsonProperty("custom_metadata")
|
||||
private HashMap<String, String> customMetadata;
|
||||
|
||||
@JsonProperty("delete_version_after")
|
||||
private String deleteVersionAfter;
|
||||
|
||||
/**
|
||||
* @return Time of secret creation.
|
||||
*/
|
||||
public ZonedDateTime getCreatedTime() {
|
||||
return createdTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current version number.
|
||||
*/
|
||||
public Integer getCurrentVersion() {
|
||||
return currentVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Maximum number of versions.
|
||||
*/
|
||||
public Integer getMaxVersions() {
|
||||
return maxVersions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Oldest available version number.
|
||||
*/
|
||||
public Integer getOldestVersion() {
|
||||
return oldestVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Time of secret update.
|
||||
*/
|
||||
public ZonedDateTime getUpdatedTime() {
|
||||
return updatedTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Version of the entry.
|
||||
*/
|
||||
public Map<Integer, VersionMetadata> getVersions() {
|
||||
return versions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CAS required?
|
||||
* @since 1.3
|
||||
*/
|
||||
public Boolean isCasRequired() {
|
||||
return casRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Custom metadata.
|
||||
* @since 1.3
|
||||
*/
|
||||
public Map<String, String> getCustomMetadata() {
|
||||
return customMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return time duration to delete version
|
||||
* @since 1.3
|
||||
*/
|
||||
public String getDeleteVersionAfter() {
|
||||
return deleteVersionAfter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SecretMetadata that = (SecretMetadata) o;
|
||||
return Objects.equals(createdTime, that.createdTime) &&
|
||||
Objects.equals(currentVersion, that.currentVersion) &&
|
||||
Objects.equals(maxVersions, that.maxVersions) &&
|
||||
Objects.equals(oldestVersion, that.oldestVersion) &&
|
||||
Objects.equals(updatedTime, that.updatedTime) &&
|
||||
Objects.equals(versions, that.versions) &&
|
||||
Objects.equals(casRequired, that.casRequired) &&
|
||||
Objects.equals(customMetadata, that.customMetadata) &&
|
||||
Objects.equals(deleteVersionAfter, that.deleteVersionAfter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(createdTime, currentVersion, maxVersions, oldestVersion, updatedTime, versions, casRequired,
|
||||
customMetadata, deleteVersionAfter);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package de.stklcode.jvault.connector.model.response.embedded;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Wrapper object for secret data and metadata.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 1.1
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SecretWrapper implements Serializable {
|
||||
private static final long serialVersionUID = 8600413181758893378L;
|
||||
|
||||
@JsonProperty("data")
|
||||
private Map<String, Serializable> data;
|
||||
|
||||
@JsonProperty("metadata")
|
||||
private VersionMetadata metadata;
|
||||
|
||||
public Map<String, Serializable> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public VersionMetadata getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SecretWrapper that = (SecretWrapper) o;
|
||||
return Objects.equals(data, that.data) && Objects.equals(metadata, that.metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(data, metadata);
|
||||
}
|
||||
}
|
@ -1,16 +1,41 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 java.io.Serializable;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Embedded token information inside Vault response.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.1
|
||||
* @since 1.1 implements {@link Serializable}
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class TokenData {
|
||||
public final class TokenData implements Serializable {
|
||||
private static final long serialVersionUID = -5749716740973138916L;
|
||||
|
||||
@JsonProperty("accessor")
|
||||
private String accessor;
|
||||
|
||||
@ -18,16 +43,28 @@ public class TokenData {
|
||||
private Integer creationTime;
|
||||
|
||||
@JsonProperty("creation_ttl")
|
||||
private Integer creatinTtl;
|
||||
private Integer creationTtl;
|
||||
|
||||
@JsonProperty("display_name")
|
||||
private String name;
|
||||
|
||||
@JsonProperty("entity_id")
|
||||
private String entityId;
|
||||
|
||||
@JsonProperty("expire_time")
|
||||
private ZonedDateTime expireTime;
|
||||
|
||||
@JsonProperty("explicit_max_ttl")
|
||||
private Integer explicitMaxTtl;
|
||||
|
||||
@JsonProperty("id")
|
||||
private String id;
|
||||
|
||||
@JsonProperty("issue_time")
|
||||
private ZonedDateTime issueTime;
|
||||
|
||||
@JsonProperty("meta")
|
||||
private String meta;
|
||||
private Map<String, Object> meta;
|
||||
|
||||
@JsonProperty("num_uses")
|
||||
private Integer numUses;
|
||||
@ -38,53 +75,174 @@ public class TokenData {
|
||||
@JsonProperty("path")
|
||||
private String path;
|
||||
|
||||
@JsonProperty("role")
|
||||
private String role;
|
||||
@JsonProperty("policies")
|
||||
private List<String> policies;
|
||||
|
||||
@JsonProperty("renewable")
|
||||
private boolean renewable;
|
||||
|
||||
@JsonProperty("ttl")
|
||||
private Integer ttl;
|
||||
|
||||
@JsonProperty("type")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* @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 Entity ID
|
||||
* @since 0.9
|
||||
*/
|
||||
public String getEntityId() {
|
||||
return entityId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Expire time (parsed)
|
||||
* @since 0.9
|
||||
*/
|
||||
public ZonedDateTime getExpireTime() {
|
||||
return expireTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Explicit maximum TTL
|
||||
* @since 0.9
|
||||
*/
|
||||
public Integer getExplicitMaxTtl() {
|
||||
return explicitMaxTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token ID
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Expire time (parsed)
|
||||
* @since 0.9
|
||||
*/
|
||||
public ZonedDateTime getIssueTime() {
|
||||
return issueTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token type
|
||||
* @since 0.9
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
public String getRole() {
|
||||
return role;
|
||||
/**
|
||||
* @return Token policies
|
||||
* @since 0.9
|
||||
*/
|
||||
public List<String> getPolicies() {
|
||||
return policies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token is renewable
|
||||
* @since 0.9
|
||||
*/
|
||||
public boolean isRenewable() {
|
||||
return renewable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Token TTL (in seconds)
|
||||
*/
|
||||
public Integer getTtl() {
|
||||
return ttl;
|
||||
}
|
||||
|
||||
public String getMeta() {
|
||||
/**
|
||||
* @return Metadata
|
||||
*/
|
||||
public Map<String, Object> getMeta() {
|
||||
return meta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TokenData tokenData = (TokenData) o;
|
||||
return orphan == tokenData.orphan &&
|
||||
renewable == tokenData.renewable &&
|
||||
Objects.equals(accessor, tokenData.accessor) &&
|
||||
Objects.equals(creationTime, tokenData.creationTime) &&
|
||||
Objects.equals(creationTtl, tokenData.creationTtl) &&
|
||||
Objects.equals(name, tokenData.name) &&
|
||||
Objects.equals(entityId, tokenData.entityId) &&
|
||||
Objects.equals(expireTime, tokenData.expireTime) &&
|
||||
Objects.equals(explicitMaxTtl, tokenData.explicitMaxTtl) &&
|
||||
Objects.equals(id, tokenData.id) &&
|
||||
Objects.equals(issueTime, tokenData.issueTime) &&
|
||||
Objects.equals(meta, tokenData.meta) &&
|
||||
Objects.equals(numUses, tokenData.numUses) &&
|
||||
Objects.equals(path, tokenData.path) &&
|
||||
Objects.equals(policies, tokenData.policies) &&
|
||||
Objects.equals(ttl, tokenData.ttl) &&
|
||||
Objects.equals(type, tokenData.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(accessor, creationTime, creationTtl, name, entityId, expireTime, explicitMaxTtl, id,
|
||||
issueTime, meta, numUses, orphan, path, policies, renewable, ttl, type);
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package de.stklcode.jvault.connector.model.response.embedded;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Embedded user lockout config output.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 1.2
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class UserLockoutConfig implements Serializable {
|
||||
private static final long serialVersionUID = -8051060041593140550L;
|
||||
|
||||
@JsonProperty("lockout_threshold")
|
||||
private Integer lockoutThreshold;
|
||||
|
||||
@JsonProperty("lockout_duration")
|
||||
private Integer lockoutDuration;
|
||||
|
||||
@JsonProperty("lockout_counter_reset_duration")
|
||||
private Integer lockoutCounterResetDuration;
|
||||
|
||||
@JsonProperty("lockout_disable")
|
||||
private Boolean lockoutDisable;
|
||||
|
||||
/**
|
||||
* @return Lockout threshold
|
||||
*/
|
||||
public Integer getLockoutThreshold() {
|
||||
return lockoutThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Lockout duration
|
||||
*/
|
||||
public Integer getLockoutDuration() {
|
||||
return lockoutDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Lockout counter reset duration
|
||||
*/
|
||||
public Integer getLockoutCounterResetDuration() {
|
||||
return lockoutCounterResetDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Lockout disabled?
|
||||
*/
|
||||
public Boolean getLockoutDisable() {
|
||||
return lockoutDisable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
UserLockoutConfig that = (UserLockoutConfig) o;
|
||||
return Objects.equals(lockoutThreshold, that.lockoutThreshold) &&
|
||||
Objects.equals(lockoutDuration, that.lockoutDuration) &&
|
||||
Objects.equals(lockoutCounterResetDuration, that.lockoutCounterResetDuration) &&
|
||||
Objects.equals(lockoutDisable, that.lockoutDisable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(lockoutThreshold, lockoutDuration, lockoutCounterResetDuration, lockoutDisable);
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 java.io.Serializable;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Embedded metadata for a single Key-Value v2 version.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.8
|
||||
* @since 1.1 implements {@link Serializable}
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class VersionMetadata implements Serializable {
|
||||
private static final long serialVersionUID = 8495687554714216478L;
|
||||
|
||||
@JsonProperty("created_time")
|
||||
private ZonedDateTime createdTime;
|
||||
|
||||
@JsonProperty("deletion_time")
|
||||
private ZonedDateTime deletionTime;
|
||||
|
||||
@JsonProperty("destroyed")
|
||||
private boolean destroyed;
|
||||
|
||||
@JsonProperty("version")
|
||||
private Integer version;
|
||||
|
||||
@JsonProperty("custom_metadata")
|
||||
private HashMap<String, String> customMetadata;
|
||||
|
||||
/**
|
||||
* @return Time of secret creation.
|
||||
*/
|
||||
public ZonedDateTime getCreatedTime() {
|
||||
return createdTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Time for secret deletion.
|
||||
*/
|
||||
public ZonedDateTime getDeletionTime() {
|
||||
return deletionTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the secret is destroyed.
|
||||
*/
|
||||
public boolean isDestroyed() {
|
||||
return destroyed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Version of the entry.
|
||||
*/
|
||||
public Integer getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Custom metadata.
|
||||
* @since 1.3
|
||||
*/
|
||||
public Map<String, String> getCustomMetadata() {
|
||||
return customMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
VersionMetadata that = (VersionMetadata) o;
|
||||
return destroyed == that.destroyed &&
|
||||
Objects.equals(createdTime, that.createdTime) &&
|
||||
Objects.equals(deletionTime, that.deletionTime) &&
|
||||
Objects.equals(version, that.version) &&
|
||||
Objects.equals(customMetadata, that.customMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(createdTime, deletionTime, destroyed, version, customMetadata);
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.JsonProperty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Wrapping information object.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 1.1
|
||||
*/
|
||||
public class WrapInfo implements Serializable {
|
||||
private static final long serialVersionUID = 4864973237090355607L;
|
||||
|
||||
@JsonProperty("token")
|
||||
private String token;
|
||||
|
||||
@JsonProperty("ttl")
|
||||
private Integer ttl;
|
||||
|
||||
@JsonProperty("creation_time")
|
||||
private ZonedDateTime creationTime;
|
||||
|
||||
@JsonProperty("creation_path")
|
||||
private String creationPath;
|
||||
|
||||
/**
|
||||
* @return Token
|
||||
*/
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TTL (in seconds)
|
||||
*/
|
||||
public Integer getTtl() {
|
||||
return ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Creation time
|
||||
*/
|
||||
public ZonedDateTime getCreationTime() {
|
||||
return creationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Creation path
|
||||
*/
|
||||
public String getCreationPath() {
|
||||
return creationPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
WrapInfo that = (WrapInfo) o;
|
||||
return Objects.equals(token, that.token) &&
|
||||
Objects.equals(ttl, that.ttl) &&
|
||||
Objects.equals(creationTime, that.creationTime) &&
|
||||
Objects.equals(creationPath, that.creationPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(token, ttl, creationTime, creationPath);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Embedded data classes for responses from the Vault API.
|
||||
*/
|
||||
package de.stklcode.jvault.connector.model.response.embedded;
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Model classes for responses from the Vault API.
|
||||
*/
|
||||
package de.stklcode.jvault.connector.model.response;
|
21
src/main/java/de/stklcode/jvault/connector/package-info.java
Normal file
21
src/main/java/de/stklcode/jvault/connector/package-info.java
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Java Vault Connector base package - contains {@link de.stklcode.jvault.connector.VaultConnector} interface and
|
||||
* default implementation.
|
||||
*/
|
||||
package de.stklcode.jvault.connector;
|
37
src/main/java/module-info.java
Normal file
37
src/main/java/module-info.java
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JVaultConnector module.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
*/
|
||||
module de.stklcode.jvault.connector {
|
||||
exports de.stklcode.jvault.connector;
|
||||
exports de.stklcode.jvault.connector.exception;
|
||||
exports de.stklcode.jvault.connector.model;
|
||||
exports de.stklcode.jvault.connector.model.response;
|
||||
exports de.stklcode.jvault.connector.model.response.embedded;
|
||||
|
||||
opens de.stklcode.jvault.connector.model to com.fasterxml.jackson.databind;
|
||||
opens de.stklcode.jvault.connector.model.response to com.fasterxml.jackson.databind;
|
||||
opens de.stklcode.jvault.connector.model.response.embedded to com.fasterxml.jackson.databind;
|
||||
|
||||
requires java.net.http;
|
||||
requires com.fasterxml.jackson.annotation;
|
||||
requires com.fasterxml.jackson.databind;
|
||||
requires com.fasterxml.jackson.datatype.jsr310;
|
||||
}
|
13
src/main/javadoc/overview.html
Normal file
13
src/main/javadoc/overview.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>API Overview</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Java Vault Connector is a connector library for Vault by Hashicorp written in Java.</p>
|
||||
<p>The connector allows simple usage of Vault's secret store in own applications.</p>
|
||||
<p>It features a default implementation for the HTTP(S) interface and supports various authorization methods including
|
||||
AppRole, token and secret handling.</p>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 com.github.stefanbirkner.systemlambda.SystemLambda;
|
||||
import de.stklcode.jvault.connector.exception.ConnectionException;
|
||||
import de.stklcode.jvault.connector.exception.TlsException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit test for HTTP Vault connector factory
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.8.0
|
||||
*/
|
||||
class HTTPVaultConnectorBuilderTest {
|
||||
private static final String VAULT_ADDR = "https://localhost:8201";
|
||||
private static final String VAULT_ADDR_2 = "http://localhost";
|
||||
private static final String VAULT_ADDR_3 = "https://localhost/vault/";
|
||||
private static final Integer VAULT_MAX_RETRIES = 13;
|
||||
private static final String VAULT_TOKEN = "00001111-2222-3333-4444-555566667777";
|
||||
|
||||
@TempDir
|
||||
File tempDir;
|
||||
|
||||
/**
|
||||
* Test the builder.
|
||||
*/
|
||||
@Test
|
||||
void builderTest() throws Exception {
|
||||
// Minimal configuration.
|
||||
HTTPVaultConnector connector = HTTPVaultConnector.builder().withHost("vault.example.com").build();
|
||||
|
||||
assertEquals("https://vault.example.com:8200/v1/", getRequestHelperPrivate(connector, "baseURL"), "URL not set correctly");
|
||||
assertNull(getRequestHelperPrivate(connector, "trustedCaCert"), "Trusted CA cert set when no cert provided");
|
||||
assertEquals(0, getRequestHelperPrivate(connector, "retries"), "Number of retries unexpectedly set");
|
||||
|
||||
// Specify all options.
|
||||
HTTPVaultConnectorBuilder builder = HTTPVaultConnector.builder()
|
||||
.withHost("vault2.example.com")
|
||||
.withoutTLS()
|
||||
.withPort(1234)
|
||||
.withPrefix("/foo/")
|
||||
.withTimeout(5678)
|
||||
.withNumberOfRetries(9);
|
||||
connector = builder.build();
|
||||
|
||||
assertEquals("http://vault2.example.com:1234/foo/", getRequestHelperPrivate(connector, "baseURL"), "URL not set correctly");
|
||||
assertNull(getRequestHelperPrivate(connector, "trustedCaCert"), "Trusted CA cert set when no cert provided");
|
||||
assertEquals(9, getRequestHelperPrivate(connector, "retries"), "Unexpected number of retries");
|
||||
assertEquals(5678, getRequestHelperPrivate(connector, "timeout"), "Number timeout value");
|
||||
assertThrows(ConnectionException.class, builder::buildAndAuth, "Immediate authentication should throw exception without token");
|
||||
|
||||
// Initialization from URL.
|
||||
assertThrows(
|
||||
URISyntaxException.class,
|
||||
() -> HTTPVaultConnector.builder().withBaseURL("foo:/\\1nv4l1d_UrL"),
|
||||
"Initialization from invalid URL should fail"
|
||||
);
|
||||
connector = assertDoesNotThrow(
|
||||
() -> HTTPVaultConnector.builder().withBaseURL("https://vault3.example.com:5678/bar/").build(),
|
||||
"Initialization from valid URL should not fail"
|
||||
);
|
||||
assertEquals("https://vault3.example.com:5678/bar/", getRequestHelperPrivate(connector, "baseURL"), "URL not set correctly");
|
||||
|
||||
// Port numbers.
|
||||
assertThrows(IllegalArgumentException.class, () -> HTTPVaultConnector.builder().withPort(65536), "Too large port number should throw an exception");
|
||||
assertThrows(IllegalArgumentException.class, () -> HTTPVaultConnector.builder().withPort(0), "Port number 0 should throw an exception");
|
||||
builder = assertDoesNotThrow(() -> HTTPVaultConnector.builder().withPort(-1), "Port number -1 should not throw an exception");
|
||||
assertNull(builder.getPort(), "Port number -1 should be omitted");
|
||||
builder = assertDoesNotThrow(() -> HTTPVaultConnector.builder().withPort(null), "Port number NULL should not throw an exception");
|
||||
assertNull(builder.getPort(), "Port number NULL should be passed through");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test building from environment variables
|
||||
*/
|
||||
@Test
|
||||
void testFromEnv() throws Exception {
|
||||
// Provide address only should be enough.
|
||||
withVaultEnv(VAULT_ADDR, null, null, null).execute(() -> {
|
||||
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
|
||||
() -> HTTPVaultConnector.builder().fromEnv(),
|
||||
"Factory creation from minimal environment failed"
|
||||
);
|
||||
HTTPVaultConnector connector = builder.build();
|
||||
|
||||
assertEquals(VAULT_ADDR + "/v1/", getRequestHelperPrivate(connector, "baseURL"), "URL not set correctly");
|
||||
assertNull(getRequestHelperPrivate(connector, "trustedCaCert"), "Trusted CA cert set when no cert provided");
|
||||
assertEquals(0, getRequestHelperPrivate(connector, "retries"), "Non-default number of retries, when none set");
|
||||
|
||||
return null;
|
||||
});
|
||||
withVaultEnv(VAULT_ADDR_2, null, null, null).execute(() -> {
|
||||
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
|
||||
() -> HTTPVaultConnector.builder().fromEnv(),
|
||||
"Factory creation from minimal environment failed"
|
||||
);
|
||||
assertEquals(VAULT_ADDR_2 + "/v1/", getRequestHelperPrivate(builder.build(), "baseURL"), "URL without port not set correctly");
|
||||
return null;
|
||||
});
|
||||
withVaultEnv(VAULT_ADDR_3, null, null, null).execute(() -> {
|
||||
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
|
||||
() -> HTTPVaultConnector.builder().fromEnv(),
|
||||
"Factory creation from minimal environment failed"
|
||||
);
|
||||
assertEquals(VAULT_ADDR_3, getRequestHelperPrivate(builder.build(), "baseURL"), "URL with custom path not set correctly");
|
||||
return null;
|
||||
});
|
||||
|
||||
// Provide address and number of retries.
|
||||
withVaultEnv(VAULT_ADDR, null, VAULT_MAX_RETRIES.toString(), null).execute(() -> {
|
||||
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
|
||||
() -> HTTPVaultConnector.builder().fromEnv(),
|
||||
"Factory creation from environment failed"
|
||||
);
|
||||
HTTPVaultConnector connector = builder.build();
|
||||
|
||||
assertEquals(VAULT_ADDR + "/v1/", getRequestHelperPrivate(connector, "baseURL"), "URL not set correctly");
|
||||
assertNull(getRequestHelperPrivate(connector, "trustedCaCert"), "Trusted CA cert set when no cert provided");
|
||||
assertEquals(VAULT_MAX_RETRIES, getRequestHelperPrivate(connector, "retries"), "Number of retries not set correctly");
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
// Automatic authentication.
|
||||
withVaultEnv(VAULT_ADDR, null, VAULT_MAX_RETRIES.toString(), VAULT_TOKEN).execute(() -> {
|
||||
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
|
||||
() -> HTTPVaultConnector.builder().fromEnv(),
|
||||
"Factory creation from minimal environment failed"
|
||||
);
|
||||
assertEquals(VAULT_TOKEN, getPrivate(builder, "token"), "Token not set correctly");
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
// Invalid URL.
|
||||
withVaultEnv("This is not a valid URL!", null, VAULT_MAX_RETRIES.toString(), VAULT_TOKEN).execute(() -> {
|
||||
assertThrows(
|
||||
ConnectionException.class,
|
||||
() -> HTTPVaultConnector.builder().fromEnv(),
|
||||
"Invalid URL from environment should raise an exception"
|
||||
);
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test CA certificate handling from environment variables
|
||||
*/
|
||||
@Test
|
||||
void testCertificateFromEnv() throws Exception {
|
||||
// From direct PEM content
|
||||
String pem = Files.readString(Paths.get(getClass().getResource("/tls/ca.pem").toURI()));
|
||||
AtomicReference<Object> certFromPem = new AtomicReference<>();
|
||||
withVaultEnv(VAULT_ADDR, pem, null, null).execute(() -> {
|
||||
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
|
||||
() -> HTTPVaultConnector.builder().fromEnv(),
|
||||
"Builder with PEM certificate from environment failed"
|
||||
);
|
||||
HTTPVaultConnector connector = builder.build();
|
||||
|
||||
certFromPem.set(getRequestHelperPrivate(connector, "trustedCaCert"));
|
||||
assertNotNull(certFromPem.get(), "Trusted CA cert from PEM not set");
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
// From file path
|
||||
String file = Paths.get(getClass().getResource("/tls/ca.pem").toURI()).toString();
|
||||
AtomicReference<Object> certFromFile = new AtomicReference<>();
|
||||
withVaultEnv(VAULT_ADDR, file, null, null).execute(() -> {
|
||||
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
|
||||
() -> HTTPVaultConnector.builder().fromEnv(),
|
||||
"Builder with certificate path from environment failed"
|
||||
);
|
||||
HTTPVaultConnector connector = builder.build();
|
||||
|
||||
certFromFile.set(getRequestHelperPrivate(connector, "trustedCaCert"));
|
||||
assertNotNull(certFromFile.get(), "Trusted CA cert from file not set");
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
assertEquals(certFromPem.get(), certFromFile.get(), "Certificates from PEM and file should be equal");
|
||||
|
||||
// Non-existing path CA certificate path
|
||||
String doesNotExist = tempDir.toString() + "/doesnotexist";
|
||||
withVaultEnv(VAULT_ADDR, doesNotExist, VAULT_MAX_RETRIES.toString(), null).execute(() -> {
|
||||
TlsException e = assertThrows(
|
||||
TlsException.class,
|
||||
() -> HTTPVaultConnector.builder().fromEnv(),
|
||||
"Creation with unknown cert path failed"
|
||||
);
|
||||
assertEquals(doesNotExist, assertInstanceOf(NoSuchFileException.class, e.getCause()).getFile());
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private SystemLambda.WithEnvironmentVariables withVaultEnv(String vaultAddr, String vaultCacert, String vaultMaxRetries, String vaultToken) {
|
||||
return withEnvironmentVariable("VAULT_ADDR", vaultAddr)
|
||||
.and("VAULT_CACERT", vaultCacert)
|
||||
.and("VAULT_MAX_RETRIES", vaultMaxRetries)
|
||||
.and("VAULT_TOKEN", vaultToken);
|
||||
}
|
||||
|
||||
private Object getRequestHelperPrivate(HTTPVaultConnector connector, String fieldName) throws NoSuchFieldException, IllegalAccessException {
|
||||
return getPrivate(getPrivate(connector, "request"), fieldName);
|
||||
}
|
||||
|
||||
private Object getPrivate(Object target, String fieldName) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = target.getClass().getDeclaredField(fieldName);
|
||||
if (field.canAccess(target)) {
|
||||
return field.get(target);
|
||||
}
|
||||
field.setAccessible(true);
|
||||
Object value = field.get(target);
|
||||
field.setAccessible(false);
|
||||
return value;
|
||||
}
|
||||
}
|
1302
src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorIT.java
Normal file
1302
src/test/java/de/stklcode/jvault/connector/HTTPVaultConnectorIT.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,377 +1,314 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.test.VaultConfiguration;
|
||||
import de.stklcode.jvault.connector.exception.InvalidRequestException;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
|
||||
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
|
||||
import de.stklcode.jvault.connector.exception.ConnectionException;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import de.stklcode.jvault.connector.exception.PermissionDeniedException;
|
||||
import de.stklcode.jvault.connector.exception.VaultConnectorException;
|
||||
import de.stklcode.jvault.connector.factory.VaultConnectorFactory;
|
||||
import de.stklcode.jvault.connector.model.AuthBackend;
|
||||
import de.stklcode.jvault.connector.model.response.AuthResponse;
|
||||
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 org.junit.*;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.function.Executable;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.List;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.hamcrest.CoreMatchers.hasItems;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
import static org.junit.Assume.assumeNotNull;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for HTTP Vault connector.
|
||||
* 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.1
|
||||
* @since 0.7.0
|
||||
*/
|
||||
public class HTTPVaultConnectorTest {
|
||||
private static String KEY = "81011a8061e5c028bd0d9503eeba40bd9054b9af0408d080cb24f57405c27a61";
|
||||
private static String TOKEN_ROOT = "d1bd50e2-587b-6e68-d80b-a9a507625cb7";
|
||||
private static String USER_VALID = "validUser";
|
||||
private static String PASS_VALID = "validPass";
|
||||
private static String APP_ID = "152AEA38-85FB-47A8-9CBD-612D645BFACA";
|
||||
private static String USER_ID = "5ADF8218-D7FB-4089-9E38-287465DBF37E";
|
||||
private static String SECRET_PATH = "userstore";
|
||||
private static String SECRET_KEY = "foo";
|
||||
private static String SECRET_VALUE = "bar";
|
||||
|
||||
private Process vaultProcess;
|
||||
private VaultConnector connector;
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder tmpDir = new TemporaryFolder();
|
||||
@WireMockTest
|
||||
class HTTPVaultConnectorTest {
|
||||
|
||||
/**
|
||||
* Initialize Vault instance with generated configuration and provided file backend.
|
||||
* Requires "vault" binary to be in current user's executable path. Not using MLock, so no extended rights required.
|
||||
*/
|
||||
@Before
|
||||
public void setUp() {
|
||||
/* Initialize Vault */
|
||||
VaultConfiguration config = initializeVault();
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
/* Initialize connector */
|
||||
connector = VaultConnectorFactory.httpFactory()
|
||||
.withHost(config.getHost())
|
||||
.withPort(config.getPort())
|
||||
.withoutTLS()
|
||||
.build();
|
||||
/* Unseal Vault and check result */
|
||||
SealResponse sealStatus = connector.unseal(KEY);
|
||||
assumeNotNull(sealStatus);
|
||||
assumeFalse(sealStatus.isSealed());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (vaultProcess != null && vaultProcess.isAlive())
|
||||
vaultProcess.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test listing of authentication backends
|
||||
* Test exceptions thrown during request.
|
||||
*/
|
||||
@Test
|
||||
public void authMethodsTest() {
|
||||
/* Authenticate as valid user */
|
||||
try {
|
||||
connector.authToken(TOKEN_ROOT);
|
||||
}
|
||||
catch(VaultConnectorException ignored) {
|
||||
}
|
||||
assumeTrue(connector.isAuthorized());
|
||||
void requestExceptionTest(WireMockRuntimeInfo wireMock) throws IOException, URISyntaxException {
|
||||
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withTimeout(250).build();
|
||||
|
||||
List<AuthBackend> supportedBackends = null;
|
||||
try {
|
||||
supportedBackends = connector.getAuthBackends();
|
||||
} catch (VaultConnectorException e) {
|
||||
fail("Could not list supported auth backends: " + e.getMessage());
|
||||
// Test invalid response code.
|
||||
final int responseCode = 400;
|
||||
mockHttpResponse(responseCode, "", "application/json");
|
||||
VaultConnectorException e = assertThrows(
|
||||
InvalidResponseException.class,
|
||||
connector::getHealth,
|
||||
"Querying health status succeeded on invalid instance"
|
||||
);
|
||||
assertEquals("Invalid response code", e.getMessage(), "Unexpected exception message");
|
||||
assertEquals(responseCode, ((InvalidResponseException) e).getStatusCode(), "Unexpected status code in exception");
|
||||
assertNull(((InvalidResponseException) e).getResponse(), "Response message where none was expected");
|
||||
|
||||
// Simulate permission denied response.
|
||||
mockHttpResponse(responseCode, "{\"errors\":[\"permission denied\"]}", "application/json");
|
||||
assertThrows(
|
||||
PermissionDeniedException.class,
|
||||
connector::getHealth,
|
||||
"Querying health status succeeded on invalid instance"
|
||||
);
|
||||
|
||||
// Test exception thrown during request.
|
||||
try (ServerSocket s = new ServerSocket(0)) {
|
||||
connector = HTTPVaultConnector.builder("http://localst:" + s.getLocalPort() + "/").withTimeout(250).build();
|
||||
}
|
||||
assertThat(supportedBackends.size(), is(3));
|
||||
assertThat(supportedBackends, hasItems(AuthBackend.TOKEN, AuthBackend.USERPASS, AuthBackend.APPID));
|
||||
e = assertThrows(
|
||||
ConnectionException.class,
|
||||
connector::getHealth,
|
||||
"Querying health status succeeded on invalid instance"
|
||||
);
|
||||
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
|
||||
assertInstanceOf(IOException.class, e.getCause(), "Unexpected cause");
|
||||
|
||||
// Now simulate a failing request that succeeds on second try.
|
||||
connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withNumberOfRetries(1).withTimeout(250).build();
|
||||
|
||||
stubFor(
|
||||
WireMock.any(anyUrl())
|
||||
.willReturn(aResponse().withStatus(500))
|
||||
.willReturn(aResponse().withStatus(500))
|
||||
.willReturn(aResponse().withStatus(500))
|
||||
.willReturn(aResponse().withStatus(200).withBody("{}").withHeader("Content-Type", "application/json"))
|
||||
);
|
||||
assertDoesNotThrow(connector::getHealth, "Request failed unexpectedly");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test authentication using token.
|
||||
* Test constructors of the {@link HTTPVaultConnector} class.
|
||||
*/
|
||||
@Test
|
||||
public void authTokenTest() {
|
||||
TokenResponse res = null;
|
||||
try {
|
||||
res = connector.authToken("52135869df23a5e64c5d33a9785af5edb456b8a4a235d1fe135e6fba1c35edf6");
|
||||
fail("Logged in with invalid token");
|
||||
} catch (VaultConnectorException ignored) {
|
||||
void constructorTest() throws IOException, CertificateException, URISyntaxException {
|
||||
final String url = "https://vault.example.net/test/";
|
||||
final String hostname = "vault.example.com";
|
||||
final Integer port = 1337;
|
||||
final String prefix = "/custom/prefix/";
|
||||
final int retries = 42;
|
||||
final String expectedNoTls = "http://" + hostname + ":8200/v1/";
|
||||
final String expectedCustomPort = "https://" + hostname + ":" + port + "/v1/";
|
||||
final String expectedCustomPrefix = "https://" + hostname + ":" + port + prefix;
|
||||
X509Certificate trustedCaCert;
|
||||
|
||||
try (InputStream is = getClass().getResourceAsStream("/tls/ca.pem")) {
|
||||
trustedCaCert = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
|
||||
}
|
||||
|
||||
try {
|
||||
res = connector.authToken(TOKEN_ROOT);
|
||||
assertNotNull("Login failed with valid token", res);
|
||||
assertThat("Login failed with valid token", connector.isAuthorized(), is(true));
|
||||
} catch (VaultConnectorException ignored) {
|
||||
fail("Login failed with valid token");
|
||||
}
|
||||
// Most basic constructor expects complete URL.
|
||||
HTTPVaultConnector connector = HTTPVaultConnector.builder(url).build();
|
||||
assertEquals(url, getRequestHelperPrivate(connector, "baseURL"), "Unexpected base URL");
|
||||
|
||||
// Now override TLS usage.
|
||||
connector = HTTPVaultConnector.builder().withHost(hostname).withoutTLS().build();
|
||||
assertEquals(expectedNoTls, getRequestHelperPrivate(connector, "baseURL"), "Unexpected base URL with TLS disabled");
|
||||
|
||||
// Specify custom port.
|
||||
connector = HTTPVaultConnector.builder().withHost(hostname).withTLS().withPort(port).build();
|
||||
assertEquals(expectedCustomPort, getRequestHelperPrivate(connector, "baseURL"), "Unexpected base URL with custom port");
|
||||
|
||||
// Specify custom prefix.
|
||||
connector = HTTPVaultConnector.builder().withHost(hostname).withTLS().withPort(port).withPrefix(prefix).build();
|
||||
assertEquals(expectedCustomPrefix, getRequestHelperPrivate(connector, "baseURL"), "Unexpected base URL with custom prefix");
|
||||
assertNull(getRequestHelperPrivate(connector, "trustedCaCert"), "Trusted CA cert set, but not specified");
|
||||
|
||||
// Specify number of retries.
|
||||
connector = HTTPVaultConnector.builder(url).withTrustedCA(trustedCaCert).withNumberOfRetries(retries).build();
|
||||
assertEquals(retries, getRequestHelperPrivate(connector, "retries"), "Number of retries not set correctly");
|
||||
|
||||
// Test TLS version (#22).
|
||||
assertEquals("TLSv1.2", getRequestHelperPrivate(connector, "tlsVersion"), "TLS version should be 1.2 if not specified");
|
||||
// Now override.
|
||||
connector = HTTPVaultConnector.builder(url).withTrustedCA(trustedCaCert).withNumberOfRetries(retries).withTLS("TLSv1.1").build();
|
||||
assertEquals("TLSv1.1", getRequestHelperPrivate(connector, "tlsVersion"), "Overridden TLS version 1.1 not correct");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test authentication using username and password.
|
||||
* This test is designed to test exceptions caught and thrown by seal-methods if Vault is not reachable.
|
||||
*/
|
||||
@Test
|
||||
public void authUserPassTest() {
|
||||
AuthResponse res = null;
|
||||
try {
|
||||
connector.authUserPass("foo", "bar");
|
||||
fail("Logged in with invalid credentials");
|
||||
void sealExceptionTest() throws IOException, URISyntaxException {
|
||||
// Simulate no connection.
|
||||
VaultConnector connector;
|
||||
try (ServerSocket s = new ServerSocket(0)) {
|
||||
connector = HTTPVaultConnector.builder("http://localst:" + s.getLocalPort()).withTimeout(250).build();
|
||||
}
|
||||
catch(VaultConnectorException ignored) {
|
||||
}
|
||||
|
||||
try {
|
||||
res = connector.authUserPass(USER_VALID, PASS_VALID);
|
||||
} catch (VaultConnectorException ignored) {
|
||||
fail("Login failed with valid credentials: Exception thrown");
|
||||
}
|
||||
assertNotNull("Login failed with valid credentials: Response not available", res.getAuth());
|
||||
assertThat("Login failed with valid credentials: Connector not authorized", connector.isAuthorized(), is(true));
|
||||
ConnectionException e = assertThrows(
|
||||
ConnectionException.class,
|
||||
connector::sealStatus,
|
||||
"Querying seal status succeeded on invalid instance"
|
||||
);
|
||||
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
|
||||
}
|
||||
|
||||
/**
|
||||
* App-ID authentication roundtrip.
|
||||
* This test is designed to test exceptions caught and thrown by seal-methods if Vault is not reachable.
|
||||
*/
|
||||
@Test
|
||||
public void authAppIdTest() {
|
||||
authRoot();
|
||||
assumeTrue(connector.isAuthorized());
|
||||
|
||||
/* Register App-ID */
|
||||
try {
|
||||
boolean res = connector.registerAppId(APP_ID, "user", "App Name");
|
||||
assertThat("Failed to register App-ID", res, is(true));
|
||||
}
|
||||
catch (VaultConnectorException e) {
|
||||
fail("Failed to register App-ID: " + e.getMessage());
|
||||
}
|
||||
|
||||
/* Register User-ID */
|
||||
try {
|
||||
boolean res = connector.registerUserId(APP_ID, USER_ID);
|
||||
assertThat("Failed to register App-ID", res, is(true));
|
||||
}
|
||||
catch (VaultConnectorException e) {
|
||||
fail("Failed to register App-ID: " + e.getMessage());
|
||||
}
|
||||
|
||||
connector.resetAuth();
|
||||
assumeFalse(connector.isAuthorized());
|
||||
|
||||
/* Authenticate with created credentials */
|
||||
try {
|
||||
AuthResponse res = connector.authAppId(APP_ID, USER_ID);
|
||||
assertThat("Authorization flag not set after App-ID login.", connector.isAuthorized(), is(true));
|
||||
} catch (VaultConnectorException e) {
|
||||
fail("Failed to authenticate using App-ID: " + e.getMessage());
|
||||
void healthExceptionTest() throws IOException, URISyntaxException {
|
||||
// Simulate no connection.
|
||||
HTTPVaultConnector connector;
|
||||
try (ServerSocket s = new ServerSocket(0)) {
|
||||
connector = HTTPVaultConnector.builder("http://localhost:" + s.getLocalPort() + "/").withTimeout(250).build();
|
||||
}
|
||||
ConnectionException e = assertThrows(
|
||||
ConnectionException.class,
|
||||
connector::getHealth,
|
||||
"Querying health status succeeded on invalid instance"
|
||||
);
|
||||
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test reading of secrets.
|
||||
* Test behavior on unparsable responses.
|
||||
*/
|
||||
@Test
|
||||
public void readSecretTest() {
|
||||
authUser();
|
||||
assumeTrue(connector.isAuthorized());
|
||||
void parseExceptionTest(WireMockRuntimeInfo wireMock) throws URISyntaxException {
|
||||
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withTimeout(250).build();
|
||||
// Mock authorization.
|
||||
setPrivate(connector, "authorized", true);
|
||||
// Mock response.
|
||||
mockHttpResponse(200, "invalid", "application/json");
|
||||
|
||||
/* Try to read path user has no permission to read */
|
||||
SecretResponse res = null;
|
||||
try {
|
||||
res = connector.readSecret("invalid/path");
|
||||
fail("Invalid secret path successfully read.");
|
||||
} catch (VaultConnectorException e) {
|
||||
assertThat(e, instanceOf(PermissionDeniedException.class));
|
||||
}
|
||||
/* Try to read accessible path with known value */
|
||||
try {
|
||||
res = connector.readSecret(SECRET_PATH + "/" + SECRET_KEY);
|
||||
assertThat("Known secret returned invalid value.", res.getValue(), is(SECRET_VALUE));
|
||||
} catch (VaultConnectorException e) {
|
||||
fail("Valid secret path could not be read: " + e.getMessage());
|
||||
// Now test the methods.
|
||||
assertParseError(connector::sealStatus, "sealStatus() succeeded on invalid instance");
|
||||
assertParseError(() -> connector.unseal("key"), "unseal() succeeded on invalid instance");
|
||||
assertParseError(connector::getHealth, "getHealth() succeeded on invalid instance");
|
||||
assertParseError(connector::getAuthBackends, "getAuthBackends() succeeded on invalid instance");
|
||||
assertParseError(() -> connector.authToken("token"), "authToken() succeeded on invalid instance");
|
||||
assertParseError(() -> connector.lookupAppRole("roleName"), "lookupAppRole() succeeded on invalid instance");
|
||||
assertParseError(() -> connector.getAppRoleID("roleName"), "getAppRoleID() succeeded on invalid instance");
|
||||
assertParseError(() -> connector.createAppRoleSecret("roleName"), "createAppRoleSecret() succeeded on invalid instance");
|
||||
assertParseError(() -> connector.lookupAppRoleSecret("roleName", "secretID"), "lookupAppRoleSecret() succeeded on invalid instance");
|
||||
assertParseError(connector::listAppRoles, "listAppRoles() succeeded on invalid instance");
|
||||
assertParseError(() -> connector.listAppRoleSecrets("roleName"), "listAppRoleSecrets() succeeded on invalid instance");
|
||||
assertParseError(() -> connector.read("key"), "read() succeeded on invalid instance");
|
||||
assertParseError(() -> connector.list("path"), "list() succeeded on invalid instance");
|
||||
assertParseError(() -> connector.renew("leaseID"), "renew() succeeded on invalid instance");
|
||||
assertParseError(() -> connector.lookupToken("token"), "lookupToken() succeeded on invalid instance");
|
||||
}
|
||||
|
||||
private void assertParseError(Executable executable, String message) {
|
||||
InvalidResponseException e = assertThrows(InvalidResponseException.class, executable, message);
|
||||
assertEquals("Unable to parse response", e.getMessage(), "Unexpected exception message");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test listing secrets.
|
||||
* Test requests that expect an empty response with code 204, but receive a 200 body.
|
||||
*/
|
||||
@Test
|
||||
public void listSecretsTest() {
|
||||
authRoot();
|
||||
assumeTrue(connector.isAuthorized());
|
||||
/* Try to list secrets from valid path */
|
||||
void nonEmpty204ResponseTest(WireMockRuntimeInfo wireMock) throws URISyntaxException {
|
||||
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withTimeout(250).build();
|
||||
// Mock authorization.
|
||||
setPrivate(connector, "authorized", true);
|
||||
// Mock response.
|
||||
mockHttpResponse(200, "{}", "application/json");
|
||||
|
||||
// Now test the methods expecting a 204.
|
||||
assertThrows(
|
||||
InvalidResponseException.class,
|
||||
() -> connector.createAppRole("appID", Collections.singletonList("policy")),
|
||||
"createAppRole() with 200 response succeeded"
|
||||
);
|
||||
|
||||
assertThrows(
|
||||
InvalidResponseException.class,
|
||||
() -> connector.deleteAppRole("roleName"),
|
||||
"deleteAppRole() with 200 response succeeded"
|
||||
);
|
||||
|
||||
assertThrows(
|
||||
InvalidResponseException.class,
|
||||
() -> connector.setAppRoleID("roleName", "roleID"),
|
||||
"setAppRoleID() with 200 response succeeded"
|
||||
);
|
||||
|
||||
assertThrows(
|
||||
InvalidResponseException.class,
|
||||
() -> connector.destroyAppRoleSecret("roleName", "secretID"),
|
||||
"destroyAppRoleSecret() with 200 response succeeded"
|
||||
);
|
||||
|
||||
assertThrows(
|
||||
InvalidResponseException.class,
|
||||
() -> connector.destroyAppRoleSecret("roleName", "secretUD"),
|
||||
"destroyAppRoleSecret() with 200 response succeeded"
|
||||
);
|
||||
|
||||
assertThrows(
|
||||
InvalidResponseException.class,
|
||||
() -> connector.delete("key"),
|
||||
"delete() with 200 response succeeded"
|
||||
);
|
||||
|
||||
assertThrows(
|
||||
InvalidResponseException.class,
|
||||
() -> connector.revoke("leaseID"),
|
||||
"destroyAppRoleSecret() with 200 response succeeded"
|
||||
);
|
||||
}
|
||||
|
||||
private Object getRequestHelperPrivate(HTTPVaultConnector connector, String fieldName) {
|
||||
try {
|
||||
List<String> secrets = connector.listSecrets(SECRET_PATH);
|
||||
assertThat("Invalid nmber of secrets.", secrets.size(), greaterThan(0));
|
||||
assertThat("Known secret key not found", secrets, hasItem(SECRET_KEY));
|
||||
} catch (VaultConnectorException e) {
|
||||
fail("Secrets could not be listed: " + e.getMessage());
|
||||
return getPrivate(getPrivate(connector, "request"), fieldName);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test writing secrets.
|
||||
*/
|
||||
@Test
|
||||
public void writeSecretTest() {
|
||||
authUser();
|
||||
assumeTrue(connector.isAuthorized());
|
||||
private Object getPrivate(Object target, String fieldName) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = target.getClass().getDeclaredField(fieldName);
|
||||
if (field.canAccess(target)) {
|
||||
return field.get(target);
|
||||
}
|
||||
field.setAccessible(true);
|
||||
Object value = field.get(target);
|
||||
field.setAccessible(false);
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Try to write to null path */
|
||||
private void setPrivate(Object target, String fieldName, Object value) {
|
||||
try {
|
||||
boolean res = connector.writeSecret(null, "someValue");
|
||||
fail("Secret written to null path.");
|
||||
} catch (VaultConnectorException e) {
|
||||
assertThat(e, instanceOf(InvalidRequestException.class));
|
||||
}
|
||||
/* Try to write to invalid path */
|
||||
try {
|
||||
boolean res = connector.writeSecret("", "someValue");
|
||||
fail("Secret written to invalid path.");
|
||||
} catch (VaultConnectorException e) {
|
||||
assertThat(e, instanceOf(InvalidRequestException.class));
|
||||
}
|
||||
/* Try to write to a path the user has no access for */
|
||||
try {
|
||||
boolean res = connector.writeSecret("invalid/path", "someValue");
|
||||
fail("Secret written to inaccessible path.");
|
||||
} catch (VaultConnectorException e) {
|
||||
assertThat(e, instanceOf(PermissionDeniedException.class));
|
||||
}
|
||||
/* Perform a valid write/read roundtrip to valid path. Also check UTF8-encoding. */
|
||||
try {
|
||||
boolean res = connector.writeSecret(SECRET_PATH + "/temp", "Abc123äöü,!");
|
||||
assertThat("Secret could not be written to valid path.", res, is(true));
|
||||
} catch (VaultConnectorException e) {
|
||||
fail("Secret written to inaccessible path.");
|
||||
}
|
||||
try {
|
||||
SecretResponse res = connector.readSecret(SECRET_PATH + "/temp");
|
||||
assertThat(res.getValue(), is("Abc123äöü,!"));
|
||||
} catch (VaultConnectorException e) {
|
||||
fail("Written secret could not be read.");
|
||||
Field field = target.getClass().getDeclaredField(fieldName);
|
||||
boolean accessible = field.canAccess(target);
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Vault with resource datastore and generated configuration.
|
||||
* @return Vault Configuration
|
||||
* @throws IllegalStateException
|
||||
*/
|
||||
private VaultConfiguration initializeVault() throws IllegalStateException {
|
||||
String dataResource = getClass().getResource("/data_dir").getPath();
|
||||
|
||||
/* Generate vault local unencrypted configuration */
|
||||
VaultConfiguration config = new VaultConfiguration()
|
||||
.withHost("127.0.0.1")
|
||||
.withPort(getFreePort())
|
||||
.withDataLocation(dataResource)
|
||||
.disableMlock();
|
||||
|
||||
/* Write configuration file */
|
||||
BufferedWriter bw = null;
|
||||
File configFIle = null;
|
||||
try {
|
||||
configFIle = tmpDir.newFile("vault.conf");
|
||||
bw = new BufferedWriter(new FileWriter(configFIle));
|
||||
bw.write(config.toString());
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new IllegalStateException("Unable to generate config file.");
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (bw != null)
|
||||
bw.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/* Start vault process */
|
||||
try {
|
||||
vaultProcess = Runtime.getRuntime().exec("vault server -config " + configFIle.toString());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new IllegalStateException("Unable to start vault. Make sure vault binary is in your executable path.");
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate with root token.
|
||||
*/
|
||||
private void authRoot() {
|
||||
/* Authenticate as valid user */
|
||||
try {
|
||||
connector.authToken(TOKEN_ROOT);
|
||||
}
|
||||
catch(VaultConnectorException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate with user credentials.
|
||||
*/
|
||||
private void authUser() {
|
||||
try {
|
||||
connector.authUserPass(USER_VALID, PASS_VALID);
|
||||
}
|
||||
catch(VaultConnectorException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and return a free TCP port.
|
||||
* @return port number
|
||||
*/
|
||||
private static Integer getFreePort() {
|
||||
ServerSocket socket = null;
|
||||
try {
|
||||
socket = new ServerSocket(0);
|
||||
socket.setReuseAddress(true);
|
||||
int port = socket.getLocalPort();
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
// Ignore IOException on close()
|
||||
}
|
||||
return port;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Unable to find a free TCP port.");
|
||||
private void mockHttpResponse(int status, String body, String contentType) {
|
||||
stubFor(
|
||||
WireMock.any(anyUrl()).willReturn(
|
||||
aResponse().withStatus(status).withBody(body).withHeader("Content-Type", contentType)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
/**
|
||||
* Common JUnit test for Exceptions extending {@link VaultConnectorException}.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.6.2
|
||||
*/
|
||||
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
|
||||
void authorizationRequiredExceptionTest() {
|
||||
assertEmptyConstructor(new AuthorizationRequiredException());
|
||||
}
|
||||
|
||||
@Test
|
||||
void connectionExceptionTest() {
|
||||
assertEmptyConstructor(new ConnectionException());
|
||||
assertMsgConstructor(new ConnectionException(MSG));
|
||||
assertCauseConstructor(new ConnectionException(CAUSE));
|
||||
assertMsgCauseConstructor(new ConnectionException(MSG, CAUSE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void invalidRequestExceptionTest() {
|
||||
assertEmptyConstructor(new InvalidRequestException());
|
||||
assertMsgConstructor(new InvalidRequestException(MSG));
|
||||
assertCauseConstructor(new InvalidRequestException(CAUSE));
|
||||
assertMsgCauseConstructor(new InvalidRequestException(MSG, CAUSE));
|
||||
}
|
||||
|
||||
@Test
|
||||
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);
|
||||
assertEquals(MSG, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
assertEquals(STATUS_CODE, e.getStatusCode());
|
||||
assertNull(e.getResponse());
|
||||
|
||||
// Constructor with message, status code and cause.
|
||||
e = new InvalidResponseException(MSG, STATUS_CODE, CAUSE);
|
||||
assertEquals(MSG, e.getMessage());
|
||||
assertEquals(CAUSE, e.getCause());
|
||||
assertEquals(STATUS_CODE, e.getStatusCode());
|
||||
assertNull(e.getResponse());
|
||||
|
||||
// Constructor with message, status code and response.
|
||||
e = new InvalidResponseException(MSG, STATUS_CODE, RESPONSE);
|
||||
assertEquals(MSG, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
assertEquals(STATUS_CODE, e.getStatusCode());
|
||||
assertEquals(RESPONSE, e.getResponse());
|
||||
|
||||
// Constructor with message, status code, response and cause.
|
||||
e = new InvalidResponseException(MSG, STATUS_CODE, RESPONSE, CAUSE);
|
||||
assertEquals(MSG, e.getMessage());
|
||||
assertEquals(CAUSE, e.getCause());
|
||||
assertEquals(STATUS_CODE, e.getStatusCode());
|
||||
assertEquals(RESPONSE, e.getResponse());
|
||||
}
|
||||
|
||||
@Test
|
||||
void permissionDeniedExceptionTest() {
|
||||
// Default message overwritten.
|
||||
PermissionDeniedException e = new PermissionDeniedException();
|
||||
assertEquals("Permission denied", e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
|
||||
assertMsgConstructor(new PermissionDeniedException(MSG));
|
||||
assertCauseConstructor(new PermissionDeniedException(CAUSE));
|
||||
assertMsgCauseConstructor(new PermissionDeniedException(MSG, CAUSE));
|
||||
}
|
||||
|
||||
@Test
|
||||
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) {
|
||||
assertNull(e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
/**
|
||||
* Assertions for constructor with message.
|
||||
*
|
||||
* @param e the exception
|
||||
*/
|
||||
private void assertMsgConstructor(VaultConnectorException e) {
|
||||
assertEquals(MSG, e.getMessage());
|
||||
assertNull(e.getCause());
|
||||
}
|
||||
|
||||
/**
|
||||
* Assertions for constructor with cause.
|
||||
*
|
||||
* @param e the exception
|
||||
*/
|
||||
private void assertCauseConstructor(VaultConnectorException e) {
|
||||
assertEquals(CAUSE.toString(), e.getMessage());
|
||||
assertEquals(CAUSE, e.getCause());
|
||||
}
|
||||
|
||||
/**
|
||||
* Assertions for constructor with message and cause.
|
||||
*
|
||||
* @param e the exception
|
||||
*/
|
||||
private void assertMsgCauseConstructor(VaultConnectorException e) {
|
||||
assertEquals(MSG, e.getMessage());
|
||||
assertEquals(CAUSE, e.getCause());
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package de.stklcode.jvault.connector.model;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import nl.jqno.equalsverifier.EqualsVerifier;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* Abstract testcase for model classes.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 1.1
|
||||
*/
|
||||
public abstract class AbstractModelTest<T> {
|
||||
protected final Class<?> modelClass;
|
||||
protected final ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* Test case constructor.
|
||||
*
|
||||
* @param modelClass Target class to test.
|
||||
*/
|
||||
protected AbstractModelTest(Class<T> modelClass) {
|
||||
this.modelClass = modelClass;
|
||||
this.objectMapper = JsonMapper.builder()
|
||||
.addModule(new JavaTimeModule())
|
||||
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
||||
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a "full" model instance.
|
||||
*
|
||||
* @return Model instance.
|
||||
*/
|
||||
protected abstract T createFull();
|
||||
|
||||
/**
|
||||
* Test if {@link Object#equals(Object)} and {@link Object#hashCode()} are implemented, s.t. all fields are covered.
|
||||
*/
|
||||
@Test
|
||||
void testEqualsHashcode() {
|
||||
EqualsVerifier.simple().forClass(modelClass).verify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Java serialization of a full model instance.
|
||||
* Serialization and deserialization must not fail and the resulting object should equal the original object.
|
||||
*/
|
||||
@Test
|
||||
void serializationTest() {
|
||||
T original = createFull();
|
||||
byte[] bytes;
|
||||
try (var bos = new ByteArrayOutputStream();
|
||||
var oos = new ObjectOutputStream(bos)) {
|
||||
oos.writeObject(original);
|
||||
bytes = bos.toByteArray();
|
||||
} catch (IOException e) {
|
||||
fail("Serialization failed", e);
|
||||
return;
|
||||
}
|
||||
|
||||
try (var bis = new ByteArrayInputStream(bytes);
|
||||
var ois = new ObjectInputStream(bis)) {
|
||||
Object copy = ois.readObject();
|
||||
assertEquals(modelClass, copy.getClass(), "Invalid class after deserialization");
|
||||
assertEquals(original, copy, "Deserialized object should be equal to the original");
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
fail("Deserialization failed", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
|
||||
/**
|
||||
* JUnit Test for AppRoleSecret model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.5.0
|
||||
*/
|
||||
class AppRoleSecretTest extends AbstractModelTest<AppRoleSecret> {
|
||||
private static final String TEST_ID = "abc123";
|
||||
private static final Map<String, Object> TEST_META = Map.of(
|
||||
"foo", "bar",
|
||||
"number", 1337
|
||||
);
|
||||
private static final List<String> TEST_CIDR = List.of("203.0.113.0/24", "198.51.100.0/24");
|
||||
|
||||
AppRoleSecretTest() {
|
||||
super(AppRoleSecret.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AppRoleSecret createFull() {
|
||||
return new AppRoleSecret(TEST_ID, TEST_META, TEST_CIDR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test constructors.
|
||||
*/
|
||||
@Test
|
||||
void constructorTest() {
|
||||
// Empty constructor.
|
||||
AppRoleSecret secret = new AppRoleSecret();
|
||||
assertNull(secret.getId());
|
||||
assertNull(secret.getAccessor());
|
||||
assertNull(secret.getMetadata());
|
||||
assertNull(secret.getCidrList());
|
||||
assertEquals("", secret.getCidrListString());
|
||||
assertNull(secret.getCreationTime());
|
||||
assertNull(secret.getExpirationTime());
|
||||
assertNull(secret.getLastUpdatedTime());
|
||||
assertNull(secret.getNumUses());
|
||||
assertNull(secret.getTtl());
|
||||
|
||||
// Constructor with ID.
|
||||
secret = new AppRoleSecret(TEST_ID);
|
||||
assertEquals(TEST_ID, secret.getId());
|
||||
assertNull(secret.getAccessor());
|
||||
assertNull(secret.getMetadata());
|
||||
assertNull(secret.getCidrList());
|
||||
assertEquals("", secret.getCidrListString());
|
||||
assertNull(secret.getCreationTime());
|
||||
assertNull(secret.getExpirationTime());
|
||||
assertNull(secret.getLastUpdatedTime());
|
||||
assertNull(secret.getNumUses());
|
||||
assertNull(secret.getTtl());
|
||||
|
||||
// Constructor with Metadata and CIDR bindings.
|
||||
secret = new AppRoleSecret(TEST_ID, TEST_META, TEST_CIDR);
|
||||
assertEquals(TEST_ID, secret.getId());
|
||||
assertNull(secret.getAccessor());
|
||||
assertEquals(TEST_META, secret.getMetadata());
|
||||
assertEquals(TEST_CIDR, secret.getCidrList());
|
||||
assertEquals(String.join(",", TEST_CIDR), secret.getCidrListString());
|
||||
assertNull(secret.getCreationTime());
|
||||
assertNull(secret.getExpirationTime());
|
||||
assertNull(secret.getLastUpdatedTime());
|
||||
assertNull(secret.getNumUses());
|
||||
assertNull(secret.getTtl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setter.
|
||||
*/
|
||||
@Test
|
||||
void setterTest() {
|
||||
AppRoleSecret secret = new AppRoleSecret(TEST_ID);
|
||||
assertNull(secret.getCidrList());
|
||||
assertEquals("", secret.getCidrListString());
|
||||
secret.setCidrList(TEST_CIDR);
|
||||
assertEquals(TEST_CIDR, secret.getCidrList());
|
||||
assertEquals(String.join(",", TEST_CIDR), secret.getCidrListString());
|
||||
secret.setCidrList(null);
|
||||
assertNull(secret.getCidrList());
|
||||
assertEquals("", secret.getCidrListString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test JSON (de)serialization.
|
||||
*/
|
||||
@Test
|
||||
void jsonTest() throws NoSuchFieldException, IllegalAccessException {
|
||||
// A simple roundtrip first. All set fields should be present afterward.
|
||||
AppRoleSecret secret = new AppRoleSecret(TEST_ID, TEST_META, TEST_CIDR);
|
||||
String secretJson = assertDoesNotThrow(() -> objectMapper.writeValueAsString(secret), "Serialization failed");
|
||||
// CIDR list is comma-separated when used as input, but List otherwise, hence convert string to list.
|
||||
String secretJson2 = commaSeparatedToList(secretJson);
|
||||
|
||||
AppRoleSecret secret2 = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(secretJson2, AppRoleSecret.class),
|
||||
"Deserialization failed"
|
||||
);
|
||||
assertEquals(secret2.getId(), secret.getId());
|
||||
assertEquals(secret2.getMetadata(), secret.getMetadata());
|
||||
assertEquals(secret2.getCidrList(), secret.getCidrList());
|
||||
|
||||
// Test fields, that should not be written to JSON.
|
||||
setPrivateField(secret, "accessor", "TEST_ACCESSOR");
|
||||
assumeTrue("TEST_ACCESSOR".equals(secret.getAccessor()));
|
||||
setPrivateField(secret, "creationTime", "TEST_CREATION");
|
||||
assumeTrue("TEST_CREATION".equals(secret.getCreationTime()));
|
||||
setPrivateField(secret, "expirationTime", "TEST_EXPIRATION");
|
||||
assumeTrue("TEST_EXPIRATION".equals(secret.getExpirationTime()));
|
||||
setPrivateField(secret, "lastUpdatedTime", "TEST_UPDATETIME");
|
||||
assumeTrue("TEST_UPDATETIME".equals(secret.getLastUpdatedTime()));
|
||||
setPrivateField(secret, "numUses", 678);
|
||||
assumeTrue(secret.getNumUses() == 678);
|
||||
setPrivateField(secret, "ttl", 12345);
|
||||
assumeTrue(secret.getTtl() == 12345);
|
||||
String secretJson3 = assertDoesNotThrow(() -> objectMapper.writeValueAsString(secret), "Serialization failed");
|
||||
secret2 = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(commaSeparatedToList(secretJson3), AppRoleSecret.class),
|
||||
"Deserialization failed"
|
||||
);
|
||||
assertEquals(secret2.getId(), secret.getId());
|
||||
assertEquals(secret2.getMetadata(), secret.getMetadata());
|
||||
assertEquals(secret2.getCidrList(), secret.getCidrList());
|
||||
assertNull(secret2.getAccessor());
|
||||
assertNull(secret2.getCreationTime());
|
||||
assertNull(secret2.getExpirationTime());
|
||||
assertNull(secret2.getLastUpdatedTime());
|
||||
assertNull(secret2.getNumUses());
|
||||
assertNull(secret2.getTtl());
|
||||
|
||||
// Those fields should be deserialized from JSON though.
|
||||
String secretJson4 = "{\"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}";
|
||||
secret2 = assertDoesNotThrow(() -> objectMapper.readValue(secretJson4, AppRoleSecret.class), "Deserialization failed");
|
||||
assertEquals("TEST_ACCESSOR", secret2.getAccessor());
|
||||
assertEquals("TEST_CREATION", secret2.getCreationTime());
|
||||
assertEquals("TEST_EXPIRATION", secret2.getExpirationTime());
|
||||
assertEquals("TEST_LASTUPDATE", secret2.getLastUpdatedTime());
|
||||
assertEquals(678, secret2.getNumUses());
|
||||
assertEquals(12345, secret2.getTtl());
|
||||
}
|
||||
|
||||
private static void setPrivateField(Object object, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = object.getClass().getDeclaredField(fieldName);
|
||||
boolean accessible = field.canAccess(object);
|
||||
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\"");
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link AppRole} and {@link AppRole.Builder}.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
*/
|
||||
class AppRoleTest extends AbstractModelTest<AppRole> {
|
||||
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 Boolean LOCAL_SECRET_IDS = false;
|
||||
private static final Integer TOKEN_TTL = 4800;
|
||||
private static final Integer TOKEN_MAX_TTL = 9600;
|
||||
private static final Integer TOKEN_EXPLICIT_MAX_TTL = 14400;
|
||||
private static final Boolean TOKEN_NO_DEFAULT_POLICY = false;
|
||||
private static final Integer TOKEN_NUM_USES = 42;
|
||||
private static final Integer TOKEN_PERIOD = 1234;
|
||||
private static final Token.Type TOKEN_TYPE = Token.Type.DEFAULT_SERVICE;
|
||||
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,\"secret_id_bound_cidrs\":\"%s\",\"secret_id_num_uses\":%d,\"secret_id_ttl\":%d,\"local_secret_ids\":%s,\"token_ttl\":%d,\"token_max_ttl\":%d,\"token_policies\":\"%s\",\"token_bound_cidrs\":\"%s\",\"token_explicit_max_ttl\":%d,\"token_no_default_policy\":%s,\"token_num_uses\":%d,\"token_period\":%d,\"token_type\":\"%s\"}",
|
||||
NAME, ID, BIND_SECRET_ID, CIDR_1, SECRET_ID_NUM_USES, SECRET_ID_TTL, LOCAL_SECRET_IDS, TOKEN_TTL, TOKEN_MAX_TTL, POLICY, CIDR_1, TOKEN_EXPLICIT_MAX_TTL, TOKEN_NO_DEFAULT_POLICY, TOKEN_NUM_USES, TOKEN_PERIOD, TOKEN_TYPE.value());
|
||||
|
||||
AppRoleTest() {
|
||||
super(AppRole.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AppRole createFull() {
|
||||
return AppRole.builder(NAME)
|
||||
.withId(ID)
|
||||
.withBindSecretID(BIND_SECRET_ID)
|
||||
.withSecretIdBoundCidrs(BOUND_CIDR_LIST)
|
||||
.withTokenPolicies(POLICIES)
|
||||
.withSecretIdNumUses(SECRET_ID_NUM_USES)
|
||||
.withSecretIdTtl(SECRET_ID_TTL)
|
||||
.withLocalSecretIds(LOCAL_SECRET_IDS)
|
||||
.withTokenTtl(TOKEN_TTL)
|
||||
.withTokenMaxTtl(TOKEN_MAX_TTL)
|
||||
.withTokenBoundCidrs(BOUND_CIDR_LIST)
|
||||
.withTokenExplicitMaxTtl(TOKEN_EXPLICIT_MAX_TTL)
|
||||
.withTokenNoDefaultPolicy(TOKEN_NO_DEFAULT_POLICY)
|
||||
.withTokenNumUses(TOKEN_NUM_USES)
|
||||
.withTokenPeriod(TOKEN_PERIOD)
|
||||
.withTokenType(TOKEN_TYPE)
|
||||
.build();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
static void init() {
|
||||
BOUND_CIDR_LIST.add(CIDR_1);
|
||||
POLICIES.add(POLICY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build role with only a name.
|
||||
*/
|
||||
@Test
|
||||
void buildDefaultTest() throws JsonProcessingException {
|
||||
AppRole role = AppRole.builder(NAME).build();
|
||||
assertNull(role.getId());
|
||||
assertNull(role.getBindSecretId());
|
||||
assertNull(role.getSecretIdBoundCidrs());
|
||||
assertNull(role.getTokenPolicies());
|
||||
assertNull(role.getSecretIdNumUses());
|
||||
assertNull(role.getSecretIdTtl());
|
||||
assertNull(role.getLocalSecretIds());
|
||||
assertNull(role.getTokenTtl());
|
||||
assertNull(role.getTokenMaxTtl());
|
||||
assertNull(role.getTokenBoundCidrs());
|
||||
assertNull(role.getTokenExplicitMaxTtl());
|
||||
assertNull(role.getTokenNoDefaultPolicy());
|
||||
assertNull(role.getTokenNumUses());
|
||||
assertNull(role.getTokenPeriod());
|
||||
assertNull(role.getTokenType());
|
||||
|
||||
// Optional fields should be ignored, so JSON string should only contain role_name.
|
||||
assertEquals(JSON_MIN, objectMapper.writeValueAsString(role));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build token without all parameters set.
|
||||
*/
|
||||
@Test
|
||||
void buildFullTest() throws JsonProcessingException {
|
||||
AppRole role = createFull();
|
||||
assertEquals(NAME, role.getName());
|
||||
assertEquals(ID, role.getId());
|
||||
assertEquals(BIND_SECRET_ID, role.getBindSecretId());
|
||||
assertEquals(BOUND_CIDR_LIST, role.getSecretIdBoundCidrs());
|
||||
assertEquals(POLICIES, role.getTokenPolicies());
|
||||
assertEquals(SECRET_ID_NUM_USES, role.getSecretIdNumUses());
|
||||
assertEquals(SECRET_ID_TTL, role.getSecretIdTtl());
|
||||
assertEquals(LOCAL_SECRET_IDS, role.getLocalSecretIds());
|
||||
assertEquals(TOKEN_TTL, role.getTokenTtl());
|
||||
assertEquals(TOKEN_MAX_TTL, role.getTokenMaxTtl());
|
||||
assertEquals(BOUND_CIDR_LIST, role.getTokenBoundCidrs());
|
||||
assertEquals(TOKEN_EXPLICIT_MAX_TTL, role.getTokenExplicitMaxTtl());
|
||||
assertEquals(TOKEN_NO_DEFAULT_POLICY, role.getTokenNoDefaultPolicy());
|
||||
assertEquals(TOKEN_NUM_USES, role.getTokenNumUses());
|
||||
assertEquals(TOKEN_PERIOD, role.getTokenPeriod());
|
||||
assertEquals(TOKEN_TYPE.value(), role.getTokenType());
|
||||
|
||||
// Verify that all parameters are included in JSON string.
|
||||
assertEquals(JSON_FULL, objectMapper.writeValueAsString(role));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test convenience methods
|
||||
*/
|
||||
@Test
|
||||
void convenienceMethodsTest() {
|
||||
// bind_secret_id.
|
||||
AppRole role = AppRole.builder(NAME).build();
|
||||
assertNull(role.getBindSecretId());
|
||||
role = AppRole.builder(NAME).withBindSecretID().build();
|
||||
assertEquals(true, role.getBindSecretId());
|
||||
role = AppRole.builder(NAME).withoutBindSecretID().build();
|
||||
assertEquals(false, role.getBindSecretId());
|
||||
|
||||
// Add single CIDR subnet.
|
||||
role = AppRole.builder(NAME).withSecretBoundCidr(CIDR_2).withTokenBoundCidr(CIDR_2).build();
|
||||
assertEquals(1, role.getSecretIdBoundCidrs().size());
|
||||
assertEquals(CIDR_2, role.getSecretIdBoundCidrs().get(0));
|
||||
assertEquals(1, role.getTokenBoundCidrs().size());
|
||||
assertEquals(CIDR_2, role.getTokenBoundCidrs().get(0));
|
||||
role = AppRole.builder(NAME)
|
||||
.withSecretIdBoundCidrs(BOUND_CIDR_LIST)
|
||||
.withSecretBoundCidr(CIDR_2)
|
||||
.withTokenBoundCidrs(BOUND_CIDR_LIST)
|
||||
.withTokenBoundCidr(CIDR_2)
|
||||
.build();
|
||||
assertEquals(2, role.getSecretIdBoundCidrs().size());
|
||||
assertTrue(role.getSecretIdBoundCidrs().containsAll(List.of(CIDR_1, CIDR_2)));
|
||||
assertEquals(2, role.getTokenBoundCidrs().size());
|
||||
assertTrue(role.getSecretIdBoundCidrs().containsAll(List.of(CIDR_1, CIDR_2)));
|
||||
|
||||
// Add single policy.
|
||||
role = AppRole.builder(NAME).withTokenPolicy(POLICY_2).build();
|
||||
assertEquals(1, role.getTokenPolicies().size());
|
||||
assertEquals(POLICY_2, role.getTokenPolicies().get(0));
|
||||
role = AppRole.builder(NAME)
|
||||
.withTokenPolicies(POLICIES)
|
||||
.withTokenPolicy(POLICY_2)
|
||||
.build();
|
||||
assertEquals(2, role.getTokenPolicies().size());
|
||||
assertTrue(role.getTokenPolicies().containsAll(List.of(POLICY, POLICY_2)));
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/**
|
||||
* JUnit Test for AuthBackend model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
*/
|
||||
class AuthBackendTest {
|
||||
|
||||
/**
|
||||
* Test forType() method.
|
||||
*/
|
||||
@Test
|
||||
void forTypeTest() {
|
||||
assertEquals(AuthBackend.TOKEN, AuthBackend.forType("token"));
|
||||
assertEquals(AuthBackend.USERPASS, AuthBackend.forType("userpass"));
|
||||
assertEquals(AuthBackend.GITHUB, AuthBackend.forType("github"));
|
||||
assertEquals(AuthBackend.UNKNOWN, AuthBackend.forType(""));
|
||||
assertEquals(AuthBackend.UNKNOWN, AuthBackend.forType("foobar"));
|
||||
}
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Unit Test for {@link TokenRole} and {@link TokenRole.Builder}.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.9
|
||||
*/
|
||||
class TokenRoleTest extends AbstractModelTest<TokenRole> {
|
||||
private static final String NAME = "test-role";
|
||||
private static final String ALLOWED_POLICY_1 = "apol-1";
|
||||
private static final String ALLOWED_POLICY_2 = "apol-2";
|
||||
private static final String ALLOWED_POLICY_3 = "apol-3";
|
||||
private static final List<String> ALLOWED_POLICIES = Arrays.asList(ALLOWED_POLICY_1, ALLOWED_POLICY_2);
|
||||
private static final String ALLOWED_POLICY_GLOB_1 = "apol-g1*";
|
||||
private static final String ALLOWED_POLICY_GLOB_2 = "apol-g2*";
|
||||
private static final String ALLOWED_POLICY_GLOB_3 = "apol-g3*";
|
||||
private static final List<String> ALLOWED_POLICIES_GLOB = Arrays.asList(ALLOWED_POLICY_GLOB_2, ALLOWED_POLICY_GLOB_3);
|
||||
private static final String DISALLOWED_POLICY_1 = "dpol-1";
|
||||
private static final String DISALLOWED_POLICY_2 = "dpol-2";
|
||||
private static final String DISALLOWED_POLICY_3 = "dpol-3";
|
||||
private static final List<String> DISALLOWED_POLICIES = Arrays.asList(DISALLOWED_POLICY_2, DISALLOWED_POLICY_3);
|
||||
private static final String DISALLOWED_POLICY_GLOB_1 = "dpol-g1*";
|
||||
private static final String DISALLOWED_POLICY_GLOB_2 = "dpol-g2*";
|
||||
private static final String DISALLOWED_POLICY_GLOB_3 = "dpol-g3*";
|
||||
private static final List<String> DISALLOWED_POLICIES_GLOB = Arrays.asList(DISALLOWED_POLICY_GLOB_1, DISALLOWED_POLICY_GLOB_2);
|
||||
private static final Boolean ORPHAN = false;
|
||||
private static final Boolean RENEWABLE = true;
|
||||
private static final String PATH_SUFFIX = "ps";
|
||||
private static final String ALLOWED_ENTITY_ALIAS_1 = "alias-1";
|
||||
private static final String ALLOWED_ENTITY_ALIAS_2 = "alias-2";
|
||||
private static final String ALLOWED_ENTITY_ALIAS_3 = "alias-3";
|
||||
private static final List<String> ALLOWED_ENTITY_ALIASES = Arrays.asList(ALLOWED_ENTITY_ALIAS_1, ALLOWED_ENTITY_ALIAS_3);
|
||||
private static final String TOKEN_BOUND_CIDR_1 = "192.0.2.0/24";
|
||||
private static final String TOKEN_BOUND_CIDR_2 = "198.51.100.0/24";
|
||||
private static final String TOKEN_BOUND_CIDR_3 = "203.0.113.0/24";
|
||||
private static final List<String> TOKEN_BOUND_CIDRS = Arrays.asList(TOKEN_BOUND_CIDR_2, TOKEN_BOUND_CIDR_1);
|
||||
private static final Integer TOKEN_EXPLICIT_MAX_TTL = 1234;
|
||||
private static final Boolean TOKEN_NO_DEFAULT_POLICY = false;
|
||||
private static final Integer TOKEN_NUM_USES = 5;
|
||||
private static final Integer TOKEN_PERIOD = 2345;
|
||||
private static final Token.Type TOKEN_TYPE = Token.Type.SERVICE;
|
||||
|
||||
private static final String JSON_FULL = "{" +
|
||||
"\"name\":\"" + NAME + "\"," +
|
||||
"\"allowed_policies\":[\"" + ALLOWED_POLICY_1 + "\",\"" + ALLOWED_POLICY_2 + "\",\"" + ALLOWED_POLICY_3 + "\"]," +
|
||||
"\"allowed_policies_glob\":[\"" + ALLOWED_POLICY_GLOB_1 + "\",\"" + ALLOWED_POLICY_GLOB_2 + "\",\"" + ALLOWED_POLICY_GLOB_3 + "\"]," +
|
||||
"\"disallowed_policies\":[\"" + DISALLOWED_POLICY_1 + "\",\"" + DISALLOWED_POLICY_2 + "\",\"" + DISALLOWED_POLICY_3 + "\"]," +
|
||||
"\"disallowed_policies_glob\":[\"" + DISALLOWED_POLICY_GLOB_1 + "\",\"" + DISALLOWED_POLICY_GLOB_2 + "\",\"" + DISALLOWED_POLICY_GLOB_3 + "\"]," +
|
||||
"\"orphan\":" + ORPHAN + "," +
|
||||
"\"renewable\":" + RENEWABLE + "," +
|
||||
"\"path_suffix\":\"" + PATH_SUFFIX + "\"," +
|
||||
"\"allowed_entity_aliases\":[\"" + ALLOWED_ENTITY_ALIAS_1 + "\",\"" + ALLOWED_ENTITY_ALIAS_3 + "\",\"" + ALLOWED_ENTITY_ALIAS_2 + "\"]," +
|
||||
"\"token_bound_cidrs\":[\"" + TOKEN_BOUND_CIDR_3 + "\",\"" + TOKEN_BOUND_CIDR_2 + "\",\"" + TOKEN_BOUND_CIDR_1 + "\"]," +
|
||||
"\"token_explicit_max_ttl\":" + TOKEN_EXPLICIT_MAX_TTL + "," +
|
||||
"\"token_no_default_policy\":" + TOKEN_NO_DEFAULT_POLICY + "," +
|
||||
"\"token_num_uses\":" + TOKEN_NUM_USES + "," +
|
||||
"\"token_period\":" + TOKEN_PERIOD + "," +
|
||||
"\"token_type\":\"" + TOKEN_TYPE.value() + "\"}";
|
||||
|
||||
TokenRoleTest() {
|
||||
super(TokenRole.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TokenRole createFull() {
|
||||
return TokenRole.builder()
|
||||
.forName(NAME)
|
||||
.withAllowedPolicies(ALLOWED_POLICIES)
|
||||
.withAllowedPolicy(ALLOWED_POLICY_3)
|
||||
.withAllowedPolicyGlob(ALLOWED_POLICY_GLOB_1)
|
||||
.withAllowedPoliciesGlob(ALLOWED_POLICIES_GLOB)
|
||||
.withDisallowedPolicy(DISALLOWED_POLICY_1)
|
||||
.withDisallowedPolicies(DISALLOWED_POLICIES)
|
||||
.withDisallowedPoliciesGlob(DISALLOWED_POLICIES_GLOB)
|
||||
.withDisallowedPolicyGlob(DISALLOWED_POLICY_GLOB_3)
|
||||
.orphan(ORPHAN)
|
||||
.renewable(RENEWABLE)
|
||||
.withPathSuffix(PATH_SUFFIX)
|
||||
.withAllowedEntityAliases(ALLOWED_ENTITY_ALIASES)
|
||||
.withAllowedEntityAlias(ALLOWED_ENTITY_ALIAS_2)
|
||||
.withTokenBoundCidr(TOKEN_BOUND_CIDR_3)
|
||||
.withTokenBoundCidrs(TOKEN_BOUND_CIDRS)
|
||||
.withTokenExplicitMaxTtl(TOKEN_EXPLICIT_MAX_TTL)
|
||||
.withTokenNoDefaultPolicy(TOKEN_NO_DEFAULT_POLICY)
|
||||
.withTokenNumUses(TOKEN_NUM_USES)
|
||||
.withTokenPeriod(TOKEN_PERIOD)
|
||||
.withTokenType(TOKEN_TYPE)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build token without any parameters.
|
||||
*/
|
||||
@Test
|
||||
void buildDefaultTest() throws JsonProcessingException {
|
||||
TokenRole role = TokenRole.builder().build();
|
||||
assertNull(role.getAllowedPolicies());
|
||||
assertNull(role.getDisallowedPolicies());
|
||||
assertNull(role.getOrphan());
|
||||
assertNull(role.getRenewable());
|
||||
assertNull(role.getAllowedEntityAliases());
|
||||
assertNull(role.getTokenBoundCidrs());
|
||||
assertNull(role.getTokenExplicitMaxTtl());
|
||||
assertNull(role.getTokenNoDefaultPolicy());
|
||||
assertNull(role.getTokenNumUses());
|
||||
assertNull(role.getTokenPeriod());
|
||||
assertNull(role.getTokenType());
|
||||
|
||||
// Optional fields should be ignored, so JSON string should be empty.
|
||||
assertEquals("{}", objectMapper.writeValueAsString(role));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build token without all parameters NULL.
|
||||
*/
|
||||
@Test
|
||||
void buildNullTest() throws JsonProcessingException {
|
||||
TokenRole role = TokenRole.builder()
|
||||
.forName(null)
|
||||
.withAllowedPolicies(null)
|
||||
.withAllowedPolicy(null)
|
||||
.withDisallowedPolicy(null)
|
||||
.withDisallowedPolicies(null)
|
||||
.orphan(null)
|
||||
.renewable(null)
|
||||
.withPathSuffix(null)
|
||||
.withAllowedEntityAliases(null)
|
||||
.withAllowedEntityAlias(null)
|
||||
.withTokenBoundCidr(null)
|
||||
.withTokenBoundCidrs(null)
|
||||
.withTokenExplicitMaxTtl(null)
|
||||
.withTokenNoDefaultPolicy(null)
|
||||
.withTokenNumUses(null)
|
||||
.withTokenPeriod(null)
|
||||
.withTokenType(null)
|
||||
.build();
|
||||
|
||||
assertNull(role.getAllowedPolicies());
|
||||
assertNull(role.getDisallowedPolicies());
|
||||
assertNull(role.getOrphan());
|
||||
assertNull(role.getRenewable());
|
||||
assertNull(role.getAllowedEntityAliases());
|
||||
assertNull(role.getTokenBoundCidrs());
|
||||
assertNull(role.getTokenExplicitMaxTtl());
|
||||
assertNull(role.getTokenNoDefaultPolicy());
|
||||
assertNull(role.getTokenNumUses());
|
||||
assertNull(role.getTokenPeriod());
|
||||
assertNull(role.getTokenType());
|
||||
|
||||
// Empty builder should be equal to no-arg construction.
|
||||
assertEquals(new TokenRole(), role);
|
||||
|
||||
// Optional fields should be ignored, so JSON string should be empty.
|
||||
assertEquals("{}", objectMapper.writeValueAsString(role));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build token without all parameters set.
|
||||
*/
|
||||
@Test
|
||||
void buildFullTest() throws JsonProcessingException {
|
||||
TokenRole role = createFull();
|
||||
assertEquals(NAME, role.getName());
|
||||
assertEquals(ALLOWED_POLICIES.size() + 1, role.getAllowedPolicies().size());
|
||||
assertTrue(role.getAllowedPolicies().containsAll(List.of(ALLOWED_POLICY_1, ALLOWED_POLICY_2, ALLOWED_POLICY_3)));
|
||||
assertEquals(ALLOWED_POLICIES_GLOB.size() + 1, role.getAllowedPoliciesGlob().size());
|
||||
assertTrue(role.getAllowedPoliciesGlob().containsAll(List.of(ALLOWED_POLICY_GLOB_1, ALLOWED_POLICY_GLOB_2, ALLOWED_POLICY_GLOB_3)));
|
||||
assertEquals(DISALLOWED_POLICIES.size() + 1, role.getDisallowedPolicies().size());
|
||||
assertTrue(role.getDisallowedPolicies().containsAll(List.of(DISALLOWED_POLICY_1, DISALLOWED_POLICY_2, DISALLOWED_POLICY_3)));
|
||||
assertEquals(DISALLOWED_POLICIES_GLOB.size() + 1, role.getDisallowedPoliciesGlob().size());
|
||||
assertTrue(role.getDisallowedPoliciesGlob().containsAll(List.of(DISALLOWED_POLICY_GLOB_1, DISALLOWED_POLICY_GLOB_2, DISALLOWED_POLICY_GLOB_3)));
|
||||
assertEquals(ORPHAN, role.getOrphan());
|
||||
assertEquals(RENEWABLE, role.getRenewable());
|
||||
assertEquals(PATH_SUFFIX, role.getPathSuffix());
|
||||
assertEquals(ALLOWED_ENTITY_ALIASES.size() + 1, role.getAllowedEntityAliases().size());
|
||||
assertTrue(role.getAllowedEntityAliases().containsAll(List.of(ALLOWED_ENTITY_ALIAS_1, ALLOWED_ENTITY_ALIAS_2, ALLOWED_ENTITY_ALIAS_3)));
|
||||
assertEquals(TOKEN_BOUND_CIDRS.size() + 1, role.getTokenBoundCidrs().size());
|
||||
assertTrue(role.getTokenBoundCidrs().containsAll(List.of(TOKEN_BOUND_CIDR_1, TOKEN_BOUND_CIDR_2, TOKEN_BOUND_CIDR_3)));
|
||||
assertEquals(TOKEN_NO_DEFAULT_POLICY, role.getTokenNoDefaultPolicy());
|
||||
assertEquals(TOKEN_NUM_USES, role.getTokenNumUses());
|
||||
assertEquals(TOKEN_PERIOD, role.getTokenPeriod());
|
||||
assertEquals(TOKEN_TYPE.value(), role.getTokenType());
|
||||
|
||||
// Verify that all parameters are included in JSON string.
|
||||
assertEquals(JSON_FULL, objectMapper.writeValueAsString(role));
|
||||
}
|
||||
}
|
181
src/test/java/de/stklcode/jvault/connector/model/TokenTest.java
Normal file
181
src/test/java/de/stklcode/jvault/connector/model/TokenTest.java
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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 org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link Token} and {@link Token.Builder}.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.4.0
|
||||
*/
|
||||
class TokenTest extends AbstractModelTest<Token> {
|
||||
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 EXPLICIT_MAX_TTL = 456;
|
||||
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 Integer PERIOD = 3600;
|
||||
private static final String ENTITY_ALIAS = "alias-value";
|
||||
private static final String JSON_FULL = "{\"id\":\"test-id\",\"type\":\"service\",\"display_name\":\"display-name\",\"no_parent\":false,\"no_default_policy\":false,\"ttl\":123,\"explicit_max_ttl\":456,\"num_uses\":4,\"policies\":[\"policy\"],\"meta\":{\"key\":\"value\"},\"renewable\":true,\"period\":3600,\"entity_alias\":\"alias-value\"}";
|
||||
|
||||
TokenTest() {
|
||||
super(Token.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Token createFull() {
|
||||
return Token.builder()
|
||||
.withId(ID)
|
||||
.withType(Token.Type.SERVICE)
|
||||
.withDisplayName(DISPLAY_NAME)
|
||||
.withNoParent(NO_PARENT)
|
||||
.withNoDefaultPolicy(NO_DEFAULT_POLICY)
|
||||
.withTtl(TTL)
|
||||
.withExplicitMaxTtl(EXPLICIT_MAX_TTL)
|
||||
.withNumUses(NUM_USES)
|
||||
.withPolicies(POLICIES)
|
||||
.withMeta(META)
|
||||
.withRenewable(RENEWABLE)
|
||||
.withPeriod(PERIOD)
|
||||
.withEntityAlias(ENTITY_ALIAS)
|
||||
.build();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
static void init() {
|
||||
POLICIES.add(POLICY);
|
||||
META.put(META_KEY, META_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build token without any parameters.
|
||||
*/
|
||||
@Test
|
||||
void buildDefaultTest() throws JsonProcessingException {
|
||||
Token token = Token.builder().build();
|
||||
assertNull(token.getId());
|
||||
assertNull(token.getType());
|
||||
assertNull(token.getDisplayName());
|
||||
assertNull(token.getNoParent());
|
||||
assertNull(token.getNoDefaultPolicy());
|
||||
assertNull(token.getTtl());
|
||||
assertNull(token.getExplicitMaxTtl());
|
||||
assertNull(token.getNumUses());
|
||||
assertNull(token.getPolicies());
|
||||
assertNull(token.getMeta());
|
||||
assertNull(token.isRenewable());
|
||||
assertNull(token.getPeriod());
|
||||
assertNull(token.getEntityAlias());
|
||||
|
||||
// Optional fields should be ignored, so JSON string should be empty.
|
||||
assertEquals("{}", objectMapper.writeValueAsString(token));
|
||||
|
||||
// Empty builder should be equal to no-arg construction.
|
||||
assertEquals(new Token(), token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build token without all parameters set.
|
||||
*/
|
||||
@Test
|
||||
void buildFullTest() throws JsonProcessingException {
|
||||
Token token = createFull();
|
||||
assertEquals(ID, token.getId());
|
||||
assertEquals(Token.Type.SERVICE.value(), token.getType());
|
||||
assertEquals(DISPLAY_NAME, token.getDisplayName());
|
||||
assertEquals(NO_PARENT, token.getNoParent());
|
||||
assertEquals(NO_DEFAULT_POLICY, token.getNoDefaultPolicy());
|
||||
assertEquals(TTL, token.getTtl());
|
||||
assertEquals(EXPLICIT_MAX_TTL, token.getExplicitMaxTtl());
|
||||
assertEquals(NUM_USES, token.getNumUses());
|
||||
assertEquals(POLICIES, token.getPolicies());
|
||||
assertEquals(META, token.getMeta());
|
||||
assertEquals(RENEWABLE, token.isRenewable());
|
||||
assertEquals(PERIOD, token.getPeriod());
|
||||
|
||||
// Verify that all parameters are included in JSON string.
|
||||
assertEquals(JSON_FULL, objectMapper.writeValueAsString(token));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test convenience methods
|
||||
*/
|
||||
@Test
|
||||
void convenienceMethodsTest() {
|
||||
// Parent.
|
||||
Token token = Token.builder().asOrphan().build();
|
||||
assertEquals(true, token.getNoParent());
|
||||
token = Token.builder().withParent().build();
|
||||
assertEquals(false, token.getNoParent());
|
||||
|
||||
// Default policy.
|
||||
token = Token.builder().withDefaultPolicy().build();
|
||||
assertEquals(false, token.getNoDefaultPolicy());
|
||||
token = Token.builder().withoutDefaultPolicy().build();
|
||||
assertEquals(true, token.getNoDefaultPolicy());
|
||||
|
||||
// Renewability.
|
||||
token = Token.builder().renewable().build();
|
||||
assertEquals(true, token.isRenewable());
|
||||
token = Token.builder().notRenewable().build();
|
||||
assertEquals(false, token.isRenewable());
|
||||
|
||||
// Add single policy.
|
||||
token = Token.builder().withPolicy(POLICY_2).build();
|
||||
assertEquals(1, token.getPolicies().size());
|
||||
assertEquals(List.of(POLICY_2), token.getPolicies());
|
||||
token = Token.builder()
|
||||
.withPolicies(POLICY, POLICY_2)
|
||||
.withPolicy(POLICY_3)
|
||||
.build();
|
||||
assertEquals(3, token.getPolicies().size());
|
||||
assertTrue(token.getPolicies().containsAll(List.of(POLICY, POLICY_2, POLICY_3)));
|
||||
|
||||
// Add single metadata.
|
||||
token = Token.builder().withMeta(META_KEY_2, META_VALUE_2).build();
|
||||
assertEquals(1, token.getMeta().size());
|
||||
assertEquals(Set.of(META_KEY_2), token.getMeta().keySet());
|
||||
assertEquals(META_VALUE_2, token.getMeta().get(META_KEY_2));
|
||||
token = Token.builder()
|
||||
.withMeta(META)
|
||||
.withMeta(META_KEY_2, META_VALUE_2)
|
||||
.build();
|
||||
assertEquals(2, token.getMeta().size());
|
||||
assertEquals(META_VALUE, token.getMeta().get(META_KEY));
|
||||
assertEquals(META_VALUE_2, token.getMeta().get(META_KEY_2));
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import de.stklcode.jvault.connector.model.AppRole;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link AppRoleResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.6.2
|
||||
*/
|
||||
class AppRoleResponseTest extends AbstractModelTest<AppRoleResponse> {
|
||||
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" +
|
||||
" \"token_policies\": [\n" +
|
||||
" \"" + ROLE_POLICY + "\"\n" +
|
||||
" ],\n" +
|
||||
" \"token_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" +
|
||||
"}";
|
||||
|
||||
AppRoleResponseTest() {
|
||||
super(AppRoleResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AppRoleResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(RES_JSON, AppRoleResponse.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getter, setter and get-methods for response data.
|
||||
*/
|
||||
@Test
|
||||
void getDataRoundtrip() {
|
||||
// Create empty Object.
|
||||
AppRoleResponse res = new AppRoleResponse();
|
||||
assertNull(res.getRole(), "Initial data should be empty");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
void jsonRoundtrip() {
|
||||
AppRoleResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(RES_JSON, AppRoleResponse.class),
|
||||
"AuthResponse deserialization failed"
|
||||
);
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
// Extract role data.
|
||||
AppRole role = res.getRole();
|
||||
assertNotNull(role, "Role data is NULL");
|
||||
assertEquals(ROLE_TOKEN_TTL, role.getTokenTtl(), "Incorrect token TTL");
|
||||
assertEquals(ROLE_TOKEN_MAX_TTL, role.getTokenMaxTtl(), "Incorrect token max TTL");
|
||||
assertEquals(ROLE_SECRET_TTL, role.getSecretIdTtl(), "Incorrect secret ID TTL");
|
||||
assertEquals(ROLE_SECRET_NUM_USES, role.getSecretIdNumUses(), "Incorrect secret ID umber of uses");
|
||||
assertEquals(List.of(ROLE_POLICY), role.getTokenPolicies(), "Incorrect policies");
|
||||
assertEquals(ROLE_PERIOD, role.getTokenPeriod(), "Incorrect role period");
|
||||
assertEquals(ROLE_BIND_SECRET, role.getBindSecretId(), "Incorrect role bind secret ID flag");
|
||||
assertNull(role.getTokenBoundCidrs(), "Incorrect bound CIDR list");
|
||||
assertEquals("", role.getTokenBoundCidrsString(), "Incorrect bound CIDR list string");
|
||||
}
|
||||
}
|
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import de.stklcode.jvault.connector.model.AuthBackend;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.AuthMethod;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link AuthMethodsResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.6.2
|
||||
*/
|
||||
class AuthMethodsResponseTest extends AbstractModelTest<AuthMethodsResponse> {
|
||||
private static final String GH_PATH = "github/";
|
||||
private static final String GH_TYPE = "github";
|
||||
private static final String GH_UUID = "4b42d1a4-0a0d-3c88-ae90-997e0c8b41be";
|
||||
private static final String GH_ACCESSOR = "auth_github_badd7fd0";
|
||||
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_UUID = "32ea9681-6bd6-6cec-eec3-d11260ba9741";
|
||||
private static final String TK_ACCESSOR = "auth_token_ac0dd95a";
|
||||
private static final String TK_DESCR = "token based credentials";
|
||||
private static final Integer TK_LEASE_TTL = 0;
|
||||
private static final Boolean TK_FORCE_NO_CACHE = false;
|
||||
private static final Integer TK_MAX_LEASE_TTL = 0;
|
||||
private static final String TK_TOKEN_TYPE = "default-service";
|
||||
private static final String TK_RUNNING_PLUGIN_VERSION = "v1.15.3+builtin.vault";
|
||||
|
||||
private static final String RES_JSON = "{\n" +
|
||||
" \"data\": {" +
|
||||
" \"" + GH_PATH + "\": {\n" +
|
||||
" \"uuid\": \"" + GH_UUID + "\",\n" +
|
||||
" \"type\": \"" + GH_TYPE + "\",\n" +
|
||||
" \"accessor\": \"" + GH_ACCESSOR + "\",\n" +
|
||||
" \"description\": \"" + GH_DESCR + "\",\n" +
|
||||
" \"external_entropy_access\": false,\n" +
|
||||
" \"local\": false,\n" +
|
||||
" \"seal_wrap\": false\n" +
|
||||
" },\n" +
|
||||
" \"" + TK_PATH + "\": {\n" +
|
||||
" \"config\": {\n" +
|
||||
" \"default_lease_ttl\": " + TK_LEASE_TTL + ",\n" +
|
||||
" \"force_no_cache\": " + TK_FORCE_NO_CACHE + ",\n" +
|
||||
" \"max_lease_ttl\": " + TK_MAX_LEASE_TTL + ",\n" +
|
||||
" \"token_type\": \"" + TK_TOKEN_TYPE + "\"\n" +
|
||||
" },\n" +
|
||||
" \"description\": \"" + TK_DESCR + "\",\n" +
|
||||
" \"options\": null,\n" +
|
||||
" \"plugin_version\": \"\",\n" +
|
||||
" \"running_plugin_version\": \"" + TK_RUNNING_PLUGIN_VERSION + "\",\n" +
|
||||
" \"running_sha256\": \"\",\n" +
|
||||
" \"type\": \"" + TK_TYPE + "\",\n" +
|
||||
" \"uuid\": \"" + TK_UUID + "\",\n" +
|
||||
" \"accessor\": \"" + TK_ACCESSOR + "\",\n" +
|
||||
" \"external_entropy_access\": false,\n" +
|
||||
" \"local\": true,\n" +
|
||||
" \"seal_wrap\": false\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
AuthMethodsResponseTest() {
|
||||
super(AuthMethodsResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthMethodsResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(RES_JSON, AuthMethodsResponse.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getter, setter and get-methods for response data.
|
||||
*/
|
||||
@Test
|
||||
void getDataRoundtrip() {
|
||||
// Create empty Object.
|
||||
AuthMethodsResponse res = new AuthMethodsResponse();
|
||||
assertEquals(Collections.emptyMap(), res.getSupportedMethods(), "Initial method map should be empty");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
void jsonRoundtrip() {
|
||||
AuthMethodsResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(RES_JSON, AuthMethodsResponse.class),
|
||||
"AuthResponse deserialization failed"
|
||||
);
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
// Extract auth data.
|
||||
Map<String, AuthMethod> supported = res.getSupportedMethods();
|
||||
assertNotNull(supported, "Auth data is NULL");
|
||||
assertEquals(2, supported.size(), "Incorrect number of supported methods");
|
||||
assertTrue(supported.keySet().containsAll(Set.of(GH_PATH, TK_PATH)), "Incorrect method paths");
|
||||
|
||||
// Verify first method.
|
||||
AuthMethod method = supported.get(GH_PATH);
|
||||
assertEquals(GH_TYPE, method.getRawType(), "Incorrect raw type for GitHub");
|
||||
assertEquals(AuthBackend.GITHUB, method.getType(), "Incorrect parsed type for GitHub");
|
||||
assertEquals(GH_DESCR, method.getDescription(), "Incorrect description for GitHub");
|
||||
assertNull(method.getConfig(), "Unexpected config for GitHub");
|
||||
assertEquals(GH_UUID, method.getUuid(), "Unexpected UUID for GitHub");
|
||||
assertEquals(GH_ACCESSOR, method.getAccessor(), "Unexpected accessor for GitHub");
|
||||
assertFalse(method.isLocal(), "Unexpected local flag for GitHub");
|
||||
assertFalse(method.isExternalEntropyAccess(), "Unexpected external entropy flag for GitHub");
|
||||
assertFalse(method.isSealWrap(), "Unexpected seal wrap flag for GitHub");
|
||||
|
||||
// Verify second method.
|
||||
method = supported.get(TK_PATH);
|
||||
assertEquals(TK_TYPE, method.getRawType(), "Incorrect raw type for Token");
|
||||
assertEquals(AuthBackend.TOKEN, method.getType(), "Incorrect parsed type for Token");
|
||||
assertEquals(TK_DESCR, method.getDescription(), "Incorrect description for Token");
|
||||
assertEquals(TK_UUID, method.getUuid(), "Unexpected UUID for Token");
|
||||
assertEquals(TK_ACCESSOR, method.getAccessor(), "Unexpected accessor for Token");
|
||||
assertTrue(method.isLocal(), "Unexpected local flag for Token");
|
||||
assertFalse(method.isExternalEntropyAccess(), "Unexpected external entropy flag for Token");
|
||||
assertFalse(method.isSealWrap(), "Unexpected seal wrap flag for GitHub");
|
||||
assertEquals("", method.getPluginVersion(), "Unexpected plugin version");
|
||||
assertEquals(TK_RUNNING_PLUGIN_VERSION, method.getRunningPluginVersion(), "Unexpected running plugin version");
|
||||
assertEquals("", method.getRunningSha256(), "Unexpected running SHA256");
|
||||
|
||||
assertNotNull(method.getConfig(), "Missing config for Token");
|
||||
assertEquals(TK_LEASE_TTL, method.getConfig().getDefaultLeaseTtl(), "Unexpected default TTL");
|
||||
assertEquals(TK_MAX_LEASE_TTL, method.getConfig().getMaxLeaseTtl(), "Unexpected max TTL");
|
||||
assertEquals(TK_FORCE_NO_CACHE, method.getConfig().getForceNoCache(), "Unexpected force no cache flag");
|
||||
assertEquals(TK_TOKEN_TYPE, method.getConfig().getTokenType(), "Unexpected token type");
|
||||
|
||||
assertNull(method.getOptions(), "Unexpected options");
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.AuthData;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.MfaConstraintAny;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.MfaMethodId;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.MfaRequirement;
|
||||
import nl.jqno.equalsverifier.EqualsVerifier;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link AuthResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.6.2
|
||||
*/
|
||||
class AuthResponseTest extends AbstractModelTest<AuthResponse> {
|
||||
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 AUTH_ENTITY_ID = "";
|
||||
private static final String AUTH_TOKEN_TYPE = "service";
|
||||
private static final Boolean AUTH_ORPHAN = false;
|
||||
private static final Integer AUTH_NUM_USES = 42;
|
||||
private static final String MFA_REQUEST_ID = "d0c9eec7-6921-8cc0-be62-202b289ef163";
|
||||
private static final String MFA_KEY = "enforcementConfigUserpass";
|
||||
private static final String MFA_METHOD_TYPE = "totp";
|
||||
private static final String MFA_METHOD_ID = "820997b3-110e-c251-7e8b-ff4aa428a6e1";
|
||||
private static final Boolean MFA_METHOD_USES_PASSCODE = true;
|
||||
private static final String MFA_METHOD_NAME = "sample_mfa_method_name";
|
||||
|
||||
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" +
|
||||
" \"token_policies\": [\n" +
|
||||
" \"" + AUTH_POLICY_2 + "\",\n" +
|
||||
" \"" + AUTH_POLICY_1 + "\" \n" +
|
||||
" ],\n" +
|
||||
" \"metadata\": {\n" +
|
||||
" \"" + AUTH_META_KEY + "\": \"" + AUTH_META_VALUE + "\"\n" +
|
||||
" },\n" +
|
||||
" \"lease_duration\": " + AUTH_LEASE_DURATION + ",\n" +
|
||||
" \"renewable\": " + AUTH_RENEWABLE + ",\n" +
|
||||
" \"entity_id\": \"" + AUTH_ENTITY_ID + "\",\n" +
|
||||
" \"token_type\": \"" + AUTH_TOKEN_TYPE + "\",\n" +
|
||||
" \"orphan\": " + AUTH_ORPHAN + ",\n" +
|
||||
" \"num_uses\": " + AUTH_NUM_USES + ",\n" +
|
||||
" \"mfa_requirement\": {\n" +
|
||||
" \"mfa_request_id\": \"" + MFA_REQUEST_ID + "\",\n" +
|
||||
" \"mfa_constraints\": {\n" +
|
||||
" \"" + MFA_KEY + "\": {\n" +
|
||||
" \"any\": [\n" +
|
||||
" {\n" +
|
||||
" \"type\": \"" + MFA_METHOD_TYPE + "\",\n" +
|
||||
" \"id\": \"" + MFA_METHOD_ID + "\",\n" +
|
||||
" \"uses_passcode\": " + MFA_METHOD_USES_PASSCODE + ",\n" +
|
||||
" \"name\": \"" + MFA_METHOD_NAME + "\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
AuthResponseTest() {
|
||||
super(AuthResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(RES_JSON, AuthResponse.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEqualsHashcodeMfa() {
|
||||
EqualsVerifier.simple().forClass(MfaRequirement.class).verify();
|
||||
EqualsVerifier.simple().forClass(MfaConstraintAny.class).verify();
|
||||
EqualsVerifier.simple().forClass(MfaMethodId.class).verify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
void jsonRoundtrip() {
|
||||
AuthResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(RES_JSON, AuthResponse.class),
|
||||
"AuthResponse deserialization failed"
|
||||
);
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
// Extract auth data.
|
||||
AuthData data = res.getAuth();
|
||||
assertNotNull(data, "Auth data is NULL");
|
||||
assertEquals(AUTH_ACCESSOR, data.getAccessor(), "Incorrect auth accessor");
|
||||
assertEquals(AUTH_CLIENT_TOKEN, data.getClientToken(), "Incorrect auth client token");
|
||||
assertEquals(AUTH_LEASE_DURATION, data.getLeaseDuration(), "Incorrect auth lease duration");
|
||||
assertEquals(AUTH_RENEWABLE, data.isRenewable(), "Incorrect auth renewable flag");
|
||||
assertEquals(AUTH_ORPHAN, data.isOrphan(), "Incorrect auth orphan flag");
|
||||
assertEquals(AUTH_TOKEN_TYPE, data.getTokenType(), "Incorrect auth token type");
|
||||
assertEquals(AUTH_ENTITY_ID, data.getEntityId(), "Incorrect auth entity id");
|
||||
assertEquals(AUTH_NUM_USES, data.getNumUses(), "Incorrect auth num uses");
|
||||
assertEquals(2, data.getPolicies().size(), "Incorrect number of policies");
|
||||
assertTrue(data.getPolicies().containsAll(Set.of(AUTH_POLICY_1, AUTH_POLICY_2)));
|
||||
assertEquals(2, data.getTokenPolicies().size(), "Incorrect number of token policies");
|
||||
assertTrue(data.getTokenPolicies().containsAll(Set.of(AUTH_POLICY_2, AUTH_POLICY_1)), "Incorrect token policies");
|
||||
assertEquals(Map.of(AUTH_META_KEY, AUTH_META_VALUE), data.getMetadata(), "Incorrect auth metadata");
|
||||
|
||||
assertEquals(MFA_REQUEST_ID, data.getMfaRequirement().getMfaRequestId(), "Incorrect MFA request ID");
|
||||
assertEquals(Set.of(MFA_KEY), data.getMfaRequirement().getMfaConstraints().keySet(), "Incorrect MFA constraint keys");
|
||||
var mfaConstraint = data.getMfaRequirement().getMfaConstraints().get(MFA_KEY);
|
||||
assertEquals(1, mfaConstraint.getAny().size(), "Incorrect number of any constraints");
|
||||
assertEquals(MFA_METHOD_TYPE, mfaConstraint.getAny().get(0).getType(), "Incorrect MFA method type");
|
||||
assertEquals(MFA_METHOD_ID, mfaConstraint.getAny().get(0).getId(), "Incorrect MFA method type");
|
||||
assertEquals(MFA_METHOD_USES_PASSCODE, mfaConstraint.getAny().get(0).getUsesPasscode(), "Incorrect MFA method uses passcode");
|
||||
assertEquals(MFA_METHOD_NAME, mfaConstraint.getAny().get(0).getName(), "Incorrect MFA method uses passcode");
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link CredentialsResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.8
|
||||
*/
|
||||
class CredentialsResponseTest extends AbstractModelTest<CredentialsResponse> {
|
||||
private static final String VAL_USER = "testUserName";
|
||||
private static final String VAL_PASS = "5up3r5ecr3tP455";
|
||||
private static final String JSON = "{\n" +
|
||||
" \"request_id\": \"68315073-6658-e3ff-2da7-67939fb91bbd\",\n" +
|
||||
" \"lease_id\": \"\",\n" +
|
||||
" \"lease_duration\": 2764800,\n" +
|
||||
" \"renewable\": false,\n" +
|
||||
" \"data\": {\n" +
|
||||
" \"username\": \"" + VAL_USER + "\",\n" +
|
||||
" \"password\": \"" + VAL_PASS + "\"\n" +
|
||||
" },\n" +
|
||||
" \"warnings\": null\n" +
|
||||
"}";
|
||||
|
||||
CredentialsResponseTest() {
|
||||
super(CredentialsResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CredentialsResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(JSON, CredentialsResponse.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getter, setter and get-methods for response data.
|
||||
*/
|
||||
@Test
|
||||
void getCredentialsTest() {
|
||||
// Create empty Object.
|
||||
CredentialsResponse res = new CredentialsResponse();
|
||||
assertNull(res.getUsername(), "Username not present in data map should not return anything");
|
||||
assertNull(res.getPassword(), "Password not present in data map should not return anything");
|
||||
|
||||
res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(JSON, CredentialsResponse.class),
|
||||
"Deserialization of CredentialsResponse failed"
|
||||
);
|
||||
assertEquals(VAL_USER, res.getUsername(), "Incorrect username");
|
||||
assertEquals(VAL_PASS, res.getPassword(), "Incorrect password");
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link ErrorResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
*/
|
||||
class ErrorResponseTest extends AbstractModelTest<ErrorResponse> {
|
||||
private static final String ERROR_1 = "Error #1";
|
||||
private static final String ERROR_2 = "Error #2";
|
||||
|
||||
private static final String JSON = "{\"errors\":[\"" + ERROR_1 + "\",\"" + ERROR_2 + "\"]}";
|
||||
private static final String JSON_EMPTY = "{\"errors\":[]}";
|
||||
|
||||
ErrorResponseTest() {
|
||||
super(ErrorResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ErrorResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(JSON, ErrorResponse.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault.
|
||||
*/
|
||||
@Test
|
||||
void jsonRoundtrip() {
|
||||
ErrorResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(JSON, ErrorResponse.class),
|
||||
"ErrorResponse deserialization failed"
|
||||
);
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
assertEquals(List.of(ERROR_1, ERROR_2), res.getErrors(), "Unexpected error messages");
|
||||
assertEquals(
|
||||
JSON,
|
||||
assertDoesNotThrow(() -> objectMapper.writeValueAsString(res), "ErrorResponse serialization failed"),
|
||||
"Unexpected JSON string after serialization"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testToString() {
|
||||
ErrorResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(JSON, ErrorResponse.class),
|
||||
"ErrorResponse deserialization failed"
|
||||
);
|
||||
assertEquals(ERROR_1, res.toString());
|
||||
|
||||
res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(JSON_EMPTY, ErrorResponse.class),
|
||||
"ErrorResponse deserialization failed with empty list"
|
||||
);
|
||||
assertEquals("error response", res.toString());
|
||||
|
||||
assertEquals("error response", new ErrorResponse().toString());
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link AuthResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.7.0
|
||||
*/
|
||||
class HealthResponseTest extends AbstractModelTest<HealthResponse> {
|
||||
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.17.0";
|
||||
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 Boolean PERF_STANDBY = false;
|
||||
private static final String REPL_PERF_MODE = "disabled";
|
||||
private static final String REPL_DR_MODE = "disabled";
|
||||
private static final Long ECHO_DURATION = 1L;
|
||||
private static final Long CLOCK_SKEW = 0L;
|
||||
private static final Long REPL_PRIM_CANARY_AGE = 2L;
|
||||
private static final Boolean ENTERPRISE = false;
|
||||
|
||||
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" +
|
||||
" \"replication_performance_mode\": \"" + REPL_PERF_MODE + "\",\n" +
|
||||
" \"replication_dr_mode\": \"" + REPL_DR_MODE + "\",\n" +
|
||||
" \"performance_standby\": " + PERF_STANDBY + ",\n" +
|
||||
" \"echo_duration_ms\": " + ECHO_DURATION + ",\n" +
|
||||
" \"clock_skew_ms\": " + CLOCK_SKEW + ",\n" +
|
||||
" \"replication_primary_canary_age_ms\": " + REPL_PRIM_CANARY_AGE + ",\n" +
|
||||
" \"enterprise\": " + ENTERPRISE + "\n" +
|
||||
"}";
|
||||
|
||||
HealthResponseTest() {
|
||||
super(HealthResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HealthResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(RES_JSON, HealthResponse.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
void jsonRoundtrip() {
|
||||
HealthResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(RES_JSON, HealthResponse.class),
|
||||
"Health deserialization failed"
|
||||
);
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
assertEquals(CLUSTER_ID, res.getClusterID(), "Incorrect cluster ID");
|
||||
assertEquals(CLUSTER_NAME, res.getClusterName(), "Incorrect cluster name");
|
||||
assertEquals(VERSION, res.getVersion(), "Incorrect version");
|
||||
assertEquals(SERVER_TIME_UTC, res.getServerTimeUTC(), "Incorrect server time");
|
||||
assertEquals(STANDBY, res.isStandby(), "Incorrect standby state");
|
||||
assertEquals(SEALED, res.isSealed(), "Incorrect seal state");
|
||||
assertEquals(INITIALIZED, res.isInitialized(), "Incorrect initialization state");
|
||||
assertEquals(PERF_STANDBY, res.isPerformanceStandby(), "Incorrect performance standby state");
|
||||
assertEquals(REPL_PERF_MODE, res.getReplicationPerfMode(), "Incorrect replication perf mode");
|
||||
assertEquals(REPL_DR_MODE, res.getReplicationDrMode(), "Incorrect replication DR mode");
|
||||
assertEquals(ECHO_DURATION, res.getEchoDurationMs(), "Incorrect echo duration");
|
||||
assertEquals(CLOCK_SKEW, res.getClockSkewMs(), "Incorrect clock skew");
|
||||
assertEquals(REPL_PRIM_CANARY_AGE, res.getReplicationPrimaryCanaryAgeMs(), "Incorrect canary age");
|
||||
assertEquals(ENTERPRISE, res.isEnterprise(), "Incorrect enterprise flag");
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link HelpResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
*/
|
||||
class HelpResponseTest extends AbstractModelTest<HelpResponse> {
|
||||
private static final String HELP = "Help Text.";
|
||||
|
||||
private static final String JSON = "{\"help\":\"" + HELP + "\"}";
|
||||
|
||||
HelpResponseTest() {
|
||||
super(HelpResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HelpResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(JSON, HelpResponse.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault.
|
||||
*/
|
||||
@Test
|
||||
void jsonRoundtrip() {
|
||||
HelpResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(JSON, HelpResponse.class),
|
||||
"HelpResponse deserialization failed"
|
||||
);
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
assertEquals(HELP, res.getHelp(), "Unexpected help text");
|
||||
assertEquals(
|
||||
JSON,
|
||||
assertDoesNotThrow(() -> objectMapper.writeValueAsString(res), "HelpResponse serialization failed"),
|
||||
"Unexpected JSON string after serialization"
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link MetaSecretResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.6.2
|
||||
*/
|
||||
class MetaSecretResponseTest extends AbstractModelTest<MetaSecretResponse> {
|
||||
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 String SECRET_META_CREATED = "2018-03-22T02:24:06.945319214Z";
|
||||
private static final String SECRET_META_DELETED = "2018-03-23T03:25:07.056420325Z";
|
||||
private static final List<String> SECRET_WARNINGS = null;
|
||||
private static final String CUSTOM_META_KEY = "foo";
|
||||
private static final String CUSTOM_META_VAL = "bar";
|
||||
|
||||
private static final String SECRET_JSON_V2 = "{\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" +
|
||||
" \"data\": {\n" +
|
||||
" \"" + SECRET_DATA_K1 + "\": \"" + SECRET_DATA_V1 + "\",\n" +
|
||||
" \"" + SECRET_DATA_K2 + "\": \"" + SECRET_DATA_V2 + "\"\n" +
|
||||
" },\n" +
|
||||
" \"metadata\": {\n" +
|
||||
" \"created_time\": \"" + SECRET_META_CREATED + "\",\n" +
|
||||
" \"custom_metadata\": null,\n" +
|
||||
" \"deletion_time\": \"\",\n" +
|
||||
" \"destroyed\": false,\n" +
|
||||
" \"version\": 1\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"warnings\": " + SECRET_WARNINGS + "\n" +
|
||||
"}";
|
||||
private static final String SECRET_JSON_V2_2 = "{\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" +
|
||||
" \"data\": {\n" +
|
||||
" \"" + SECRET_DATA_K1 + "\": \"" + SECRET_DATA_V1 + "\",\n" +
|
||||
" \"" + SECRET_DATA_K2 + "\": \"" + SECRET_DATA_V2 + "\"\n" +
|
||||
" },\n" +
|
||||
" \"metadata\": {\n" +
|
||||
" \"created_time\": \"" + SECRET_META_CREATED + "\",\n" +
|
||||
" \"custom_metadata\": {" +
|
||||
" \"" + CUSTOM_META_KEY + "\": \"" + CUSTOM_META_VAL + "\"" +
|
||||
" },\n" +
|
||||
" \"deletion_time\": \"" + SECRET_META_DELETED + "\",\n" +
|
||||
" \"destroyed\": true,\n" +
|
||||
" \"version\": 2\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"warnings\": " + SECRET_WARNINGS + "\n" +
|
||||
"}";
|
||||
|
||||
MetaSecretResponseTest() {
|
||||
super(MetaSecretResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MetaSecretResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(SECRET_JSON_V2, MetaSecretResponse.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
void jsonRoundtrip() {
|
||||
// KV v2 secret.
|
||||
MetaSecretResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(SECRET_JSON_V2, MetaSecretResponse.class),
|
||||
"SecretResponse deserialization failed"
|
||||
);
|
||||
assertSecretData(res);
|
||||
assertNotNull(res.getMetadata(), "SecretResponse does not contain metadata");
|
||||
assertNotNull(res.getMetadata().getCreatedTime(), "Creation date parsing failed");
|
||||
assertNull(res.getMetadata().getDeletionTime(), "Incorrect deletion date");
|
||||
assertFalse(res.getMetadata().isDestroyed(), "Secret destroyed when not expected");
|
||||
assertEquals(1, res.getMetadata().getVersion(), "Incorrect secret version");
|
||||
assertNull(res.getMetadata().getCustomMetadata(), "Incorrect custom metadata");
|
||||
|
||||
// Deleted KV v2 secret.
|
||||
res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(SECRET_JSON_V2_2, MetaSecretResponse.class),
|
||||
"SecretResponse deserialization failed"
|
||||
);
|
||||
assertSecretData(res);
|
||||
assertNotNull(res.getMetadata(), "SecretResponse does not contain metadata");
|
||||
assertNotNull(res.getMetadata().getCreatedTime(), "Creation date parsing failed");
|
||||
assertNotNull(res.getMetadata().getDeletionTime(), "Incorrect deletion date");
|
||||
assertTrue(res.getMetadata().isDestroyed(), "Secret destroyed when not expected");
|
||||
assertEquals(2, res.getMetadata().getVersion(), "Incorrect secret version");
|
||||
assertEquals(Map.of(CUSTOM_META_KEY, CUSTOM_META_VAL), res.getMetadata().getCustomMetadata(), "Incorrect custom metadata");
|
||||
}
|
||||
|
||||
private void assertSecretData(SecretResponse res) {
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
assertEquals(SECRET_REQUEST_ID, res.getRequestId(), "Incorrect request ID");
|
||||
assertEquals(SECRET_LEASE_ID, res.getLeaseId(), "Incorrect lease ID");
|
||||
assertEquals(SECRET_LEASE_DURATION, res.getLeaseDuration(), "Incorrect lease duration");
|
||||
assertEquals(SECRET_RENEWABLE, res.isRenewable(), "Incorrect renewable status");
|
||||
assertEquals(SECRET_WARNINGS, res.getWarnings(), "Incorrect warnings");
|
||||
assertEquals(SECRET_DATA_V1, res.get(SECRET_DATA_K1), "Response does not contain correct data");
|
||||
assertEquals(SECRET_DATA_V2, res.get(SECRET_DATA_K2), "Response does not contain correct data");
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link MetadataResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.8
|
||||
*/
|
||||
class MetadataResponseTest extends AbstractModelTest<MetadataResponse> {
|
||||
private static final String V1_TIME = "2018-03-22T02:24:06.945319214Z";
|
||||
private static final String V3_TIME = "2018-03-22T02:36:43.986212308Z";
|
||||
private static final String V2_TIME = "2018-03-22T02:36:33.954880664Z";
|
||||
private static final Integer CURRENT_VERSION = 3;
|
||||
private static final Integer MAX_VERSIONS = 0;
|
||||
private static final Integer OLDEST_VERSION = 1;
|
||||
private static final Boolean CAS_REQUIRED = false;
|
||||
private static final String CUSTOM_META_KEY = "test";
|
||||
private static final String CUSTOM_META_VAL = "123";
|
||||
private static final String DELETE_VERSION_AFTER = "0s";
|
||||
|
||||
private static final String META_JSON = "{\n" +
|
||||
" \"data\": {\n" +
|
||||
" \"cas_required\": " + CAS_REQUIRED + ",\n" +
|
||||
" \"created_time\": \"" + V1_TIME + "\",\n" +
|
||||
" \"current_version\": " + CURRENT_VERSION + ",\n" +
|
||||
" \"custom_metadata\": {" +
|
||||
" \"" + CUSTOM_META_KEY + "\": \"" + CUSTOM_META_VAL + "\"" +
|
||||
" },\n" +
|
||||
" \"delete_version_after\": \"" + DELETE_VERSION_AFTER + "\"," +
|
||||
" \"max_versions\": " + MAX_VERSIONS + ",\n" +
|
||||
" \"oldest_version\": " + OLDEST_VERSION + ",\n" +
|
||||
" \"updated_time\": \"" + V3_TIME + "\",\n" +
|
||||
" \"versions\": {\n" +
|
||||
" \"1\": {\n" +
|
||||
" \"created_time\": \"" + V1_TIME + "\",\n" +
|
||||
" \"deletion_time\": \"" + V2_TIME + "\",\n" +
|
||||
" \"destroyed\": true\n" +
|
||||
" },\n" +
|
||||
" \"2\": {\n" +
|
||||
" \"created_time\": \"" + V2_TIME + "\",\n" +
|
||||
" \"deletion_time\": \"\",\n" +
|
||||
" \"destroyed\": false\n" +
|
||||
" },\n" +
|
||||
" \"3\": {\n" +
|
||||
" \"created_time\": \"" + V3_TIME + "\",\n" +
|
||||
" \"deletion_time\": \"\",\n" +
|
||||
" \"destroyed\": false\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
MetadataResponseTest() {
|
||||
super(MetadataResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MetadataResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(META_JSON, MetadataResponse.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
void jsonRoundtrip() {
|
||||
MetadataResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(META_JSON, MetadataResponse.class),
|
||||
"MetadataResponse deserialization failed"
|
||||
);
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
assertNotNull(res.getMetadata(), "Parsed metadata is NULL");
|
||||
assertEquals(CAS_REQUIRED, res.getMetadata().isCasRequired(), "Incorrect CAS required flag");
|
||||
assertNotNull(res.getMetadata().getCreatedTime(), "Parting created time failed");
|
||||
assertEquals(CURRENT_VERSION, res.getMetadata().getCurrentVersion(), "Incorrect current version");
|
||||
assertEquals(MAX_VERSIONS, res.getMetadata().getMaxVersions(), "Incorrect max versions");
|
||||
assertEquals(OLDEST_VERSION, res.getMetadata().getOldestVersion(), "Incorrect oldest version");
|
||||
assertEquals(Map.of(CUSTOM_META_KEY, CUSTOM_META_VAL), res.getMetadata().getCustomMetadata(), "Incorrect custom metadata");
|
||||
assertEquals(DELETE_VERSION_AFTER, res.getMetadata().getDeleteVersionAfter(), "Incorrect delete version after");
|
||||
assertNotNull(res.getMetadata().getUpdatedTime(), "Parting updated time failed");
|
||||
assertEquals(3, res.getMetadata().getVersions().size(), "Incorrect number of versions");
|
||||
assertNotNull(res.getMetadata().getVersions().get(1).getDeletionTime(), "Parsing version delete time failed");
|
||||
assertTrue(res.getMetadata().getVersions().get(1).isDestroyed(), "Incorrect version 1 destroyed state");
|
||||
assertNotNull(res.getMetadata().getVersions().get(2).getCreatedTime(), "Parsing version created failed");
|
||||
assertFalse(res.getMetadata().getVersions().get(3).isDestroyed(), "Incorrect version 3 destroyed state");
|
||||
}
|
||||
}
|
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link PlainSecretResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.6.2
|
||||
*/
|
||||
class PlainSecretResponseTest extends AbstractModelTest<PlainSecretResponse> {
|
||||
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" +
|
||||
"}";
|
||||
|
||||
PlainSecretResponseTest() {
|
||||
super(PlainSecretResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PlainSecretResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(SECRET_JSON, PlainSecretResponse.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
void jsonRoundtrip() {
|
||||
SecretResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(SECRET_JSON, PlainSecretResponse.class),
|
||||
"SecretResponse deserialization failed"
|
||||
);
|
||||
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
assertEquals(SECRET_REQUEST_ID, res.getRequestId(), "Incorrect request ID");
|
||||
assertEquals(SECRET_LEASE_ID, res.getLeaseId(), "Incorrect lease ID");
|
||||
assertEquals(SECRET_LEASE_DURATION, res.getLeaseDuration(), "Incorrect lease duration");
|
||||
assertEquals(SECRET_RENEWABLE, res.isRenewable(), "Incorrect renewable status");
|
||||
assertEquals(SECRET_WARNINGS, res.getWarnings(), "Incorrect warnings");
|
||||
assertEquals(SECRET_DATA_V1, res.get(SECRET_DATA_K1), "Response does not contain correct data");
|
||||
assertEquals(SECRET_DATA_V2, res.get(SECRET_DATA_K2), "Response does not contain correct data");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
void testGetter() {
|
||||
final var stringKey = "string";
|
||||
final var stringVal = "test";
|
||||
|
||||
final var numberKey = "number";
|
||||
final var numberVal = 123.45;
|
||||
|
||||
final var listKey = "list";
|
||||
final var listVal = List.of("foo", "bar");
|
||||
|
||||
final var complexKey = "complex";
|
||||
final var complexVal = new ComplexType("val1", 678);
|
||||
|
||||
SecretResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(
|
||||
"{\n" +
|
||||
" \"request_id\": \"req-id\",\n" +
|
||||
" \"lease_id\": \"lea-id\",\n" +
|
||||
" \"lease_duration\": " + 123456 + ",\n" +
|
||||
" \"renewable\": true,\n" +
|
||||
" \"data\": {\n" +
|
||||
" \"" + stringKey + "\": \"" + stringVal + "\",\n" +
|
||||
" \"" + numberKey + "\": \"" + numberVal + "\",\n" +
|
||||
" \"" + listKey + "\": [\"" + String.join("\", \"", listVal) + "\"],\n" +
|
||||
" \"" + complexKey + "\": {" +
|
||||
" \"field1\": \"" + complexVal.field1 + "\",\n" +
|
||||
" \"field2\": " + complexVal.field2 + "\n" +
|
||||
" },\n" +
|
||||
" \"" + complexKey + "Json\": \"" + objectMapper.writeValueAsString(complexVal).replace("\"", "\\\"") + "\"\n" +
|
||||
" }\n" +
|
||||
"}",
|
||||
PlainSecretResponse.class
|
||||
),
|
||||
"SecretResponse deserialization failed"
|
||||
);
|
||||
|
||||
assertEquals(stringVal, res.get(stringKey), "unexpected value for string (implicit)");
|
||||
assertEquals(
|
||||
stringVal,
|
||||
assertDoesNotThrow(() -> res.get(stringKey, String.class), "getting string failed"),
|
||||
"unexpected value for string (explicit)"
|
||||
);
|
||||
|
||||
assertEquals(String.valueOf(numberVal), res.get(numberKey), "unexpected value for number (implicit)");
|
||||
assertEquals(
|
||||
numberVal,
|
||||
assertDoesNotThrow(() -> res.get(numberKey, Double.class), "getting number failed"),
|
||||
"unexpected value for number (explicit)"
|
||||
);
|
||||
assertEquals(
|
||||
String.valueOf(numberVal),
|
||||
assertDoesNotThrow(() -> res.get(numberKey, String.class), "getting number as string failed"),
|
||||
"unexpected value for number as string (explicit)"
|
||||
);
|
||||
|
||||
assertEquals(listVal, res.get(listKey), "unexpected value for list (implicit)");
|
||||
assertEquals(
|
||||
listVal,
|
||||
assertDoesNotThrow(() -> res.get(listKey, ArrayList.class), "getting list failed"),
|
||||
"unexpected value for list (explicit)"
|
||||
);
|
||||
|
||||
assertEquals(complexVal.toMap(), res.get(complexKey), "unexpected value for complex type (implicit)");
|
||||
assertEquals(
|
||||
complexVal.toMap(),
|
||||
assertDoesNotThrow(() -> res.get(complexKey, HashMap.class), "getting complex type as map failed"),
|
||||
"unexpected value for complex type as map (explicit)"
|
||||
);
|
||||
assertEquals(
|
||||
complexVal,
|
||||
assertDoesNotThrow(() -> res.get(complexKey, ComplexType.class), "getting complex type failed"),
|
||||
"unexpected value for complex type (explicit)"
|
||||
);
|
||||
assertThrows(
|
||||
InvalidResponseException.class,
|
||||
() -> res.get(complexKey, Integer.class),
|
||||
"getting complex type as integer should fail"
|
||||
);
|
||||
assertEquals(
|
||||
complexVal,
|
||||
assertDoesNotThrow(() -> res.get(complexKey + "Json", ComplexType.class), "getting complex type from JSON string failed"),
|
||||
"unexpected value for complex type from JSON string"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test class for complex field mapping.
|
||||
*/
|
||||
private static class ComplexType {
|
||||
@JsonProperty("field1")
|
||||
private String field1;
|
||||
|
||||
@JsonProperty("field2")
|
||||
private Integer field2;
|
||||
|
||||
private ComplexType() {
|
||||
// Required for JSON deserialization.
|
||||
}
|
||||
|
||||
private ComplexType(String field1, Integer field2) {
|
||||
this.field1 = field1;
|
||||
this.field2 = field2;
|
||||
}
|
||||
|
||||
private Map<String, Object> toMap() {
|
||||
return Map.of(
|
||||
"field1", field1,
|
||||
"field2", field2
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ComplexType that = (ComplexType) o;
|
||||
return Objects.equals(field1, that.field1) && Objects.equals(field2, that.field2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(field1, field2);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link SealResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.8
|
||||
*/
|
||||
class SealResponseTest extends AbstractModelTest<SealResponse> {
|
||||
private static final String TYPE = "shamir";
|
||||
private static final Integer THRESHOLD = 3;
|
||||
private static final Integer SHARES = 5;
|
||||
private static final Integer PROGRESS_SEALED = 2;
|
||||
private static final Integer PROGRESS_UNSEALED = 0;
|
||||
private static final String VERSION = "1.15.4";
|
||||
private static final String BUILD_DATE = "2023-11-22T20:59:54Z";
|
||||
private static final String CLUSTER_NAME = "vault-cluster-d6ec3c7f";
|
||||
private static final String CLUSTER_ID = "3e8b3fec-3749-e056-ba41-b62a63b997e8";
|
||||
private static final String NONCE = "ef05d55d-4d2c-c594-a5e8-55bc88604c24";
|
||||
private static final Boolean MIGRATION = false;
|
||||
private static final Boolean RECOVERY_SEAL = false;
|
||||
private static final String STORAGE_TYPE = "file";
|
||||
|
||||
private static final String RES_SEALED = "{\n" +
|
||||
" \"type\": \"" + TYPE + "\",\n" +
|
||||
" \"sealed\": true,\n" +
|
||||
" \"initialized\": true,\n" +
|
||||
" \"t\": " + THRESHOLD + ",\n" +
|
||||
" \"n\": " + SHARES + ",\n" +
|
||||
" \"progress\": " + PROGRESS_SEALED + ",\n" +
|
||||
" \"nonce\": \"\",\n" +
|
||||
" \"version\": \"" + VERSION + "\",\n" +
|
||||
" \"build_date\": \"" + BUILD_DATE + "\",\n" +
|
||||
" \"migration\": \"" + MIGRATION + "\",\n" +
|
||||
" \"recovery_seal\": \"" + RECOVERY_SEAL + "\",\n" +
|
||||
" \"storage_type\": \"" + STORAGE_TYPE + "\"\n" +
|
||||
"}";
|
||||
|
||||
private static final String RES_UNSEALED = "{\n" +
|
||||
" \"type\": \"" + TYPE + "\",\n" +
|
||||
" \"sealed\": false,\n" +
|
||||
" \"initialized\": true,\n" +
|
||||
" \"t\": " + THRESHOLD + ",\n" +
|
||||
" \"n\": " + SHARES + ",\n" +
|
||||
" \"progress\": " + PROGRESS_UNSEALED + ",\n" +
|
||||
" \"version\": \"" + VERSION + "\",\n" +
|
||||
" \"build_date\": \"" + BUILD_DATE + "\",\n" +
|
||||
" \"cluster_name\": \"" + CLUSTER_NAME + "\",\n" +
|
||||
" \"cluster_id\": \"" + CLUSTER_ID + "\",\n" +
|
||||
" \"nonce\": \"" + NONCE + "\",\n" +
|
||||
" \"migration\": \"" + MIGRATION + "\",\n" +
|
||||
" \"recovery_seal\": \"" + RECOVERY_SEAL + "\",\n" +
|
||||
" \"storage_type\": \"" + STORAGE_TYPE + "\"\n" +
|
||||
"}";
|
||||
|
||||
SealResponseTest() {
|
||||
super(SealResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SealResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(RES_UNSEALED, SealResponse.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault when sealed (JSON example close to Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
void jsonRoundtripSealed() {
|
||||
// First test sealed Vault's response.
|
||||
SealResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(RES_SEALED, SealResponse.class),
|
||||
"SealResponse deserialization failed"
|
||||
);
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
assertEquals(TYPE, res.getType(), "Incorrect seal type");
|
||||
assertTrue(res.isSealed(), "Incorrect seal status");
|
||||
assertTrue(res.isInitialized(), "Incorrect initialization status");
|
||||
assertEquals(THRESHOLD, res.getThreshold(), "Incorrect threshold");
|
||||
assertEquals(SHARES, res.getNumberOfShares(), "Incorrect number of shares");
|
||||
assertEquals(PROGRESS_SEALED, res.getProgress(), "Incorrect progress");
|
||||
assertEquals("", res.getNonce(), "Nonce not empty");
|
||||
assertEquals(VERSION, res.getVersion(), "Incorrect version");
|
||||
assertEquals(ZonedDateTime.parse(BUILD_DATE), res.getBuildDate(), "Incorrect build date");
|
||||
assertEquals(MIGRATION, res.getMigration(), "Incorrect migration");
|
||||
assertEquals(RECOVERY_SEAL, res.getRecoverySeal(), "Incorrect recovery seal");
|
||||
assertEquals(STORAGE_TYPE, res.getStorageType(), "Incorrect storage type");
|
||||
// And the fields, that should not be filled.
|
||||
assertNull(res.getClusterName(), "Cluster name should not be populated");
|
||||
assertNull(res.getClusterId(), "Cluster ID should not be populated");
|
||||
|
||||
|
||||
// Not test unsealed Vault's response.
|
||||
res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(RES_UNSEALED, SealResponse.class),
|
||||
"SealResponse deserialization failed"
|
||||
);
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
assertEquals(TYPE, res.getType(), "Incorrect seal type");
|
||||
assertFalse(res.isSealed(), "Incorrect seal status");
|
||||
assertTrue(res.isInitialized(), "Incorrect initialization status");
|
||||
assertEquals(THRESHOLD, res.getThreshold(), "Incorrect threshold");
|
||||
assertEquals(SHARES, res.getNumberOfShares(), "Incorrect number of shares");
|
||||
assertEquals(PROGRESS_UNSEALED, res.getProgress(), "Incorrect progress");
|
||||
assertEquals(NONCE, res.getNonce(), "Incorrect nonce");
|
||||
assertEquals(VERSION, res.getVersion(), "Incorrect version");
|
||||
assertEquals(ZonedDateTime.parse(BUILD_DATE), res.getBuildDate(), "Incorrect build date");
|
||||
assertEquals(CLUSTER_NAME, res.getClusterName(), "Incorrect cluster name");
|
||||
assertEquals(CLUSTER_ID, res.getClusterId(), "Incorrect cluster ID");
|
||||
assertEquals(MIGRATION, res.getMigration(), "Incorrect migration");
|
||||
assertEquals(RECOVERY_SEAL, res.getRecoverySeal(), "Incorrect recovery seal");
|
||||
assertEquals(STORAGE_TYPE, res.getStorageType(), "Incorrect storage type");
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link SecretListResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.8
|
||||
*/
|
||||
class SecretListResponseTest extends AbstractModelTest<SecretListResponse> {
|
||||
private static final String KEY1 = "key1";
|
||||
private static final String KEY2 = "key-2";
|
||||
private static final String JSON = "{\n" +
|
||||
" \"auth\": null,\n" +
|
||||
" \"data\": {\n" +
|
||||
" \"keys\": [" +
|
||||
" \"" + KEY1 + "\",\n" +
|
||||
" \"" + KEY2 + "\"\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" \"lease_duration\": 2764800,\n" +
|
||||
" \"lease_id\": \"\",\n" +
|
||||
" \"renewable\": false\n" +
|
||||
"}";
|
||||
|
||||
SecretListResponseTest() {
|
||||
super(SecretListResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SecretListResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(JSON, SecretListResponse.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test JSON deserialization and key getter.
|
||||
*/
|
||||
@Test
|
||||
void getKeysTest() {
|
||||
SecretListResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(JSON, SecretListResponse.class),
|
||||
"SecretListResponse deserialization failed"
|
||||
);
|
||||
|
||||
assertEquals(List.of(KEY1, KEY2), res.getKeys(), "Unexpected secret keys");
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link SecretVersionResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.8
|
||||
*/
|
||||
class SecretVersionResponseTest extends AbstractModelTest<SecretVersionResponse> {
|
||||
private static final String CREATION_TIME = "2018-03-22T02:24:06.945319214Z";
|
||||
private static final String DELETION_TIME = "2018-03-22T02:36:43.986212308Z";
|
||||
private static final Integer VERSION = 42;
|
||||
|
||||
private static final String META_JSON = "{\n" +
|
||||
" \"data\": {\n" +
|
||||
" \"created_time\": \"" + CREATION_TIME + "\",\n" +
|
||||
" \"deletion_time\": \"" + DELETION_TIME + "\",\n" +
|
||||
" \"destroyed\": false,\n" +
|
||||
" \"version\": " + VERSION + "\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
SecretVersionResponseTest() {
|
||||
super(SecretVersionResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SecretVersionResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(META_JSON, SecretVersionResponse.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
void jsonRoundtrip() {
|
||||
SecretVersionResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(META_JSON, SecretVersionResponse.class),
|
||||
"SecretVersionResponse deserialization failed"
|
||||
);
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
assertNotNull(res.getMetadata(), "Parsed metadata is NULL");
|
||||
assertFalse(res.getMetadata().isDestroyed(), "Incorrect destroyed state");
|
||||
assertEquals(VERSION, res.getMetadata().getVersion(), "Incorrect version");
|
||||
}
|
||||
}
|
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link TokenResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 0.6.2
|
||||
*/
|
||||
class TokenResponseTest extends AbstractModelTest<TokenResponse> {
|
||||
private static final Integer TOKEN_CREATION_TIME = 1457533232;
|
||||
private static final Integer TOKEN_TTL = 2764800;
|
||||
private static final Integer TOKEN_EXPLICIT_MAX_TTL = 0;
|
||||
private static final String TOKEN_DISPLAY_NAME = "token";
|
||||
private static final String TOKEN_META_KEY = "foo";
|
||||
private static final String TOKEN_META_VALUE = "bar";
|
||||
private static final Integer TOKEN_NUM_USES = 0;
|
||||
private static final Boolean TOKEN_ORPHAN = false;
|
||||
private static final Boolean TOKEN_RENEWABLE = true;
|
||||
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 TOKEN_ACCESSOR = "VKvzT2fKHFsZFUus9LyoXCvu";
|
||||
private static final String TOKEN_ENTITY_ID = "7d2e3179-f69b-450c-7179-ac8ee8bd8ca9";
|
||||
private static final String TOKEN_EXPIRE_TIME = "2018-05-19T11:35:54.466476215-04:00";
|
||||
private static final String TOKEN_ID = "my-token";
|
||||
private static final String TOKEN_ISSUE_TIME = "2018-04-17T11:35:54.466476078-04:00";
|
||||
private static final String TOKEN_TYPE = "service";
|
||||
private static final String MOUNT_TYPE = "token";
|
||||
|
||||
private static final String RES_JSON = "{\n" +
|
||||
" \"lease_id\": \"\",\n" +
|
||||
" \"renewable\": " + RES_RENEWABLE + ",\n" +
|
||||
" \"lease_duration\": " + RES_LEASE_DURATION + ",\n" +
|
||||
" \"data\": {\n" +
|
||||
" \"accessor\": \"" + TOKEN_ACCESSOR + "\",\n" +
|
||||
" \"creation_time\": " + TOKEN_CREATION_TIME + ",\n" +
|
||||
" \"creation_ttl\": " + TOKEN_TTL + ",\n" +
|
||||
" \"display_name\": \"" + TOKEN_DISPLAY_NAME + "\",\n" +
|
||||
" \"entity_id\": \"" + TOKEN_ENTITY_ID + "\",\n" +
|
||||
" \"expire_time\": \"" + TOKEN_EXPIRE_TIME + "\",\n" +
|
||||
" \"explicit_max_ttl\": \"" + TOKEN_EXPLICIT_MAX_TTL + "\",\n" +
|
||||
" \"id\": \"" + TOKEN_ID + "\",\n" +
|
||||
" \"issue_time\": \"" + TOKEN_ISSUE_TIME + "\",\n" +
|
||||
" \"meta\": {\n" +
|
||||
" \"" + TOKEN_META_KEY + "\": \"" + TOKEN_META_VALUE + "\"\n" +
|
||||
" },\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" +
|
||||
" \"renewable\": " + TOKEN_RENEWABLE + ",\n" +
|
||||
" \"ttl\": " + RES_TTL + ",\n" +
|
||||
" \"type\": \"" + TOKEN_TYPE + "\"\n" +
|
||||
" },\n" +
|
||||
" \"warnings\": null,\n" +
|
||||
" \"auth\": null,\n" +
|
||||
" \"mount_type\": \"" + MOUNT_TYPE + "\"\n" +
|
||||
"}";
|
||||
|
||||
TokenResponseTest() {
|
||||
super(TokenResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TokenResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(RES_JSON, TokenResponse.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getter, setter and get-methods for response data.
|
||||
*/
|
||||
@Test
|
||||
void getDataRoundtrip() {
|
||||
// Create empty Object.
|
||||
TokenResponse res = new TokenResponse();
|
||||
assertNull(res.getData(), "Initial data should be empty");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
void jsonRoundtrip() {
|
||||
TokenResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(RES_JSON, TokenResponse.class),
|
||||
"TokenResponse deserialization failed"
|
||||
);
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
assertEquals(RES_LEASE_DURATION, res.getLeaseDuration(), "Incorrect lease duration");
|
||||
assertEquals(RES_RENEWABLE, res.isRenewable(), "Incorrect response renewable flag");
|
||||
assertEquals(RES_LEASE_DURATION, res.getLeaseDuration(), "Incorrect response lease duration");
|
||||
assertEquals(MOUNT_TYPE, res.getMountType(), "Incorrect mount type");
|
||||
// Extract token data.
|
||||
TokenData data = res.getData();
|
||||
assertNotNull(data, "Token data is NULL");
|
||||
assertEquals(TOKEN_ACCESSOR, data.getAccessor(), "Incorrect token accessor");
|
||||
assertEquals(TOKEN_CREATION_TIME, data.getCreationTime(), "Incorrect token creation time");
|
||||
assertEquals(TOKEN_TTL, data.getCreationTtl(), "Incorrect token creation TTL");
|
||||
assertEquals(TOKEN_DISPLAY_NAME, data.getName(), "Incorrect token display name");
|
||||
assertEquals(TOKEN_ENTITY_ID, data.getEntityId(), "Incorrect token entity ID");
|
||||
assertEquals(ZonedDateTime.parse(TOKEN_EXPIRE_TIME), data.getExpireTime(), "Incorrect parsed token expire time");
|
||||
assertEquals(TOKEN_EXPLICIT_MAX_TTL, data.getExplicitMaxTtl(), "Incorrect token explicit max TTL");
|
||||
assertEquals(TOKEN_ID, data.getId(), "Incorrect token ID");
|
||||
assertEquals(ZonedDateTime.parse(TOKEN_ISSUE_TIME), data.getIssueTime(), "Incorrect parsed token issue time");
|
||||
assertEquals(Map.of(TOKEN_META_KEY, TOKEN_META_VALUE), data.getMeta(), "Incorrect token metadata");
|
||||
assertEquals(TOKEN_NUM_USES, data.getNumUses(), "Incorrect token number of uses");
|
||||
assertEquals(TOKEN_ORPHAN, data.isOrphan(), "Incorrect token orphan flag");
|
||||
assertEquals(TOKEN_PATH, data.getPath(), "Incorrect token path");
|
||||
assertEquals(2, data.getPolicies().size(), "Incorrect number of token policies");
|
||||
assertTrue(data.getPolicies().containsAll(List.of(TOKEN_POLICY_1, TOKEN_POLICY_2)), "Incorrect token policies");
|
||||
assertEquals(TOKEN_RENEWABLE, data.isRenewable(), "Incorrect token renewable flag");
|
||||
assertEquals(RES_TTL, data.getTtl(), "Incorrect token TTL");
|
||||
assertEquals(TOKEN_TYPE, data.getType(), "Incorrect token type");
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* JUnit Test for {@link TransitResponse} model.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
* @since 1.5.0
|
||||
*/
|
||||
class TransitResponseTest extends AbstractModelTest<TransitResponse> {
|
||||
private static final String CIPHERTEXT = "vault:v1:XjsPWPjqPrBi1N2Ms2s1QM798YyFWnO4TR4lsFA=";
|
||||
private static final String PLAINTEXT = "dGhlIHF1aWNrIGJyb3duIGZveAo=";
|
||||
private static final String SUM = "dGhlIHF1aWNrIGJyb3duIGZveAo=";
|
||||
|
||||
TransitResponseTest() {
|
||||
super(TransitResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransitResponse createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(
|
||||
json(
|
||||
"\"ciphertext\": \"" + CIPHERTEXT + "\", " +
|
||||
"\"plaintext\": \"" + PLAINTEXT + "\", " +
|
||||
"\"sum\": \"" + SUM + "\""
|
||||
),
|
||||
TransitResponse.class
|
||||
);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void encryptionTest() {
|
||||
TransitResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(
|
||||
json("\"ciphertext\": \"" + CIPHERTEXT + "\""),
|
||||
TransitResponse.class
|
||||
),
|
||||
"TransitResponse deserialization failed"
|
||||
);
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
assertEquals("987c6daf-b0e2-4142-a970-1e61fdb249d7", res.getRequestId(), "Incorrect request id");
|
||||
assertEquals("", res.getLeaseId(), "Unexpected lease id");
|
||||
assertFalse(res.isRenewable(), "Unexpected renewable flag");
|
||||
assertEquals(0, res.getLeaseDuration(), "Unexpected lease duration");
|
||||
assertEquals(CIPHERTEXT, res.getCiphertext(), "Incorrect ciphertext");
|
||||
assertNull(res.getPlaintext(), "Unexpected plaintext");
|
||||
assertNull(res.getSum(), "Unexpected sum");
|
||||
assertNull(res.getWrapInfo(), "Unexpected wrap info");
|
||||
assertNull(res.getWarnings(), "Unexpected warnings");
|
||||
assertNull(res.getAuth(), "Unexpected auth");
|
||||
}
|
||||
|
||||
@Test
|
||||
void decryptionTest() {
|
||||
TransitResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(
|
||||
json("\"plaintext\": \"" + PLAINTEXT + "\""),
|
||||
TransitResponse.class
|
||||
),
|
||||
"TransitResponse deserialization failed"
|
||||
);
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
assertEquals("987c6daf-b0e2-4142-a970-1e61fdb249d7", res.getRequestId(), "Incorrect request id");
|
||||
assertEquals("", res.getLeaseId(), "Unexpected lease id");
|
||||
assertFalse(res.isRenewable(), "Unexpected renewable flag");
|
||||
assertEquals(0, res.getLeaseDuration(), "Unexpected lease duration");
|
||||
assertNull(res.getCiphertext(), "Unexpected ciphertext");
|
||||
assertEquals(PLAINTEXT, res.getPlaintext(), "Incorrect plaintext");
|
||||
assertNull(res.getSum(), "Unexpected sum");
|
||||
assertNull(res.getWrapInfo(), "Unexpected wrap info");
|
||||
assertNull(res.getWarnings(), "Unexpected warnings");
|
||||
assertNull(res.getAuth(), "Unexpected auth");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hashTest() {
|
||||
TransitResponse res = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(
|
||||
json("\"sum\": \"" + SUM + "\""),
|
||||
TransitResponse.class
|
||||
),
|
||||
"TransitResponse deserialization failed"
|
||||
);
|
||||
assertNotNull(res, "Parsed response is NULL");
|
||||
assertEquals("987c6daf-b0e2-4142-a970-1e61fdb249d7", res.getRequestId(), "Incorrect request id");
|
||||
assertEquals("", res.getLeaseId(), "Unexpected lease id");
|
||||
assertFalse(res.isRenewable(), "Unexpected renewable flag");
|
||||
assertEquals(0, res.getLeaseDuration(), "Unexpected lease duration");
|
||||
assertNull(res.getCiphertext(), "Unexpected ciphertext");
|
||||
assertNull(res.getPlaintext(), "Unexpected plaintext");
|
||||
assertEquals(SUM, res.getSum(), "Incorrect sum");
|
||||
assertNull(res.getWrapInfo(), "Unexpected wrap info");
|
||||
assertNull(res.getWarnings(), "Unexpected warnings");
|
||||
assertNull(res.getAuth(), "Unexpected auth");
|
||||
}
|
||||
|
||||
private static String json(String data) {
|
||||
return "{\n" +
|
||||
" \"request_id\" : \"987c6daf-b0e2-4142-a970-1e61fdb249d7\",\n" +
|
||||
" \"lease_id\" : \"\",\n" +
|
||||
" \"renewable\" : false,\n" +
|
||||
" \"lease_duration\" : 0,\n" +
|
||||
" \"data\" : {\n" +
|
||||
" " + data + "\n" +
|
||||
" },\n" +
|
||||
" \"wrap_info\" : null,\n" +
|
||||
" \"warnings\" : null,\n" +
|
||||
" \"auth\" : null\n" +
|
||||
"}";
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package de.stklcode.jvault.connector.model.response.embedded;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import de.stklcode.jvault.connector.model.AbstractModelTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Unit test for {@link MountConfig}.
|
||||
*
|
||||
* @author Stefan Kalscheuer
|
||||
*/
|
||||
class MountConfigTest extends AbstractModelTest<MountConfig> {
|
||||
private static final Integer DEFAULT_LEASE_TTL = 1800;
|
||||
private static final Integer MAX_LEASE_TTL = 3600;
|
||||
private static final Boolean FORCE_NO_CACHE = false;
|
||||
private static final String TOKEN_TYPE = "default-service";
|
||||
private static final String AUDIT_NON_HMAC_REQ_KEYS_1 = "req1";
|
||||
private static final String AUDIT_NON_HMAC_REQ_KEYS_2 = "req2";
|
||||
private static final String AUDIT_NON_HMAC_RES_KEYS_1 = "res1";
|
||||
private static final String AUDIT_NON_HMAC_RES_KEYS_2 = "res2";
|
||||
private static final String LISTING_VISIBILITY = "unauth";
|
||||
private static final String PT_REQ_HEADER_1 = "prh1";
|
||||
private static final String PT_REQ_HEADER_2 = "prh2";
|
||||
private static final String ALLOWED_RES_HEADER_1 = "arh1";
|
||||
private static final String ALLOWED_RES_HEADER_2 = "arh2";
|
||||
private static final String ALLOWED_MANAGED_KEY_1 = "amk1";
|
||||
private static final String ALLOWED_MANAGED_KEY_2 = "amk2";
|
||||
private static final String DEL_AUTH_ACCESSOR_1 = "daa1";
|
||||
private static final String DEL_AUTH_ACCESSOR_2 = "daa2";
|
||||
private static final Integer LOCKOUT_THRESH = 7200;
|
||||
private static final Integer LOCKOUT_DURATION = 86400;
|
||||
private static final Integer LOCKOUT_CNT_RESET_DURATION = 43200;
|
||||
private static final Boolean LOCKOUT_DISABLE = false;
|
||||
|
||||
private static final String RES_JSON = "{\n" +
|
||||
" \"default_lease_ttl\": " + DEFAULT_LEASE_TTL + ",\n" +
|
||||
" \"force_no_cache\": " + FORCE_NO_CACHE + ",\n" +
|
||||
" \"max_lease_ttl\": " + MAX_LEASE_TTL + ",\n" +
|
||||
" \"token_type\": \"" + TOKEN_TYPE + "\",\n" +
|
||||
" \"audit_non_hmac_request_keys\": [\"" + AUDIT_NON_HMAC_REQ_KEYS_1 + "\", \"" + AUDIT_NON_HMAC_REQ_KEYS_2 + "\"],\n" +
|
||||
" \"audit_non_hmac_response_keys\": [\"" + AUDIT_NON_HMAC_RES_KEYS_1 + "\", \"" + AUDIT_NON_HMAC_RES_KEYS_2 + "\"],\n" +
|
||||
" \"listing_visibility\": \"" + LISTING_VISIBILITY + "\",\n" +
|
||||
" \"passthrough_request_headers\": [\"" + PT_REQ_HEADER_1 + "\", \"" + PT_REQ_HEADER_2 + "\"],\n" +
|
||||
" \"allowed_response_headers\": [\"" + ALLOWED_RES_HEADER_1 + "\", \"" + ALLOWED_RES_HEADER_2 + "\"],\n" +
|
||||
" \"allowed_managed_keys\": [\"" + ALLOWED_MANAGED_KEY_1 + "\", \"" + ALLOWED_MANAGED_KEY_2 + "\"],\n" +
|
||||
" \"delegated_auth_accessors\": [\"" + DEL_AUTH_ACCESSOR_1 + "\", \"" + DEL_AUTH_ACCESSOR_2 + "\"],\n" +
|
||||
" \"user_lockout_config\": {\n" +
|
||||
" \"lockout_threshold\": " + LOCKOUT_THRESH + ",\n" +
|
||||
" \"lockout_duration\": " + LOCKOUT_DURATION + ",\n" +
|
||||
" \"lockout_counter_reset_duration\": " + LOCKOUT_CNT_RESET_DURATION + ",\n" +
|
||||
" \"lockout_disable\": " + LOCKOUT_DISABLE + "\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
MountConfigTest() {
|
||||
super(MountConfig.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MountConfig createFull() {
|
||||
try {
|
||||
return objectMapper.readValue(RES_JSON, MountConfig.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
fail("Creation of full model instance failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
|
||||
*/
|
||||
@Test
|
||||
void jsonRoundtrip() {
|
||||
MountConfig mountConfig = assertDoesNotThrow(
|
||||
() -> objectMapper.readValue(RES_JSON, MountConfig.class),
|
||||
"MountConfig deserialization failed"
|
||||
);
|
||||
assertNotNull(mountConfig, "Parsed response is NULL");
|
||||
|
||||
// Verify data.
|
||||
assertEquals(DEFAULT_LEASE_TTL, mountConfig.getDefaultLeaseTtl(), "Unexpected default lease TTL");
|
||||
assertEquals(MAX_LEASE_TTL, mountConfig.getMaxLeaseTtl(), "Unexpected max lease TTL");
|
||||
assertEquals(FORCE_NO_CACHE, mountConfig.getForceNoCache(), "Unexpected force no cache");
|
||||
assertEquals(TOKEN_TYPE, mountConfig.getTokenType(), "Unexpected token type");
|
||||
assertEquals(List.of(AUDIT_NON_HMAC_REQ_KEYS_1, AUDIT_NON_HMAC_REQ_KEYS_2), mountConfig.getAuditNonHmacRequestKeys(), "Unexpected audit no HMAC request keys");
|
||||
assertEquals(List.of(AUDIT_NON_HMAC_RES_KEYS_1, AUDIT_NON_HMAC_RES_KEYS_2), mountConfig.getAuditNonHmacResponseKeys(), "Unexpected audit no HMAC response keys");
|
||||
assertEquals(LISTING_VISIBILITY, mountConfig.getListingVisibility(), "Unexpected listing visibility");
|
||||
assertEquals(List.of(PT_REQ_HEADER_1, PT_REQ_HEADER_2), mountConfig.getPassthroughRequestHeaders(), "Unexpected passthrough request headers");
|
||||
assertEquals(List.of(ALLOWED_RES_HEADER_1, ALLOWED_RES_HEADER_2), mountConfig.getAllowedResponseHeaders(), "Unexpected allowed response headers");
|
||||
assertEquals(List.of(ALLOWED_MANAGED_KEY_1, ALLOWED_MANAGED_KEY_2), mountConfig.getAllowedManagedKeys(), "Unexpected allowed managed keys");
|
||||
assertEquals(List.of(DEL_AUTH_ACCESSOR_1, DEL_AUTH_ACCESSOR_2), mountConfig.getDelegatedAuthAccessors(), "Unexpected delegate auth accessors");
|
||||
assertNotNull(mountConfig.getUserLockoutConfig(), "Missing user lockout config");
|
||||
var ulc = mountConfig.getUserLockoutConfig();
|
||||
assertEquals(LOCKOUT_THRESH, ulc.getLockoutThreshold(), "Unexpected lockout threshold");
|
||||
assertEquals(LOCKOUT_DURATION, ulc.getLockoutDuration(), "Unexpected lockout duration");
|
||||
assertEquals(LOCKOUT_CNT_RESET_DURATION, ulc.getLockoutCounterResetDuration(), "Unexpected lockout counter reset duration");
|
||||
assertEquals(LOCKOUT_DISABLE, ulc.getLockoutDisable(), "Unexpected lockout disable");
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2016-2025 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;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user