Compare commits

...

45 Commits
v1.3.1 ... main

Author SHA1 Message Date
80abbda46f
docs: update version and features in README
All checks were successful
CI / build (11) (push) Successful in 39s
CI / build (17) (push) Successful in 39s
CI / build (true, 21) (push) Successful in 34s
CI / build-with-it (11, 1.2.0) (push) Successful in 55s
CI / build-with-it (11, 1.19.0) (push) Successful in 1m2s
CI / build-with-it (17, 1.2.0) (push) Successful in 54s
CI / build-with-it (17, 1.19.0) (push) Successful in 1m0s
CI / build-with-it (21, 1.2.0) (push) Successful in 52s
CI / build-with-it (true, 21, 1.19.0) (push) Successful in 59s
2025-04-24 18:36:36 +02:00
a8e85b88d1
test: use WireMockTest annotation 2025-04-24 18:30:32 +02:00
91baed4fe5
test: update wiremock to 3.13.0 2025-04-24 18:30:04 +02:00
2ea261d36a
prepare for next development iteration
All checks were successful
CI / build (11) (push) Successful in 36s
CI / build (17) (push) Successful in 36s
CI / build (true, 21) (push) Successful in 28s
2025-04-13 12:25:18 +02:00
43da0f5109
prepare release v1.5.0
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 52s
CI / build-with-it (11, 1.19.0) (push) Successful in 59s
CI / build-with-it (21, 1.2.0) (push) Successful in 49s
CI / build-with-it (true, 21, 1.19.0) (push) Successful in 55s
CI / build-with-it (17, 1.19.0) (push) Successful in 57s
CI / build-with-it (17, 1.2.0) (push) Successful in 52s
2025-04-13 11:25:49 +02:00
cc5ca13aeb
refactor: use builder to instantiate ObjectMapper (#95)
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 52s
CI / build-with-it (11, 1.19.0) (push) Successful in 58s
CI / build-with-it (17, 1.2.0) (push) Successful in 52s
CI / build-with-it (17, 1.19.0) (push) Successful in 57s
CI / build-with-it (21, 1.2.0) (push) Successful in 47s
CI / build-with-it (true, 21, 1.19.0) (push) Successful in 54s
Instead of applying configuration to a new ObjectMapper instance we use
the JsonMapper builder pattern to create our mapper.

The resulting mappers are not yet fully immutable, but the old way will
be removed in Jackson 3.0.
2025-04-13 10:49:42 +02:00
71842eb758
deps: update test dependencies
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 50s
CI / build-with-it (11, 1.19.0) (push) Successful in 58s
CI / build-with-it (17, 1.2.0) (push) Successful in 51s
CI / build-with-it (17, 1.19.0) (push) Successful in 1m1s
CI / build-with-it (21, 1.2.0) (push) Successful in 54s
CI / build-with-it (true, 21, 1.19.0) (push) Successful in 58s
2025-04-13 10:31:58 +02:00
e9aeda9a55
style: trim multiline indentation to 4 spaces
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 56s
CI / build-with-it (17, 1.2.0) (push) Successful in 56s
CI / build-with-it (21, 1.2.0) (push) Successful in 51s
CI / build-with-it (17, 1.19.0) (push) Successful in 49s
CI / build-with-it (11, 1.19.0) (push) Successful in 51s
CI / build-with-it (true, 21, 1.19.0) (push) Successful in 57s
2025-04-11 17:20:24 +02:00
d51af06e29
build: update jacoco-maven-plugin to 0.8.13
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 49s
CI / build-with-it (11, 1.19.0) (push) Successful in 55s
CI / build-with-it (17, 1.2.0) (push) Successful in 49s
CI / build-with-it (17, 1.19.0) (push) Successful in 55s
CI / build-with-it (21, 1.2.0) (push) Successful in 45s
CI / build-with-it (true, 21, 1.19.0) (push) Successful in 51s
2025-04-03 11:04:23 +02:00
7b2b137d53
build: update surefire and failsafe plugin to 3.5.3 2025-04-03 11:03:50 +02:00
ee2543e3ad
reuse builder methods when initializing from environment
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 51s
CI / build-with-it (17, 1.19.0) (push) Successful in 54s
CI / build-with-it (17, 1.2.0) (push) Successful in 51s
CI / build-with-it (21, 1.2.0) (push) Successful in 46s
CI / build-with-it (true, 21, 1.19.0) (push) Successful in 55s
CI / build-with-it (11, 1.19.0) (push) Successful in 48s
We can just pass the environment variable to other pre-existing methods
instead of parsing the URL twice. This also fixes URLs without explicit
ports where we should not store "-1" in this case.
2025-03-29 11:50:29 +01:00
dad35023eb
replace deprecated java.net.URL usage with java.net.URI (#94)
Deprecated in Java 20. Migrate URL parsing to backward compatible URI.
2025-03-28 18:30:37 +01:00
0127cf30be
feat: introduce methods for transit API interaction (#89)
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 50s
CI / build-with-it (11, 1.19.0) (push) Successful in 55s
CI / build-with-it (17, 1.2.0) (push) Successful in 50s
CI / build-with-it (17, 1.19.0) (push) Successful in 56s
CI / build-with-it (21, 1.2.0) (push) Successful in 47s
CI / build-with-it (true, 21, 1.19.0) (push) Successful in 54s
Support hashing and de-/encryption using Vault's transit API.
2025-03-02 18:24:16 +01:00
90f8bb7f20
build: update sonar-maven-plugin to 5.1.0.4751
All checks were successful
CI / build-with-it (17, 1.2.0) (push) Successful in 51s
CI / build-with-it (21, 1.2.0) (push) Successful in 46s
CI / build-with-it (true, 21, 1.19.0) (push) Successful in 55s
CI / build-with-it (11, 1.2.0) (push) Successful in 52s
CI / build-with-it (11, 1.19.0) (push) Successful in 58s
CI / build-with-it (17, 1.19.0) (push) Successful in 46s
2025-03-28 18:03:27 +01:00
ff6d2140cf
feat: support PEM certificate string from VAULT_CACERT env var (#93)
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 53s
CI / build-with-it (11, 1.19.0) (push) Successful in 1m0s
CI / build-with-it (17, 1.19.0) (push) Successful in 57s
CI / build-with-it (17, 1.2.0) (push) Successful in 52s
CI / build-with-it (21, 1.2.0) (push) Successful in 48s
CI / build-with-it (true, 21, 1.19.0) (push) Successful in 54s
Vault CLI and the connector up to 1.4 support providing a path to a CA
certificate file. Introduce support for providing PEM encoded content
directly which might be convenient in container environments to provide
a certificate e.g. from secrets without mounting it to some path.
2025-03-23 12:10:15 +01:00
076cd8b607
replace trim/isEmpty with isBlank
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 53s
CI / build-with-it (11, 1.19.0) (push) Successful in 1m1s
CI / build-with-it (17, 1.2.0) (push) Successful in 53s
CI / build-with-it (21, 1.2.0) (push) Successful in 48s
CI / build-with-it (true, 21, 1.19.0) (push) Successful in 55s
CI / build-with-it (17, 1.19.0) (push) Successful in 49s
2025-03-22 18:39:39 +01:00
2e0d092cae
deps: update test dependencies 2025-03-22 18:36:41 +01:00
d329af2c67
deprecate default methods to read specific database credentials (#92)
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 57s
CI / build-with-it (11, 1.19.0) (push) Successful in 1m3s
CI / build-with-it (17, 1.2.0) (push) Successful in 57s
CI / build-with-it (17, 1.19.0) (push) Successful in 1m4s
CI / build-with-it (21, 1.2.0) (push) Successful in 54s
CI / build-with-it (true, 21, 1.19.0) (push) Successful in 1m2s
The interface has some methods to read database credentials from
specific mountpoints like "mysql". While ann database mounts share
the same credential endpoints, the mount point itself can have any
name. Let's clean up some methods of low benefit and deprecate the
convenience methods.

Trivial replacement is `getDbCredentials()` with explicit mount point,
if it's actually mounted on that path.
2025-03-09 11:43:15 +01:00
f50f5c5de7
test: run IT against Vault 1.19.0 (#91)
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 59s
CI / build-with-it (17, 1.2.0) (push) Successful in 56s
CI / build-with-it (17, 1.19.0) (push) Successful in 1m2s
CI / build-with-it (21, 1.2.0) (push) Successful in 50s
CI / build-with-it (true, 21, 1.19.0) (push) Successful in 57s
CI / build-with-it (11, 1.19.0) (push) Successful in 1m4s
2025-03-07 20:30:48 +01:00
c8a6015f3f
deps: update jackson to 2.18.3 (#90)
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 55s
CI / build-with-it (11, 1.18.2) (push) Successful in 1m0s
CI / build-with-it (17, 1.2.0) (push) Successful in 54s
CI / build-with-it (17, 1.18.2) (push) Successful in 1m0s
CI / build-with-it (21, 1.2.0) (push) Successful in 42s
CI / build-with-it (true, 21, 1.18.2) (push) Successful in 49s
2025-03-02 18:40:01 +01:00
835372eb3b
test: swap expected and actual arguments in some assertions
All checks were successful
CI / build (11) (push) Successful in 38s
CI / build (17) (push) Successful in 37s
CI / build (true, 21) (push) Successful in 29s
CI / build-with-it (11, 1.2.0) (push) Successful in 56s
CI / build-with-it (11, 1.18.2) (push) Successful in 59s
CI / build-with-it (17, 1.2.0) (push) Successful in 54s
CI / build-with-it (21, 1.2.0) (push) Successful in 47s
CI / build-with-it (true, 21, 1.18.2) (push) Successful in 54s
CI / build-with-it (17, 1.18.2) (push) Successful in 51s
2025-03-02 18:28:20 +01:00
11ece9974f
build: update Maven plugins
All checks were successful
CI / build-with-it (21, 1.2.0) (push) Successful in 52s
CI / build-with-it (true, 21, 1.18.2) (push) Successful in 59s
CI / build-with-it (11, 1.2.0) (push) Successful in 58s
CI / build-with-it (11, 1.18.2) (push) Successful in 1m5s
CI / build-with-it (17, 1.18.2) (push) Successful in 1m1s
CI / build-with-it (17, 1.2.0) (push) Successful in 57s
CI / build (11) (push) Successful in 40s
CI / build (17) (push) Successful in 41s
CI / build (true, 21) (push) Successful in 31s
2025-02-23 14:00:08 +01:00
0d0fbb5461
deps: update test dependencies 2025-02-23 13:57:57 +01:00
6c9a1fc10e
build: update dependency-check-maven to v12.1.0
All checks were successful
CI / build-with-it (21, 1.2.0) (push) Successful in 52s
CI / build-with-it (true, 21, 1.18.2) (push) Successful in 59s
CI / build-with-it (11, 1.2.0) (push) Successful in 57s
CI / build-with-it (11, 1.18.2) (push) Successful in 1m3s
CI / build-with-it (17, 1.2.0) (push) Successful in 56s
CI / build-with-it (17, 1.18.2) (push) Successful in 50s
2025-02-23 13:56:01 +01:00
7e05f4937d
build: update dependency-check-maven to v12.0.2 2025-01-31 18:04:47 +01:00
fd9045d7cd
build: add maven-enforcer-plugin
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 1m5s
CI / build-with-it (17, 1.2.0) (push) Successful in 1m1s
CI / build-with-it (21, 1.2.0) (push) Successful in 59s
CI / build-with-it (17, 1.18.2) (push) Successful in 57s
CI / build-with-it (11, 1.18.2) (push) Successful in 56s
CI / build-with-it (true, 21, 1.18.2) (push) Successful in 1m3s
2025-01-07 17:44:39 +01:00
e938f81954
deps: update test dependencies and maven plugins
* equalsverifier 3.18
* junit-jupiter 5.11.4
* mockito-core 5.15.2

* maven-javadoc-plugin 3.11.2
2025-01-07 17:44:20 +01:00
e5dd207c8c
update license headers to 2025 2025-01-07 17:35:54 +01:00
92d5750c1d
prepare release of v1.4.0 (#88)
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 53s
CI / build-with-it (11, 1.18.2) (push) Successful in 1m1s
CI / build-with-it (17, 1.2.0) (push) Successful in 54s
CI / build-with-it (21, 1.2.0) (push) Successful in 51s
CI / build-with-it (true, 21, 1.18.2) (push) Successful in 59s
CI / build-with-it (17, 1.18.2) (push) Successful in 49s
CI / build (11) (push) Successful in 41s
CI / build (17) (push) Successful in 41s
CI / build (true, 21) (push) Successful in 32s
2024-12-07 11:54:46 +01:00
2011a83fd9
deps: update test dependencies and maven plugins
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 55s
CI / build-with-it (11, 1.18.2) (push) Successful in 1m3s
CI / build-with-it (17, 1.2.0) (push) Successful in 57s
CI / build-with-it (21, 1.2.0) (push) Successful in 52s
CI / build-with-it (true, 21, 1.18.2) (push) Successful in 1m0s
CI / build-with-it (17, 1.18.2) (push) Successful in 50s
* equalsverifier 3.17.5
* dependency-check-maven 1.11.1
2024-12-07 11:47:45 +01:00
d3da00372c
test: run IT against Vault 1.18.2 and remove 1.11 job (#87)
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 59s
CI / build-with-it (11, 1.18.2) (push) Successful in 1m5s
CI / build-with-it (17, 1.2.0) (push) Successful in 56s
CI / build-with-it (17, 1.18.2) (push) Successful in 1m3s
CI / build-with-it (21, 1.2.0) (push) Successful in 52s
CI / build-with-it (true, 21, 1.18.2) (push) Successful in 1m1s
CI / build (11) (push) Successful in 38s
CI / build (17) (push) Successful in 38s
CI / build (true, 21) (push) Successful in 34s
2024-12-07 11:26:54 +01:00
d90dfc8ba7
ci: remove Drone CI configuration
All checks were successful
CI / build-with-it (11, 1.18.0) (push) Successful in 1m0s
CI / build-with-it (11, 1.11.12) (push) Successful in 1m4s
CI / build-with-it (11, 1.2.0) (push) Successful in 54s
CI / build-with-it (17, 1.11.12) (push) Successful in 1m5s
CI / build-with-it (17, 1.2.0) (push) Successful in 54s
CI / build-with-it (21, 1.2.0) (push) Successful in 53s
CI / build-with-it (21, 1.11.12) (push) Successful in 1m3s
CI / build (11) (push) Successful in 38s
CI / build-with-it (true, 21, 1.18.0) (push) Successful in 1m3s
CI / build (17) (push) Successful in 37s
CI / build (true, 21) (push) Successful in 33s
CI / build-with-it (17, 1.18.0) (push) Successful in 51s
All build systems now GitHub Actions workflows, so we can remove the
alternative configuration and only keep a single pipeline definition.
2024-12-07 11:12:25 +01:00
8bf0f9c45f
ci: split jobs for unit and integration tests 2024-12-07 11:11:17 +01:00
4fcfa6938e
build: introduce maven wrapper
Some checks failed
continuous-integration/drone/push Build is passing
CI / build (11, 1.11.12) (push) Successful in 41s
CI / build (11, 1.18.0) (push) Successful in 39s
CI / build (11, 1.2.0) (push) Successful in 38s
CI / build (17, 1.11.12) (push) Successful in 39s
CI / build (17, 1.18.0) (push) Successful in 39s
CI / build (17, 1.2.0) (push) Successful in 38s
CI / build (21, 1.11.12) (push) Successful in 38s
CI / build (21, 1.2.0) (push) Successful in 38s
CI / build (true, 21, 1.18.0) (push) Failing after 37s
2024-12-07 10:54:24 +01:00
26cfceb581
deps: update test dependencies and maven plugins
All checks were successful
continuous-integration/drone/push Build is passing
2024-11-29 20:25:20 +01:00
ccf820d524
deps: update jackson to 2.18.2 (#85) 2024-11-29 20:22:34 +01:00
5a9d6d9183
fix: add jackson annotation module dependency (#84)
All checks were successful
continuous-integration/drone/push Build is passing
2024-11-23 12:42:50 +01:00
a1dd2b20fb
build: use release option instead of source and target for compiler
All checks were successful
continuous-integration/drone/push Build is passing
2024-11-23 10:45:18 +01:00
b0c6ea2d19
deps: update jackson to 2.18.1 (#83)
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-31 12:14:56 +01:00
9b6aa91e52
deps: update test dependencies and maven plugins 2024-10-31 12:12:47 +01:00
01812bf492
ci: run integration tests on PR against main branch
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-09 18:23:45 +02:00
e6ef19f1a1
test: run IT against Vault 1.18.0 (#82) 2024-10-09 18:09:30 +02:00
d4066c1829
drop support for deprecated App-ID auth backend (#61) (#78)
All checks were successful
continuous-integration/drone/push Build is passing
App-ID is deprecated since Vault 0.6 and was removed in 1.12.
Our compatibility methods are deprecated since Connector 0.4. It's time
to drop it for good.
2024-06-29 15:09:38 +02:00
498e46d94d
remove deprecated get...TimeString() methods from model classes (#77)
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-29 15:07:47 +02:00
658f005433
build: migrate maven central deployment to publishing api
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-03 18:57:22 +02:00
139 changed files with 1682 additions and 942 deletions

View File

@ -1,49 +0,0 @@
kind: pipeline
name: default
steps:
- name: compile
image: maven:3-eclipse-temurin-21
commands:
- mvn -B clean compile
when:
branch:
- main
- develop
- feature/*
- fix/*
- release/*
- name: unit-tests
image: maven:3-eclipse-temurin-21
commands:
- mvn -B test
when:
branch:
- develop
- feature/*
- fix/*
- name: setup-vault
image: alpine:latest
environment:
VAULT_VERSION: 1.17.6
commands:
- wget -q -O vault_$${VAULT_VERSION}_linux_amd64.zip https://releases.hashicorp.com/vault/$${VAULT_VERSION}/vault_$${VAULT_VERSION}_linux_amd64.zip
- wget -q -O - https://releases.hashicorp.com/vault/$${VAULT_VERSION}/vault_$${VAULT_VERSION}_SHA256SUMS | grep linux_amd64 | sha256sum -c
- mkdir -p .bin
- unzip vault_$${VAULT_VERSION}_linux_amd64.zip -d .bin
- rm vault_$${VAULT_VERSION}_linux_amd64.zip
when:
branch:
- main
- release/*
- name: unit-integration-tests
image: maven:3-eclipse-temurin-21
environment:
VAULT_VERSION: 1.17.6
commands:
- export PATH=$${DRONE_WORKSPACE}/.bin:$${PATH}
- mvn -B -P integration-test verify
when:
branch:
- main
- release/*

56
.github/workflows/ci-it.yml vendored Normal file
View 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 }}

View File

@ -1,15 +1,23 @@
name: CI
on: [ push, pull_request ]
on:
push:
branches:
- '**'
- '!main'
pull_request:
branches:
- '**'
- '!main'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
jdk: [ 11, 17, 21 ]
vault: [ '1.2.0', '1.11.12', '1.17.6' ]
include:
- jdk: 21
vault: '1.11.12'
analysis: true
steps:
- name: Checkout
@ -22,29 +30,13 @@ jobs:
java-version: ${{ matrix.jdk }}
distribution: 'temurin'
- name: Compile
run: mvn -B clean compile
- name: Set up Vault
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')
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)
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')
env:
VAULT_VERSION: ${{ matrix.vault }}
run: mvn -B -P coverage -P integration-test verify
run: ./mvnw -B clean compile
- name: Test (Unit)
if: github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/heads/release/')
run: mvn -B -P coverage verify
run: ./mvnw -B -P coverage verify
- name: Analysis
if: matrix.analysis
if: matrix.analysis && env.SONAR_TOKEN != ''
run: >
mvn -B sonar:sonar
./mvnw -B sonar:sonar
-Dsonar.host.url=https://sonarcloud.io
-Dsonar.organization=stklcode-github
env:

1
.gitignore vendored
View File

@ -7,6 +7,7 @@ release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar
.idea
*.iml

2
.mvn/wrapper/maven-wrapper.properties vendored Normal file
View 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

View File

@ -1,3 +1,41 @@
## 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

View File

@ -5,7 +5,7 @@
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/stklcode/jvaultconnector/blob/main/LICENSE.txt)
[![Maven Central Version](https://img.shields.io/maven-central/v/de.stklcode.jvault/jvault-connector)](https://central.sonatype.com/artifact/de.stklcode.jvault/jvault-connector)
![Logo](https://raw.githubusercontent.com/stklcode/jvaultconnector/main/assets/logo.png)
![Logo](assets/logo.png)
Java Vault Connector is a connector library for [Vault](https://www.vaultproject.io) by [Hashicorp](https://www.hashicorp.com) written in Java. The connector allows simple usage of Vault's secret store in own applications.
@ -18,7 +18,6 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
* Token
* Username/Password
* AppRole (register and authenticate)
* AppID (register and authenticate) [_deprecated_]
* Tokens
* Creation and lookup of tokens and token roles
* TokenBuilder for speaking creation of complex configurations
@ -29,10 +28,11 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
* Delete secrets
* Renew/revoke leases
* Raw secret content or JSON decoding
* SQL secret handling
* KV v1 and v2 support
* Database secret handling
* Transit API support
* Connector Factory with builder pattern
* Tested against Vault 1.2 to 1.17
* Tested against Vault 1.2 to 1.19
## Maven Artifact
@ -40,7 +40,7 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
<dependency>
<groupId>de.stklcode.jvault</groupId>
<artifactId>jvault-connector</artifactId>
<version>1.3.1</version>
<version>1.5.0</version>
</dependency>
```

332
mvnw vendored Executable file
View 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
View 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%

98
pom.xml
View File

@ -4,7 +4,7 @@
<groupId>de.stklcode.jvault</groupId>
<artifactId>jvault-connector</artifactId>
<version>1.3.1</version>
<version>1.5.1-SNAPSHOT</version>
<packaging>jar</packaging>
@ -33,6 +33,7 @@
<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>
@ -49,24 +50,24 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.18.0</version>
<version>2.18.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.18.0</version>
<version>2.18.3</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.1</version>
<version>5.12.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.14.1</version>
<version>5.17.0</version>
<scope>test</scope>
</dependency>
<dependency>
@ -78,25 +79,25 @@
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId>
<version>3.9.1</version>
<version>3.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.17.0</version>
<version>2.19.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>3.17.1</version>
<version>3.19.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>4.2.2</version>
<version>4.3.0</version>
<scope>test</scope>
</dependency>
</dependencies>
@ -107,26 +108,25 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<version>3.14.0</version>
<configuration>
<source>11</source>
<target>11</target>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>3.4.0</version>
<version>3.4.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.3</version>
<version>3.1.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.5.0</version>
<version>3.5.3</version>
<configuration>
<argLine>
@{argLine}
@ -137,7 +137,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.3</version>
<version>3.1.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -157,7 +157,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.0</version>
<version>3.5.3</version>
<configuration>
<argLine>
@{argLine}
@ -175,20 +175,46 @@
<plugin>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
<version>2.8.2</version>
<version>2.9.1</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.12</version>
<version>0.8.13</version>
</plugin>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>4.0.0.4121</version>
<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>
@ -225,7 +251,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.10.0</version>
<version>3.11.2</version>
<configuration>
<source>11</source>
</configuration>
@ -255,6 +281,9 @@
<goals>
<goal>makeBom</goal>
</goals>
<configuration>
<skipNotDeployed>false</skipNotDeployed>
</configuration>
</execution>
</executions>
</plugin>
@ -340,7 +369,7 @@
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>10.0.4</version>
<version>12.1.1</version>
<configuration>
<nvdApiKey>${env.NVD_API_KEY}</nvdApiKey>
<nvdDatafeedUrl>${env.NVD_DATAFEED_URL}</nvdDatafeedUrl>
@ -358,17 +387,20 @@
</profile>
<profile>
<id>sonatype</id>
<distributionManagement>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
<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>
</profile>
<profile>

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -58,7 +58,6 @@ public class HTTPVaultConnector implements VaultConnector {
private static final String PATH_ROLES = "/roles";
private static final String PATH_CREATE_ORPHAN = "/create-orphan";
private static final String PATH_AUTH_USERPASS = PATH_AUTH + "/userpass/login/";
private static final String PATH_AUTH_APPID = PATH_AUTH + "/app-id";
private static final String PATH_AUTH_APPROLE = PATH_AUTH + "/approle";
private static final String PATH_AUTH_APPROLE_ROLE = PATH_AUTH_APPROLE + "/role/%s%s";
@ -69,6 +68,11 @@ public class HTTPVaultConnector implements VaultConnector {
private static final String PATH_UNDELETE = "/undelete/";
private static final String PATH_DESTROY = "/destroy/";
private static final String PATH_TRANSIT = "transit";
private static final String PATH_TRANSIT_ENCRYPT = PATH_TRANSIT + "/encrypt/";
private static final String PATH_TRANSIT_DECRYPT = PATH_TRANSIT + "/decrypt/";
private static final String PATH_TRANSIT_HASH = PATH_TRANSIT + "/hash/";
private final RequestHelper request;
private boolean authorized = false; // Authorization status.
@ -82,14 +86,14 @@ public class HTTPVaultConnector implements VaultConnector {
*/
HTTPVaultConnector(final HTTPVaultConnectorBuilder builder) {
this.request = new RequestHelper(
((builder.isWithTLS()) ? "https" : "http") + "://" +
builder.getHost() +
((builder.getPort() != null) ? ":" + builder.getPort() : "") +
builder.getPrefix(),
builder.getNumberOfRetries(),
builder.getTimeout(),
builder.getTlsVersion(),
builder.getTrustedCA()
((builder.isWithTLS()) ? "https" : "http") + "://" +
builder.getHost() +
((builder.getPort() != null) ? ":" + builder.getPort() : "") +
builder.getPrefix(),
builder.getNumberOfRetries(),
builder.getTimeout(),
builder.getTlsVersion(),
builder.getTrustedCA()
);
}
@ -146,8 +150,8 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final SealResponse unseal(final String key, final Boolean reset) throws VaultConnectorException {
Map<String, String> param = mapOfStrings(
"key", key,
"reset", reset
"key", key,
"reset", reset
);
return request.put(PATH_UNSEAL, param, token, SealResponse.class);
@ -157,15 +161,15 @@ public class HTTPVaultConnector implements VaultConnector {
public HealthResponse getHealth() throws VaultConnectorException {
return request.get(
PATH_HEALTH,
// Force status code to be 200, so we don't need to modify the request sequence.
Map.of(
"standbycode", "200", // Default: 429.
"sealedcode", "200", // Default: 503.
"uninitcode", "200" // Default: 501.
),
token,
HealthResponse.class
PATH_HEALTH,
// Force status code to be 200, so we don't need to modify the request sequence.
Map.of(
"standbycode", "200", // Default: 429.
"sealedcode", "200", // Default: 503.
"uninitcode", "200" // Default: 501.
),
token,
HealthResponse.class
);
}
@ -195,28 +199,16 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final AuthResponse authUserPass(final String username, final String password)
throws VaultConnectorException {
throws VaultConnectorException {
final Map<String, String> payload = singletonMap("password", password);
return queryAuth(PATH_AUTH_USERPASS + username, payload);
}
@Override
@Deprecated(since = "0.4", forRemoval = true)
public final AuthResponse authAppId(final String appID, final String userID) throws VaultConnectorException {
return queryAuth(
PATH_AUTH_APPID + PATH_LOGIN,
Map.of(
"app_id", appID,
"user_id", userID
)
);
}
@Override
public final AuthResponse authAppRole(final String roleID, final String secretID) throws VaultConnectorException {
final Map<String, String> payload = mapOfStrings(
"role_id", roleID,
"secret_id", secretID
"role_id", roleID,
"secret_id", secretID
);
return queryAuth(PATH_AUTH_APPROLE + PATH_LOGIN, payload);
}
@ -230,7 +222,7 @@ public class HTTPVaultConnector implements VaultConnector {
* @throws VaultConnectorException on errors
*/
private AuthResponse queryAuth(final String path, final Map<String, String> payload)
throws VaultConnectorException {
throws VaultConnectorException {
/* Issue request and parse response */
AuthResponse auth = request.post(path, payload, token, AuthResponse.class);
/* verify response */
@ -241,40 +233,6 @@ public class HTTPVaultConnector implements VaultConnector {
return auth;
}
@Override
@Deprecated(since = "0.4", forRemoval = true)
public final boolean registerAppId(final String appID, final String policy, final String displayName)
throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
PATH_AUTH_APPID + "/map/app-id/" + appID,
Map.of(
"value", policy,
"display_name", displayName
),
token
);
return true;
}
@Override
@Deprecated(since = "0.4", forRemoval = true)
public final boolean registerUserId(final String appID, final String userID) throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
PATH_AUTH_APPID + "/map/user-id/" + userID,
singletonMap("value", appID),
token
);
return true;
}
@Override
public final boolean createAppRole(final AppRole role) throws VaultConnectorException {
requireAuth();
@ -291,10 +249,10 @@ public class HTTPVaultConnector implements VaultConnector {
requireAuth();
/* Request HTTP response and parse Secret */
return request.get(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, ""),
emptyMap(),
token,
AppRoleResponse.class
String.format(PATH_AUTH_APPROLE_ROLE, roleName, ""),
emptyMap(),
token,
AppRoleResponse.class
);
}
@ -313,10 +271,10 @@ public class HTTPVaultConnector implements VaultConnector {
requireAuth();
/* Issue request, parse response and extract Role ID */
return request.get(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/role-id"),
emptyMap(),
token,
RawDataResponse.class
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/role-id"),
emptyMap(),
token,
RawDataResponse.class
).getData().get("role_id").toString();
}
@ -326,9 +284,9 @@ public class HTTPVaultConnector implements VaultConnector {
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/role-id"),
singletonMap("role_id", roleID),
token
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/role-id"),
singletonMap("role_id", roleID),
token
);
return true;
@ -336,49 +294,49 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final AppRoleSecretResponse createAppRoleSecret(final String roleName, final AppRoleSecret secret)
throws VaultConnectorException {
throws VaultConnectorException {
requireAuth();
if (secret.getId() != null && !secret.getId().isEmpty()) {
return request.post(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/custom-secret-id"),
secret,
token,
AppRoleSecretResponse.class
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/custom-secret-id"),
secret,
token,
AppRoleSecretResponse.class
);
} else {
return request.post(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id"),
secret, token,
AppRoleSecretResponse.class
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id"),
secret, token,
AppRoleSecretResponse.class
);
}
}
@Override
public final AppRoleSecretResponse lookupAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException {
throws VaultConnectorException {
requireAuth();
/* Issue request and parse secret response */
return request.post(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id/lookup"),
new AppRoleSecret(secretID),
token,
AppRoleSecretResponse.class
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id/lookup"),
new AppRoleSecret(secretID),
token,
AppRoleSecretResponse.class
);
}
@Override
public final boolean destroyAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException {
throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id/destroy"),
new AppRoleSecret(secretID),
token);
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id/destroy"),
new AppRoleSecret(secretID),
token);
return true;
}
@ -388,10 +346,10 @@ public class HTTPVaultConnector implements VaultConnector {
requireAuth();
SecretListResponse secrets = request.get(
PATH_AUTH_APPROLE + "/role?list=true",
emptyMap(),
token,
SecretListResponse.class
PATH_AUTH_APPROLE + "/role?list=true",
emptyMap(),
token,
SecretListResponse.class
);
return secrets.getKeys();
@ -402,10 +360,10 @@ public class HTTPVaultConnector implements VaultConnector {
requireAuth();
SecretListResponse secrets = request.get(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id?list=true"),
emptyMap(),
token,
SecretListResponse.class
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id?list=true"),
emptyMap(),
token,
SecretListResponse.class
);
return secrets.getKeys();
@ -420,7 +378,7 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final SecretResponse readSecretVersion(final String mount, final String key, final Integer version)
throws VaultConnectorException {
throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse secret metadata */
Map<String, String> args = mapOfStrings("version", version);
@ -430,7 +388,7 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final MetadataResponse readSecretMetadata(final String mount, final String key)
throws VaultConnectorException {
throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse secret metadata */
@ -445,8 +403,8 @@ public class HTTPVaultConnector implements VaultConnector {
requireAuth();
Map<String, Object> payload = mapOf(
"max_versions", maxVersions,
"cas_required", casRequired
"max_versions", maxVersions,
"cas_required", casRequired
);
write(mount + PATH_METADATA + key, payload);
@ -468,13 +426,13 @@ public class HTTPVaultConnector implements VaultConnector {
/* Issue request and parse metadata response */
return request.post(
mount + PATH_DATA + key,
Map.of(
"data", data,
"options", options
),
token,
SecretVersionResponse.class
mount + PATH_DATA + key,
Map.of(
"data", data,
"options", options
),
token,
SecretVersionResponse.class
);
}
@ -489,7 +447,7 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final void write(final String key, final Map<String, Object> data, final Map<String, Object> options)
throws VaultConnectorException {
throws VaultConnectorException {
requireAuth();
if (key == null || key.isEmpty()) {
@ -502,8 +460,8 @@ public class HTTPVaultConnector implements VaultConnector {
// If options are given, split payload in two parts.
if (options != null) {
payload = Map.of(
"data", data,
"options", options
"data", data,
"options", options
);
}
@ -531,19 +489,19 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final void deleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
throws VaultConnectorException {
handleSecretVersions(mount, PATH_DELETE, key, versions);
}
@Override
public final void undeleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
throws VaultConnectorException {
handleSecretVersions(mount, PATH_UNDELETE, key, versions);
}
@Override
public final void destroySecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
throws VaultConnectorException {
handleSecretVersions(mount, PATH_DESTROY, key, versions);
}
@ -583,8 +541,8 @@ public class HTTPVaultConnector implements VaultConnector {
requireAuth();
Map<String, String> payload = mapOfStrings(
"lease_id", leaseID,
"increment", increment
"lease_id", leaseID,
"increment", increment
);
/* Issue request and parse secret response */
@ -641,10 +599,10 @@ public class HTTPVaultConnector implements VaultConnector {
/* Request HTTP response and parse Secret */
return request.get(
PATH_AUTH_TOKEN + PATH_LOOKUP,
singletonMap("token", token),
token,
TokenResponse.class
PATH_AUTH_TOKEN + PATH_LOOKUP,
singletonMap("token", token),
token,
TokenResponse.class
);
}
@ -693,6 +651,47 @@ public class HTTPVaultConnector implements VaultConnector {
return true;
}
@Override
public final TransitResponse transitEncrypt(final String keyName, final String plaintext)
throws VaultConnectorException {
requireAuth();
Map<String, Object> payload = mapOf(
"plaintext", plaintext
);
return request.post(PATH_TRANSIT_ENCRYPT + keyName, payload, token, TransitResponse.class);
}
@Override
public final TransitResponse transitDecrypt(final String keyName, final String ciphertext)
throws VaultConnectorException {
requireAuth();
Map<String, Object> payload = mapOf(
"ciphertext", ciphertext
);
return request.post(PATH_TRANSIT_DECRYPT + keyName, payload, token, TransitResponse.class);
}
@Override
public final TransitResponse transitHash(final String algorithm, final String input, final String format)
throws VaultConnectorException {
if (format != null && !"hex".equals(format) && !"base64".equals(format)) {
throw new IllegalArgumentException("Unsupported format " + format);
}
requireAuth();
Map<String, Object> payload = mapOf(
"input", input,
"format", format
);
return request.post(PATH_TRANSIT_HASH + algorithm, payload, token, TransitResponse.class);
}
/**
* Check for required authorization.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -20,18 +20,17 @@ 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.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
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;
import java.util.Objects;
/**
* Vault Connector Builder implementation for HTTP Vault connectors.
@ -96,10 +95,14 @@ public final class HTTPVaultConnectorBuilder {
* @since 1.0
*/
public HTTPVaultConnectorBuilder withBaseURL(final URI baseURL) {
return withTLS(!("http".equalsIgnoreCase(Objects.requireNonNullElse(baseURL.getScheme(), ""))))
.withHost(baseURL.getHost())
.withPort(baseURL.getPort())
.withPrefix(baseURL.getPath());
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);
}
/**
@ -301,13 +304,10 @@ public final class HTTPVaultConnectorBuilder {
*/
public HTTPVaultConnectorBuilder fromEnv() throws VaultConnectorException {
/* Parse URL from environment variable */
if (System.getenv(ENV_VAULT_ADDR) != null && !System.getenv(ENV_VAULT_ADDR).trim().isEmpty()) {
if (System.getenv(ENV_VAULT_ADDR) != null && !System.getenv(ENV_VAULT_ADDR).isBlank()) {
try {
var url = new URL(System.getenv(ENV_VAULT_ADDR));
this.host = url.getHost();
this.port = url.getPort();
this.tls = url.getProtocol().equals("https");
} catch (MalformedURLException e) {
withBaseURL(System.getenv(ENV_VAULT_ADDR));
} catch (URISyntaxException e) {
throw new ConnectionException("URL provided in environment variable malformed", e);
}
}
@ -315,7 +315,7 @@ public final class HTTPVaultConnectorBuilder {
/* Read number of retries */
if (System.getenv(ENV_VAULT_MAX_RETRIES) != null) {
try {
numberOfRetries = Integer.parseInt(System.getenv(ENV_VAULT_MAX_RETRIES));
withNumberOfRetries(Integer.parseInt(System.getenv(ENV_VAULT_MAX_RETRIES)));
} catch (NumberFormatException ignored) {
/* Ignore malformed values. */
}
@ -325,8 +325,12 @@ public final class HTTPVaultConnectorBuilder {
token = System.getenv(ENV_VAULT_TOKEN);
/* Parse certificate, if set */
if (System.getenv(ENV_VAULT_CACERT) != null && !System.getenv(ENV_VAULT_CACERT).trim().isEmpty()) {
return withTrustedCA(Paths.get(System.getenv(ENV_VAULT_CACERT)));
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;
}
@ -398,6 +402,28 @@ public final class HTTPVaultConnectorBuilder {
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.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -21,10 +21,7 @@ import de.stklcode.jvault.connector.model.*;
import de.stklcode.jvault.connector.model.response.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* Vault Connector interface.
@ -112,19 +109,6 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
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 The {@link AuthResponse}
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. App-ID was removed in Vault 1.12.
* Consider using {@link #authAppRole} instead.
*/
@Deprecated(since = "0.4", forRemoval = true)
AuthResponse authAppId(final String appID, final String userID) throws VaultConnectorException;
/**
* Authorize to Vault using AppRole method without secret ID.
*
@ -148,21 +132,6 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
AuthResponse authAppRole(final String roleID, final String secretID) throws VaultConnectorException;
/**
* Register new App-ID with policy.
*
* @param appID The unique App-ID
* @param policy The policy to associate with
* @param displayName Arbitrary name to display
* @return {@code true} on success
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. App-ID was removed in Vault 1.12.
* Consider using {@link #createAppRole} instead.
*/
@Deprecated(since = "0.4", forRemoval = true)
boolean registerAppId(final String appID, final String policy, final String displayName)
throws VaultConnectorException;
/**
* Register a new AppRole role from given metamodel.
*
@ -222,7 +191,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @since 0.4.0
*/
default boolean createAppRole(final String roleName, final List<String> policies, final String roleID)
throws VaultConnectorException {
throws VaultConnectorException {
return createAppRole(AppRole.builder(roleName).withTokenPolicies(policies).withId(roleID).build());
}
@ -288,7 +257,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @since 0.4.0
*/
default AppRoleSecretResponse createAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException {
throws VaultConnectorException {
return createAppRoleSecret(roleName, new AppRoleSecret(secretID));
}
@ -302,7 +271,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @since 0.4.0
*/
AppRoleSecretResponse createAppRoleSecret(final String roleName, final AppRoleSecret secret)
throws VaultConnectorException;
throws VaultConnectorException;
/**
* Lookup an AppRole secret.
@ -314,7 +283,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @since 0.4.0
*/
AppRoleSecretResponse lookupAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException;
throws VaultConnectorException;
/**
* Destroy an AppRole secret.
@ -344,38 +313,6 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
List<String> listAppRoleSecrets(final String roleName) throws VaultConnectorException;
/**
* Register User-ID with App-ID.
*
* @param appID The App-ID
* @param userID The User-ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. App-ID was removed in Vault 1.12.
* Consider using {@link #createAppRoleSecret} instead.
*/
@Deprecated(since = "0.4", forRemoval = true)
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 {@code true} on success
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. App-ID was removed in Vault 1.12.
*/
@Deprecated(since = "0.4", forRemoval = true)
default boolean registerAppUserId(final String appID,
final String policy,
final String displayName,
final String userID) throws VaultConnectorException {
return registerAppId(appID, policy, userID) && registerUserId(appID, userID);
}
/**
* Get authorization status.
*
@ -461,7 +398,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @since 0.8
*/
SecretResponse readSecretVersion(final String mount, final String key, final Integer version)
throws VaultConnectorException;
throws VaultConnectorException;
/**
* Retrieve secret metadata from Vault.
@ -539,7 +476,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @since 0.8 {@code options} parameter added
*/
void write(final String key, final Map<String, Object> data, final Map<String, Object> options)
throws VaultConnectorException;
throws VaultConnectorException;
/**
* Delete key from Vault.
@ -587,7 +524,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @since 0.8
*/
void deleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
throws VaultConnectorException;
/**
* Undelete (restore) secret versions from Vault.
@ -600,7 +537,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @since 0.8
*/
void undeleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
throws VaultConnectorException;
/**
* Destroy secret versions from Vault.
@ -613,7 +550,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @since 0.8
*/
void destroySecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
throws VaultConnectorException;
/**
* Revoke given lease immediately.
@ -734,6 +671,82 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
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.
*
@ -741,7 +754,9 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @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");
}
@ -753,7 +768,9 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @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");
}
@ -765,34 +782,38 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @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 MSSQL backend at default mount point.
* 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 SQL backends.
* Read credentials for database backends.
*
* @param role the role name
* @param mount mount point of the SQL backend
* @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 {
throws VaultConnectorException {
return (CredentialsResponse) read(mount + "/creds/" + role);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -2,8 +2,8 @@ package de.stklcode.jvault.connector.internal;
import com.fasterxml.jackson.core.JsonProcessingException;
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 de.stklcode.jvault.connector.exception.*;
import de.stklcode.jvault.connector.model.response.ErrorResponse;
@ -44,7 +44,7 @@ public final class RequestHelper implements Serializable {
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 ObjectMapper jsonMapper;
private final JsonMapper jsonMapper;
/**
* Constructor of the request helper.
@ -65,10 +65,11 @@ public final class RequestHelper implements Serializable {
this.timeout = timeout;
this.tlsVersion = tlsVersion;
this.trustedCaCert = trustedCaCert;
this.jsonMapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
this.jsonMapper = JsonMapper.builder()
.addModule(new JavaTimeModule())
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
.build();
}
/**
@ -115,7 +116,7 @@ public final class RequestHelper implements Serializable {
* @since 0.8
*/
public <T> T post(final String path, final Object payload, final String token, final Class<T> target)
throws VaultConnectorException {
throws VaultConnectorException {
try {
String response = post(path, payload, token);
return jsonMapper.readValue(response, target);
@ -134,7 +135,7 @@ public final class RequestHelper implements Serializable {
* @since 0.8
*/
public void postWithoutResponse(final String path, final Object payload, final String token)
throws VaultConnectorException {
throws VaultConnectorException {
if (!post(path, payload, token).isEmpty()) {
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
}
@ -151,7 +152,7 @@ public final class RequestHelper implements Serializable {
* @since 0.8 Added {@code token} parameter.
*/
public String put(final String path, final Map<String, String> payload, final String token)
throws VaultConnectorException {
throws VaultConnectorException {
// Initialize PUT.
var req = HttpRequest.newBuilder(URI.create(baseURL + path));
@ -185,7 +186,7 @@ public final class RequestHelper implements Serializable {
* @since 0.8
*/
public <T> T put(final String path, final Map<String, String> payload, final String token, final Class<T> target)
throws VaultConnectorException {
throws VaultConnectorException {
try {
String response = put(path, payload, token);
return jsonMapper.readValue(response, target);
@ -204,7 +205,7 @@ public final class RequestHelper implements Serializable {
* @since 0.8
*/
public void putWithoutResponse(final String path, final Map<String, String> payload, final String token)
throws VaultConnectorException {
throws VaultConnectorException {
if (!put(path, payload, token).isEmpty()) {
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
}
@ -256,15 +257,15 @@ public final class RequestHelper implements Serializable {
* @since 0.8 Added {@code token} parameter.
*/
public String get(final String path, final Map<String, String> payload, final String token)
throws VaultConnectorException {
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("&"))
payload.entrySet().stream().map(par ->
URLEncoder.encode(par.getKey(), UTF_8) + "=" + URLEncoder.encode(par.getValue(), UTF_8)
).collect(Collectors.joining("&"))
);
}
@ -297,7 +298,7 @@ public final class RequestHelper implements Serializable {
* @since 0.8
*/
public <T> T get(final String path, final Map<String, String> payload, final String token, final Class<T> target)
throws VaultConnectorException {
throws VaultConnectorException {
try {
String response = get(path, payload, token);
return jsonMapper.readValue(response, target);
@ -333,8 +334,8 @@ public final class RequestHelper implements Serializable {
// Execute request.
try {
HttpResponse<InputStream> response = client.sendAsync(
requestBuilder.build(),
HttpResponse.BodyHandlers.ofInputStream()
requestBuilder.build(),
HttpResponse.BodyHandlers.ofInputStream()
).join();
/* Check if response is valid */

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -331,28 +331,28 @@ public final class AppRole implements Serializable {
}
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);
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);
localSecretIds, tokenTtl, tokenMaxTtl, tokenPolicies, tokenBoundCidrs, tokenExplicitMaxTtl,
tokenNoDefaultPolicy, tokenNumUses, tokenPeriod, tokenType);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -181,19 +181,19 @@ public final class AppRoleSecret implements Serializable {
}
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);
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);
ttl);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -24,8 +24,6 @@ package de.stklcode.jvault.connector.model;
*/
public enum AuthBackend {
TOKEN("token"),
@Deprecated(since = "1.1.3", forRemoval = true)
APPID("app-id"),
APPROLE("approle"),
USERPASS("userpass"),
GITHUB("github"), // Not supported yet.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -227,24 +227,24 @@ public final class Token implements Serializable {
}
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);
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);
meta, renewable, period, entityAlias);
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -245,27 +245,27 @@ public final class TokenRole implements Serializable {
}
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);
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);
orphan, renewable, pathSuffix, allowedEntityAliases, tokenBoundCidrs, tokenExplicitMaxTtl,
tokenNoDefaultPolicy, tokenNumUses, tokenPeriod, tokenType);
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -187,19 +187,19 @@ public final class HealthResponse implements VaultResponse {
}
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);
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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -191,24 +191,24 @@ public final class SealResponse implements VaultResponse {
}
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);
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);
clusterName, clusterId, migration, recoverySeal, storageType);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -18,8 +18,8 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
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 de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
@ -85,10 +85,11 @@ public abstract class SecretResponse extends VaultDataResponse {
} else if (type.isInstance(rawValue)) {
return type.cast(rawValue);
} else {
var om = new ObjectMapper()
.registerModule(new JavaTimeModule())
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
var om = JsonMapper.builder()
.addModule(new JavaTimeModule())
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
.build();
if (rawValue instanceof String) {
return om.readValue((String) rawValue, type);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -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);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -115,6 +115,7 @@ public abstract class VaultDataResponse implements VaultResponse {
public final String getMountType() {
return mountType;
}
@Override
public boolean equals(Object o) {
if (this == o) {
@ -124,13 +125,13 @@ public abstract class VaultDataResponse implements VaultResponse {
}
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);
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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -171,22 +171,22 @@ public final class AuthData implements Serializable {
}
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);
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);
entityId, tokenType, orphan, numUses, mfaRequirement);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -202,19 +202,19 @@ public final class AuthMethod implements Serializable {
}
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);
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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -21,7 +21,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@ -37,9 +36,6 @@ import java.util.Objects;
public final class SecretMetadata implements Serializable {
private static final long serialVersionUID = -905059942871916214L;
private static final DateTimeFormatter TIME_FORMAT =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX");
@JsonProperty("created_time")
private ZonedDateTime createdTime;
@ -67,19 +63,6 @@ public final class SecretMetadata implements Serializable {
@JsonProperty("delete_version_after")
private String deleteVersionAfter;
/**
* @return Time of secret creation as raw string representation.
* @deprecated Method left for backwards compatibility only. Use {@link #getCreatedTime()} instead.
*/
@Deprecated(since = "1.2", forRemoval = true)
public String getCreatedTimeString() {
if (createdTime != null) {
return TIME_FORMAT.format(createdTime);
}
return null;
}
/**
* @return Time of secret creation.
*/
@ -108,19 +91,6 @@ public final class SecretMetadata implements Serializable {
return oldestVersion;
}
/**
* @return Time of secret update as raw string representation.
* @deprecated Method left for backwards compatibility only. Use {@link #getUpdatedTime()} instead.
*/
@Deprecated(since = "1.2", forRemoval = true)
public String getUpdatedTimeString() {
if (updatedTime != null) {
return TIME_FORMAT.format(updatedTime);
}
return null;
}
/**
* @return Time of secret update.
*/
@ -168,14 +138,14 @@ public final class SecretMetadata implements Serializable {
}
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);
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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -21,7 +21,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -37,9 +36,6 @@ import java.util.Objects;
public final class TokenData implements Serializable {
private static final long serialVersionUID = -5749716740973138916L;
private static final DateTimeFormatter TIME_FORMAT =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX");
@JsonProperty("accessor")
private String accessor;
@ -127,20 +123,6 @@ public final class TokenData implements Serializable {
return entityId;
}
/**
* @return Expire time as raw string value
* @since 0.9
* @deprecated Method left for backwards compatibility only. Use {@link #getExpireTime()} instead.
*/
@Deprecated(since = "1.2", forRemoval = true)
public String getExpireTimeString() {
if (expireTime != null) {
return TIME_FORMAT.format(expireTime);
}
return null;
}
/**
* @return Expire time (parsed)
* @since 0.9
@ -164,20 +146,6 @@ public final class TokenData implements Serializable {
return id;
}
/**
* @return Issue time as raw string value
* @since 0.9
* @deprecated Method left for backwards compatibility only. Use {@link #getIssueTime()} instead.
*/
@Deprecated(since = "1.2", forRemoval = true)
public String getIssueTimeString() {
if (issueTime != null) {
return TIME_FORMAT.format(issueTime);
}
return null;
}
/**
* @return Expire time (parsed)
* @since 0.9
@ -254,27 +222,27 @@ public final class TokenData implements Serializable {
}
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);
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);
issueTime, meta, numUses, orphan, path, policies, renewable, ttl, type);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -21,7 +21,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@ -37,9 +36,6 @@ import java.util.Objects;
public final class VersionMetadata implements Serializable {
private static final long serialVersionUID = 8495687554714216478L;
private static final DateTimeFormatter TIME_FORMAT =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX");
@JsonProperty("created_time")
private ZonedDateTime createdTime;
@ -55,19 +51,6 @@ public final class VersionMetadata implements Serializable {
@JsonProperty("custom_metadata")
private HashMap<String, String> customMetadata;
/**
* @return Time of secret creation as raw string representation.
* @deprecated Method left for backwards compatibility only. Use {@link #getCreatedTime()} instead.
*/
@Deprecated(since = "1.2", forRemoval = true)
public String getCreatedTimeString() {
if (createdTime != null) {
return TIME_FORMAT.format(createdTime);
}
return null;
}
/**
* @return Time of secret creation.
*/
@ -75,19 +58,6 @@ public final class VersionMetadata implements Serializable {
return createdTime;
}
/**
* @return Time for secret deletion as raw string representation.
* @deprecated Method left for backwards compatibility only. Use {@link #getDeletionTime()} instead.
*/
@Deprecated(since = "1.2", forRemoval = true)
public String getDeletionTimeString() {
if (deletionTime != null) {
return TIME_FORMAT.format(deletionTime);
}
return null;
}
/**
* @return Time for secret deletion.
*/
@ -126,10 +96,10 @@ public final class VersionMetadata implements Serializable {
}
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);
Objects.equals(createdTime, that.createdTime) &&
Objects.equals(deletionTime, that.deletionTime) &&
Objects.equals(version, that.version) &&
Objects.equals(customMetadata, that.customMetadata);
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -80,9 +80,9 @@ public class WrapInfo implements Serializable {
}
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);
Objects.equals(ttl, that.ttl) &&
Objects.equals(creationTime, that.creationTime) &&
Objects.equals(creationPath, that.creationPath);
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -31,6 +31,7 @@ module de.stklcode.jvault.connector {
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;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -25,7 +25,10 @@ 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.*;
@ -38,6 +41,8 @@ import static org.junit.jupiter.api.Assertions.*;
*/
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";
@ -112,6 +117,22 @@ class HTTPVaultConnectorBuilderTest {
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(() -> {
@ -128,19 +149,6 @@ class HTTPVaultConnectorBuilderTest {
return null;
});
// Provide CA certificate.
String vaultCacert = tempDir.toString() + "/doesnotexist";
withVaultEnv(VAULT_ADDR, vaultCacert, VAULT_MAX_RETRIES.toString(), null).execute(() -> {
TlsException e = assertThrows(
TlsException.class,
() -> HTTPVaultConnector.builder().fromEnv(),
"Creation with unknown cert path failed"
);
assertEquals(vaultCacert, assertInstanceOf(NoSuchFileException.class, e.getCause()).getFile());
return null;
});
// Automatic authentication.
withVaultEnv(VAULT_ADDR, null, VAULT_MAX_RETRIES.toString(), VAULT_TOKEN).execute(() -> {
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
@ -164,6 +172,59 @@ class HTTPVaultConnectorBuilderTest {
});
}
/**
* 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)

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -25,7 +25,6 @@ import de.stklcode.jvault.connector.model.response.*;
import de.stklcode.jvault.connector.test.Credentials;
import de.stklcode.jvault.connector.test.VaultConfiguration;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.condition.EnabledIf;
import org.junit.jupiter.api.io.TempDir;
import java.io.*;
@ -53,7 +52,7 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
* @since 0.1
*/
class HTTPVaultConnectorIT {
private static String VAULT_VERSION = "1.17.6"; // The vault version this test is supposed to run against.
private static String VAULT_VERSION = "1.19.0"; // The vault version this test is supposed to run against.
private static final String KEY1 = "E38bkCm0VhUvpdCKGQpcohhD9XmcHJ/2hreOSY019Lho";
private static final String KEY2 = "O5OHwDleY3IiPdgw61cgHlhsrEm6tVJkrxhF6QAnILd1";
private static final String KEY3 = "mw7Bm3nbt/UWa/juDjjL2EPQ04kiJ0saC5JEXwJvXYsB";
@ -61,7 +60,6 @@ class HTTPVaultConnectorIT {
private static final String USER_VALID = "validUser";
private static final String PASS_VALID = "validPass";
private static boolean legacy;
private Process vaultProcess;
private VaultConnector connector;
@ -72,9 +70,6 @@ class HTTPVaultConnectorIT {
VAULT_VERSION = System.getenv("VAULT_VERSION");
System.out.println("Vault version set to " + VAULT_VERSION);
}
if (compareVersions(VAULT_VERSION, "1.12.0") < 0) {
legacy = true;
}
}
/**
@ -549,74 +544,6 @@ class HTTPVaultConnectorIT {
}
}
@Nested
@DisplayName("App-ID Tests")
@EnabledIf(value = "de.stklcode.jvault.connector.HTTPVaultConnectorIT#isLegacy",
disabledReason = "AppID tests no longer available for Vault 1.12 and above")
@SuppressWarnings("deprecation")
class AppIdTests {
private static final String APP_ID = "152AEA38-85FB-47A8-9CBD-612D645BFACA";
private static final String USER_ID = "5ADF8218-D7FB-4089-9E38-287465DBF37E";
/**
* App-ID authentication roundtrip.
*/
@Test
@Order(10)
@DisplayName("Authenticate with App-ID")
void authAppIdTest() {
// Try unauthorized access first.
assumeFalse(connector.isAuthorized());
assertThrows(
AuthorizationRequiredException.class,
() -> connector.registerAppId("", "", ""),
"Expected exception not thrown"
);
assertThrows(
AuthorizationRequiredException.class,
() -> connector.registerUserId("", ""),
"Expected exception not thrown"
);
}
/**
* App-ID authentication roundtrip.
*/
@Test
@Order(20)
@DisplayName("Register App-ID")
void registerAppIdTest() {
// Authorize.
authRoot();
assumeTrue(connector.isAuthorized());
// Register App-ID.
boolean res = assertDoesNotThrow(
() -> connector.registerAppId(APP_ID, "user", "App Name"),
"Failed to register App-ID"
);
assertTrue(res, "Failed to register App-ID");
// Register User-ID.
res = assertDoesNotThrow(
() -> connector.registerUserId(APP_ID, USER_ID),
"Failed to register App-ID"
);
assertTrue(res, "Failed to register App-ID");
connector.resetAuth();
assumeFalse(connector.isAuthorized());
// Authenticate with created credentials.
assertDoesNotThrow(
() -> connector.authAppId(APP_ID, USER_ID),
"Failed to authenticate using App-ID"
);
assertTrue(connector.isAuthorized(), "Authorization flag not set after App-ID login");
}
}
@Nested
@DisplayName("AppRole Tests")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ -1062,6 +989,75 @@ class HTTPVaultConnectorIT {
}
}
@Nested
@DisplayName("Transit Tests")
class TransitTests {
@Test
@DisplayName("Transit encryption")
void transitEncryptTest() {
assertDoesNotThrow(() -> connector.authToken(TOKEN_ROOT));
assumeTrue(connector.isAuthorized());
TransitResponse transitResponse = assertDoesNotThrow(
() -> connector.transitEncrypt("my-key", "dGVzdCBtZQ=="),
"Failed to encrypt via transit"
);
assertNotNull(transitResponse.getCiphertext());
assertTrue(transitResponse.getCiphertext().startsWith("vault:v1:"));
transitResponse = assertDoesNotThrow(
() -> connector.transitEncrypt("my-key", "test me".getBytes(UTF_8)),
"Failed to encrypt binary data via transit"
);
assertNotNull(transitResponse.getCiphertext());
assertTrue(transitResponse.getCiphertext().startsWith("vault:v1:"));
}
@Test
@DisplayName("Transit decryption")
void transitDecryptTest() {
assertDoesNotThrow(() -> connector.authToken(TOKEN_ROOT));
assumeTrue(connector.isAuthorized());
TransitResponse transitResponse = assertDoesNotThrow(
() -> connector.transitDecrypt("my-key", "vault:v1:1mhLVkBAR2nrFtIkJF/qg57DWfRj0FWgR6tvkGO8XOnL6sw="),
"Failed to decrypt via transit"
);
assertEquals("dGVzdCBtZQ==", transitResponse.getPlaintext());
}
@Test
@DisplayName("Transit hash")
void transitHashText() {
assertDoesNotThrow(() -> connector.authToken(TOKEN_ROOT));
assumeTrue(connector.isAuthorized());
TransitResponse transitResponse = assertDoesNotThrow(
() -> connector.transitHash("sha2-512", "dGVzdCBtZQ=="),
"Failed to hash via transit"
);
assertEquals("7677af0ee4effaa9f35e9b1e82d182f79516ab8321786baa23002de7c06851059492dd37d5fc3791f17d81d4b58198d24a6fd8bbd62c42c1c30b371da500f193", transitResponse.getSum());
TransitResponse transitResponseBase64 = assertDoesNotThrow(
() -> connector.transitHash("sha2-256", "dGVzdCBtZQ==", "base64"),
"Failed to hash via transit with base64 output"
);
assertEquals("5DfYkW7cvGLkfy36cXhqmZcygEy9HpnFNB4WWXKOl1M=", transitResponseBase64.getSum());
transitResponseBase64 = assertDoesNotThrow(
() -> connector.transitHash("sha2-256", "test me".getBytes(UTF_8), "base64"),
"Failed to hash binary data via transit"
);
assertEquals("5DfYkW7cvGLkfy36cXhqmZcygEy9HpnFNB4WWXKOl1M=", transitResponseBase64.getSum());
}
}
@Nested
@DisplayName("Misc Tests")
class MiscTests {
@ -1079,13 +1075,9 @@ class HTTPVaultConnectorIT {
() -> connector.getAuthBackends(),
"Could not list supported auth backends"
);
if (legacy) {
assertEquals(4, supportedBackends.size());
assertTrue(supportedBackends.containsAll(List.of(AuthBackend.TOKEN, AuthBackend.USERPASS, AuthBackend.APPID, AuthBackend.APPROLE)));
} else {
assertEquals(3, supportedBackends.size());
assertTrue(supportedBackends.containsAll(List.of(AuthBackend.TOKEN, AuthBackend.USERPASS, AuthBackend.APPROLE)));
}
assertEquals(3, supportedBackends.size());
assertTrue(supportedBackends.containsAll(List.of(AuthBackend.TOKEN, AuthBackend.USERPASS, AuthBackend.APPROLE)));
}
/**
@ -1211,11 +1203,7 @@ class HTTPVaultConnectorIT {
*/
private VaultConfiguration initializeVault(File dir, boolean tls) throws IllegalStateException, IOException {
File dataDir = new File(dir, "data");
if (legacy) {
copyDirectory(new File(getClass().getResource("/data_dir_legacy").getPath()), dataDir);
} else {
copyDirectory(new File(getClass().getResource("/data_dir").getPath()), dataDir);
}
copyDirectory(new File(getClass().getResource("/data_dir").getPath()), dataDir);
// Generate vault local unencrypted configuration.
VaultConfiguration config = new VaultConfiguration()
@ -1311,35 +1299,4 @@ class HTTPVaultConnectorIT {
th.printStackTrace(new PrintWriter(sw, true));
return sw.getBuffer().toString();
}
/**
* Compare two version strings.
*
* @param version1 Version 1
* @param version2 Version 2
* @return negative value if version 1 is smaller than version2, positive value of version 1 is greater, 0 if equal
*/
private static int compareVersions(String version1, String version2) {
int comparisonResult = 0;
String[] version1Splits = version1.split("\\.");
String[] version2Splits = version2.split("\\.");
int maxLengthOfVersionSplits = Math.max(version1Splits.length, version2Splits.length);
for (int i = 0; i < maxLengthOfVersionSplits; i++) {
Integer v1 = i < version1Splits.length ? Integer.parseInt(version1Splits[i]) : 0;
Integer v2 = i < version2Splits.length ? Integer.parseInt(version2Splits[i]) : 0;
int compare = v1.compareTo(v2);
if (compare != 0) {
comparisonResult = compare;
break;
}
}
return comparisonResult;
}
private static boolean isLegacy() {
return legacy;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -17,13 +17,13 @@
package de.stklcode.jvault.connector;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
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 org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.function.Executable;
import java.io.IOException;
@ -36,9 +36,7 @@ import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collections;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.junit.jupiter.api.Assertions.*;
/**
@ -48,26 +46,23 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.7.0
*/
@WireMockTest
class HTTPVaultConnectorTest {
@RegisterExtension
static WireMockExtension wireMock = WireMockExtension.newInstance()
.options(wireMockConfig().dynamicPort())
.build();
/**
* Test exceptions thrown during request.
*/
@Test
void requestExceptionTest() throws IOException, URISyntaxException {
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.url("/")).withTimeout(250).build();
void requestExceptionTest(WireMockRuntimeInfo wireMock) throws IOException, URISyntaxException {
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withTimeout(250).build();
// 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"
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");
@ -76,9 +71,9 @@ class HTTPVaultConnectorTest {
// Simulate permission denied response.
mockHttpResponse(responseCode, "{\"errors\":[\"permission denied\"]}", "application/json");
assertThrows(
PermissionDeniedException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
PermissionDeniedException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
// Test exception thrown during request.
@ -86,22 +81,22 @@ class HTTPVaultConnectorTest {
connector = HTTPVaultConnector.builder("http://localst:" + s.getLocalPort() + "/").withTimeout(250).build();
}
e = assertThrows(
ConnectionException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
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.url("/")).withNumberOfRetries(1).withTimeout(250).build();
connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withNumberOfRetries(1).withTimeout(250).build();
wireMock.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"))
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");
}
@ -164,9 +159,9 @@ class HTTPVaultConnectorTest {
connector = HTTPVaultConnector.builder("http://localst:" + s.getLocalPort()).withTimeout(250).build();
}
ConnectionException e = assertThrows(
ConnectionException.class,
connector::sealStatus,
"Querying seal status succeeded on invalid instance"
ConnectionException.class,
connector::sealStatus,
"Querying seal status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
}
@ -182,9 +177,9 @@ class HTTPVaultConnectorTest {
connector = HTTPVaultConnector.builder("http://localhost:" + s.getLocalPort() + "/").withTimeout(250).build();
}
ConnectionException e = assertThrows(
ConnectionException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
ConnectionException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
}
@ -193,8 +188,8 @@ class HTTPVaultConnectorTest {
* Test behavior on unparsable responses.
*/
@Test
void parseExceptionTest() throws URISyntaxException {
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.url("/")).withTimeout(250).build();
void parseExceptionTest(WireMockRuntimeInfo wireMock) throws URISyntaxException {
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withTimeout(250).build();
// Mock authorization.
setPrivate(connector, "authorized", true);
// Mock response.
@ -227,8 +222,8 @@ class HTTPVaultConnectorTest {
* Test requests that expect an empty response with code 204, but receive a 200 body.
*/
@Test
void nonEmpty204ResponseTest() throws URISyntaxException {
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.url("/")).withTimeout(250).build();
void nonEmpty204ResponseTest(WireMockRuntimeInfo wireMock) throws URISyntaxException {
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withTimeout(250).build();
// Mock authorization.
setPrivate(connector, "authorized", true);
// Mock response.
@ -236,57 +231,45 @@ class HTTPVaultConnectorTest {
// Now test the methods expecting a 204.
assertThrows(
InvalidResponseException.class,
() -> connector.registerAppId("appID", "policy", "displayName"),
"registerAppId() with 200 response succeeded"
InvalidResponseException.class,
() -> connector.createAppRole("appID", Collections.singletonList("policy")),
"createAppRole() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.registerUserId("appID", "userID"),
"registerUserId() with 200 response succeeded"
InvalidResponseException.class,
() -> connector.deleteAppRole("roleName"),
"deleteAppRole() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.createAppRole("appID", Collections.singletonList("policy")),
"createAppRole() with 200 response succeeded"
InvalidResponseException.class,
() -> connector.setAppRoleID("roleName", "roleID"),
"setAppRoleID() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.deleteAppRole("roleName"),
"deleteAppRole() with 200 response succeeded"
InvalidResponseException.class,
() -> connector.destroyAppRoleSecret("roleName", "secretID"),
"destroyAppRoleSecret() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.setAppRoleID("roleName", "roleID"),
"setAppRoleID() with 200 response succeeded"
InvalidResponseException.class,
() -> connector.destroyAppRoleSecret("roleName", "secretUD"),
"destroyAppRoleSecret() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.destroyAppRoleSecret("roleName", "secretID"),
"destroyAppRoleSecret() with 200 response succeeded"
InvalidResponseException.class,
() -> connector.delete("key"),
"delete() 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"
InvalidResponseException.class,
() -> connector.revoke("leaseID"),
"destroyAppRoleSecret() with 200 response succeeded"
);
}
@ -322,10 +305,10 @@ class HTTPVaultConnectorTest {
}
private void mockHttpResponse(int status, String body, String contentType) {
wireMock.stubFor(
WireMock.any(anyUrl()).willReturn(
aResponse().withStatus(status).withBody(body).withHeader("Content-Type", contentType)
)
stubFor(
WireMock.any(anyUrl()).willReturn(
aResponse().withStatus(status).withBody(body).withHeader("Content-Type", contentType)
)
);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -3,6 +3,7 @@ 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;
@ -29,10 +30,11 @@ public abstract class AbstractModelTest<T> {
*/
protected AbstractModelTest(Class<T> modelClass) {
this.modelClass = modelClass;
this.objectMapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);
this.objectMapper = JsonMapper.builder()
.addModule(new JavaTimeModule())
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
.build();
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -33,10 +33,8 @@ class AuthBackendTest {
* Test forType() method.
*/
@Test
@SuppressWarnings("deprecation")
void forTypeTest() {
assertEquals(AuthBackend.TOKEN, AuthBackend.forType("token"));
assertEquals(AuthBackend.APPID, AuthBackend.forType("app-id"));
assertEquals(AuthBackend.USERPASS, AuthBackend.forType("userpass"));
assertEquals(AuthBackend.GITHUB, AuthBackend.forType("github"));
assertEquals(AuthBackend.UNKNOWN, AuthBackend.forType(""));

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -173,7 +173,7 @@ class TokenRoleTest extends AbstractModelTest<TokenRole> {
assertNull(role.getTokenType());
// Empty builder should be equal to no-arg construction.
assertEquals(role, new TokenRole());
assertEquals(new TokenRole(), role);
// Optional fields should be ignored, so JSON string should be empty.
assertEquals("{}", objectMapper.writeValueAsString(role));

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -105,7 +105,7 @@ class TokenTest extends AbstractModelTest<Token> {
assertEquals("{}", objectMapper.writeValueAsString(token));
// Empty builder should be equal to no-arg construction.
assertEquals(token, new Token());
assertEquals(new Token(), token);
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -115,9 +115,7 @@ class MetaSecretResponseTest extends AbstractModelTest<MetaSecretResponse> {
);
assertSecretData(res);
assertNotNull(res.getMetadata(), "SecretResponse does not contain metadata");
assertEquals(SECRET_META_CREATED, res.getMetadata().getCreatedTimeString(), "Incorrect creation date string");
assertNotNull(res.getMetadata().getCreatedTime(), "Creation date parsing failed");
assertNull(res.getMetadata().getDeletionTimeString(), "Incorrect deletion date string");
assertNull(res.getMetadata().getDeletionTime(), "Incorrect deletion date");
assertFalse(res.getMetadata().isDestroyed(), "Secret destroyed when not expected");
assertEquals(1, res.getMetadata().getVersion(), "Incorrect secret version");
@ -130,9 +128,7 @@ class MetaSecretResponseTest extends AbstractModelTest<MetaSecretResponse> {
);
assertSecretData(res);
assertNotNull(res.getMetadata(), "SecretResponse does not contain metadata");
assertEquals(SECRET_META_CREATED, res.getMetadata().getCreatedTimeString(), "Incorrect creation date string");
assertNotNull(res.getMetadata().getCreatedTime(), "Creation date parsing failed");
assertEquals(SECRET_META_DELETED, res.getMetadata().getDeletionTimeString(), "Incorrect deletion date string");
assertNotNull(res.getMetadata().getDeletionTime(), "Incorrect deletion date");
assertTrue(res.getMetadata().isDestroyed(), "Secret destroyed when not expected");
assertEquals(2, res.getMetadata().getVersion(), "Incorrect secret version");

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -100,20 +100,16 @@ class MetadataResponseTest extends AbstractModelTest<MetadataResponse> {
assertNotNull(res, "Parsed response is NULL");
assertNotNull(res.getMetadata(), "Parsed metadata is NULL");
assertEquals(CAS_REQUIRED, res.getMetadata().isCasRequired(), "Incorrect CAS required flag");
assertEquals(V1_TIME, res.getMetadata().getCreatedTimeString(), "Incorrect created time");
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");
assertEquals(V3_TIME, res.getMetadata().getUpdatedTimeString(), "Incorrect updated time");
assertNotNull(res.getMetadata().getUpdatedTime(), "Parting updated time failed");
assertEquals(3, res.getMetadata().getVersions().size(), "Incorrect number of versions");
assertEquals(V2_TIME, res.getMetadata().getVersions().get(1).getDeletionTimeString(), "Incorrect version 1 delete time");
assertNotNull(res.getMetadata().getVersions().get(1).getDeletionTime(), "Parsing version delete time failed");
assertTrue(res.getMetadata().getVersions().get(1).isDestroyed(), "Incorrect version 1 destroyed state");
assertEquals(V2_TIME, res.getMetadata().getVersions().get(2).getCreatedTimeString(), "Incorrect version 2 created time");
assertNotNull(res.getMetadata().getVersions().get(2).getCreatedTime(), "Parsing version created failed");
assertFalse(res.getMetadata().getVersions().get(3).isDestroyed(), "Incorrect version 3 destroyed state");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -67,8 +67,6 @@ class SecretVersionResponseTest extends AbstractModelTest<SecretVersionResponse>
);
assertNotNull(res, "Parsed response is NULL");
assertNotNull(res.getMetadata(), "Parsed metadata is NULL");
assertEquals(CREATION_TIME, res.getMetadata().getCreatedTimeString(), "Incorrect created time");
assertEquals(DELETION_TIME, res.getMetadata().getDeletionTimeString(), "Incorrect deletion time");
assertFalse(res.getMetadata().isDestroyed(), "Incorrect destroyed state");
assertEquals(VERSION, res.getMetadata().getVersion(), "Incorrect version");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.
@ -136,11 +136,9 @@ class TokenResponseTest extends AbstractModelTest<TokenResponse> {
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(TOKEN_EXPIRE_TIME, data.getExpireTimeString(), "Incorrect token expire time");
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(TOKEN_ISSUE_TIME, data.getIssueTimeString(), "Incorrect token issue time");
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");

View File

@ -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" +
"}";
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2024 Stefan Kalscheuer
* 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.

View File

@ -1 +1 @@
{"Value":"AAAAAQIOTEuNxtf2ZfGu6k9+65GFonDBiaetJnyLYFk1qfWPrE/VqUunbxuTv/QyK4pgC/q14sqypdxPe4Ygp/5mxzzuY6JXB0VKiDMXe9R5BltTG7++rLmKH/j+G7nEh71LER1/qVktU6x8dmDmTbpTgl5xzAB5DIXLMMKjjWda/7qJ3ivNI0pEOQ3JyT27SkqjqM49Dp1JIgKnjIEVQORqKcsSP+aqIncMjIo2iGXOGlDYAesp5tZ4hln3VCwXaIlrU8z6Mmntgcg7NeK/O2WTl86K644dbJUh6frGFDujrjOh/Pgp9n9u0BI3E9K9GD1Z1S1wEb1MCqzT/e9oHG7I7D8ku8PH11wGWGH6BmYlESYUG/KRVqu0XOQEfroLHZQiLE00yHBdStW/UJ9y5pmGpu1aiQ88Q8fpjF5xmRey99b4c6KUIpHjw5Af0XA9ZKsEJUyjS/dbMKPM6PBOW21LYefXH5b0poXMWgLW6LJV0zLuVMyVZJqANbzCVtheDPSsEjkHHwR/CLa2zs2Z6wJF3j1GDZxUFf4nbnuXQzz3M3kVPPtS6htlb0d8RN0/dkOrqUue+c4UjnXhiacXyVUnQQzUVu0sGak4vrQi0020aBzMXM2ZG7rNgvw+wcYFS4txO90kwJL6aOMXT2BeJiQ3wjjHb7M74/sSd0ffRTUlJSODSDotO7Q7Dfcnc1FLrIhXPRFPavTjFoL5HRy77xuGG7U7jTMoGra+rK54v0sxqKbS5WZi1hADQmAVIO8bPb+jA1qoejRFygW6sLgAdmEFQQJOhCV/BoKP3A=="}
{"Value":"AAAAAQJ7mykBIbHX5k81qdXEpvlLgRF1ZSlODETcB1JBZ7nj0Muskpvvl3jofN5XH1Td8ibJlrR0o5o/OUjZAz9t0Da+ZzCy4ga9G2SmgWkUAravTqfPO/ZxWh2hqTso2WPBXRM3/IeR0SAv/zh7m7JILxjKybJmnl9U6fkjPID/us0AscckZ9kgJ4g8jwaTzPfRp5U8jMebHYbABXZ65PeUOvNiDVcOvQDWPJrMxICz12xbeJ8mKs5MHpcNkLtPoRCQSpsh0YYTwkuF7NvpIciqIJ4/Yb7wYO+vp9AATbiIs3sSFBWxXEl0OAg/SAmOvaR27Y7/NHN//mg81jkMOHv62/Fxf11I8t1d63oyWFQhP0xR9eoq5hGNQ/30I2m1prhZtLRC2ieKASBDMxTzyNS5G5bsVXvhCsxn8tiC0Ma+ySOfxMQzBRfbx8rtoGmLFP+l/d6VMOPGFxmYqzLS5HvvpCryscCqLn7A8i6TMSrZiF7ZevyfEBpThqhJiYHzUxf07O5IAe6JBSGuNV9gLE+uJXaiYLedJwSfjRKwdQyzer730dU1IegW3KYTb/5hSW4eaETKkjc/alC536WlvAv+5FyckDBc3aVC+hHB7lKZG5YANkOUS3m5I8epemOmuKQ5pnXLOdDkQ14DyNCC79NwLltkp0d6sTNstQ44XAbs0HlLjs4EFwg5Hps9qHeXgTOXeAvwUerJgM20nKszlB+Oy+JzZm0xOK5xoJwy+z0/U3PtJ+7pwAipesIa2QEzqMt3EneuPuwEcv3bPUcowukq542sCEK0CuZjLqTUU9nNqiZan5f5pWuL0hYw4NFIkNfQyRlqgKpMaplDk/2fBqaV98yn0DWceEMWRY4NXpEMS+ysPDIeamX99auWqakb95AZ7tySpkRAkZYtq1nY5Nu0w7NyJrJZ1lhBHs2ZjW0tpXn2CL0MhMVArg=="}

View File

@ -0,0 +1 @@
{"Value":"AAAAAQIwsBgPcs7Hxl7UnB8OkTq9+5HERx4Fzn8jAzR8uIhoQZfpNG/15m2LEEsDJw1o+lxc6u+h7XcOB1QRqrKz8k7CFR15A+qsxD0UclHZdnk+MmMwXL9SSvYugp7XPiXmpG/uTZVf1QtigXQuehEEJeFfJVI7aFACu2AHEGVt+5b6yDQEgTUruo0seazRXuVU+J6NFCDU3ZvkR8e0al6OcMail59KamzjSCYiqDF4TeUuOQ6Zyr7zIG7gSaas1sog2JIlvrh+wkHW6I+OyD9SJSTinGEGRXl0tq15qoBJ4srfXdWODmKtExEupArbiDR5PyvSI3KlIHKIFduslJZKkJwiV3dBscdva4Rqb98FffMVYuM4G4s+VpvDDX+WVsqWF1ssoHRAFWCNAJGsenVDTxblzAF/4rGkJ7LC9yjLGsBtMOCkCZAKDQ3C9VFu+LGhbMRA5p2RKxNKWGem4Cyp5AqMmx62UzDAgMLGgm89A0g9s1/3FnCoLPdVmlWc6cg4QahN30qJCInJeAmH7T9NwIjv6/QxyJxyDVtdMtcfnMNxx15Q29lbyWTcbaI1iabHpc16iS/gwAPQeBTSbcvc4OxqwC5PDFThFq6bwZXaekYz4ghC13j9Ht79GVKH9cPZb5M="}

View File

@ -0,0 +1 @@
{"Value":"AAAAAQKfotDJ0SihB+f5i4PxZ6lq1kxtH4QMprGI7Hj8HimEwXsW0Gbj/1B7YM4DQt4t5JFD4gKwFVOwlJDyusaJj92ar0QLSreCWyJTKUadqZplMFyB/bAdK42QdH+ZS8Z9KHUNchbRpNhnvOFIahoDG8dZ+nbCIXblJONCaey4/ri3H+GQbk/jfre1VByh7zVIN0ISew5PzZRCTkbO1CvcQZhrRGoUGiPmLywKVbHEMsvimVuZY5py6OfL+70QmElBmN9O45bTgX9XPbfSmyQIcGrElO1foi0WwZLPsb/fZcAIgrhC768jOnzeimChoX4zc0DPxuyV1YPvsD1yAlsnsFuJW6CP7TGkszbJU+rwDpg0TgqKtvFr1Lgkxyfcxg0h++1BSiEgoJU7b2IgIWP7reJVjc1tbAsoR1tOBCSAAhvqWZVpn2oht5rfe9aN370bV3Jcu17hFWyhB+VhzbCCPRcofPXX3f2U2dcQ0X7bU4nMiq1v6NQP6u/D5GAPj4Jc0519tPW4KQrd9SNqR20ct6OvqxjMFWV4GZXVcsL4+3xup87Yib6EDb0+hhe6XEpC6isYgD3D5OTTOWphHlsglGkGFi9lUc+h8zNPM4FHwha6uVTLmaqaLGbLziwT9WXF1ATacwtNW0t3kZlFUBvMwSwWzoPqO1+jxs+id4ie/VI6ZTOeowi4ceK2eWJ1/t9MB/gjvadpgE+FYt5QG6dFav4ujQN5Ne/yY78PGF5tp0CT4koox0rMUuxyD1xOIXkm0NBpJm1y9/J06yqLpMKqS40/jGcSQaycRngXDb+6H9rj7mheiO4qxcFGqViqECCUjDG3PnLP/fy9py5kFq7mf0pq7L0Jq/lLWC+iKJF9UaZmCaz8DwlQ9zC03XOFqABPNe8gMFlb8zU09VKBbY+g5gukOonjcBeoFOTRqQxuaWwwwB2lj8XnZScOyIcVJGkH"}

View File

@ -1 +0,0 @@
{"Value":"AAAAAQINZKQEssY4IzHI/0k27nBtxSvnC6LkivYrqky6CblcjyAmQIg/4/cKQIBCXzmrWEv/SqMQbLw+4Lp63Xu1niF+U0NbyqDmFaPqnD2yfPs7meXvZr21+P9E/0APZMHQaSR7DIEY46zedHRjQ/pkhR2Axcjuy5gdfzBzC2XvUcNqdyR0pQwcDwGhAIdO0gxJfZCeBuvv8ceYS+aPs4gDHtIlA3szi+5qAQ8HvPBTDKQn1lHVYnzTdNbMS7v3mtzCyG8AeMkaUw=="}

View File

@ -1 +0,0 @@
{"Value":"AAAAAQJiN0bHxM8aNJpY7aHGZ/p3qOhJbd7JIXwFMEI4LtKmO6pP5Oa4P5z+2LK+2qzZhhX/iDeM4u+nR+lxt/GsBPKf"}

View File

@ -1 +0,0 @@
{"Value":"AAAAAQIZ5rvzLtBcBQvWqwwDoRADwUo6W0ECKgmcvXejbLKiYcbO0hP8fceCqB12J41wxcMViQ8vvWoIgyOX2HwcZS09GGCqQbjvyVfz/w+kyox9dJzr845f26tJjHVYlHX2YFsnxytwe5qCKdCsD5QP9kyz8J0="}

View File

@ -1 +0,0 @@
{"Value":"AAAAAQJIKXgvJ2Prr92Fn7qZK/WZxb+Q+vJsXyjMo44en/+zqbbnLfs5m7uH7hEUOfDM/MjzTrhfkOWxf6qcrC4MR3ocrFJwtbJ6j+QrNLg61gVIiLBUVBkvh8ErqCFnSjNIqhaIMQhuZXWANsgGF9K2+HBGJerWGe26C1rdWRZV4J0M23HnxLBf8aYDlOfkHe24I30rHUqXIk9/BKEuekcnhETw9Tx4Fk7KxxxEdGmHPbg+4G14c27wVj8IrpWHBpyLmt55Qdb/y24i5RzFYv1FQ2kQZIO6TQiYkwAUxJ5cIdCiAsEDNt+rBJ9zX1MvkEfkVj/WvzC9pxB7ad+j5vYIJgCUD1o09t0w2ChjBojGoOAWDSvNAeY8kr5PDKwYk+gBY5M2JHDI6ELvOVu8gsW+sqk9St9V3VisShTfU3+qln7TOWw/LQ+fUzGvYrAWG6UyPVpIEYeNmN0iGCIM8rzjQYvVC3KcQMG96MwK3ZlSQzgPpvTGxNxFm2omTn3ue7QHn7Ni6+c/K6xVy0bbJ+jS4yyfl2wFBm1tF1l3BITLqw3TiP3LEw=="}

View File

@ -1 +0,0 @@
{"Value":"AAAAAQIUt2iYYy9zOwkx1mtNMHt69RjdHbUmcN8zydVQTMGjhv1kjEW+d4AaBv1qE22rPTs0xL3pJ1AjIvkBXXVBAuc/FE63t5dE81Fa+MvSY4tBeMtl6i09ykkAYyQUeeV2HlbjRpMUwPyq2QIslYw3d4lc73yT0S82s5I3MfjodKmDpheWMOgg5hGes/wstBHN5HEZkKV8gOPRZ/BsTM7tMXH1piM/JT8sNfsDh6TAGD1OEsS+N2QlKvS4yImNzcKrH0EgdkXB4sRZ9e/SmMaEVaagB1n0M5LukC+pyExgC7eK4EU8o2Xye3iij3YMWBaGollDzJBJFP5aSO4E5u+NnRc5/ZbLRCbqgfQj8IY86WF9hya31aJxbc8Pg28Yfez8hbGRJZZws/ojIUgEz+VtH3OyaW2Wohnycop7i4fK8xlJ2gYOGvlw43czOH6Y6joTce+QBZWI7KR6ugB0dI8pnK2eFy14OZeww1NEew7r1u7PgD10Obg8okIJSD8cGkxUHu/oOLxvKKOAJBLSPfKnJfKEiKrqYED7EPkmgP/t7okvo4c95qeuWy1BLtKfxw5lkv0="}

View File

@ -1 +0,0 @@
{"Value":"AAAAAQKv0Yr+QFSWxYe8o51TBwGz/yAhNYFmkNHPISEK6EbIVGkpEJMHFYvHWxTXUzF7f2/a"}

View File

@ -1 +0,0 @@
{"Value":"AAAAAQKs2/ICwQPLv6siBGDbBnB52fBVo52BkSKGvm74p4oHrdMEvejJ4cJljOADYyDT2QYa"}

Some files were not shown because too many files have changed in this diff Show More