Compare commits

..

No commits in common. "main" and "v0.1" have entirely different histories.
main ... v0.1

167 changed files with 1184 additions and 14675 deletions

View File

@ -1,14 +0,0 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
max_line_length = 120
tab_width = 4
trim_trailing_whitespace = true
[{*.yaml,*.yml}]
indent_size = 2

View File

@ -1,56 +0,0 @@
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,44 +0,0 @@
name: CI
on:
push:
branches:
- '**'
- '!main'
pull_request:
branches:
- '**'
- '!main'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
jdk: [ 11, 17, 21 ]
include:
- jdk: 21
analysis: true
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Java
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.jdk }}
distribution: 'temurin'
- name: Compile
run: ./mvnw -B clean compile
- name: Test (Unit)
run: ./mvnw -B -P coverage verify
- name: Analysis
if: matrix.analysis && env.SONAR_TOKEN != ''
run: >
./mvnw -B sonar:sonar
-Dsonar.host.url=https://sonarcloud.io
-Dsonar.organization=stklcode-github
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

17
.gitignore vendored
View File

@ -1,17 +0,0 @@
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar
.idea
*.iml
.bin
*~

View File

@ -1,2 +0,0 @@
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,453 +0,0 @@
## 1.5.0 (2025-04-13)
### Deprecations
* `read...Credentials()` methods for specific database mounts (#92)
### Features
* Support Vault transit API (#89)
* Support PEM certificate string from `VAULT_CACERT` environment variable (#93)
### Improvements
* Replace deprecated `java.net.URL` usage with `java.net.URI` (#94)
### Fix
* Fix initialization from environment without explicit port
### Dependencies
* Updated Jackson to 2.18.3 (#90)
### Test
* Tested against Vault 1.2 to 1.19
## 1.4.0 (2024-12-07)
### Removal
* Remove deprecated `get...TimeString()` on model classes (#77)
* Drop support for deprecated `App-ID` auth backend (#61) (#78)
### Fix
* Add jackson-annotations requirement to module-info (#84)
### Dependencies
* Updated Jackson to 2.18.2 (#85)
### Test
* Tested against Vault 1.2 to 1.18
## 1.3.1 (2024-10-03)
### Dependencies
* Updated Jackson to 2.18.0 (#80)
### Fix
* Remove `Automatic-Module-Name` from JAR manifest (#79)
## 1.3.0 (2024-06-29)
### Improvements
* Simplify JSON parsing in error handler
* Add new fields from Vault 1.16 and 1.17 to `HealthResponse`
* `echo_duration_ms`
* `clock_skew_ms`
* `replication_primary_canary_age_ms`
* `enterprise`
* Add missing `num_uses` field to `AuthData`
* Add `mount_type` attribute to common response model
* Add `auth` attribute to common response model
* Add `custom_metadata`, `cas_required` and `delete_version_after` fields for KVv2 metadata
* Generate and attach CycloneDX SBOM
### Fix
* Rename `enable_local_secret_id` to `local_secret_ids` in `AppRole` model
### Dependencies
* Updated Jackson to 2.17.1
### Test
* Tested against Vault 1.2 to 1.17
## 1.2.0 (2023-12-11)
### Deprecations
* `get...TimeString()` methods on various model classes are now deprecated
### Improvements
* Parse timestamps as `ZonedDateTime` instead of `String` representation
* Remove redundant `java.base` requirement from _module-info.java_ (#69)
* Close Java HTTP Client when running on Java 21 or later (#70)
* Add MFA requirements tu `AuthResponse` (#71)
* Extend `AuthMethod` data model (#72)
### Dependencies
* Updated Jackson to 2.16.0
## 1.1.5 (2023-08-19)
### Fix
* Fixed JSON type conversion in `SecretResponse#get(String, Class)` (#67)
### Test
* Tested against Vault 1.2 to 1.15
## 1.1.4 (2023-06-15)
### Fix
* Use `[+-]XX:XX` notation for timezone in date/time parsing
### Improvements
* Use explicit UTF-8 encoding for parsing responses
### Dependencies
* Updated Jackson to 2.15.2
### Test
* Tested against Vault 1.2.0 to 1.13.3
## 1.1.3 (2023-01-31)
### Deprecations
* AppID components (deprecated since 0.4) are marked for removal with the next major release
### Dependencies
* Updated Jackson to 2.14.2
### Improvements
* Minor internal refactoring
### Test
* Tested against Vault 1.2.0 to 1.12.2
## 1.1.2 (2022-10-26)
### Dependencies
* Updated Jackson to 2.13.4.2
### Test
* Tested against Vault 1.2.0 to 1.12.0
* Disable AppID tests for Vault 1.12 and above (auth method removed)
* Tested with Java 19
## 1.1.1 (2022-08-29)
### Dependencies
* Updated Jackson to 2.13.3
### Test
* Tested against Vault 1.11.2
* Tested with Java 18
## 1.1.0 (2022-04-24)
### Fix
* Use `replication_performance_mode` instead of `replication_perf_mode` in health response.
### Improvements
* Add `migration`, `recovery_seal` and `storage_type` fields to `SealReponse` model
* Add support for `wrap_info` in data response models
* Dependency updates
* Model and response classes implement `Serializable` (#57)
* Split `SercretResponse` into `PlainSecretResponse` and `MetaSecretResponse` subclasses (common API unchanged)
* Add missing fields to `AuthMethod` model
* Add support for (dis)allowed policy glob patterns in `TokenRole`
* Add request ID to data response models
### Test
* Tested against Vault 1.10.1
## 1.0.1 (2021-11-21)
### Fix
* Make `HTTPVaultConnectorBuilder#withPort(Integer)` null-safe (#56)
* Make system-lambda dependency test-only (#58)
### Test
* Tested against Vault 1.9.0
## 1.0.0 (2021-10-02)
### Breaking
* Requires Java 11 or later
* Builder invocation has changed, use `HTTPVaultConnector.builder()....build()`
### Removal
* Remove deprecated `VaultConnectorFactory` in favor of `VaultConnectorBuilder` with identical API
* Remove deprecated `AppRoleBuilder` and `TokenBuilder` in favor of `AppRole.Builder` and `Token.Builder`
* Remove deprecated `Period`, `Policy` and `Policies` methods from `AppRole` in favor of `Token`-prefixed versions
* Remove deprecated `SecretResponse#getValue()` method, use `get("value")` instead
* Remove deprecated convenience methods for interaction with "secret" mount
### Improvements
* Use pre-sized map objects for fixed-size payloads
* Remove Apache HTTP Client dependency in favor of Java 11 HTTP
* Introduce Java module descriptor
### Test
* Tested against Vault 1.8.3
## 0.9.5 (2021-07-28)
### Deprecations
* Deprecate ` {read,write,delete}Secret()` convenience methods. Use `{read,write,delete}("secret/...")` instead (#52)
* Deprecated builder invocation `VaultConnectorBuilder.http()` in favor of `HTTPVaultConnector.builder()` (#51)
* Deprecated `de.stklcode.jvault.connector.builder.HTTPVaultConnectorBuilder` in favor of `de.stklcode.jvault.connector.HTTPVaultConnectorBuilder` (only package changed) (#51)
Old builders will be removed in 1.0
### Improvements
* Minor dependency updates
### Test
* Tested against Vault 1.8.0
## 0.9.4 (2021-06-06)
### Deprecations
* `AppRole.Builder#wit0hTokenPeriod()` is deprecated in favor of `#withTokenPeriod()` (#49)
### Improvements
* Minor dependency updates
### Test
* Tested against Vault 1.7.2
## 0.9.3 (2021-04-02)
### Improvements
* Use pre-sized map objects for fixed-size payloads
* Minor dependency updates
* Unit test adjustments for JDK 16 build environments
### Test
* Tested against Vault 1.7.0
## 0.9.2 (2021-01-24)
### Fixes
* Only initialize custom trust managers, if CA certificate is actually provided (#43)
### Improvements
* Minor dependency updates
## 0.9.1 (2021-01-03)
### Improvements
* Dependency updates
### Test
* Tested against Vault 1.6.1
## 0.9.0 (2020-04-29)
### Fixes
* Correctly parse Map field for token metadata (#34)
* Correctly map token policies on token lookup (#35)
### Features
* Support for token types (#26)
* Support for token role handling (#27) (#37)
### Improvements
* Added `entity_id`, `token_policies`, `token_type` and `orphan` flags to auth response
* Added `entity_id`, `expire_time`, `explicit_max_ttl`, `issue_time`, `renewable` and `type` flags to token data
* Added `explicit_max_ttl`, `period` and `entity_alias` flags to _Token_ model (#41)
* Added `enable_local_secret_ids`, `token_bound_cidrs`, `token_explicit_max_ttl`, `token_no_default_policy`,
`token_num_uses`, `token_period` and `token_type` flags to _AppRole_ model
* Minor dependency updates
### Deprecations
* `AppRole#getPolicies()` and `#setPolicies()` are deprecated in favor of `#getTokenPolicies()` and `#setTokenPolicies()`
* `AppRole#getPeriod()` is deprecated in favor of `#getTokenPeriod()`
* `AppRoleBuilder` and `TokenBuilder` in favor of `AppRole.Builder` and `Token.Builder`
* All-arg constructors of `AppRole` and `Token` in favor of `.builder()....build()` introduced in 0.8
### Removals
* Deprecated methods `AppRole#getBoundCidrList()`, `#setBoundCidrList()` and `getBoundCidrListString()` have been removed.
### Test
* Tested against Vault 1.4.0
## 0.8.2 (2019-10-20)
### Fixes
* Fixed token lookup (#31)
### Improvements
* Updated dependencies
## 0.8.1 (2019-08-16)
### Fixes
* Removed compile dependency to JUnit library (#30)
### Improvements
* Updated dependencies
### Test
* Tested against Vault 1.2.2
## 0.8.0 (2019-03-24)
### Breaking
* Moved Maven artifact to `de.stklcode.jvault:jvault-connector` (#28)
* Removed support for `HTTPVaultConnectorFactory#withSslContext()` in favor of `#withTrustedCA()` due to
### Features
* Support for KV version 2 secret engine (#16)
* Ability to pass custom mount point to KV v2 read/write methods (#25)
### Improvements
* refactoring of the internal SSL handling (#17)
* `VaultConnector` extends `java.io.Serializable` (#19)
* Added missing flags to `SealResponse` (#20)
* Added replication flags to `HealthResponse` (#21)
* Enforce TLS 1.2 by default with option to override (#22)
* Build environment and tests now compatible with Java 10
* Updated dependencies to fix vulnerabilities (i.e. CVE-2018-7489)
* New static method `Token.builder()` to get token builder instance
* New static method `AppRole.builder()` to get AppRole builder instance
### Deprecation
* `VaultConnectorFactory` is deprecated in favor of `VaultConnectorBuilder` with identical API (#18)
* `AppRoleBuilder#withBoundCidrList(List)` is deprecated in favor of `AppRoleBuilder#withSecretIdBoundCidrs(List)` (#24)
## 0.7.1 (2018-03-17)
### Improvements
* Added automatic module name for JPMS compatibility
* Minor dependency updates
### Test
* Tested against Vault 0.9.5
## 0.7.0 (2017-10-03)
### Features
* Retrieval of health status via `getHealth()` (#15)
### Improvements
* `seal()`, `unseal()` are now `void` and throw Exception on error (#12)
* Adaptation to Vault 0.8 endpoints for `renew` and `revoke`, **breaking** 0.7 compatibility (#11)
### Removed
* Removed deprecated `listAppRoleSecretss()` (use `listAppRoleSecrets()`) (#14)
### Test
* Tested against Vault 0.8.3
## 0.6.2 [2017-08-19]
### Fixes
* Prevent potential NPE on SecretResponse getter
* Removed stack traces on PUT request and response deserialization (#13)
### Improvements
* Fields of InvalidResposneException made final
### Deprecation
* `listAppRoleSecretss()` in favor of `listAppRoleSecrets()` (#14)
### Test
* Tested against Vault 0.8.1, increased coverage
## 0.6.1 (2017-08-02)
### Fixes
* `TokenModel.getPassword()` returned username instead of password
* `TokenModel.getUsername()` and `getPassword()` could produce NPE in multithreaded environments
* `TokenData.getCreatinTtl()` renamed to `getCreationTtl()` (typo fix)
### Test
* Tested against Vault 0.7.3
## 0.6.0 (2017-05-12)
### Features
* Initialization from environment variables using `fromEnv()` in factory (#8)
* Automatic authentication with `buildAndAuth()`
* Custom timeout and number of retries (#9)
* Connector implements `AutoCloseable`
### Fixes
* `SecretResponse` does not throw NPE on `get(key)` and `getData()`
### Test
* Tested against Vault 0.7.2
## 0.5.0 (2017-03-18)
### Features
* Convenience methods for DB credentials (#7)
### Fixes
* Minor bugfix in TokenBuilder
### Deprecation
* `SecretResponse.getValue()` deprecated
### Test
* Tested against Vault 0.7.0
## 0.4.1 [2016-12-24]
### Fixes
* Factory Null-tolerant for trusted certificate (#6)
### Test
* StackTraces tested for secret leaks
* Tested against Vault 0.6.4
## 0.4.0 (2016-11-06)
### Features
* Option to provide a trusted CA certificate (#2)
* Deletion, revocation and renewal of secrets (#3)
* Token creation (#4)
* AppRole auth backend supported (#5)
### Improvements
* Support for complex secrets
### Deprecation
* App-ID backend marked as deprecated
## 0.3.0 (2016-10-07)
### Features
* Retrieval of JSON objects (#1)
### Test
* Tested against Vault 0.6.2
## 0.2.0 (2016-09-01)
### Improvements
* Dependecies updated and CommonsIO removed
### Fixes
* Fixed auth backend detection for Vault 0.6.1
### Test
* Tested against Vault 0.6.1
## 0.1.1 (2016-06-20)
### Fixes
* Check for "permission denied" without status code 400 instead of 403
### Test
* Tested against Vault 0.6.0
## 0.1.0 (2016-03-29)
* First release

View File

@ -1,112 +0,0 @@
# How to contribute
As for all great Open Source projects, contributions in form of bug reports and code are welcome and important to keep the project alive.
In general, this project follows the [GitHub Flow](https://guides.github.com/introduction/flow/).
Fork the project, commit your changes to your branch, open a pull request and it will probably be merged.
However, to ensure maintainability and quality of the code, there are some guidelines you might be more or less familiar with.
For that purpose, this document describes the important points.
## Opening an Issue
If you experience any issues with the library or the code, don't hesitate to file an issue.
### Bug Reports
Think you found a bug?
Please clearly state what happens and describe your environment to help tracking down the issue.
* Which version of the connector are you running?
* Which version of Java (architecture and OS if relevant)?
* Which version of Vault?
### Feature Requests
Missing a feature or like to have certain functionality enhanced?
No problem, please open an issue and describe what and why you think this change is required.
## Pull Requests
If you want to contribute your code to solve an issue or implement a desired feature yourself, you might open a pull request.
If the changes introduce new functionality or affect major parts of existing code, please consider opening an issue for discussion first.
Extending or adapting JUnit test cases would be nice (no hard criterion though).
The `main` branch also be target for most pull requests.
However, if it features new functionality you might want to target the `develop` branch instead (see next section for details on branches).
### Branches
The `main` branch represents the current, more or less stable state of development.
Please ensure your initial code is up to date with it at the time you start development.
In addition, this project features a `develop` branch, which holds bleeding edge developments, not necessarily considered stable or even compatible.
Do not expect this code to run smoothly, but you might have a look into the history to see if some work on an issue has already been started there.
For fixes and features, there might be additional branches, likely prefixed by `fix/` or `feature/` followed by an issue number (if applicable) and/or a title.
Feel free to adapt this naming scheme to your forks.
### Merge Requirements
To be merged into the main branch, your code has to pass the automated continuous integration tests, to ensure compatibility.
In addition, your code has to be approved by a project member.
#### What if my code fails the tests?
Don't worry, you can submit your PR anyway.
The reviewing process might help you to solve remaining issues.
### Commit messages
Please use speaking titles and messages for your commits, to ensure a transparent history.
If your patch fixes an issue, reference the ID in the first line.
If you feel like you have to _briefly_ explain your changes, do it (for long explanations and discussion, consider opening an issue or describe in the PR).
**Example commit:**
```text
Fix nasty bug from #1337
This example commit fixes the issue that some people write non-speaking commit messages like 'done magic'.
A short description is helpful sometimes.
```
You might sign your work, although that's no must.
### When will it be merged?
Short answer: When it makes sense.
Bugfixes should be merged in time - assuming they pass the above criteria.
New features might be assigned to a certain milestone and as a result of this be scheduled according to the planned release cycle.
## Compatibility
To ensure usability for a wide range of users, please take note on the software requirements stated in the `README`.
This includes especially Java versions and a minimum version of _Vault_.
If you are unsure if your code matches these versions, the test will probably tell you.
In case you think, your change is more important than maintaining backwards compatibility, please start a discussion to see,
if we might increase the minimum version or find a workaround for legacy systems.
## Build Environment
All you need to start off - besides your favorite IDE and a JDK of course - is [Maven](https://maven.apache.org/).
## Unit Tests
The code is tested by JUnit tests.
For standalone testing against mocked APIs the _Maven_ profile `offline-test` should be used.
Otherwise, there is a test suite that requires an actual _Vault_ binary in the executable path to start a real server instance.
## Continuous Integration
Automated tests are run using [GitHub Actions](https://github.com/features/actions) for every commit including pull requests.
Tests usually run against the minimal supported version, all supported LTS versions and the latest version of Java.
There is an automated code quality analysis pushing results to [SonarCloud](https://sonarcloud.io/dashboard?id=de.stklcode.jvault%3Ajvault-connector).
## Still Open Questions?
If anything is still left unanswered and you're unsure if you got it right, don't hesitate to contact a team member.
In any case you might submit your request/issue anyway, we won't refuse good code only for formal reasons.

125
README.md
View File

@ -1,127 +1,58 @@
# Java Vault Connector
[![CI](https://github.com/stklcode/jvaultconnector/actions/workflows/ci.yml/badge.svg)](https://github.com/stklcode/jvaultconnector/actions/workflows/ci.yml)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=de.stklcode.jvault%3Ajvault-connector&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=de.stklcode.jvault%3Ajvault-connector)
[![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](assets/logo.png)
Java Vault Connector
=========
Java Vault Connector is a connector library for [Vault](https://www.vaultproject.io) by [Hashicorp](https://www.hashicorp.com) written in Java. The connector allows simple usage of Vault's secret store in own applications.
## Features:
**Current available features:**
* HTTP(S) backend connector
* Ability to provide or enforce custom CA certificate
* Optional initialization from environment variables
* Authorization methods
* Authorization methods:
* Token
* Username/Password
* AppRole (register and authenticate)
* Tokens
* Creation and lookup of tokens and token roles
* TokenBuilder for speaking creation of complex configurations
* AppID (register and authenticate)
* Secrets
* Read secrets
* Write secrets
* List secrets
* Delete secrets
* Renew/revoke leases
* Raw secret content or JSON decoding
* KV v1 and v2 support
* Database secret handling
* Transit API support
* Connector Factory with builder pattern
* Tested against Vault 1.2 to 1.19
* Tested against Vault 0.5.2
## Maven Artifact
```xml
<dependency>
<groupId>de.stklcode.jvault</groupId>
<artifactId>jvault-connector</artifactId>
<version>1.5.0</version>
</dependency>
```
## Usage Examples
### Initialization
**Usage Example**
```java
// Instantiate using builder pattern style factory (TLS enabled by default)
VaultConnector vault = HTTPVaultConnector.builder()
.withHost("127.0.0.1")
// Instanciate using builder pattern style factory
VaultConnector vault = VaultConnectorFactory.httpFactory()
.wiithHost("127.0.0.1")
.withPort(8200)
.withTLS()
.build();
// Instantiate with custom SSL context
VaultConnector vault = HTTPVaultConnector.builder("https://example.com:8200/v1/")
.withTrustedCA(Paths.get("/path/to/CA.pem"))
.build();
// Initialization from environment variables
VaultConnector vault = HTTPVaultConnector.builder()
.fromEnv()
.build();
```
### Authentication
```java
// Authenticate with token.
//authenticate with token
vault.authToken("01234567-89ab-cdef-0123-456789abcdef");
// Authenticate with username and password.
vault.authUserPass("username", "p4ssw0rd");
// Authenticate with AppRole (secret - 2nd argument - is optional).
vault.authAppRole("01234567-89ab-cdef-0123-456789abcdef", "fedcba98-7654-3210-fedc-ba9876543210");
// retrieve secret
String secret = vault.readSecret("some/secret/key").getValue();
```
### Secret read & write
```java
// Retrieve secret (prefix "secret/" assumed, use read() to read arbitrary paths)
String secret = vault.read("secret/some/key").get("value", String.class);
// Complex secret.
Map<String, Object> secretData = vault.read("secret/another/key").getData();
// Write simple secret.
vault.write("secret/new/key", "secret value");
// Write complex data.
Map<String, Object> map = ...;
vault.write("path/to/write", map);
// Delete secret.
vault.delete("path/to/delete");
**Maven Artifact**
```
<dependency>
<groupId>de.stklcode.jvault</groupId>
<artifactId>connector</artifactId>
<version>0.1</version>
</dependency>
```
### Token and role creation
**Links**
```java
// Create token using TokenBuilder
Token token = Token.builder()
.withId("token id")
.withDisplayName("new test token")
.withPolicies("pol1", "pol2")
.build();
vault.createToken(token);
[Project Page](http://jvault.stklcode.de)
// Create AppRole credentials
vault.createAppRole("testrole", policyList);
AppRoleSecretResponse secret = vault.createAppRoleSecret("testrole");
```
[JavaDoc API](http://jvault.stklcode.de/apidocs/)
## Links
**Planned features:**
[Project Page](https://jvault.stklcode.de)
* Creation and modification of policies
* Implement more authentication methods
[JavaDoc API](https://jvault.stklcode.de/apidocs/)
**License**
## License
The project is licensed under [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
The project is licensed under [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128">
<path d="M4,12 l60,104 l60,-104 z" stroke="none" fill="#000000" />
<rect x="74" y="20" width="8" height="8" stroke="none" fill="#00abe0" />
<rect x="74" y="34" width="8" height="8" stroke="none" fill="#00abe0" />
<rect x="74" y="48" width="8" height="8" stroke="none" fill="#00abe0" />
<rect x="74" y="62" width="8" height="8" stroke="none" fill="#00abe0" />
<rect x="68" y="74" width="8" height="8" stroke="none" fill="#00abe0" />
<rect x="54" y="74" width="8" height="8" stroke="none" fill="#00abe0" />
<rect x="48" y="62" width="8" height="8" stroke="none" fill="#00abe0" />
</svg>

Before

Width:  |  Height:  |  Size: 837 B

332
mvnw vendored
View File

@ -1,332 +0,0 @@
#!/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
View File

@ -1,206 +0,0 @@
@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%

452
pom.xml
View File

@ -2,419 +2,65 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.stklcode.jvault</groupId>
<artifactId>jvault-connector</artifactId>
<version>1.5.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>jVaultConnector</name>
<description>Connector artifact for Hashicorp's Vault secret management</description>
<url>https://jvault.stklcode.de</url>
<inceptionYear>2016</inceptionYear>
<licenses>
<license>
<name>Apache License 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.html</url>
<distribution>repo</distribution>
</license>
</licenses>
<developers>
<developer>
<name>Stefan Kalscheuer</name>
<email>stefan@stklcode.de</email>
<timezone>Europe/Berlin</timezone>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/stklcode/jvaultconnector.git</connection>
<developerConnection>scm:git:git@github.com:stklcode/jvaultconnector.git</developerConnection>
<url>https://github.com/stklcode/jvaultconnector</url>
<tag>HEAD</tag>
</scm>
<issueManagement>
<system>GitHub Issues</system>
<url>https://github.com/stklcode/jvaultconnector/issues</url>
</issueManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<argLine></argLine>
</properties>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.12.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.17.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-lambda</artifactId>
<version>1.2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId>
<version>3.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.19.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>3.19.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>4.3.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<groupId>de.stklcode.jvault</groupId>
<artifactId>connector</artifactId>
<version>0.1</version>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>3.4.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.5.3</version>
<configuration>
<argLine>
@{argLine}
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.test=com.fasterxml.jackson.databind
</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.3</version>
<configuration>
<argLine>
@{argLine}
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector=ALL-UNNAMED
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.exception=ALL-UNNAMED
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.model=ALL-UNNAMED
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.model.response=ALL-UNNAMED
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.model.response.embedded=ALL-UNNAMED
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.test=com.fasterxml.jackson.databind
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.test=com.fasterxml.jackson.datatype.jsr310
</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
<version>2.9.1</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.13</version>
</plugin>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>5.1.0.4751</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<id>enforce-versions</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireMavenVersion>
<version>[3.6.3,)</version>
</requireMavenVersion>
<requireJavaVersion>
<version>[11,)</version>
</requireJavaVersion>
</rules>
</configuration>
</execution>
</executions>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<packaging>jar</packaging>
<profiles>
<profile>
<id>sources</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.2</version>
</dependency>
<profile>
<id>javadoc</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.11.2</version>
<configuration>
<source>11</source>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>sbom</id>
<build>
<plugins>
<plugin>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>makeBom</goal>
</goals>
<configuration>
<skipNotDeployed>false</skipNotDeployed>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>sign</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.7</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<keyname>${gpg.keyname}</keyname>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>coverage</id>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>integration-test</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>dependency-check</id>
<build>
<plugins>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>12.1.1</version>
<configuration>
<nvdApiKey>${env.NVD_API_KEY}</nvdApiKey>
<nvdDatafeedUrl>${env.NVD_DATAFEED_URL}</nvdDatafeedUrl>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>central</id>
<build>
<plugins>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.7.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>local</id>
<distributionManagement>
<repository>
<id>stklcode</id>
<url>${dist.repo.local}</url>
</repository>
<snapshotRepository>
<id>stklcode</id>
<url>${dist.repo.local.snapshot}</url>
</snapshotRepository>
</distributionManagement>
</profile>
</profiles>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-junit</artifactId>
<version>2.0.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,442 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector;
import de.stklcode.jvault.connector.exception.ConnectionException;
import de.stklcode.jvault.connector.exception.TlsException;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
/**
* Vault Connector Builder implementation for HTTP Vault connectors.
*
* @author Stefan Kalscheuer
* @since 0.8.0
* @since 0.9.5 Package {@link de.stklcode.jvault.connector}
*/
public final class HTTPVaultConnectorBuilder {
private static final String ENV_VAULT_ADDR = "VAULT_ADDR";
private static final String ENV_VAULT_CACERT = "VAULT_CACERT";
private static final String ENV_VAULT_TOKEN = "VAULT_TOKEN";
private static final String ENV_VAULT_MAX_RETRIES = "VAULT_MAX_RETRIES";
public static final String DEFAULT_HOST = "127.0.0.1";
public static final Integer DEFAULT_PORT = 8200;
public static final boolean DEFAULT_TLS = true;
public static final String DEFAULT_TLS_VERSION = "TLSv1.2";
public static final String DEFAULT_PREFIX = "/v1/";
public static final int DEFAULT_NUMBER_OF_RETRIES = 0;
private String host;
private Integer port;
private boolean tls;
private String tlsVersion;
private String prefix;
private X509Certificate trustedCA;
private int numberOfRetries;
private Integer timeout;
private String token;
/**
* Default empty constructor.
* Initializes factory with default values.
*/
HTTPVaultConnectorBuilder() {
host = DEFAULT_HOST;
port = DEFAULT_PORT;
tls = DEFAULT_TLS;
tlsVersion = DEFAULT_TLS_VERSION;
prefix = DEFAULT_PREFIX;
numberOfRetries = DEFAULT_NUMBER_OF_RETRIES;
}
/**
* Set base URL, e.g. "protocol://host:port/prefix".
*
* @param baseURL Base URL
* @return self
* @throws URISyntaxException Invalid URI syntax.
* @since 1.0
*/
public HTTPVaultConnectorBuilder withBaseURL(final String baseURL) throws URISyntaxException {
return withBaseURL(new URI(baseURL));
}
/**
* Set base URL, e.g. "protocol://host:port/prefix".
*
* @param baseURL Base URL
* @return self
* @since 1.0
*/
public HTTPVaultConnectorBuilder withBaseURL(final URI baseURL) {
String path = baseURL.getPath();
if (path == null || path.isBlank()) {
path = DEFAULT_PREFIX;
}
return withTLS(!("http".equalsIgnoreCase(baseURL.getScheme())))
.withHost(baseURL.getHost())
.withPort(baseURL.getPort())
.withPrefix(path);
}
/**
* Set hostname (default: 127.0.0.1).
*
* @param host Hostname or IP address
* @return self
*/
public HTTPVaultConnectorBuilder withHost(final String host) {
this.host = host;
return this;
}
/**
* Get hostname.
*
* @return Hostname or IP address
*/
String getHost() {
return this.host;
}
/**
* Set port (default: 8200).
* A value of {@code null} or {@code -1} indicates that no port is specified, i.e. the protocol default is used.
* Otherwise, a valid port number between 1 and 65535 is expected.
*
* @param port Vault TCP port
* @return self
*/
public HTTPVaultConnectorBuilder withPort(final Integer port) {
if (port == null || port < 0) {
this.port = null;
} else if (port < 1 || port > 65535) {
throw new IllegalArgumentException("Port number " + port + " out of range");
} else {
this.port = port;
}
return this;
}
/**
* Set port..
*
* @return Vault TCP port
*/
Integer getPort() {
return this.port;
}
/**
* Set TLS usage (default: TRUE).
*
* @param useTLS use TLS or not
* @return self
*/
public HTTPVaultConnectorBuilder withTLS(final boolean useTLS) {
this.tls = useTLS;
return this;
}
/**
* Get TLS usage flag.
*
* @return use TLS or not
*/
boolean isWithTLS() {
return this.tls;
}
/**
* Get TLS version.
*
* @return TLS version.
*/
String getTlsVersion() {
return this.tlsVersion;
}
/**
* Set TLS usage (default: TRUE).
*
* @param useTLS Use TLS or not.
* @param version Supported TLS version ({@code TLSv1.2}, {@code TLSv1.1}, {@code TLSv1.0}, {@code TLS}).
* @return self
* @since 0.8 Added version parameter (#22).
*/
public HTTPVaultConnectorBuilder withTLS(final boolean useTLS, final String version) {
this.tls = useTLS;
this.tlsVersion = version;
return this;
}
/**
* Convenience Method for TLS usage (enabled by default).
*
* @param version Supported TLS version ({@code TLSv1.2}, {@code TLSv1.1}, {@code TLSv1.0}, {@code TLS}).
* @return self
* @since 0.8 Added version parameter (#22).
*/
public HTTPVaultConnectorBuilder withTLS(final String version) {
return withTLS(true, version);
}
/**
* Convenience Method for TLS usage (enabled by default).
*
* @return self
*/
public HTTPVaultConnectorBuilder withTLS() {
return withTLS(true);
}
/**
* Convenience Method for NOT using TLS.
*
* @return self
*/
public HTTPVaultConnectorBuilder withoutTLS() {
return withTLS(false);
}
/**
* Set API prefix. Default is "/v1/" and changes should not be necessary for current state of development.
*
* @param prefix Vault API prefix (default: "/v1/")
* @return self
*/
public HTTPVaultConnectorBuilder withPrefix(final String prefix) {
this.prefix = prefix;
return this;
}
/**
* Get API prefix.
*
* @return Vault API prefix.
*/
String getPrefix() {
return this.prefix;
}
/**
* Add a trusted CA certificate for HTTPS connections.
*
* @param cert path to certificate file
* @return self
* @throws VaultConnectorException on error
* @since 0.4.0
*/
public HTTPVaultConnectorBuilder withTrustedCA(final Path cert) throws VaultConnectorException {
if (cert != null) {
return withTrustedCA(certificateFromFile(cert));
} else {
this.trustedCA = null;
}
return this;
}
/**
* Add a trusted CA certificate for HTTPS connections.
*
* @param cert path to certificate file
* @return self
* @since 0.8.0
*/
public HTTPVaultConnectorBuilder withTrustedCA(final X509Certificate cert) {
this.trustedCA = cert;
return this;
}
/**
* Get the trusted CA certificate for HTTPS connections.
*
* @return path to certificate file, if specified.
*/
X509Certificate getTrustedCA() {
return this.trustedCA;
}
/**
* Set token for automatic authentication, using {@link #buildAndAuth()}.
*
* @param token Vault token
* @return self
* @since 0.6.0
*/
public HTTPVaultConnectorBuilder withToken(final String token) {
this.token = token;
return this;
}
/**
* Build connector based on the {@code VAULT_ADDR} and {@code VAULT_CACERT} (optional) environment variables.
*
* @return self
* @throws VaultConnectorException if Vault address from environment variables is malformed
* @since 0.6.0
*/
public HTTPVaultConnectorBuilder fromEnv() throws VaultConnectorException {
/* Parse URL from environment variable */
if (System.getenv(ENV_VAULT_ADDR) != null && !System.getenv(ENV_VAULT_ADDR).isBlank()) {
try {
withBaseURL(System.getenv(ENV_VAULT_ADDR));
} catch (URISyntaxException e) {
throw new ConnectionException("URL provided in environment variable malformed", e);
}
}
/* Read number of retries */
if (System.getenv(ENV_VAULT_MAX_RETRIES) != null) {
try {
withNumberOfRetries(Integer.parseInt(System.getenv(ENV_VAULT_MAX_RETRIES)));
} catch (NumberFormatException ignored) {
/* Ignore malformed values. */
}
}
/* Read token */
token = System.getenv(ENV_VAULT_TOKEN);
/* Parse certificate, if set */
if (System.getenv(ENV_VAULT_CACERT) != null && !System.getenv(ENV_VAULT_CACERT).isBlank()) {
X509Certificate cert = certificateFromString(System.getenv(ENV_VAULT_CACERT));
if (cert == null) {
cert = certificateFromFile(Paths.get(System.getenv(ENV_VAULT_CACERT)));
}
return withTrustedCA(cert);
}
return this;
}
/**
* Define the number of retries to attempt on 5xx errors.
*
* @param numberOfRetries The number of retries to attempt on 5xx errors (default: 0)
* @return self
* @since 0.6.0
*/
public HTTPVaultConnectorBuilder withNumberOfRetries(final int numberOfRetries) {
this.numberOfRetries = numberOfRetries;
return this;
}
/**
* Get the number of retries to attempt on 5xx errors.
*
* @return The number of retries to attempt on 5xx errors (default: 0)
*/
int getNumberOfRetries() {
return this.numberOfRetries;
}
/**
* Define a custom timeout for the HTTP connection.
*
* @param milliseconds Timeout value in milliseconds.
* @return self
* @since 0.6.0
*/
public HTTPVaultConnectorBuilder withTimeout(final int milliseconds) {
this.timeout = milliseconds;
return this;
}
/**
* Get custom timeout for the HTTP connection.
*
* @return Timeout value in milliseconds.
*/
Integer getTimeout() {
return this.timeout;
}
/**
* Build command, produces connector after initialization.
*
* @return Vault Connector instance.
*/
public HTTPVaultConnector build() {
return new HTTPVaultConnector(this);
}
/**
* Build connector and authenticate with token set in factory or from environment.
*
* @return Authenticated Vault connector instance.
* @throws VaultConnectorException if authentication failed
* @since 0.6.0
*/
public HTTPVaultConnector buildAndAuth() throws VaultConnectorException {
if (token == null) {
throw new ConnectionException("No vault token provided, unable to authenticate.");
}
HTTPVaultConnector con = build();
con.authToken(token);
return con;
}
/**
* Read given certificate file to X.509 certificate.
*
* @param cert Certificate string (optionally PEM)
* @return X.509 Certificate object if parseable, else {@code null}
* @throws TlsException on error
* @since 1.5.0
*/
private X509Certificate certificateFromString(final String cert) throws TlsException {
// Check if PEM header is present in given string
if (cert.contains("-BEGIN ") && cert.contains("-END")) {
try (var is = new ByteArrayInputStream(cert.getBytes(StandardCharsets.UTF_8))) {
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
} catch (IOException | CertificateException e) {
throw new TlsException("Unable to read certificate.", e);
}
}
// Not am PEM string, skip
return null;
}
/**
* Read given certificate file to X.509 certificate.
*
* @param certFile Path to certificate file
* @return X.509 Certificate object
* @throws TlsException on error
* @since 0.4.0
*/
private X509Certificate certificateFromFile(final Path certFile) throws TlsException {
try (var is = Files.newInputStream(certFile)) {
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
} catch (IOException | CertificateException e) {
throw new TlsException("Unable to read certificate.", e);
}
}
}

View File

@ -1,36 +1,27 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import de.stklcode.jvault.connector.model.*;
import de.stklcode.jvault.connector.model.response.*;
import de.stklcode.jvault.connector.model.AuthBackend;
import de.stklcode.jvault.connector.model.response.SealResponse;
import de.stklcode.jvault.connector.model.response.SecretResponse;
import de.stklcode.jvault.connector.model.response.TokenResponse;
import de.stklcode.jvault.connector.model.response.AuthResponse;
import java.io.Serializable;
import java.util.*;
import java.util.List;
/**
* Vault Connector interface.
* Provides methods to connect with Vault backend and handle secrets.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public interface VaultConnector extends AutoCloseable, Serializable {
public interface VaultConnector {
/**
* Verify that vault connection is initialized.
* @return TRUE if correctly initialized
*/
boolean init();
/**
* Reset authorization information.
@ -39,781 +30,120 @@ public interface VaultConnector extends AutoCloseable, Serializable {
/**
* Retrieve status of vault seal.
*
* @return Seal status
* @throws VaultConnectorException on error
* @return Seal status
*/
SealResponse sealStatus() throws VaultConnectorException;
SealResponse sealStatus();
/**
* Seal vault.
*
* @throws VaultConnectorException on error
* @return TRUE on success
*/
void seal() throws VaultConnectorException;
boolean seal();
/**
* Unseal vault.
*
* @param key A single master share key
* @param reset Discard previously provided keys (optional)
* @return Response with seal status
* @throws VaultConnectorException on error
* @param key A single master share key
* @param reset Discard previously provided keys (optional)
* @return TRUE on success
*/
SealResponse unseal(final String key, final Boolean reset) throws VaultConnectorException;
SealResponse unseal(final String key, final Boolean reset);
/**
* Unseal vault.
*
* @param key A single master share key
* @return Response with seal status
* @throws VaultConnectorException on error
* @param key A single master share key
* @return TRUE on success
*/
default SealResponse unseal(final String key) throws VaultConnectorException {
default SealResponse unseal(final String key) {
return unseal(key, null);
}
/**
* Query server health information.
*
* @return Health information.
* @throws VaultConnectorException on error
* @since 0.7.0
*/
HealthResponse getHealth() throws VaultConnectorException;
/**
* Get all available authentication backends.
*
* @return List of backends
* @throws VaultConnectorException on error
* Get all availale authentication backends.
* @return List of backends
*/
List<AuthBackend> getAuthBackends() throws VaultConnectorException;
/**
* Authorize to Vault using token.
*
* @param token The token
* @return Token response
* @throws VaultConnectorException on error
* @param token The token
* @return Token response
*/
TokenResponse authToken(final String token) throws VaultConnectorException;
/**
* Authorize to Vault using username and password.
*
* @param username The username
* @param password The password
* @return Authorization result
* @throws VaultConnectorException on error
* @param username The username
* @param password The password
* @return Authorization result
* @throws VaultConnectorException
*/
AuthResponse authUserPass(final String username, final String password) throws VaultConnectorException;
/**
* Authorize to Vault using AppRole method without secret ID.
*
* @param roleID The role ID
* @return The {@link AuthResponse}
* @throws VaultConnectorException on error
* @since 0.4.0
* Authorize to Vault using AppID method.
* @param appID The App ID
* @param userID The User ID
* @return TRUE on success
*/
default AuthResponse authAppRole(final String roleID) throws VaultConnectorException {
return authAppRole(roleID, null);
AuthResponse authAppId(final String appID, final String userID) throws VaultConnectorException;
/**
* Register new App-ID with policy.
* @param appID The unique App-ID
* @param policy The policy to associate with
* @param displayName Arbitrary name to display
* @return TRUE on success
* @throws VaultConnectorException
*/
boolean registerAppId(final String appID, final String policy, final String displayName) throws VaultConnectorException;
/**
* Register User-ID with App-ID
* @param appID The App-ID
* @param userID The User-ID
* @return TRUE on success
* @throws VaultConnectorException
*/
boolean registerUserId(final String appID, final String userID) throws VaultConnectorException;
/**
* Register new App-ID and User-ID at once.
* @param appID The App-ID
* @param policy The policy to associate with
* @param displayName Arbitrary name to display
* @param userID The User-ID
* @return TRUE on success
* @throws VaultConnectorException
*/
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);
}
/**
* Authorize to Vault using AppRole method.
*
* @param roleID The role ID
* @param secretID The secret ID
* @return The {@link AuthResponse}
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AuthResponse authAppRole(final String roleID, final String secretID) throws VaultConnectorException;
/**
* Register a new AppRole role from given metamodel.
*
* @param role The role
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean createAppRole(final AppRole role) throws VaultConnectorException;
/**
* Register new AppRole role with default policy.
*
* @param roleName The role name
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName) throws VaultConnectorException {
return createAppRole(roleName, new ArrayList<>());
}
/**
* Register new AppRole role with policies.
*
* @param roleName The role name
* @param policies The policies to associate with
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName, final List<String> policies) throws VaultConnectorException {
return createAppRole(roleName, policies, null);
}
/**
* Register new AppRole role with default policy and custom ID.
*
* @param roleName The role name
* @param roleID A custom role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName, final String roleID) throws VaultConnectorException {
return createAppRole(roleName, new ArrayList<>(), roleID);
}
/**
* Register new AppRole role with policies and custom ID.
*
* @param roleName The role name
* @param policies The policies to associate with
* @param roleID A custom role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName, final List<String> policies, final String roleID)
throws VaultConnectorException {
return createAppRole(AppRole.builder(roleName).withTokenPolicies(policies).withId(roleID).build());
}
/**
* Delete AppRole role from Vault.
*
* @param roleName The role name
* @return {@code true} on success
* @throws VaultConnectorException on error
*/
boolean deleteAppRole(final String roleName) throws VaultConnectorException;
/**
* Lookup an AppRole role.
*
* @param roleName The role name
* @return Result of the lookup
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleResponse lookupAppRole(final String roleName) throws VaultConnectorException;
/**
* Retrieve ID for an AppRole role.
*
* @param roleName The role name
* @return The role ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
String getAppRoleID(final String roleName) throws VaultConnectorException;
/**
* Set custom ID for an AppRole role.
*
* @param roleName The role name
* @param roleID The role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean setAppRoleID(final String roleName, final String roleID) throws VaultConnectorException;
/**
* Register new random generated AppRole secret.
*
* @param roleName The role name
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default AppRoleSecretResponse createAppRoleSecret(final String roleName) throws VaultConnectorException {
return createAppRoleSecret(roleName, new AppRoleSecret());
}
/**
* Register new AppRole secret with custom ID.
*
* @param roleName The role name
* @param secretID A custom secret ID
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default AppRoleSecretResponse createAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException {
return createAppRoleSecret(roleName, new AppRoleSecret(secretID));
}
/**
* Register new AppRole secret with custom ID.
*
* @param roleName The role name
* @param secret The secret meta object
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleSecretResponse createAppRoleSecret(final String roleName, final AppRoleSecret secret)
throws VaultConnectorException;
/**
* Lookup an AppRole secret.
*
* @param roleName The role name
* @param secretID The secret ID
* @return Result of the lookup
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleSecretResponse lookupAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException;
/**
* Destroy an AppRole secret.
*
* @param roleName The role name
* @param secretID The secret meta object
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean destroyAppRoleSecret(final String roleName, final String secretID) throws VaultConnectorException;
/**
* List existing (accessible) AppRole roles.
*
* @return List of roles
* @throws VaultConnectorException on error
*/
List<String> listAppRoles() throws VaultConnectorException;
/**
* List existing (accessible) secret IDs for AppRole role.
*
* @param roleName The role name
* @return List of roles
* @throws VaultConnectorException on error
*/
List<String> listAppRoleSecrets(final String roleName) throws VaultConnectorException;
/**
* Get authorization status.
*
* @return TRUE, if successfully authorized
* Get authorization status
* @return TRUE, if successfully authorized
*/
boolean isAuthorized();
/**
* Retrieve any nodes content from Vault.
*
* @param key Secret identifier
* @return Secret response
* @throws VaultConnectorException on error
* @since 0.5.0
* Retrieve secret form Vault.
* @param key Secret identifier
* @return Secret response
*/
SecretResponse read(final String key) throws VaultConnectorException;
SecretResponse readSecret(final String key) throws VaultConnectorException;
/**
* Retrieve the latest secret data for specific version from Vault.
* <br>
* Path {@code <mount>/data/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @return Secret response
* @throws VaultConnectorException on error
* @since 0.8
* List available secrets from Vault.
* @param path Root path to search
* @return List of secret keys
*/
default SecretResponse readSecretData(final String mount, final String key) throws VaultConnectorException {
return readSecretVersion(mount, key, null);
}
List<String> listSecrets(final String path) throws VaultConnectorException;
/**
* Write secret to Vault.
* <br>
* Path {@code <mount>/data/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @param data Secret content. Value must be be JSON serializable.
* @return Metadata for the created/updated secret.
* @throws VaultConnectorException on error
* @since 0.8
*/
default SecretVersionResponse writeSecretData(final String mount,
final String key,
final Map<String, Object> data) throws VaultConnectorException {
return writeSecretData(mount, key, data, null);
}
/**
* Write secret to Vault.
* <br>
* Path {@code <mount>/data/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @param data Secret content. Value must be be JSON serializable.
* @param cas Use Check-And-Set operation, i.e. only allow writing if current version matches this value.
* @return Metadata for the created/updated secret.
* @throws VaultConnectorException on error
* @since 0.8
*/
SecretVersionResponse writeSecretData(final String mount,
final String key,
final Map<String, Object> data,
final Integer cas) throws VaultConnectorException;
/**
* Retrieve secret data from Vault.
* <br>
* Path {@code <mount>/data/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @param version Version to read. If {@code null} or zero, the latest version will be returned.
* @return Secret response.
* @throws VaultConnectorException on error
* @since 0.8
*/
SecretResponse readSecretVersion(final String mount, final String key, final Integer version)
throws VaultConnectorException;
/**
* Retrieve secret metadata from Vault.
* <br>
* Path {@code <mount>/metadata/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @return Metadata response
* @throws VaultConnectorException on error
* @since 0.8
*/
MetadataResponse readSecretMetadata(final String mount, final String key) throws VaultConnectorException;
/**
* Update secret metadata.
* <br>
* Path {@code <mount>/metadata/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @param maxVersions Maximum number of versions (fallback to backend default if {@code null})
* @param casRequired Specify if Check-And-Set is required for this secret.
* @throws VaultConnectorException on error
* @since 0.8
*/
void updateSecretMetadata(final String mount,
final String key,
final Integer maxVersions,
final boolean casRequired) throws VaultConnectorException;
/**
* List available nodes from Vault.
*
* @param path Root path to search
* @return List of secret keys
* @throws VaultConnectorException on error
* @since 0.5.0
*/
List<String> list(final String path) throws VaultConnectorException;
/**
* Write simple value to Vault.
*
* @param key Secret path
* @param value Secret value
* @throws VaultConnectorException on error
* @since 0.5.0
* @return TRUE on success
*/
default void write(final String key, final String value) throws VaultConnectorException {
write(key, Collections.singletonMap("value", value));
}
/**
* Write value to Vault.
*
* @param key Secret path
* @param data Secret content. Value must be be JSON serializable.
* @throws VaultConnectorException on error
* @since 0.5.0
*/
default void write(final String key, final Map<String, Object> data) throws VaultConnectorException {
write(key, data, null);
}
/**
* Write value to Vault.
*
* @param key Secret path
* @param data Secret content. Value must be be JSON serializable.
* @param options Secret options (optional).
* @throws VaultConnectorException on error
* @since 0.8 {@code options} parameter added
*/
void write(final String key, final Map<String, Object> data, final Map<String, Object> options)
throws VaultConnectorException;
/**
* Delete key from Vault.
*
* @param key Secret path
* @throws VaultConnectorException on error
* @since 0.5.0
*/
void delete(final String key) throws VaultConnectorException;
/**
* Delete latest version of a secret from Vault.
* <br>
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteLatestSecretVersion(final String mount, final String key) throws VaultConnectorException;
/**
* Delete latest version of a secret from Vault.
* <br>
* Prefix {@code secret/} is automatically added to path.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteAllSecretVersions(final String mount, final String key) throws VaultConnectorException;
/**
* Delete secret versions from Vault.
* <br>
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to delete.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Undelete (restore) secret versions from Vault.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to undelete.
* @throws VaultConnectorException on error
* @since 0.8
*/
void undeleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Destroy secret versions from Vault.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to destroy.
* @throws VaultConnectorException on error
* @since 0.8
*/
void destroySecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Revoke given lease immediately.
*
* @param leaseID the lease ID
* @throws VaultConnectorException on error
*/
void revoke(final String leaseID) throws VaultConnectorException;
/**
* Renew lease with given ID.
*
* @param leaseID the lase ID
* @return Renewed lease
* @throws VaultConnectorException on error
*/
default SecretResponse renew(final String leaseID) throws VaultConnectorException {
return renew(leaseID, null);
}
/**
* Renew lease with given ID.
*
* @param leaseID the lase ID
* @param increment number of seconds to extend lease time
* @return Renewed lease
* @throws VaultConnectorException on error
*/
SecretResponse renew(final String leaseID, final Integer increment) throws VaultConnectorException;
/**
* Create a new token.
*
* @param token the token
* @return the result response
* @throws VaultConnectorException on error
*/
AuthResponse createToken(final Token token) throws VaultConnectorException;
/**
* Create a new token.
*
* @param token the token
* @param orphan create orphan token
* @return the result response
* @throws VaultConnectorException on error
*/
AuthResponse createToken(final Token token, boolean orphan) throws VaultConnectorException;
/**
* Create a new token for specific role.
*
* @param token the token
* @param role the role name
* @return the result response
* @throws VaultConnectorException on error
*/
AuthResponse createToken(final Token token, final String role) throws VaultConnectorException;
/**
* Lookup token information.
*
* @param token the token
* @return the result response
* @throws VaultConnectorException on error
*/
TokenResponse lookupToken(final String token) throws VaultConnectorException;
/**
* Create a new or update an existing token role.
*
* @param role the role entity (name must be set)
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
*/
default boolean createOrUpdateTokenRole(final TokenRole role) throws VaultConnectorException {
return createOrUpdateTokenRole(role.getName(), role);
}
/**
* Create a new or update an existing token role.
*
* @param name the role name (overrides name possibly set in role entity)
* @param role the role entity
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
*/
boolean createOrUpdateTokenRole(final String name, final TokenRole role) throws VaultConnectorException;
/**
* Lookup token information.
*
* @param name the role name
* @return the result response
* @throws VaultConnectorException on error
* @since 0.9
*/
TokenRoleResponse readTokenRole(final String name) throws VaultConnectorException;
/**
* List available token roles from Vault.
*
* @return List of token roles
* @throws VaultConnectorException on error
* @since 0.9
*/
List<String> listTokenRoles() throws VaultConnectorException;
/**
* Delete a token role.
*
* @param name the role name to delete
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
*/
boolean deleteTokenRole(final String name) throws VaultConnectorException;
/**
* Encrypt plaintext via transit engine from Vault.
*
* @param keyName Transit key name
* @param plaintext Text to encrypt (Base64 encoded)
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse transitEncrypt(final String keyName, final String plaintext) throws VaultConnectorException;
/**
* Encrypt plaintext via transit engine from Vault.
*
* @param keyName Transit key name
* @param plaintext Binary data to encrypt
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse transitEncrypt(final String keyName, final byte[] plaintext)
throws VaultConnectorException {
return transitEncrypt(keyName, Base64.getEncoder().encodeToString(plaintext));
}
/**
* Decrypt ciphertext via transit engine from Vault.
*
* @param keyName Transit key name
* @param ciphertext Text to decrypt
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse transitDecrypt(final String keyName, final String ciphertext) throws VaultConnectorException;
/**
* Hash data in hex format via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse transitHash(final String algorithm, final String input) throws VaultConnectorException {
return transitHash(algorithm, input, "hex");
}
/**
* Hash data via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash (Base64 encoded)
* @param format Specifies the output encoding (hex/base64)
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse transitHash(final String algorithm, final String input, final String format)
throws VaultConnectorException;
/**
* Hash data via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse transitHash(final String algorithm, final byte[] input, final String format)
throws VaultConnectorException {
return transitHash(algorithm, Base64.getEncoder().encodeToString(input), format);
}
/**
* Read credentials for MySQL backend at default mount point.
*
* @param role the role name
* @return the credentials response
* @throws VaultConnectorException on error
* @since 0.5.0
* @deprecated use {@link #readDbCredentials(String, String)} your MySQL mountpoint
*/
@Deprecated(since = "1.5.0", forRemoval = true)
default CredentialsResponse readMySqlCredentials(final String role) throws VaultConnectorException {
return readDbCredentials(role, "mysql");
}
/**
* Read credentials for PostgreSQL backend at default mount point.
*
* @param role the role name
* @return the credentials response
* @throws VaultConnectorException on error
* @since 0.5.0
* @deprecated use {@link #readDbCredentials(String, String)} your PostgreSQL mountpoint
*/
@Deprecated(since = "1.5.0", forRemoval = true)
default CredentialsResponse readPostgreSqlCredentials(final String role) throws VaultConnectorException {
return readDbCredentials(role, "postgresql");
}
/**
* Read credentials for MSSQL backend at default mount point.
*
* @param role the role name
* @return the credentials response
* @throws VaultConnectorException on error
* @since 0.5.0
* @deprecated use {@link #readDbCredentials(String, String)} your MSSQL mountpoint
*/
@Deprecated(since = "1.5.0", forRemoval = true)
default CredentialsResponse readMsSqlCredentials(final String role) throws VaultConnectorException {
return readDbCredentials(role, "mssql");
}
/**
* Read credentials for MongoDB backend at default mount point.
*
* @param role the role name
* @return the credentials response
* @throws VaultConnectorException on error
* @since 0.5.0
* @deprecated use {@link #readDbCredentials(String, String)} your MongoDB mountpoint
*/
@Deprecated(since = "1.5.0", forRemoval = true)
default CredentialsResponse readMongoDbCredentials(final String role) throws VaultConnectorException {
return readDbCredentials(role, "mongodb");
}
/**
* Read credentials for database backends.
*
* @param role the role name
* @param mount mount point of the database backend
* @return the credentials response
* @throws VaultConnectorException on error
* @since 0.5.0
*/
default CredentialsResponse readDbCredentials(final String role, final String mount)
throws VaultConnectorException {
return (CredentialsResponse) read(mount + "/creds/" + role);
}
boolean writeSecret(final String key, final String value) throws VaultConnectorException;
}

View File

@ -1,27 +1,10 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.exception;
/**
* Exception thrown trying to do a request without any authorization handles.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public class AuthorizationRequiredException extends VaultConnectorException {
private static final long serialVersionUID = 2629577936657393880L;
}

View File

@ -1,61 +1,24 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.exception;
/**
* Exception thrown on problems with connection to Vault backend.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public class ConnectionException extends VaultConnectorException {
private static final long serialVersionUID = 3005430116002990418L;
/**
* Constructs a new empty exception.
*/
public ConnectionException() {
}
/**
* Constructs a new exception with the specified detail message.
*
* @param message the detail message
*/
public ConnectionException(final String message) {
public ConnectionException(String message) {
super(message);
}
/**
* Constructs a new exception with the specified cause.
*
* @param cause the cause
*/
public ConnectionException(final Throwable cause) {
public ConnectionException(Throwable cause) {
super(cause);
}
/**
* Constructs a new exception with the specified detail message and cause.
*
* @param message the detail message
* @param cause the cause
*/
public ConnectionException(final String message, final Throwable cause) {
public ConnectionException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -1,61 +1,24 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.exception;
/**
* Exception thrown when trying to send malformed request.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public class InvalidRequestException extends VaultConnectorException {
private static final long serialVersionUID = -6712239648281809159L;
/**
* Constructs a new empty exception.
*/
public InvalidRequestException() {
}
/**
* Constructs a new exception with the specified detail message.
*
* @param message the detail message
*/
public InvalidRequestException(final String message) {
public InvalidRequestException(String message) {
super(message);
}
/**
* Constructs a new exception with the specified cause.
*
* @param cause the cause
*/
public InvalidRequestException(final Throwable cause) {
public InvalidRequestException(Throwable cause) {
super(cause);
}
/**
* Constructs a new exception with the specified detail message and cause.
*
* @param message the detail message
* @param cause the cause
*/
public InvalidRequestException(final String message, final Throwable cause) {
public InvalidRequestException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -1,157 +1,45 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.exception;
/**
* Exception thrown when response from vault returned with erroneous status code or payload could not be parsed
* to entity class.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public final class InvalidResponseException extends VaultConnectorException {
private static final long serialVersionUID = 2003151038614163479L;
public class InvalidResponseException extends VaultConnectorException {
private Integer statusCode;
private String response;
private final Integer statusCode;
private final String response;
/**
* Constructs a new empty exception.
*/
public InvalidResponseException() {
this.statusCode = null;
this.response = null;
}
/**
* Constructs a new exception with the specified detail message.
*
* @param message The detail message
*/
public InvalidResponseException(final String message) {
public InvalidResponseException(String message) {
super(message);
this.statusCode = null;
this.response = null;
}
/**
* Constructs a new exception with the specified cause.
*
* @param cause The cause
*/
public InvalidResponseException(final Throwable cause) {
public InvalidResponseException(Throwable cause) {
super(cause);
this.statusCode = null;
this.response = null;
}
/**
* Constructs a new exception with the specified detail message and cause.
*
* @param message The detail message
* @param cause The cause
*/
public InvalidResponseException(final String message, final Throwable cause) {
public InvalidResponseException(String message, Throwable cause) {
super(message, cause);
this.statusCode = null;
this.response = null;
}
/**
* Constructs a new exception with the specified detail message and status code.
* <p>
* The HTTP status code can be retrieved by {@link #getStatusCode()} later.
*
* @param message The detail message
* @param statusCode Status code of the HTTP response
* @since 0.6.2
*/
public InvalidResponseException(final String message, final Integer statusCode) {
super(message);
public InvalidResponseException withStatusCode(Integer statusCode) {
this.statusCode = statusCode;
this.response = null;
return this;
}
/**
* Constructs a new exception with the specified detail message, cause and status code.
* <p>
* The HTTP status code can be retrieved by {@link #getStatusCode()} later.
*
* @param message The detail message
* @param statusCode Status code of the HTTP response
* @param cause The cause
* @since 0.6.2
*/
public InvalidResponseException(final String message, final Integer statusCode, final Throwable cause) {
this(message, statusCode, null, cause);
}
/**
* Constructs a new exception with the specified detail message, cause and status code.
* <p>
* The HTTP status code can be retrieved by {@link #getStatusCode()} later.
*
* @param message The detail message
* @param statusCode Status code of the HTTP response
* @param response HTTP response string
* @since 0.6.2
*/
public InvalidResponseException(final String message,
final Integer statusCode,
final String response) {
super(message);
this.statusCode = statusCode;
public InvalidResponseException withResponse(String response) {
this.response = response;
return this;
}
/**
* Constructs a new exception with the specified detail message, cause and status code.
* <p>
* The HTTP status code can be retrieved by {@link #getStatusCode()} later.
*
* @param message The detail message
* @param statusCode Status code of the HTTP response
* @param response HTTP response string
* @param cause The cause
* @since 0.6.2
*/
public InvalidResponseException(final String message,
final Integer statusCode,
final String response,
final Throwable cause) {
super(message, cause);
this.statusCode = statusCode;
this.response = response;
}
/**
* Retrieve the HTTP status code.
*
* @return The status code or {@code null} if none specified.
*/
public Integer getStatusCode() {
return statusCode;
}
/**
* Retrieve the response text.
*
* @return The response text or {@code null} if none specified.
*/
public String getResponse() {
return response;
}

View File

@ -1,62 +1,25 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.exception;
/**
* Exception thrown when trying to access a path the current user/token does not have permission to access.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public class PermissionDeniedException extends VaultConnectorException {
private static final long serialVersionUID = -7149134015090750776L;
/**
* Constructs a new empty exception.
*/
public PermissionDeniedException() {
super("Permission denied");
}
/**
* Constructs a new exception with the specified detail message.
*
* @param message the detail message
*/
public PermissionDeniedException(final String message) {
public PermissionDeniedException(String message) {
super(message);
}
/**
* Constructs a new exception with the specified cause.
*
* @param cause the cause
*/
public PermissionDeniedException(final Throwable cause) {
public PermissionDeniedException(Throwable cause) {
super(cause);
}
/**
* Constructs a new exception with the specified detail message and cause.
*
* @param message the detail message
* @param cause the cause
*/
public PermissionDeniedException(final String message, final Throwable cause) {
public PermissionDeniedException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -1,61 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.exception;
/**
* Exception thrown on errors with TLS connection.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
public class TlsException extends VaultConnectorException {
private static final long serialVersionUID = -5139276834988258086L;
/**
* Constructs a new empty exception.
*/
public TlsException() {
}
/**
* Constructs a new exception with the specified detail message.
*
* @param message the detail message
*/
public TlsException(final String message) {
super(message);
}
/**
* Constructs a new exception with the specified cause.
*
* @param cause the cause
*/
public TlsException(final Throwable cause) {
super(cause);
}
/**
* Constructs a new exception with the specified detail message and cause.
*
* @param message the detail message
* @param cause the cause
*/
public TlsException(final String message, final Throwable cause) {
super(message, cause);
}
}

View File

@ -1,61 +1,24 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.exception;
/**
* Abstract Exception class for Vault Connector internal exceptions.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public abstract class VaultConnectorException extends Exception {
private static final long serialVersionUID = -2612477894310906036L;
/**
* Constructs a new empty exception.
*/
protected VaultConnectorException() {
public VaultConnectorException() {
}
/**
* Constructs a new exception with the specified detail message.
*
* @param message the detail message
*/
protected VaultConnectorException(final String message) {
public VaultConnectorException(String message) {
super(message);
}
/**
* Constructs a new exception with the specified cause.
*
* @param cause the cause
*/
protected VaultConnectorException(final Throwable cause) {
public VaultConnectorException(Throwable cause) {
super(cause);
}
/**
* Constructs a new exception with the specified detail message and cause.
*
* @param message the detail message
* @param cause the cause
*/
protected VaultConnectorException(final String message, final Throwable cause) {
public VaultConnectorException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -1,20 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Some custom exceptions for error handling.
*/
package de.stklcode.jvault.connector.exception;

View File

@ -0,0 +1,93 @@
package de.stklcode.jvault.connector.factory;
import de.stklcode.jvault.connector.HTTPVaultConnector;
/**
* Vault Connector Factory implementation for HTTP Vault connectors.
*
* @author Stefan Kalscheuer
* @since 0.1
*/
public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
public static final String DEFAULT_HOST = "127.0.0.1";
public static final Integer DEFAULT_PORT = 8200;
public static final boolean DEFAULT_TLS = true;
public static final String DEFAULT_PREFIX = "/v1/";
private String host;
private Integer port;
private boolean tls;
private String prefix;
/**
* Default empty constructor.
* Initializes factory with default values.
*/
public HTTPVaultConnectorFactory() {
host = DEFAULT_HOST;
port = DEFAULT_PORT;
tls = DEFAULT_TLS;
prefix = DEFAULT_PREFIX;
}
/**
* Set hostname (default: 127.0.0.1)
* @param host Hostname or IP address
* @return self
*/
public HTTPVaultConnectorFactory withHost(String host) {
this.host = host;
return this;
}
/**
* Set port (default: 8200)
* @param port Vault TCP port
* @return self
*/
public HTTPVaultConnectorFactory withPort(Integer port) {
this.port = port;
return this;
}
/**
* Set TLS usage (default: TRUE)
* @param useTLS use TLS or not
* @return self
*/
public HTTPVaultConnectorFactory withTLS(boolean useTLS) {
this.tls = useTLS;
return this;
}
/**
* Convenience Method for TLS usage (enabled by default)
* @return self
*/
public HTTPVaultConnectorFactory withTLS() {
return withTLS(true);
}
/**
* Convenience Method for NOT using TLS
* @return self
*/
public HTTPVaultConnectorFactory withoutTLS() {
return withTLS(false);
}
/**
* Set API prefix. Default is "/v1/" and changes should not be necessary for current state of development.
* @param prefix Vault API prefix (default: "/v1/"
* @return self
*/
public HTTPVaultConnectorFactory withPrefix(String prefix) {
this.prefix = prefix;
return this;
}
@Override
public HTTPVaultConnector build() {
return new HTTPVaultConnector(host, tls, port, prefix);
}
}

View File

@ -0,0 +1,26 @@
package de.stklcode.jvault.connector.factory;
import de.stklcode.jvault.connector.VaultConnector;
/**
* Abstract Vault Connector Factory interface.
* Provides builder pattern style factory for Vault connectors.
*
* @author Stefan Kalscheuer
* @since 0.1
*/
public abstract class VaultConnectorFactory {
/**
* Get Factory implementation for HTTP Vault Connector
* @return HTTP Connector Factory
*/
public static HTTPVaultConnectorFactory httpFactory() {
return new HTTPVaultConnectorFactory();
}
/**
* Build command, produces connector after initialization.
* @return Vault Connector instance.
*/
public abstract VaultConnector build();
}

View File

@ -1,39 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.internal;
/**
* Utility class to bundle common error messages.
*
* @author Stefan Kalscheuer
* @since 0.8 Extracted from static inner class.
*/
final class Error {
static final String READ_RESPONSE = "Unable to read response";
static final String PARSE_RESPONSE = "Unable to parse response";
static final String UNEXPECTED_RESPONSE = "Received response where none was expected";
static final String URI_FORMAT = "Invalid URI format";
static final String RESPONSE_CODE = "Invalid response code";
static final String INIT_SSL_CONTEXT = "Unable to initialize SSLContext";
static final String CONNECTION = "Unable to connect to Vault server";
/**
* Constructor hidden, this class should not be instantiated.
*/
private Error() {
}
}

View File

@ -1,450 +0,0 @@
package de.stklcode.jvault.connector.internal;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import de.stklcode.jvault.connector.exception.*;
import de.stklcode.jvault.connector.model.response.ErrorResponse;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.CompletionException;
import java.util.stream.Collectors;
import static java.nio.charset.StandardCharsets.UTF_8;
/**
* Helper class to bundle Vault HTTP requests.
*
* @author Stefan Kalscheuer
* @since 0.8 Extracted methods from {@link de.stklcode.jvault.connector.HTTPVaultConnector}.
*/
public final class RequestHelper implements Serializable {
private static final String HEADER_VAULT_TOKEN = "X-Vault-Token";
private final String baseURL; // Base URL of Vault.
private final Integer timeout; // Timeout in milliseconds.
private final int retries; // Number of retries on 5xx errors.
private final String tlsVersion; // TLS version (#22).
private final X509Certificate trustedCaCert; // Trusted CA certificate.
private final JsonMapper jsonMapper;
/**
* Constructor of the request helper.
*
* @param baseURL The URL
* @param retries Number of retries on 5xx errors
* @param timeout Timeout for HTTP requests (milliseconds)
* @param tlsVersion TLS Version.
* @param trustedCaCert Trusted CA certificate
*/
public RequestHelper(final String baseURL,
final int retries,
final Integer timeout,
final String tlsVersion,
final X509Certificate trustedCaCert) {
this.baseURL = baseURL + (baseURL.endsWith("/") ? "" : "/");
this.retries = retries;
this.timeout = timeout;
this.tlsVersion = tlsVersion;
this.trustedCaCert = trustedCaCert;
this.jsonMapper = JsonMapper.builder()
.addModule(new JavaTimeModule())
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
.build();
}
/**
* Execute HTTP request using POST method.
*
* @param path URL path (relative to base).
* @param payload Map of payload values (will be converted to JSON).
* @param token Vault token (may be {@code null}).
* @return HTTP response
* @throws VaultConnectorException on connection error
* @since 0.8 Added {@code token} parameter.
*/
public String post(final String path, final Object payload, final String token) throws VaultConnectorException {
// Initialize POST.
var req = HttpRequest.newBuilder(URI.create(baseURL + path));
// Generate JSON from payload.
try {
req.POST(HttpRequest.BodyPublishers.ofString(jsonMapper.writeValueAsString(payload), UTF_8));
} catch (JsonProcessingException e) {
throw new InvalidRequestException(Error.PARSE_RESPONSE, e);
}
req.setHeader("Content-Type", "application/json; charset=utf-8");
// Set X-Vault-Token header.
if (token != null) {
req.setHeader(HEADER_VAULT_TOKEN, token);
}
return request(req, retries);
}
/**
* Execute HTTP request using POST method and parse JSON result.
*
* @param path URL path (relative to base).
* @param payload Map of payload values (will be converted to JSON).
* @param token Vault token (may be {@code null}).
* @param target Target class.
* @param <T> Target type.
* @return HTTP response
* @throws VaultConnectorException on connection error
* @since 0.8
*/
public <T> T post(final String path, final Object payload, final String token, final Class<T> target)
throws VaultConnectorException {
try {
String response = post(path, payload, token);
return jsonMapper.readValue(response, target);
} catch (IOException e) {
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
}
}
/**
* Execute HTTP request using POST method and expect empty (204) response.
*
* @param path URL path (relative to base).
* @param payload Map of payload values (will be converted to JSON).
* @param token Vault token (may be {@code null}).
* @throws VaultConnectorException on connection error
* @since 0.8
*/
public void postWithoutResponse(final String path, final Object payload, final String token)
throws VaultConnectorException {
if (!post(path, payload, token).isEmpty()) {
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
}
}
/**
* Execute HTTP request using PUT method.
*
* @param path URL path (relative to base).
* @param payload Map of payload values (will be converted to JSON).
* @param token Vault token (may be {@code null}).
* @return HTTP response
* @throws VaultConnectorException on connection error
* @since 0.8 Added {@code token} parameter.
*/
public String put(final String path, final Map<String, String> payload, final String token)
throws VaultConnectorException {
// Initialize PUT.
var req = HttpRequest.newBuilder(URI.create(baseURL + path));
// Generate JSON from payload.
try {
req.PUT(HttpRequest.BodyPublishers.ofString(jsonMapper.writeValueAsString(payload), UTF_8));
} catch (JsonProcessingException e) {
throw new InvalidRequestException("Payload serialization failed", e);
}
req.setHeader("Content-Type", "application/json; charset=utf-8");
// Set X-Vault-Token header.
if (token != null) {
req.setHeader(HEADER_VAULT_TOKEN, token);
}
return request(req, retries);
}
/**
* Execute HTTP request using PUT method and parse JSON result.
*
* @param path URL path (relative to base).
* @param payload Map of payload values (will be converted to JSON).
* @param token Vault token (may be {@code null}).
* @param target Target class.
* @param <T> Target type.
* @return HTTP response
* @throws VaultConnectorException on connection error
* @since 0.8
*/
public <T> T put(final String path, final Map<String, String> payload, final String token, final Class<T> target)
throws VaultConnectorException {
try {
String response = put(path, payload, token);
return jsonMapper.readValue(response, target);
} catch (IOException e) {
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
}
}
/**
* Execute HTTP request using PUT method and expect empty (204) response.
*
* @param path URL path (relative to base).
* @param payload Map of payload values (will be converted to JSON).
* @param token Vault token (may be {@code null}).
* @throws VaultConnectorException on connection error
* @since 0.8
*/
public void putWithoutResponse(final String path, final Map<String, String> payload, final String token)
throws VaultConnectorException {
if (!put(path, payload, token).isEmpty()) {
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
}
}
/**
* Execute HTTP request using DELETE method.
*
* @param path URL path (relative to base).
* @param token Vault token (may be {@code null}).
* @return HTTP response
* @throws VaultConnectorException on connection error
* @since 0.8 Added {@code token} parameter.
*/
public String delete(final String path, final String token) throws VaultConnectorException {
// Initialize DELETE.
HttpRequest.Builder req = HttpRequest.newBuilder(URI.create(baseURL + path)).DELETE();
// Set X-Vault-Token header.
if (token != null) {
req.setHeader(HEADER_VAULT_TOKEN, token);
}
return request(req, retries);
}
/**
* Execute HTTP request using DELETE method and expect empty (204) response.
*
* @param path URL path (relative to base).
* @param token Vault token (may be {@code null}).
* @throws VaultConnectorException on connection error
* @since 0.8
*/
public void deleteWithoutResponse(final String path, final String token) throws VaultConnectorException {
if (!delete(path, token).isEmpty()) {
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
}
}
/**
* Execute HTTP request using GET method.
*
* @param path URL path (relative to base).
* @param payload Map of payload values (will be converted to JSON).
* @param token Vault token (may be {@code null}).
* @return HTTP response
* @throws VaultConnectorException on connection error
* @since 0.8 Added {@code token} parameter.
*/
public String get(final String path, final Map<String, String> payload, final String token)
throws VaultConnectorException {
// Add parameters to URI.
var uriBuilder = new StringBuilder(baseURL + path);
if (!payload.isEmpty()) {
uriBuilder.append("?").append(
payload.entrySet().stream().map(par ->
URLEncoder.encode(par.getKey(), UTF_8) + "=" + URLEncoder.encode(par.getValue(), UTF_8)
).collect(Collectors.joining("&"))
);
}
// Initialize GET.
try {
var req = HttpRequest.newBuilder(new URI(uriBuilder.toString()));
// Set X-Vault-Token header.
if (token != null) {
req.setHeader(HEADER_VAULT_TOKEN, token);
}
return request(req, retries);
} catch (URISyntaxException e) {
/* this should never occur and may leak sensible information */
throw new InvalidRequestException(Error.URI_FORMAT);
}
}
/**
* Execute HTTP request using GET method and parse JSON result to target class.
*
* @param path URL path (relative to base).
* @param payload Map of payload values (will be converted to JSON).
* @param token Vault token (may be {@code null}).
* @param target Target class.
* @param <T> Target type.
* @return HTTP response
* @throws VaultConnectorException on connection error
* @since 0.8
*/
public <T> T get(final String path, final Map<String, String> payload, final String token, final Class<T> target)
throws VaultConnectorException {
try {
String response = get(path, payload, token);
return jsonMapper.readValue(response, target);
} catch (IOException e) {
throw new InvalidResponseException(Error.PARSE_RESPONSE, e);
}
}
/**
* Execute prepared HTTP request and return result.
*
* @param requestBuilder Prepared request.
* @param retries Number of retries.
* @return HTTP response
* @throws VaultConnectorException on connection error
*/
private String request(final HttpRequest.Builder requestBuilder, final int retries) throws VaultConnectorException {
// Set JSON Header.
requestBuilder.setHeader("accept", "application/json");
var clientBuilder = HttpClient.newBuilder();
// Set custom timeout, if defined.
if (this.timeout != null) {
clientBuilder.connectTimeout(Duration.ofMillis(timeout));
}
// Set custom SSL context.
clientBuilder.sslContext(createSSLContext());
HttpClient client = clientBuilder.build();
// Execute request.
try {
HttpResponse<InputStream> response = client.sendAsync(
requestBuilder.build(),
HttpResponse.BodyHandlers.ofInputStream()
).join();
/* Check if response is valid */
if (response == null) {
throw new InvalidResponseException("Response unavailable");
}
switch (response.statusCode()) {
case 200:
return handleResult(response);
case 204:
return "";
case 403:
throw new PermissionDeniedException();
default:
if (response.statusCode() >= 500 && response.statusCode() < 600 && retries > 0) {
// Retry on 5xx errors.
return request(requestBuilder, retries - 1);
} else {
// Fail on different error code and/or no retries left.
handleError(response);
// Throw exception without details, if response entity is empty.
throw new InvalidResponseException(Error.RESPONSE_CODE, response.statusCode());
}
}
} catch (CompletionException e) {
throw new ConnectionException(Error.CONNECTION, e.getCause());
} finally {
if (client instanceof AutoCloseable) {
// Close the client, which is supported since JDK21.
try {
((AutoCloseable) client).close();
} catch (Exception ignored) {
// Ignore
}
}
}
}
/**
* Create a custom SSL context from trusted CA certificate.
*
* @return The context.
* @throws TlsException An error occurred during initialization of the SSL context.
* @since 0.8.0
* @since 0.10 Generate {@link SSLContext} instead of Apache {@code SSLConnectionSocketFactory}
*/
private SSLContext createSSLContext() throws TlsException {
try {
// Create context.
var sslContext = SSLContext.getInstance(tlsVersion);
if (trustedCaCert != null) {
// Create Keystore with trusted certificate.
var keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("trustedCert", trustedCaCert);
// Initialize TrustManager.
var tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
sslContext.init(null, tmf.getTrustManagers(), null);
} else {
sslContext.init(null, null, null);
}
return sslContext;
} catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException |
KeyManagementException e) {
throw new TlsException(Error.INIT_SSL_CONTEXT, e);
}
}
/**
* Handle successful result.
*
* @param response The raw HTTP response (assuming status code 200)
* @return Complete response body as String
* @throws InvalidResponseException on reading errors
*/
private String handleResult(final HttpResponse<InputStream> response) throws InvalidResponseException {
try (var reader = new BufferedReader(new InputStreamReader(response.body(), UTF_8))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (IOException ignored) {
throw new InvalidResponseException(Error.READ_RESPONSE, 200);
}
}
/**
* Handle unsuccessful response. Throw detailed exception if possible.
*
* @param response The raw HTTP response (assuming status code 5xx)
* @throws VaultConnectorException Expected exception with details to throw
*/
private void handleError(final HttpResponse<InputStream> response) throws VaultConnectorException {
try (var body = response.body()) {
if (body != null) {
try (var reader = new BufferedReader(new InputStreamReader(body, UTF_8))) {
ErrorResponse er = jsonMapper.readValue(reader, ErrorResponse.class);
/* Check for "permission denied" response */
if (!er.getErrors().isEmpty() && er.getErrors().get(0).equals("permission denied")) {
throw new PermissionDeniedException();
}
throw new InvalidResponseException(Error.RESPONSE_CODE, response.statusCode(), er.toString());
}
}
} catch (IOException ignored) {
// Exception ignored.
}
}
}

View File

@ -1,661 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.annotation.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Vault AppRole role metamodel.
*
* @author Stefan Kalscheuer
* @since 0.4.0
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRole implements Serializable {
private static final long serialVersionUID = 693228837510483448L;
@JsonProperty("role_name")
private String name;
@JsonProperty("role_id")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String id;
@JsonProperty("bind_secret_id")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean bindSecretId;
private List<String> secretIdBoundCidrs;
@JsonProperty("secret_id_num_uses")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer secretIdNumUses;
@JsonProperty("secret_id_ttl")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer secretIdTtl;
@JsonProperty("local_secret_ids")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean localSecretIds;
@JsonProperty("token_ttl")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer tokenTtl;
@JsonProperty("token_max_ttl")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer tokenMaxTtl;
private List<String> tokenPolicies;
@JsonProperty("token_bound_cidrs")
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<String> tokenBoundCidrs;
@JsonProperty("token_explicit_max_ttl")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer tokenExplicitMaxTtl;
@JsonProperty("token_no_default_policy")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean tokenNoDefaultPolicy;
@JsonProperty("token_num_uses")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer tokenNumUses;
@JsonProperty("token_period")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer tokenPeriod;
@JsonProperty("token_type")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String tokenType;
/**
* Construct empty {@link AppRole} object.
*/
public AppRole() {
}
/**
* Construct {@link AppRole} object from {@link AppRole.Builder}.
*
* @param builder AppRole builder.
*/
public AppRole(final Builder builder) {
this.name = builder.name;
this.id = builder.id;
this.bindSecretId = builder.bindSecretId;
this.secretIdBoundCidrs = builder.secretIdBoundCidrs;
this.secretIdNumUses = builder.secretIdNumUses;
this.secretIdTtl = builder.secretIdTtl;
this.localSecretIds = builder.localSecretIds;
this.tokenTtl = builder.tokenTtl;
this.tokenMaxTtl = builder.tokenMaxTtl;
this.tokenPolicies = builder.tokenPolicies;
this.tokenBoundCidrs = builder.tokenBoundCidrs;
this.tokenExplicitMaxTtl = builder.tokenExplicitMaxTtl;
this.tokenNoDefaultPolicy = builder.tokenNoDefaultPolicy;
this.tokenNumUses = builder.tokenNumUses;
this.tokenPeriod = builder.tokenPeriod;
this.tokenType = builder.tokenType != null ? builder.tokenType.value() : null;
}
/**
* Get {@link Builder} instance.
*
* @param name Role name.
* @return AppRole Builder.
* @since 0.8
*/
public static Builder builder(final String name) {
return new Builder(name);
}
/**
* @return the role name
*/
public String getName() {
return name;
}
/**
* @return the role ID
*/
public String getId() {
return id;
}
/**
* @return bind secret ID
*/
public Boolean getBindSecretId() {
return bindSecretId;
}
/**
* @return list of bound CIDR subnets of associated tokens
* @since 0.9
*/
public List<String> getTokenBoundCidrs() {
return tokenBoundCidrs;
}
/**
* @param boundCidrList list of subnets in CIDR notation to bind role to
* @since 0.9
*/
@JsonSetter("token_bound_cidrs")
public void setBoundCidrs(final List<String> boundCidrList) {
this.tokenBoundCidrs = boundCidrList;
}
/**
* @return list of subnets in CIDR notation as comma-separated {@link String}
* @since 0.9
*/
@JsonGetter("token_bound_cidrs")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public String getTokenBoundCidrsString() {
if (tokenBoundCidrs == null || tokenBoundCidrs.isEmpty()) {
return "";
}
return String.join(",", tokenBoundCidrs);
}
/**
* @return list of bound CIDR subnets
* @since 0.8 replaces {@code getBoundCidrList()}
*/
public List<String> getSecretIdBoundCidrs() {
return secretIdBoundCidrs;
}
/**
* @param secretIdBoundCidrs List of subnets in CIDR notation to bind secrets of this role to.
* @since 0.8 replaces {@code setBoundCidrList(List)}
*/
@JsonSetter("secret_id_bound_cidrs")
public void setSecretIdBoundCidrs(final List<String> secretIdBoundCidrs) {
this.secretIdBoundCidrs = secretIdBoundCidrs;
}
/**
* @return List of subnets in CIDR notation as comma-separated {@link String}
* @since 0.8 replaces {@code getBoundCidrListString()} ()}
*/
@JsonGetter("secret_id_bound_cidrs")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public String getSecretIdBoundCidrsString() {
if (secretIdBoundCidrs == null || secretIdBoundCidrs.isEmpty()) {
return "";
}
return String.join(",", secretIdBoundCidrs);
}
/**
* @return list of token policies
* @since 0.9
*/
public List<String> getTokenPolicies() {
return tokenPolicies;
}
/**
* @param tokenPolicies list of token policies
* @since 0.9
*/
@JsonSetter("token_policies")
public void setTokenPolicies(final List<String> tokenPolicies) {
this.tokenPolicies = tokenPolicies;
}
/**
* @return list of policies as comma-separated {@link String}
* @since 0.9
*/
@JsonGetter("token_policies")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public String getTokenPoliciesString() {
if (tokenPolicies == null || tokenPolicies.isEmpty()) {
return "";
}
return String.join(",", tokenPolicies);
}
/**
* @return maximum number of uses per secret
*/
public Integer getSecretIdNumUses() {
return secretIdNumUses;
}
/**
* @return maximum TTL in seconds for secrets
*/
public Integer getSecretIdTtl() {
return secretIdTtl;
}
/**
* @return Enable local secret IDs?
* @since 0.9
* @since 1.3 renamed to {@code getLocalSecretIds()}
*/
public Boolean getLocalSecretIds() {
return localSecretIds;
}
/**
* @return token TTL in seconds
*/
public Integer getTokenTtl() {
return tokenTtl;
}
/**
* @return maximum token TTL in seconds, including renewals
*/
public Integer getTokenMaxTtl() {
return tokenMaxTtl;
}
/**
* @return explicit maximum token TTL in seconds, including renewals
* @since 0.9
*/
public Integer getTokenExplicitMaxTtl() {
return tokenExplicitMaxTtl;
}
/**
* @return enable default policy for token?
* @since 0.9
*/
public Boolean getTokenNoDefaultPolicy() {
return tokenNoDefaultPolicy;
}
/**
* @return number of uses for token
* @since 0.9
*/
public Integer getTokenNumUses() {
return tokenNumUses;
}
/**
* @return duration in seconds, if specified
* @since 0.9
*/
public Integer getTokenPeriod() {
return tokenPeriod;
}
/**
* @return duration in seconds, if specified
* @since 0.9
*/
public String getTokenType() {
return tokenType;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
AppRole appRole = (AppRole) o;
return Objects.equals(name, appRole.name) &&
Objects.equals(id, appRole.id) &&
Objects.equals(bindSecretId, appRole.bindSecretId) &&
Objects.equals(secretIdBoundCidrs, appRole.secretIdBoundCidrs) &&
Objects.equals(secretIdNumUses, appRole.secretIdNumUses) &&
Objects.equals(secretIdTtl, appRole.secretIdTtl) &&
Objects.equals(localSecretIds, appRole.localSecretIds) &&
Objects.equals(tokenTtl, appRole.tokenTtl) &&
Objects.equals(tokenMaxTtl, appRole.tokenMaxTtl) &&
Objects.equals(tokenPolicies, appRole.tokenPolicies) &&
Objects.equals(tokenBoundCidrs, appRole.tokenBoundCidrs) &&
Objects.equals(tokenExplicitMaxTtl, appRole.tokenExplicitMaxTtl) &&
Objects.equals(tokenNoDefaultPolicy, appRole.tokenNoDefaultPolicy) &&
Objects.equals(tokenNumUses, appRole.tokenNumUses) &&
Objects.equals(tokenPeriod, appRole.tokenPeriod) &&
Objects.equals(tokenType, appRole.tokenType);
}
@Override
public int hashCode() {
return Objects.hash(name, id, bindSecretId, secretIdBoundCidrs, secretIdNumUses, secretIdTtl,
localSecretIds, tokenTtl, tokenMaxTtl, tokenPolicies, tokenBoundCidrs, tokenExplicitMaxTtl,
tokenNoDefaultPolicy, tokenNumUses, tokenPeriod, tokenType);
}
/**
* A builder for vault AppRole roles..
*
* @author Stefan Kalscheuer
* @since 0.4.0
* @since 0.9 Moved into subclass of {@link AppRole}.
*/
public static final class Builder {
private String name;
private String id;
private Boolean bindSecretId;
private List<String> secretIdBoundCidrs;
private List<String> tokenPolicies;
private Integer secretIdNumUses;
private Integer secretIdTtl;
private Boolean localSecretIds;
private Integer tokenTtl;
private Integer tokenMaxTtl;
private List<String> tokenBoundCidrs;
private Integer tokenExplicitMaxTtl;
private Boolean tokenNoDefaultPolicy;
private Integer tokenNumUses;
private Integer tokenPeriod;
private Token.Type tokenType;
/**
* Construct {@link Builder} with only the role name set.
*
* @param name Role name
*/
public Builder(final String name) {
this.name = name;
}
/**
* Add role name.
*
* @param name Role name
* @return self
*/
public Builder withName(final String name) {
this.name = name;
return this;
}
/**
* Add custom role ID. (optional)
*
* @param id the ID
* @return self
*/
public Builder withId(final String id) {
this.id = id;
return this;
}
/**
* Set if role is bound to secret ID.
*
* @param bindSecretId the display name
* @return self
*/
public Builder withBindSecretID(final Boolean bindSecretId) {
this.bindSecretId = bindSecretId;
return this;
}
/**
* Bind role to secret ID.
* Convenience method for {@link #withBindSecretID(Boolean)}
*
* @return self
*/
public Builder withBindSecretID() {
return withBindSecretID(true);
}
/**
* Do not bind role to secret ID.
* Convenience method for {@link #withBindSecretID(Boolean)}
*
* @return self
*/
public Builder withoutBindSecretID() {
return withBindSecretID(false);
}
/**
* Set bound CIDR blocks.
*
* @param secretIdBoundCidrs List of CIDR blocks which can perform login
* @return self
* @since 0.8 replaces {@code withBoundCidrList(List)}
*/
public Builder withSecretIdBoundCidrs(final List<String> secretIdBoundCidrs) {
if (this.secretIdBoundCidrs == null) {
this.secretIdBoundCidrs = new ArrayList<>();
}
this.secretIdBoundCidrs.addAll(secretIdBoundCidrs);
return this;
}
/**
* Add a CIDR block to list of bound blocks for secret.
*
* @param secretBoundCidr the CIDR block
* @return self
* @since 0.9
*/
public Builder withSecretBoundCidr(final String secretBoundCidr) {
if (secretIdBoundCidrs == null) {
secretIdBoundCidrs = new ArrayList<>();
}
secretIdBoundCidrs.add(secretBoundCidr);
return this;
}
/**
* Add given policies.
*
* @param tokenPolicies the token policies
* @return self
* @since 0.9
*/
public Builder withTokenPolicies(final List<String> tokenPolicies) {
if (this.tokenPolicies == null) {
this.tokenPolicies = new ArrayList<>();
}
this.tokenPolicies.addAll(tokenPolicies);
return this;
}
/**
* Add a single policy.
*
* @param tokenPolicy the token policy
* @return self
* @since 0.9
*/
public Builder withTokenPolicy(final String tokenPolicy) {
if (this.tokenPolicies == null) {
this.tokenPolicies = new ArrayList<>();
}
tokenPolicies.add(tokenPolicy);
return this;
}
/**
* Set number of uses for sectet IDs.
*
* @param secretIdNumUses the number of uses
* @return self
*/
public Builder withSecretIdNumUses(final Integer secretIdNumUses) {
this.secretIdNumUses = secretIdNumUses;
return this;
}
/**
* Set default sectet ID TTL in seconds.
*
* @param secretIdTtl the TTL
* @return self
*/
public Builder withSecretIdTtl(final Integer secretIdTtl) {
this.secretIdTtl = secretIdTtl;
return this;
}
/**
* Enable or disable local secret IDs.
*
* @param localSecretIds Enable local secret IDs?
* @return self
* @since 0.9
* @since 1.3 renamed to {@code withLocalSecretIds()}
*/
public Builder withLocalSecretIds(final Boolean localSecretIds) {
this.localSecretIds = localSecretIds;
return this;
}
/**
* Set default token TTL in seconds.
*
* @param tokenTtl the TTL
* @return self
*/
public Builder withTokenTtl(final Integer tokenTtl) {
this.tokenTtl = tokenTtl;
return this;
}
/**
* Set maximum token TTL in seconds.
*
* @param tokenMaxTtl the TTL
* @return self
*/
public Builder withTokenMaxTtl(final Integer tokenMaxTtl) {
this.tokenMaxTtl = tokenMaxTtl;
return this;
}
/**
* Set bound CIDR blocks for associated tokens.
*
* @param tokenBoundCidrs List of CIDR blocks which can perform login
* @return self
* @since 0.9
*/
public Builder withTokenBoundCidrs(final List<String> tokenBoundCidrs) {
if (this.tokenBoundCidrs == null) {
this.tokenBoundCidrs = new ArrayList<>();
}
this.tokenBoundCidrs.addAll(tokenBoundCidrs);
return this;
}
/**
* Add a CIDR block to list of bound blocks for token.
*
* @param tokenBoundCidr the CIDR block
* @return self
* @since 0.9
*/
public Builder withTokenBoundCidr(final String tokenBoundCidr) {
if (tokenBoundCidrs == null) {
tokenBoundCidrs = new ArrayList<>();
}
tokenBoundCidrs.add(tokenBoundCidr);
return this;
}
/**
* Set explicit maximum token TTL in seconds.
*
* @param tokenExplicitMaxTtl the TTL
* @return self
*/
public Builder withTokenExplicitMaxTtl(final Integer tokenExplicitMaxTtl) {
this.tokenExplicitMaxTtl = tokenExplicitMaxTtl;
return this;
}
/**
* Enable or disable default policy for generated token.
*
* @param tokenNoDefaultPolicy Enable default policy for token?
* @return self
* @since 0.9
*/
public Builder withTokenNoDefaultPolicy(final Boolean tokenNoDefaultPolicy) {
this.tokenNoDefaultPolicy = tokenNoDefaultPolicy;
return this;
}
/**
* Set number of uses for generated tokens.
*
* @param tokenNumUses number of uses for tokens
* @return self
* @since 0.9
*/
public Builder withTokenNumUses(final Integer tokenNumUses) {
this.tokenNumUses = tokenNumUses;
return this;
}
/**
* Set renewal period for generated token in seconds.
*
* @param tokenPeriod period in seconds
* @return self
* @since 0.9
*/
public Builder withTokenPeriod(final Integer tokenPeriod) {
this.tokenPeriod = tokenPeriod;
return this;
}
/**
* Set type of generated token.
*
* @param tokenType token type
* @return self
* @since 0.9
*/
public Builder withTokenType(final Token.Type tokenType) {
this.tokenType = tokenType;
return this;
}
/**
* Build the AppRole role based on given parameters.
*
* @return the role
*/
public AppRole build() {
return new AppRole(this);
}
}
}

View File

@ -1,199 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.annotation.*;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Vault AppRole role metamodel.
*
* @author Stefan Kalscheuer
* @since 0.4.0
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRoleSecret implements Serializable {
private static final long serialVersionUID = -3401074170145792641L;
@JsonProperty("secret_id")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String id;
@JsonProperty(value = "secret_id_accessor", access = JsonProperty.Access.WRITE_ONLY)
private String accessor;
@JsonProperty("metadata")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private Map<String, Object> metadata;
private List<String> cidrList;
@JsonProperty(value = "creation_time", access = JsonProperty.Access.WRITE_ONLY)
private String creationTime;
@JsonProperty(value = "expiration_time", access = JsonProperty.Access.WRITE_ONLY)
private String expirationTime;
@JsonProperty(value = "last_updated_time", access = JsonProperty.Access.WRITE_ONLY)
private String lastUpdatedTime;
@JsonProperty(value = "secret_id_num_uses", access = JsonProperty.Access.WRITE_ONLY)
private Integer numUses;
@JsonProperty(value = "secret_id_ttl", access = JsonProperty.Access.WRITE_ONLY)
private Integer ttl;
/**
* Construct empty {@link AppRoleSecret} object.
*/
public AppRoleSecret() {
}
/**
* Construct {@link AppRoleSecret} with secret ID.
*
* @param id Secret ID
*/
public AppRoleSecret(final String id) {
this.id = id;
}
/**
* Construct {@link AppRoleSecret} with ID and metadata.
*
* @param id Secret ID
* @param metadata Secret metadata
* @param cidrList List of subnets in CIDR notation, the role is bound to
*/
public AppRoleSecret(final String id, final Map<String, Object> metadata, final List<String> cidrList) {
this.id = id;
this.metadata = metadata;
this.cidrList = cidrList;
}
/**
* @return Secret ID
*/
public String getId() {
return id;
}
/**
* @return Secret accessor
*/
public String getAccessor() {
return accessor;
}
/**
* @return Secret metadata
*/
public Map<String, Object> getMetadata() {
return metadata;
}
/**
* @return List of bound subnets in CIDR notation
*/
public List<String> getCidrList() {
return cidrList;
}
/**
* @param cidrList List of subnets in CIDR notation
*/
@JsonSetter("cidr_list")
public void setCidrList(final List<String> cidrList) {
this.cidrList = cidrList;
}
/**
* @return List of bound subnets in CIDR notation as comma-separated {@link String}
*/
@JsonGetter("cidr_list")
public String getCidrListString() {
if (cidrList == null || cidrList.isEmpty()) {
return "";
}
return String.join(",", cidrList);
}
/**
* @return Creation time
*/
public String getCreationTime() {
return creationTime;
}
/**
* @return Expiration time
*/
public String getExpirationTime() {
return expirationTime;
}
/**
* @return Time of last update
*/
public String getLastUpdatedTime() {
return lastUpdatedTime;
}
/**
* @return Number of uses
*/
public Integer getNumUses() {
return numUses;
}
/**
* @return Time-to-live
*/
public Integer getTtl() {
return ttl;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
AppRoleSecret that = (AppRoleSecret) o;
return Objects.equals(id, that.id) &&
Objects.equals(accessor, that.accessor) &&
Objects.equals(metadata, that.metadata) &&
Objects.equals(cidrList, that.cidrList) &&
Objects.equals(creationTime, that.creationTime) &&
Objects.equals(expirationTime, that.expirationTime) &&
Objects.equals(lastUpdatedTime, that.lastUpdatedTime) &&
Objects.equals(numUses, that.numUses) &&
Objects.equals(ttl, that.ttl);
}
@Override
public int hashCode() {
return Objects.hash(id, accessor, metadata, cidrList, creationTime, expirationTime, lastUpdatedTime, numUses,
ttl);
}
}

View File

@ -1,57 +1,27 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model;
/**
* Currently supported authentication backends.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public enum AuthBackend {
TOKEN("token"),
APPROLE("approle"),
APPID("app-id"),
USERPASS("userpass"),
GITHUB("github"), // Not supported yet.
UNKNOWN("");
private final String type;
/**
* Construct {@link AuthBackend} of given type.
*
* @param type Backend type
*/
AuthBackend(final String type) {
AuthBackend(String type) {
this.type = type;
}
/**
* Retrieve {@link AuthBackend} value for given type string.
*
* @param type Type string
* @return Auth backend value
*/
public static AuthBackend forType(final String type) {
for (AuthBackend v : values()) {
if (v.type.equalsIgnoreCase(type)) {
public static AuthBackend forType(String type) {
for (AuthBackend v : values())
if (v.type.equalsIgnoreCase(type))
return v;
}
}
return UNKNOWN;
}
}

View File

@ -1,554 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.*;
/**
* Vault Token metamodel.
*
* @author Stefan Kalscheuer
* @since 0.4.0
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class Token implements Serializable {
private static final long serialVersionUID = 5208508683665365287L;
@JsonProperty("id")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String id;
@JsonProperty("type")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String type;
@JsonProperty("display_name")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String displayName;
@JsonProperty("no_parent")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean noParent;
@JsonProperty("no_default_policy")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean noDefaultPolicy;
@JsonProperty("ttl")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer ttl;
@JsonProperty("explicit_max_ttl")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer explicitMaxTtl;
@JsonProperty("num_uses")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer numUses;
@JsonProperty("policies")
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<String> policies;
@JsonProperty("meta")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Map<String, String> meta;
@JsonProperty("renewable")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean renewable;
@JsonProperty("period")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer period;
@JsonProperty("entity_alias")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String entityAlias;
/**
* Construct empty {@link Token} object.
*/
public Token() {
}
/**
* Construct {@link Token} object from {@link Builder}.
*
* @param builder Token builder.
*/
public Token(final Builder builder) {
this.id = builder.id;
this.type = builder.type != null ? builder.type.value() : null;
this.displayName = builder.displayName;
this.noParent = builder.noParent;
this.noDefaultPolicy = builder.noDefaultPolicy;
this.ttl = builder.ttl;
this.explicitMaxTtl = builder.explicitMaxTtl;
this.numUses = builder.numUses;
this.policies = builder.policies;
this.meta = builder.meta;
this.renewable = builder.renewable;
this.period = builder.period;
this.entityAlias = builder.entityAlias;
}
/**
* Get {@link Builder} instance.
*
* @return Token Builder.
* @since 0.8
*/
public static Builder builder() {
return new Builder();
}
/**
* @return Token ID
*/
public String getId() {
return id;
}
/**
* @return Token type
* @since 0.9
*/
public String getType() {
return type;
}
/**
* @return Token display name
*/
public String getDisplayName() {
return displayName;
}
/**
* @return Token has no parent
*/
public Boolean getNoParent() {
return noParent;
}
/**
* @return Token has no default policy
*/
public Boolean getNoDefaultPolicy() {
return noDefaultPolicy;
}
/**
* @return Time-to-live in seconds
*/
public Integer getTtl() {
return ttl;
}
/**
* @return Explicit maximum time-to-live in seconds
* @since 0.9
*/
public Integer getExplicitMaxTtl() {
return explicitMaxTtl;
}
/**
* @return Number of uses
*/
public Integer getNumUses() {
return numUses;
}
/**
* @return List of policies
*/
public List<String> getPolicies() {
return policies;
}
/**
* @return Metadata
*/
public Map<String, String> getMeta() {
return meta;
}
/**
* @return Token is renewable
*/
public Boolean isRenewable() {
return renewable;
}
/**
* @return Token period.
* @since 0.9
*/
public Integer getPeriod() {
return period;
}
/**
* @return Token entity alias.
* @since 0.9
*/
public String getEntityAlias() {
return entityAlias;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
Token token = (Token) o;
return Objects.equals(id, token.id) &&
Objects.equals(type, token.type) &&
Objects.equals(displayName, token.displayName) &&
Objects.equals(noParent, token.noParent) &&
Objects.equals(noDefaultPolicy, token.noDefaultPolicy) &&
Objects.equals(ttl, token.ttl) &&
Objects.equals(explicitMaxTtl, token.explicitMaxTtl) &&
Objects.equals(numUses, token.numUses) &&
Objects.equals(policies, token.policies) &&
Objects.equals(meta, token.meta) &&
Objects.equals(renewable, token.renewable) &&
Objects.equals(period, token.period) &&
Objects.equals(entityAlias, token.entityAlias);
}
@Override
public int hashCode() {
return Objects.hash(id, type, displayName, noParent, noDefaultPolicy, ttl, explicitMaxTtl, numUses, policies,
meta, renewable, period, entityAlias);
}
/**
* Constants for token types.
*/
public enum Type {
DEFAULT("default"),
BATCH("batch"),
SERVICE("service"),
DEFAULT_SERVICE("default-service"),
DEFAULT_BATCH("default-batch");
private final String value;
Type(String value) {
this.value = value;
}
public String value() {
return value;
}
}
/**
* A builder for vault tokens.
*
* @author Stefan Kalscheuer
* @since 0.4.0
* @since 0.9 Moved into subclass of {@link Token}.
*/
public static final class Builder {
private String id;
private Type type;
private String displayName;
private Boolean noParent;
private Boolean noDefaultPolicy;
private Integer ttl;
private Integer explicitMaxTtl;
private Integer numUses;
private List<String> policies;
private Map<String, String> meta;
private Boolean renewable;
private Integer period;
private String entityAlias;
/**
* Add token ID. (optional)
*
* @param id the ID
* @return self
*/
public Builder withId(final String id) {
this.id = id;
return this;
}
/**
* Specify token type.
*
* @param type the type
* @return self
* @since 0.9
*/
public Builder withType(final Token.Type type) {
this.type = type;
return this;
}
/**
* Add display name.
*
* @param displayName the display name
* @return self
*/
public Builder withDisplayName(final String displayName) {
this.displayName = displayName;
return this;
}
/**
* Set desired time to live.
*
* @param ttl the ttl
* @return self
*/
public Builder withTtl(final Integer ttl) {
this.ttl = ttl;
return this;
}
/**
* Set desired explicit maximum time to live.
*
* @param explicitMaxTtl the explicit max. TTL
* @return self
*/
public Builder withExplicitMaxTtl(final Integer explicitMaxTtl) {
this.explicitMaxTtl = explicitMaxTtl;
return this;
}
/**
* Set desired number of uses.
*
* @param numUses the number of uses
* @return self
*/
public Builder withNumUses(final Integer numUses) {
this.numUses = numUses;
return this;
}
/**
* Set TRUE if the token should be created without parent.
*
* @param noParent if TRUE, token is created as orphan
* @return self
*/
public Builder withNoParent(final boolean noParent) {
this.noParent = noParent;
return this;
}
/**
* Create token without parent.
* Convenience method for withNoParent()
*
* @return self
*/
public Builder asOrphan() {
return withNoParent(true);
}
/**
* Create token with parent.
* Convenience method for withNoParent()
*
* @return self
*/
public Builder withParent() {
return withNoParent(false);
}
/**
* Set TRUE if the default policy should not be part of this token.
*
* @param noDefaultPolicy if TRUE, default policy is not attached
* @return self
*/
public Builder withNoDefaultPolicy(final boolean noDefaultPolicy) {
this.noDefaultPolicy = noDefaultPolicy;
return this;
}
/**
* Attach default policy to token.
* Convenience method for withNoDefaultPolicy()
*
* @return self
*/
public Builder withDefaultPolicy() {
return withNoDefaultPolicy(false);
}
/**
* Do not attach default policy to token.
* Convenience method for withNoDefaultPolicy()
*
* @return self
*/
public Builder withoutDefaultPolicy() {
return withNoDefaultPolicy(true);
}
/**
* Add given policies.
*
* @param policies the policies
* @return self
* @since 0.5.0
*/
public Builder withPolicies(final String... policies) {
return withPolicies(Arrays.asList(policies));
}
/**
* Add given policies.
*
* @param policies the policies
* @return self
*/
public Builder withPolicies(final List<String> policies) {
if (this.policies == null) {
this.policies = new ArrayList<>();
}
this.policies.addAll(policies);
return this;
}
/**
* Add a single policy.
*
* @param policy the policy
* @return self
*/
public Builder withPolicy(final String policy) {
if (this.policies == null) {
this.policies = new ArrayList<>();
}
policies.add(policy);
return this;
}
/**
* Add meta data.
*
* @param meta the metadata
* @return self
*/
public Builder withMeta(final Map<String, String> meta) {
if (this.meta == null) {
this.meta = new HashMap<>();
}
this.meta.putAll(meta);
return this;
}
/**
* Add meta data.
*
* @param key the key
* @param value the value
* @return self
*/
public Builder withMeta(final String key, final String value) {
if (this.meta == null) {
this.meta = new HashMap<>();
}
this.meta.put(key, value);
return this;
}
/**
* Set if token is renewable.
*
* @param renewable TRUE, if renewable
* @return self
*/
public Builder withRenewable(final Boolean renewable) {
this.renewable = renewable;
return this;
}
/**
* Set token to be renewable.
* Convenience method for withRenewable()
*
* @return self
*/
public Builder renewable() {
return withRenewable(true);
}
/**
* Set token to be not renewable.
* Convenience method for withRenewable()
*
* @return self
*/
public Builder notRenewable() {
return withRenewable(false);
}
/**
* Set token period (former lease time).
*
* @param period Period in seconds.
* @return self
*/
public Builder withPeriod(final Integer period) {
this.period = period;
return this;
}
/**
* Set entity alias for token.
* Only works in combination with an associated token role.
*
* @param entityAlias Entity alias.
* @return self
*/
public Builder withEntityAlias(final String entityAlias) {
this.entityAlias = entityAlias;
return this;
}
/**
* Build the token based on given parameters.
*
* @return the token
*/
public Token build() {
return new Token(this);
}
}
}

View File

@ -1,598 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Vault Token Role metamodel.
*
* @author Stefan Kalscheuer
* @since 0.9
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenRole implements Serializable {
private static final long serialVersionUID = -3505215215838576321L;
@JsonProperty("name")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String name;
@JsonProperty("allowed_policies")
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<String> allowedPolicies;
@JsonProperty("allowed_policies_glob")
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<String> allowedPoliciesGlob;
@JsonProperty("disallowed_policies")
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<String> disallowedPolicies;
@JsonProperty("disallowed_policies_glob")
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<String> disallowedPoliciesGlob;
@JsonProperty("orphan")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean orphan;
@JsonProperty("renewable")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean renewable;
@JsonProperty("path_suffix")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String pathSuffix;
@JsonProperty("allowed_entity_aliases")
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<String> allowedEntityAliases;
@JsonProperty("token_bound_cidrs")
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<String> tokenBoundCidrs;
@JsonProperty("token_explicit_max_ttl")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer tokenExplicitMaxTtl;
@JsonProperty("token_no_default_policy")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean tokenNoDefaultPolicy;
@JsonProperty("token_num_uses")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer tokenNumUses;
@JsonProperty("token_period")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer tokenPeriod;
@JsonProperty("token_type")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String tokenType;
/**
* Construct empty {@link TokenRole} object.
*/
public TokenRole() {
}
public TokenRole(final Builder builder) {
this.name = builder.name;
this.allowedPolicies = builder.allowedPolicies;
this.allowedPoliciesGlob = builder.allowedPoliciesGlob;
this.disallowedPolicies = builder.disallowedPolicies;
this.disallowedPoliciesGlob = builder.disallowedPoliciesGlob;
this.orphan = builder.orphan;
this.renewable = builder.renewable;
this.pathSuffix = builder.pathSuffix;
this.allowedEntityAliases = builder.allowedEntityAliases;
this.tokenBoundCidrs = builder.tokenBoundCidrs;
this.tokenExplicitMaxTtl = builder.tokenExplicitMaxTtl;
this.tokenNoDefaultPolicy = builder.tokenNoDefaultPolicy;
this.tokenNumUses = builder.tokenNumUses;
this.tokenPeriod = builder.tokenPeriod;
this.tokenType = builder.tokenType != null ? builder.tokenType.value() : null;
}
/**
* Get {@link Builder} instance.
*
* @return Token Role Builder.
*/
public static Builder builder() {
return new Builder();
}
/**
* @return Token Role name
*/
public String getName() {
return name;
}
/**
* @return List of allowed policies
*/
public List<String> getAllowedPolicies() {
return allowedPolicies;
}
/**
* @return List of allowed policy glob patterns
* @since 1.1
*/
public List<String> getAllowedPoliciesGlob() {
return allowedPoliciesGlob;
}
/**
* @return List of disallowed policies
*/
public List<String> getDisallowedPolicies() {
return disallowedPolicies;
}
/**
* @return List of disallowed policy glob patterns
* @since 1.1
*/
public List<String> getDisallowedPoliciesGlob() {
return disallowedPoliciesGlob;
}
/**
* @return Is Token Role orphan?
*/
public Boolean getOrphan() {
return orphan;
}
/**
* @return Is Token Role renewable?
*/
public Boolean getRenewable() {
return renewable;
}
/**
* @return Path suffix
*/
public String getPathSuffix() {
return pathSuffix;
}
/**
* @return List of allowed entity aliases
*/
public List<String> getAllowedEntityAliases() {
return allowedEntityAliases;
}
/**
* @return Token bound CIDR blocks
*/
public List<String> getTokenBoundCidrs() {
return tokenBoundCidrs;
}
/**
* @return Token explicit maximum TTL
*/
public Integer getTokenExplicitMaxTtl() {
return tokenExplicitMaxTtl;
}
/**
* @return Token without default policy?
*/
public Boolean getTokenNoDefaultPolicy() {
return tokenNoDefaultPolicy;
}
/**
* @return Token number of uses
*/
public Integer getTokenNumUses() {
return tokenNumUses;
}
/**
* @return Token period
*/
public Integer getTokenPeriod() {
return tokenPeriod;
}
/**
* @return Token type
*/
public String getTokenType() {
return tokenType;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
TokenRole tokenRole = (TokenRole) o;
return Objects.equals(name, tokenRole.name) &&
Objects.equals(allowedPolicies, tokenRole.allowedPolicies) &&
Objects.equals(allowedPoliciesGlob, tokenRole.allowedPoliciesGlob) &&
Objects.equals(disallowedPolicies, tokenRole.disallowedPolicies) &&
Objects.equals(disallowedPoliciesGlob, tokenRole.disallowedPoliciesGlob) &&
Objects.equals(orphan, tokenRole.orphan) &&
Objects.equals(renewable, tokenRole.renewable) &&
Objects.equals(pathSuffix, tokenRole.pathSuffix) &&
Objects.equals(allowedEntityAliases, tokenRole.allowedEntityAliases) &&
Objects.equals(tokenBoundCidrs, tokenRole.tokenBoundCidrs) &&
Objects.equals(tokenExplicitMaxTtl, tokenRole.tokenExplicitMaxTtl) &&
Objects.equals(tokenNoDefaultPolicy, tokenRole.tokenNoDefaultPolicy) &&
Objects.equals(tokenNumUses, tokenRole.tokenNumUses) &&
Objects.equals(tokenPeriod, tokenRole.tokenPeriod) &&
Objects.equals(tokenType, tokenRole.tokenType);
}
@Override
public int hashCode() {
return Objects.hash(name, allowedPolicies, allowedPoliciesGlob, disallowedPolicies, disallowedPoliciesGlob,
orphan, renewable, pathSuffix, allowedEntityAliases, tokenBoundCidrs, tokenExplicitMaxTtl,
tokenNoDefaultPolicy, tokenNumUses, tokenPeriod, tokenType);
}
/**
* A builder for vault token roles.
*
* @author Stefan Kalscheuer
* @since 0.9
*/
public static final class Builder {
private String name;
private List<String> allowedPolicies;
private List<String> allowedPoliciesGlob;
private List<String> disallowedPolicies;
private List<String> disallowedPoliciesGlob;
private Boolean orphan;
private Boolean renewable;
private String pathSuffix;
private List<String> allowedEntityAliases;
private List<String> tokenBoundCidrs;
private Integer tokenExplicitMaxTtl;
private Boolean tokenNoDefaultPolicy;
private Integer tokenNumUses;
private Integer tokenPeriod;
private Token.Type tokenType;
/**
* Add token role name.
*
* @param name role name
* @return self
*/
public Builder forName(final String name) {
this.name = name;
return this;
}
/**
* Add an allowed policy.
*
* @param allowedPolicy allowed policy to add
* @return self
*/
public Builder withAllowedPolicy(final String allowedPolicy) {
if (allowedPolicy != null) {
if (this.allowedPolicies == null) {
this.allowedPolicies = new ArrayList<>();
}
this.allowedPolicies.add(allowedPolicy);
}
return this;
}
/**
* Add allowed policies.
*
* @param allowedPolicies list of allowed policies
* @return self
*/
public Builder withAllowedPolicies(final List<String> allowedPolicies) {
if (allowedPolicies != null) {
if (this.allowedPolicies == null) {
this.allowedPolicies = new ArrayList<>();
}
this.allowedPolicies.addAll(allowedPolicies);
}
return this;
}
/**
* Add an allowed policy glob pattern.
*
* @param allowedPolicyGlob allowed policy glob pattern to add
* @return self
* @since 1.1
*/
public Builder withAllowedPolicyGlob(final String allowedPolicyGlob) {
if (allowedPolicyGlob != null) {
if (this.allowedPoliciesGlob == null) {
this.allowedPoliciesGlob = new ArrayList<>();
}
this.allowedPoliciesGlob.add(allowedPolicyGlob);
}
return this;
}
/**
* Add allowed policy glob patterns.
*
* @param allowedPoliciesGlob list of allowed policy glob patterns
* @return self
* @since 1.1
*/
public Builder withAllowedPoliciesGlob(final List<String> allowedPoliciesGlob) {
if (allowedPoliciesGlob != null) {
if (this.allowedPoliciesGlob == null) {
this.allowedPoliciesGlob = new ArrayList<>();
}
this.allowedPoliciesGlob.addAll(allowedPoliciesGlob);
}
return this;
}
/**
* Add a disallowed policy.
*
* @param disallowedPolicy disallowed policy to add
* @return self
*/
public Builder withDisallowedPolicy(final String disallowedPolicy) {
if (disallowedPolicy != null) {
if (this.disallowedPolicies == null) {
this.disallowedPolicies = new ArrayList<>();
}
this.disallowedPolicies.add(disallowedPolicy);
}
return this;
}
/**
* Add disallowed policies.
*
* @param disallowedPolicies list of disallowed policies
* @return self
*/
public Builder withDisallowedPolicies(final List<String> disallowedPolicies) {
if (disallowedPolicies != null) {
if (this.disallowedPolicies == null) {
this.disallowedPolicies = new ArrayList<>();
}
this.disallowedPolicies.addAll(disallowedPolicies);
}
return this;
}
/**
* Add an allowed policy glob pattern.
*
* @param disallowedPolicyGlob disallowed policy glob pattern to add
* @return self
* @since 1.1
*/
public Builder withDisallowedPolicyGlob(final String disallowedPolicyGlob) {
if (disallowedPolicyGlob != null) {
if (this.disallowedPoliciesGlob == null) {
this.disallowedPoliciesGlob = new ArrayList<>();
}
this.disallowedPoliciesGlob.add(disallowedPolicyGlob);
}
return this;
}
/**
* Add disallowed policy glob patterns.
*
* @param disallowedPoliciesGlob list of disallowed policy glob patterns
* @return self
* @since 1.1
*/
public Builder withDisallowedPoliciesGlob(final List<String> disallowedPoliciesGlob) {
if (disallowedPoliciesGlob != null) {
if (this.disallowedPoliciesGlob == null) {
this.disallowedPoliciesGlob = new ArrayList<>();
}
this.disallowedPoliciesGlob.addAll(disallowedPoliciesGlob);
}
return this;
}
/**
* Set TRUE if the token role should be created orphan.
*
* @param orphan if TRUE, token role is created as orphan
* @return self
*/
public Builder orphan(final Boolean orphan) {
this.orphan = orphan;
return this;
}
/**
* Set TRUE if the token role should be created renewable.
*
* @param renewable if TRUE, token role is created renewable
* @return self
*/
public Builder renewable(final Boolean renewable) {
this.renewable = renewable;
return this;
}
/**
* Set token role path suffix.
*
* @param pathSuffix path suffix to use
* @return self
*/
public Builder withPathSuffix(final String pathSuffix) {
this.pathSuffix = pathSuffix;
return this;
}
/**
* Add an allowed entity alias.
*
* @param allowedEntityAlias allowed entity alias to add
* @return self
*/
public Builder withAllowedEntityAlias(final String allowedEntityAlias) {
if (allowedEntityAlias != null) {
if (this.allowedEntityAliases == null) {
this.allowedEntityAliases = new ArrayList<>();
}
this.allowedEntityAliases.add(allowedEntityAlias);
}
return this;
}
/**
* Add allowed entity aliases.
*
* @param allowedEntityAliases list of allowed entity aliases to add
* @return self
*/
public Builder withAllowedEntityAliases(final List<String> allowedEntityAliases) {
if (allowedEntityAliases != null) {
if (this.allowedEntityAliases == null) {
this.allowedEntityAliases = new ArrayList<>();
}
this.allowedEntityAliases.addAll(allowedEntityAliases);
}
return this;
}
/**
* Add a single bound CIDR.
*
* @param tokenBoundCidr bound CIDR to add
* @return self
*/
public Builder withTokenBoundCidr(final String tokenBoundCidr) {
if (tokenBoundCidr != null) {
if (this.tokenBoundCidrs == null) {
this.tokenBoundCidrs = new ArrayList<>();
}
this.tokenBoundCidrs.add(tokenBoundCidr);
}
return this;
}
/**
* Add a list of bound CIDRs.
*
* @param tokenBoundCidrs list of bound CIDRs to add
* @return self
*/
public Builder withTokenBoundCidrs(final List<String> tokenBoundCidrs) {
if (tokenBoundCidrs != null) {
if (this.tokenBoundCidrs == null) {
this.tokenBoundCidrs = new ArrayList<>();
}
this.tokenBoundCidrs.addAll(tokenBoundCidrs);
}
return this;
}
/**
* Set explicit max. TTL for token.
*
* @param tokenExplicitMaxTtl explicit maximum TTL
* @return self
*/
public Builder withTokenExplicitMaxTtl(final Integer tokenExplicitMaxTtl) {
this.tokenExplicitMaxTtl = tokenExplicitMaxTtl;
return this;
}
/**
* Set TRUE if the token role should be created renewable.
*
* @param tokenNoDefaultPolicy if TRUE, token is created without default policy.
* @return self
*/
public Builder withTokenNoDefaultPolicy(final Boolean tokenNoDefaultPolicy) {
this.tokenNoDefaultPolicy = tokenNoDefaultPolicy;
return this;
}
/**
* Set number of uses for tokens.
*
* @param tokenNumUses number of uses for associated tokens.
* @return self
*/
public Builder withTokenNumUses(final Integer tokenNumUses) {
this.tokenNumUses = tokenNumUses;
return this;
}
/**
* Set token period.
*
* @param tokenPeriod token period
* @return self
*/
public Builder withTokenPeriod(final Integer tokenPeriod) {
this.tokenPeriod = tokenPeriod;
return this;
}
/**
* Set token type.
*
* @param tokenType token type
* @return self
*/
public Builder withTokenType(final Token.Type tokenType) {
this.tokenType = tokenType;
return this;
}
/**
* Build the token based on given parameters.
*
* @return the token
*/
public TokenRole build() {
return new TokenRole(this);
}
}
}

View File

@ -1,20 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Model classes for communication with the Vault API.
*/
package de.stklcode.jvault.connector.model;

View File

@ -1,60 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.AppRole;
import java.util.Objects;
/**
* Vault response for AppRole lookup.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRoleResponse extends VaultDataResponse {
private static final long serialVersionUID = -6536422219633829177L;
@JsonProperty("data")
private AppRole role;
/**
* @return The role
*/
public AppRole getRole() {
return role;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
AppRoleResponse that = (AppRoleResponse) o;
return Objects.equals(role, that.role);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), role);
}
}

View File

@ -1,60 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.AppRoleSecret;
import java.util.Objects;
/**
* Vault response for AppRole lookup.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRoleSecretResponse extends VaultDataResponse {
private static final long serialVersionUID = -2484103304072370585L;
@JsonProperty("data")
private AppRoleSecret secret;
/**
* @return The secret
*/
public AppRoleSecret getSecret() {
return secret;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
AppRoleSecretResponse that = (AppRoleSecretResponse) o;
return Objects.equals(secret, that.secret);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), secret);
}
}

View File

@ -1,69 +1,32 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.AuthMethod;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Authentication method response.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthMethodsResponse extends VaultDataResponse {
private static final long serialVersionUID = -1802724129533405375L;
public class AuthMethodsResponse implements VaultResponse {
@JsonProperty("data")
private Map<String, AuthMethod> supportedMethods;
private List<AuthMethod> supportedMethods;
/**
* Construct empty {@link AuthMethodsResponse} object.
*/
public AuthMethodsResponse() {
this.supportedMethods = new HashMap<>();
@JsonAnySetter
public void setMethod(String path, Map<String, String> data) throws InvalidResponseException {
if (supportedMethods == null)
supportedMethods = new ArrayList<>();
supportedMethods.add(new AuthMethod(path, data.get("description"), data.get("type")));
}
/**
* @return Supported authentication methods
*/
public Map<String, AuthMethod> getSupportedMethods() {
public List<AuthMethod> getSupportedMethods() {
return supportedMethods;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
AuthMethodsResponse that = (AuthMethodsResponse) o;
return Objects.equals(supportedMethods, that.supportedMethods);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), supportedMethods);
}
}

View File

@ -1,31 +1,47 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.AuthData;
import java.io.IOException;
import java.util.Map;
/**
* Vault response for authentication providing auth info in {@link AuthData} field.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthResponse extends VaultDataResponse {
private static final long serialVersionUID = 1628851361067456715L;
public class AuthResponse extends VaultDataResponse {
private Map<String, Object> data;
private AuthData auth;
@JsonProperty("auth")
public void setAuth(Map<String, Object> auth) throws InvalidResponseException {
ObjectMapper mapper = new ObjectMapper();
try {
this.auth = mapper.readValue(mapper.writeValueAsString(auth), AuthData.class);
} catch (IOException e) {
e.printStackTrace();
throw new InvalidResponseException();
}
}
@Override
public void setData(Map<String, Object> data) {
this.data = data;
}
public Map<String, Object> getData() {
return data;
}
public AuthData getAuth() {
return auth;
}
}

View File

@ -1,52 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
* Vault response from credentials lookup. Simple wrapper for data objects containing username and password fields.
*
* @author Stefan Kalscheuer
* @since 0.5.0
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class CredentialsResponse extends PlainSecretResponse {
private static final long serialVersionUID = -1439692963299045425L;
/**
* @return Username
*/
public String getUsername() {
Object username = get("username");
if (username != null) {
return username.toString();
}
return null;
}
/**
* @return Password
*/
public String getPassword() {
Object password = get("password");
if (password != null) {
return password.toString();
}
return null;
}
}

View File

@ -1,69 +1,22 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import java.util.Objects;
/**
* Vault response in case of errors.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class ErrorResponse implements VaultResponse {
private static final long serialVersionUID = -6227368087842549149L;
public class ErrorResponse implements VaultResponse {
@JsonProperty("errors")
private List<String> errors;
/**
* @return List of errors
*/
public List<String> getErrors() {
public List<String > getErrors() {
return errors;
}
@Override
public String toString() {
if (errors == null || errors.isEmpty()) {
return "error response";
} else {
return errors.get(0);
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
ErrorResponse that = (ErrorResponse) o;
return Objects.equals(errors, that.errors);
}
@Override
public int hashCode() {
return Objects.hash(errors);
}
}
}

View File

@ -1,211 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Objects;
/**
* Vault response for health query.
*
* @author Stefan Kalscheuer
* @since 0.7.0
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class HealthResponse implements VaultResponse {
private static final long serialVersionUID = 8675155916902904516L;
@JsonProperty("cluster_id")
private String clusterID;
@JsonProperty("cluster_name")
private String clusterName;
@JsonProperty("version")
private String version;
@JsonProperty("server_time_utc")
private Long serverTimeUTC;
@JsonProperty("standby")
private Boolean standby;
@JsonProperty("sealed")
private Boolean sealed;
@JsonProperty("initialized")
private Boolean initialized;
@JsonProperty("replication_performance_mode")
private String replicationPerfMode;
@JsonProperty("replication_dr_mode")
private String replicationDrMode;
@JsonProperty("performance_standby")
private Boolean performanceStandby;
@JsonProperty("echo_duration_ms")
private Long echoDurationMs;
@JsonProperty("clock_skew_ms")
private Long clockSkewMs;
@JsonProperty("replication_primary_canary_age_ms")
private Long replicationPrimaryCanaryAgeMs;
@JsonProperty("enterprise")
private Boolean enterprise;
/**
* @return The Cluster ID.
*/
public String getClusterID() {
return clusterID;
}
/**
* @return The Cluster name.
*/
public String getClusterName() {
return clusterName;
}
/**
* @return Vault version.
*/
public String getVersion() {
return version;
}
/**
* @return Server time UTC (timestamp).
*/
public Long getServerTimeUTC() {
return serverTimeUTC;
}
/**
* @return Server standby status.
*/
public Boolean isStandby() {
return standby;
}
/**
* @return Server seal status.
*/
public Boolean isSealed() {
return sealed;
}
/**
* @return Server initialization status.
*/
public Boolean isInitialized() {
return initialized;
}
/**
* @return Replication performance mode of the active node (since Vault 0.9.2).
* @since 0.8 (#21)
*/
public String getReplicationPerfMode() {
return replicationPerfMode;
}
/**
* @return Replication DR mode of the active node (since Vault 0.9.2).
* @since 0.8 (#21)
*/
public String getReplicationDrMode() {
return replicationDrMode;
}
/**
* @return Performance standby status.
* @since 0.8 (#21)
*/
public Boolean isPerformanceStandby() {
return performanceStandby;
}
/**
* @return Heartbeat echo duration in milliseconds (since Vault 1.16)
* @since 1.3
*/
public Long getEchoDurationMs() {
return echoDurationMs;
}
/**
* @return Clock skew in milliseconds (since Vault 1.16)
* @since 1.3
*/
public Long getClockSkewMs() {
return clockSkewMs;
}
/**
* @return Replication primary canary age in milliseconds (since Vault 1.17)
* @since 1.3
*/
public Long getReplicationPrimaryCanaryAgeMs() {
return replicationPrimaryCanaryAgeMs;
}
/**
* @return Enterprise instance? (since Vault 1.17)
* @since 1.3
*/
public Boolean isEnterprise() {
return enterprise;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
HealthResponse that = (HealthResponse) o;
return Objects.equals(clusterID, that.clusterID) &&
Objects.equals(clusterName, that.clusterName) &&
Objects.equals(version, that.version) &&
Objects.equals(serverTimeUTC, that.serverTimeUTC) &&
Objects.equals(standby, that.standby) &&
Objects.equals(sealed, that.sealed) &&
Objects.equals(initialized, that.initialized) &&
Objects.equals(replicationPerfMode, that.replicationPerfMode) &&
Objects.equals(replicationDrMode, that.replicationDrMode) &&
Objects.equals(performanceStandby, that.performanceStandby) &&
Objects.equals(echoDurationMs, that.echoDurationMs) &&
Objects.equals(clockSkewMs, that.clockSkewMs) &&
Objects.equals(replicationPrimaryCanaryAgeMs, that.replicationPrimaryCanaryAgeMs) &&
Objects.equals(enterprise, that.enterprise);
}
@Override
public int hashCode() {
return Objects.hash(clusterID, clusterName, version, serverTimeUTC, standby, sealed, initialized,
replicationPerfMode, replicationDrMode, performanceStandby, echoDurationMs, clockSkewMs,
replicationPrimaryCanaryAgeMs, enterprise);
}
}

View File

@ -1,59 +1,20 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Objects;
/**
* Vault response for help request.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class HelpResponse implements VaultResponse {
private static final long serialVersionUID = -1152070966642848490L;
public class HelpResponse implements VaultResponse {
@JsonProperty("help")
private String help;
/**
* @return Help text
*/
public String getHelp() {
return help;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
HelpResponse that = (HelpResponse) o;
return Objects.equals(help, that.help);
}
@Override
public int hashCode() {
return Objects.hash(help);
}
}
}

View File

@ -1,75 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.SecretWrapper;
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
/**
* Vault response for secret responses with metadata.
*
* @author Stefan Kalscheuer
* @since 1.1 abstract
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class MetaSecretResponse extends SecretResponse {
private static final long serialVersionUID = -1076542846391240162L;
@JsonProperty("data")
private SecretWrapper secret;
@Override
public final Map<String, Serializable> getData() {
if (secret != null) {
return secret.getData();
} else {
return Collections.emptyMap();
}
}
@Override
public final VersionMetadata getMetadata() {
if (secret != null) {
return secret.getMetadata();
} else {
return null;
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
MetaSecretResponse that = (MetaSecretResponse) o;
return Objects.equals(secret, that.secret);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), secret);
}
}

View File

@ -1,63 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.SecretMetadata;
import java.util.Objects;
/**
* Vault response for secret metadata (KV v2).
*
* @author Stefan Kalscheuer
* @since 0.8
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class MetadataResponse extends VaultDataResponse {
private static final long serialVersionUID = -3679762333630984679L;
@JsonProperty("data")
private SecretMetadata metadata;
/**
* Get the actual metadata.
*
* @return Metadata.
*/
public SecretMetadata getMetadata() {
return metadata;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
MetadataResponse that = (MetadataResponse) o;
return Objects.equals(metadata, that.metadata);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), metadata);
}
}

View File

@ -1,66 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
/**
* Vault response for plain secret responses.
*
* @author Stefan Kalscheuer
* @since 1.1 abstract
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class PlainSecretResponse extends SecretResponse {
private static final long serialVersionUID = 3010138542437913023L;
@JsonProperty("data")
private Map<String, Serializable> data;
@Override
public final Map<String, Serializable> getData() {
return Objects.requireNonNullElseGet(data, Collections::emptyMap);
}
@Override
public final VersionMetadata getMetadata() {
return null;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
PlainSecretResponse that = (PlainSecretResponse) o;
return Objects.equals(data, that.data);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), data);
}
}

View File

@ -1,61 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
/**
* Simple Vault data response.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class RawDataResponse extends VaultDataResponse {
private static final long serialVersionUID = -319727427792124071L;
@JsonProperty("data")
private Map<String, Serializable> data;
/**
* @return Raw data {@link Map}
*/
public Map<String, Serializable> getData() {
return data;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
RawDataResponse that = (RawDataResponse) o;
return Objects.equals(data, that.data);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), data);
}
}

View File

@ -1,46 +1,19 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.ZonedDateTime;
import java.util.Objects;
/**
* Vault response for seal status or unseal request.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class SealResponse implements VaultResponse {
private static final long serialVersionUID = -6000309255473305787L;
@JsonProperty("type")
private String type;
public class SealResponse implements VaultResponse {
@JsonProperty("sealed")
private boolean sealed;
@JsonProperty("initialized")
private boolean initialized;
@JsonProperty("t")
private Integer threshold;
@ -50,165 +23,19 @@ public final class SealResponse implements VaultResponse {
@JsonProperty("progress")
private Integer progress;
@JsonProperty("version")
private String version;
@JsonProperty("build_date")
private ZonedDateTime buildDate;
@JsonProperty("nonce")
private String nonce;
@JsonProperty("cluster_name")
private String clusterName;
@JsonProperty("cluster_id")
private String clusterId;
@JsonProperty("migration")
private Boolean migration;
@JsonProperty("recovery_seal")
private Boolean recoverySeal;
@JsonProperty("storage_type")
private String storageType;
/**
* @return Seal type.
* @since 0.8
*/
public String getType() {
return type;
}
/**
* @return Seal status
*/
public boolean isSealed() {
return sealed;
}
/**
* @return Vault initialization status (since Vault 0.11.2).
* @since 0.8
*/
public boolean isInitialized() {
return initialized;
}
/**
* @return Required threshold of secret shares
*/
public Integer getThreshold() {
return threshold;
}
/**
* @return Number of secret shares
*/
public Integer getNumberOfShares() {
return numberOfShares;
}
/**
* @return Current unseal progress (remaining required shares)
*/
public Integer getProgress() {
return progress;
}
/**
* @return Vault version.
* @since 0.8
*/
public String getVersion() {
return version;
}
/**
* @return Vault build date.
* @since 1.2
*/
public ZonedDateTime getBuildDate() {
return buildDate;
}
/**
* @return A random nonce.
* @since 0.8
*/
public String getNonce() {
return nonce;
}
/**
* @return Vault cluster name (only if unsealed).
* @since 0.8
*/
public String getClusterName() {
return clusterName;
}
/**
* @return Vault cluster ID (only if unsealed).
* @since 0.8
*/
public String getClusterId() {
return clusterId;
}
/**
* @return Migration status (since Vault 1.4)
* @since 1.1
*/
public Boolean getMigration() {
return migration;
}
/**
* @return Recovery seal status.
* @since 1.1
*/
public Boolean getRecoverySeal() {
return recoverySeal;
}
/**
* @return Storage type (since Vault 1.3).
* @since 1.1
*/
public String getStorageType() {
return storageType;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
SealResponse that = (SealResponse) o;
return sealed == that.sealed &&
initialized == that.initialized &&
Objects.equals(type, that.type) &&
Objects.equals(threshold, that.threshold) &&
Objects.equals(numberOfShares, that.numberOfShares) &&
Objects.equals(progress, that.progress) &&
Objects.equals(version, that.version) &&
Objects.equals(buildDate, that.buildDate) &&
Objects.equals(nonce, that.nonce) &&
Objects.equals(clusterName, that.clusterName) &&
Objects.equals(clusterId, that.clusterId) &&
Objects.equals(migration, that.migration) &&
Objects.equals(recoverySeal, that.recoverySeal) &&
Objects.equals(storageType, that.storageType);
}
@Override
public int hashCode() {
return Objects.hash(type, sealed, initialized, threshold, numberOfShares, progress, version, buildDate, nonce,
clusterName, clusterId, migration, recoverySeal, storageType);
}
}

View File

@ -1,65 +1,33 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.SecretListWrapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Map;
/**
* Vault response for secret list request.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class SecretListResponse extends VaultDataResponse {
public class SecretListResponse extends VaultDataResponse {
private List<String> keys;
private static final long serialVersionUID = 8597121175002967213L;
@JsonProperty("data")
private SecretListWrapper data;
public void setData(Map<String, Object> data) throws InvalidResponseException {
try {
this.keys = (List<String>)data.get("keys");
}
catch (ClassCastException e) {
throw new InvalidResponseException("Keys could not be parsed from data.", e);
}
}
/**
* @return List of secret keys
*/
public List<String> getKeys() {
if (data == null) {
return Collections.emptyList();
}
return Objects.requireNonNullElseGet(data.getKeys(), Collections::emptyList);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
SecretListResponse that = (SecretListResponse) o;
return Objects.equals(data, that.data);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), data);
return keys;
}
}

View File

@ -1,104 +1,30 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
import java.io.IOException;
import java.io.Serializable;
import java.util.Map;
/**
* Vault response for secret request.
*
* @author Stefan Kalscheuer
* @since 0.1
* @since 1.1 abstract
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public abstract class SecretResponse extends VaultDataResponse {
private static final long serialVersionUID = 5198088815871692951L;
public class SecretResponse extends VaultDataResponse {
private String value;
/**
* Get complete data object.
*
* @return data map
* @since 0.4.0
* @since 1.1 Serializable map value.
*/
public abstract Map<String, Serializable> getData();
/**
* Get secret metadata. This is only available for KV v2 secrets.
*
* @return Metadata of the secret.
* @since 0.8
*/
public abstract VersionMetadata getMetadata();
/**
* Get a single value for given key.
*
* @param key the key
* @return the value or {@code null} if absent
* @since 0.4.0
*/
public final Object get(final String key) {
return getData().get(key);
}
/**
* Get response parsed as JSON.
*
* @param key the key
* @param type Class to parse response
* @param <C> Class to parse response
* @return Parsed object or {@code null} if absent
* @throws InvalidResponseException on parsing error
* @since 0.4.0
*/
public final <C> C get(final String key, final Class<C> type) throws InvalidResponseException {
@Override
public void setData(Map<String, Object> data) throws InvalidResponseException {
try {
Object rawValue = get(key);
if (rawValue == null) {
return null;
} else if (type.isInstance(rawValue)) {
return type.cast(rawValue);
} else {
var om = JsonMapper.builder()
.addModule(new JavaTimeModule())
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
.build();
if (rawValue instanceof String) {
return om.readValue((String) rawValue, type);
} else {
return om.readValue(om.writeValueAsString(rawValue), type);
}
}
} catch (IOException e) {
throw new InvalidResponseException("Unable to parse response payload: " + e.getMessage());
this.value = (String) data.get("value");
} catch (ClassCastException e) {
throw new InvalidResponseException("Value could not be parsed", e);
}
}
}
public String getValue() {
return value;
}
}

View File

@ -1,62 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
import java.util.Objects;
/**
* Vault response for a single secret version metadata, i.e. after update (KV v2).
*
* @author Stefan Kalscheuer
* @since 0.8
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SecretVersionResponse extends VaultDataResponse {
private static final long serialVersionUID = 2748635005258576174L;
@JsonProperty("data")
private VersionMetadata metadata;
/**
* Get the actual metadata.
*
* @return Metadata.
*/
public VersionMetadata getMetadata() {
return metadata;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
SecretVersionResponse that = (SecretVersionResponse) o;
return Objects.equals(metadata, that.metadata);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), metadata);
}
}

View File

@ -1,61 +1,40 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
import java.util.Objects;
import java.io.IOException;
import java.util.Map;
/**
* Vault response from token lookup providing Token information in {@link TokenData} field.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenResponse extends VaultDataResponse {
private static final long serialVersionUID = -4341114947980033457L;
@JsonProperty("data")
public class TokenResponse extends VaultDataResponse {
private TokenData data;
/**
* @return Token data
*/
@JsonProperty("auth")
private Boolean auth;
@Override
public void setData(Map<String, Object> data) throws InvalidResponseException {
ObjectMapper mapper = new ObjectMapper();
try {
this.data = mapper.readValue(mapper.writeValueAsString(data), TokenData.class);
} catch (IOException e) {
e.printStackTrace();
throw new InvalidResponseException();
}
}
public TokenData getData() {
return data;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
TokenResponse that = (TokenResponse) o;
return Objects.equals(data, that.data);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), data);
}
}

View File

@ -1,61 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.TokenRole;
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
import java.util.Objects;
/**
* Vault response from token role lookup providing Token information in {@link TokenData} field.
*
* @author Stefan Kalscheuer
* @since 0.9
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenRoleResponse extends VaultDataResponse {
private static final long serialVersionUID = 5265363857731948626L;
@JsonProperty("data")
private TokenRole data;
/**
* @return TokenRole data
*/
public TokenRole getData() {
return data;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
TokenRoleResponse that = (TokenRoleResponse) o;
return Objects.equals(data, that.data);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), data);
}
}

View File

@ -1,92 +0,0 @@
/*
* 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,40 +1,18 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.AuthData;
import de.stklcode.jvault.connector.model.response.embedded.WrapInfo;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import java.util.List;
import java.util.Objects;
import java.util.Map;
/**
* Abstract Vault response with default payload fields.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public abstract class VaultDataResponse implements VaultResponse {
private static final long serialVersionUID = 4787715235558510045L;
@JsonProperty("request_id")
private String requestId;
@JsonProperty("lease_id")
private String leaseId;
@ -47,95 +25,22 @@ public abstract class VaultDataResponse implements VaultResponse {
@JsonProperty("warnings")
private List<String> warnings;
@JsonProperty("wrap_info")
private WrapInfo wrapInfo;
@JsonProperty("data")
public abstract void setData(Map<String, Object> data) throws InvalidResponseException;
@JsonProperty("auth")
private AuthData auth;
@JsonProperty("mount_type")
private String mountType;
/**
* @return Request ID
* @since 1.1
*/
public final String getRequestId() {
return requestId;
}
/**
* @return Lease ID
*/
public final String getLeaseId() {
public String getLeaseId() {
return leaseId;
}
/**
* @return Lease is renewable
*/
public final boolean isRenewable() {
public boolean isRenewable() {
return renewable;
}
/**
* @return Lease duration
*/
public final Integer getLeaseDuration() {
public Integer getLeaseDuration() {
return leaseDuration;
}
/**
* @return List of warnings
*/
public final List<String> getWarnings() {
public List<String> getWarnings() {
return warnings;
}
/**
* @return Wrapping information
* @since 1.1
*/
public final WrapInfo getWrapInfo() {
return wrapInfo;
}
/**
* @return Authentication information for this response
* @since 1.3
*/
public final AuthData getAuth() {
return auth;
}
/**
* @return Information about the type of mount this secret is from (since Vault 1.17)
* @since 1.3
*/
public final String getMountType() {
return mountType;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
VaultDataResponse that = (VaultDataResponse) o;
return renewable == that.renewable &&
Objects.equals(requestId, that.requestId) &&
Objects.equals(leaseId, that.leaseId) &&
Objects.equals(leaseDuration, that.leaseDuration) &&
Objects.equals(warnings, that.warnings) &&
Objects.equals(wrapInfo, that.wrapInfo) &&
Objects.equals(auth, that.auth) &&
Objects.equals(mountType, that.mountType);
}
@Override
public int hashCode() {
return Objects.hash(requestId, leaseId, renewable, leaseDuration, warnings, wrapInfo, auth, mountType);
}
}

View File

@ -1,29 +1,10 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import java.io.Serializable;
/**
* Marker interface for responses from Vault backend.
*
* @author Stefan Kalscheuer
* @since 0.1
* @since 1.1 extends {@link Serializable}
* @author Stefan Kalscheuer
* @since 0.1
*/
public interface VaultResponse extends Serializable {
public interface VaultResponse {
}

View File

@ -1,40 +1,19 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Embedded authorization information inside Vault response.
*
* @author Stefan Kalscheuer
* @since 0.1
* @since 1.1 implements {@link Serializable}
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthData implements Serializable {
private static final long serialVersionUID = 5969334512309655317L;
public class AuthData {
@JsonProperty("client_token")
private String clientToken;
@ -44,9 +23,6 @@ public final class AuthData implements Serializable {
@JsonProperty("policies")
private List<String> policies;
@JsonProperty("token_policies")
private List<String> tokenPolicies;
@JsonProperty("metadata")
private Map<String, Object> metadata;
@ -56,137 +32,27 @@ public final class AuthData implements Serializable {
@JsonProperty("renewable")
private boolean renewable;
@JsonProperty("entity_id")
private String entityId;
@JsonProperty("token_type")
private String tokenType;
@JsonProperty("orphan")
private boolean orphan;
@JsonProperty("num_uses")
private Integer numUses;
@JsonProperty("mfa_requirement")
private MfaRequirement mfaRequirement;
/**
* @return Client token
*/
public String getClientToken() {
return clientToken;
}
/**
* @return Token type
* @since 0.9
*/
public String getTokenType() {
return tokenType;
}
/**
* @return List of policies
*/
public List<String> getPolicies() {
return policies;
}
/**
* @return List of policies associated with the token
* @since 0.9
*/
public List<String> getTokenPolicies() {
return tokenPolicies;
}
/**
* @return Metadata
*/
public Map<String, Object> getMetadata() {
return metadata;
}
/**
* @return Lease duration
*/
public Integer getLeaseDuration() {
return leaseDuration;
}
/**
* @return Lease is renewable
*/
public boolean isRenewable() {
return renewable;
}
/**
* @return Entity ID
* @since 0.9
*/
public String getEntityId() {
return entityId;
}
/**
* @return Token accessor
*/
public String getAccessor() {
return accessor;
}
/**
* @return allowed number of uses for the issued token
* @since 1.3
*/
public Integer getNumUses() {
return numUses;
public List<String> getPolicies() {
return policies;
}
/**
* @return Token is orphan
* @since 0.9
*/
public boolean isOrphan() {
return orphan;
public Map<String, Object> getMetadata() {
return metadata;
}
/**
* @return multi-factor requirement
* @since 1.2
*/
public MfaRequirement getMfaRequirement() {
return mfaRequirement;
public Integer getLeaseDuration() {
return leaseDuration;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AuthData authData = (AuthData) o;
return renewable == authData.renewable &&
orphan == authData.orphan &&
Objects.equals(clientToken, authData.clientToken) &&
Objects.equals(accessor, authData.accessor) &&
Objects.equals(policies, authData.policies) &&
Objects.equals(tokenPolicies, authData.tokenPolicies) &&
Objects.equals(metadata, authData.metadata) &&
Objects.equals(leaseDuration, authData.leaseDuration) &&
Objects.equals(entityId, authData.entityId) &&
Objects.equals(tokenType, authData.tokenType) &&
Objects.equals(numUses, authData.numUses) &&
Objects.equals(mfaRequirement, authData.mfaRequirement);
public boolean isRenewable() {
return renewable;
}
@Override
public int hashCode() {
return Objects.hash(clientToken, accessor, policies, tokenPolicies, metadata, leaseDuration, renewable,
entityId, tokenType, orphan, numUses, mfaRequirement);
}
}
}

View File

@ -1,225 +1,40 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import de.stklcode.jvault.connector.model.AuthBackend;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
import de.stklcode.jvault.connector.model.AuthBackend;
/**
* Embedded authentication method response.
*
* @author Stefan Kalscheuer
* @since 0.1
* @since 1.1 implements {@link Serializable}
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthMethod implements Serializable {
private static final long serialVersionUID = -439987082190917691L;
public class AuthMethod {
private AuthBackend type;
private String rawType;
@JsonProperty("accessor")
private String accessor;
@JsonProperty("deprecation_status")
private String deprecationStatus;
@JsonProperty("description")
private String path;
private String description;
@JsonProperty("config")
private MountConfig config;
@JsonProperty("external_entropy_access")
private boolean externalEntropyAccess;
@JsonProperty("local")
private boolean local;
@JsonProperty("options")
private Map<String, String> options;
@JsonProperty("plugin_version")
private String pluginVersion;
@JsonProperty("running_plugin_version")
private String runningPluginVersion;
@JsonProperty("running_sha256")
private String runningSha256;
@JsonProperty("seal_wrap")
private boolean sealWrap;
@JsonProperty("uuid")
private String uuid;
/**
* @param type Backend type, passed to {@link AuthBackend#forType(String)}
*/
@JsonSetter("type")
public void setType(final String type) {
public AuthMethod(String path, String description, String type) {
this.path = path;
this.description = description;
this.rawType = type;
this.type = AuthBackend.forType(type);
}
/**
* @return Backend type
*/
public AuthBackend getType() {
return type;
}
/**
* @return Raw backend type string
*/
public String getRawType() {
return rawType;
}
/**
* @return Accessor
* @since 1.1
*/
public String getAccessor() {
return accessor;
public String getPath() {
return path;
}
/**
* @return Deprecation status
* @since 1.2
*/
public String getDeprecationStatus() {
return deprecationStatus;
}
/**
* @return Description
*/
public String getDescription() {
return description;
}
/**
* @return Configuration data
* @since 0.2
* @since 1.2 Returns {@link MountConfig} instead of {@link Map}
*/
public MountConfig getConfig() {
return config;
}
/**
* @return Backend has access to external entropy source
* @since 1.1
*/
public boolean isExternalEntropyAccess() {
return externalEntropyAccess;
}
/**
* @return Is local backend
*/
public boolean isLocal() {
return local;
}
/**
* @return Options
* @since 1.2
*/
public Map<String, String> getOptions() {
return options;
}
/**
* @return Plugin version
* @since 1.2
*/
public String getPluginVersion() {
return pluginVersion;
}
/**
* @return Running plugin version
* @since 1.2
*/
public String getRunningPluginVersion() {
return runningPluginVersion;
}
/**
* @return Running SHA256
* @since 1.2
*/
public String getRunningSha256() {
return runningSha256;
}
/**
* @return Seal wrapping enabled
* @since 1.1
*/
public boolean isSealWrap() {
return sealWrap;
}
/**
* @return Backend UUID
* @since 1.1
*/
public String getUuid() {
return uuid;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
AuthMethod that = (AuthMethod) o;
return local == that.local &&
type == that.type &&
externalEntropyAccess == that.externalEntropyAccess &&
sealWrap == that.sealWrap &&
Objects.equals(rawType, that.rawType) &&
Objects.equals(accessor, that.accessor) &&
Objects.equals(deprecationStatus, that.deprecationStatus) &&
Objects.equals(description, that.description) &&
Objects.equals(config, that.config) &&
Objects.equals(options, that.options) &&
Objects.equals(pluginVersion, that.pluginVersion) &&
Objects.equals(runningPluginVersion, that.runningPluginVersion) &&
Objects.equals(runningSha256, that.runningSha256) &&
Objects.equals(uuid, that.uuid);
}
@Override
public int hashCode() {
return Objects.hash(type, rawType, accessor, deprecationStatus, description, config, externalEntropyAccess,
local, options, pluginVersion, runningPluginVersion, runningSha256, sealWrap, uuid);
}
}

View File

@ -1,62 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
/**
* Embedded multi-factor-authentication (MFA) constraint "any".
*
* @author Stefan Kalscheuer
* @since 1.2
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class MfaConstraintAny implements Serializable {
private static final long serialVersionUID = 1226126781813149627L;
@JsonProperty("any")
private List<MfaMethodId> any;
/**
* @return List of "any" MFA methods
*/
public List<MfaMethodId> getAny() {
return any;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MfaConstraintAny mfaRequirement = (MfaConstraintAny) o;
return Objects.equals(any, mfaRequirement.any);
}
@Override
public int hashCode() {
return Objects.hash(any);
}
}

View File

@ -1,94 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.Objects;
/**
* Embedded multi-factor-authentication (MFA) requirement.
*
* @author Stefan Kalscheuer
* @since 1.2
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class MfaMethodId implements Serializable {
private static final long serialVersionUID = 691298070242998814L;
@JsonProperty("type")
private String type;
@JsonProperty("id")
private String id;
@JsonProperty("uses_passcode")
private Boolean usesPasscode;
@JsonProperty("name")
private String name;
/**
* @return MFA method type
*/
public String getType() {
return type;
}
/**
* @return MFA method id
*/
public String getId() {
return id;
}
/**
* @return MFA uses passcode id
*/
public Boolean getUsesPasscode() {
return usesPasscode;
}
/**
* @return MFA method name
*/
public String getName() {
return name;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MfaMethodId mfaMethodId = (MfaMethodId) o;
return Objects.equals(type, mfaMethodId.type) &&
Objects.equals(id, mfaMethodId.id) &&
Objects.equals(usesPasscode, mfaMethodId.usesPasscode) &&
Objects.equals(name, mfaMethodId.name);
}
@Override
public int hashCode() {
return Objects.hash(type, id, usesPasscode, name);
}
}

View File

@ -1,73 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
/**
* Embedded multi-factor-authentication (MFA) requirement.
*
* @author Stefan Kalscheuer
* @since 1.2
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class MfaRequirement implements Serializable {
private static final long serialVersionUID = -2516941512455319638L;
@JsonProperty("mfa_request_id")
private String mfaRequestId;
@JsonProperty("mfa_constraints")
private Map<String, MfaConstraintAny> mfaConstraints;
/**
* @return MFA request ID
*/
public String getMfaRequestId() {
return mfaRequestId;
}
/**
* @return MFA constraints
*/
public Map<String, MfaConstraintAny> getMfaConstraints() {
return mfaConstraints;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MfaRequirement mfaRequirement = (MfaRequirement) o;
return Objects.equals(mfaRequestId, mfaRequirement.mfaRequestId) &&
Objects.equals(mfaConstraints, mfaRequirement.mfaConstraints);
}
@Override
public int hashCode() {
return Objects.hash(mfaRequestId, mfaConstraints);
}
}

View File

@ -1,168 +0,0 @@
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
/**
* Embedded mount config output.
*
* @author Stefan Kalscheuer
* @since 1.2
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class MountConfig implements Serializable {
private static final long serialVersionUID = -8653909672663717792L;
@JsonProperty("default_lease_ttl")
private Integer defaultLeaseTtl;
@JsonProperty("max_lease_ttl")
private Integer maxLeaseTtl;
@JsonProperty("force_no_cache")
private Boolean forceNoCache;
@JsonProperty("token_type")
private String tokenType;
@JsonProperty("audit_non_hmac_request_keys")
private List<String> auditNonHmacRequestKeys;
@JsonProperty("audit_non_hmac_response_keys")
private List<String> auditNonHmacResponseKeys;
@JsonProperty("listing_visibility")
private String listingVisibility;
@JsonProperty("passthrough_request_headers")
private List<String> passthroughRequestHeaders;
@JsonProperty("allowed_response_headers")
private List<String> allowedResponseHeaders;
@JsonProperty("allowed_managed_keys")
private List<String> allowedManagedKeys;
@JsonProperty("delegated_auth_accessors")
private List<String> delegatedAuthAccessors;
@JsonProperty("user_lockout_config")
private UserLockoutConfig userLockoutConfig;
/**
* @return Default lease TTL
*/
public Integer getDefaultLeaseTtl() {
return defaultLeaseTtl;
}
/**
* @return Maximum lease TTL
*/
public Integer getMaxLeaseTtl() {
return maxLeaseTtl;
}
/**
* @return Force no cache?
*/
public Boolean getForceNoCache() {
return forceNoCache;
}
/**
* @return Token type
*/
public String getTokenType() {
return tokenType;
}
/**
* @return Audit non HMAC request keys
*/
public List<String> getAuditNonHmacRequestKeys() {
return auditNonHmacRequestKeys;
}
/**
* @return Audit non HMAC response keys
*/
public List<String> getAuditNonHmacResponseKeys() {
return auditNonHmacResponseKeys;
}
/**
* @return Listing visibility
*/
public String getListingVisibility() {
return listingVisibility;
}
/**
* @return Passthrough request headers
*/
public List<String> getPassthroughRequestHeaders() {
return passthroughRequestHeaders;
}
/**
* @return Allowed response headers
*/
public List<String> getAllowedResponseHeaders() {
return allowedResponseHeaders;
}
/**
* @return Allowed managed keys
*/
public List<String> getAllowedManagedKeys() {
return allowedManagedKeys;
}
/**
* @return Delegated auth accessors
*/
public List<String> getDelegatedAuthAccessors() {
return delegatedAuthAccessors;
}
/**
* @return User lockout config
*/
public UserLockoutConfig getUserLockoutConfig() {
return userLockoutConfig;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
MountConfig that = (MountConfig) o;
return Objects.equals(defaultLeaseTtl, that.defaultLeaseTtl) &&
Objects.equals(maxLeaseTtl, that.maxLeaseTtl) &&
Objects.equals(forceNoCache, that.forceNoCache) &&
Objects.equals(tokenType, that.tokenType) &&
Objects.equals(auditNonHmacRequestKeys, that.auditNonHmacRequestKeys) &&
Objects.equals(auditNonHmacResponseKeys, that.auditNonHmacResponseKeys) &&
Objects.equals(listingVisibility, that.listingVisibility) &&
Objects.equals(passthroughRequestHeaders, that.passthroughRequestHeaders) &&
Objects.equals(allowedResponseHeaders, that.allowedResponseHeaders) &&
Objects.equals(allowedManagedKeys, that.allowedManagedKeys) &&
Objects.equals(delegatedAuthAccessors, that.delegatedAuthAccessors) &&
Objects.equals(userLockoutConfig, that.userLockoutConfig);
}
@Override
public int hashCode() {
return Objects.hash(defaultLeaseTtl, maxLeaseTtl, forceNoCache, tokenType, auditNonHmacRequestKeys,
auditNonHmacResponseKeys, listingVisibility, passthroughRequestHeaders, allowedResponseHeaders,
allowedManagedKeys, delegatedAuthAccessors, userLockoutConfig);
}
}

View File

@ -1,42 +0,0 @@
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
/**
* Wrapper object for secret key lists.
*
* @author Stefan Kalscheuer
* @since 1.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SecretListWrapper implements Serializable {
private static final long serialVersionUID = -8777605197063766125L;
@JsonProperty("keys")
private List<String> keys;
public List<String> getKeys() {
return keys;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
SecretListWrapper that = (SecretListWrapper) o;
return Objects.equals(keys, that.keys);
}
@Override
public int hashCode() {
return Objects.hash(keys);
}
}

View File

@ -1,156 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* Embedded metadata for Key-Value v2 secrets.
*
* @author Stefan Kalscheuer
* @since 0.8
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class SecretMetadata implements Serializable {
private static final long serialVersionUID = -905059942871916214L;
@JsonProperty("created_time")
private ZonedDateTime createdTime;
@JsonProperty("current_version")
private Integer currentVersion;
@JsonProperty("max_versions")
private Integer maxVersions;
@JsonProperty("oldest_version")
private Integer oldestVersion;
@JsonProperty("updated_time")
private ZonedDateTime updatedTime;
@JsonProperty("versions")
private Map<Integer, VersionMetadata> versions;
@JsonProperty("cas_required")
private Boolean casRequired;
@JsonProperty("custom_metadata")
private HashMap<String, String> customMetadata;
@JsonProperty("delete_version_after")
private String deleteVersionAfter;
/**
* @return Time of secret creation.
*/
public ZonedDateTime getCreatedTime() {
return createdTime;
}
/**
* @return Current version number.
*/
public Integer getCurrentVersion() {
return currentVersion;
}
/**
* @return Maximum number of versions.
*/
public Integer getMaxVersions() {
return maxVersions;
}
/**
* @return Oldest available version number.
*/
public Integer getOldestVersion() {
return oldestVersion;
}
/**
* @return Time of secret update.
*/
public ZonedDateTime getUpdatedTime() {
return updatedTime;
}
/**
* @return Version of the entry.
*/
public Map<Integer, VersionMetadata> getVersions() {
return versions;
}
/**
* @return CAS required?
* @since 1.3
*/
public Boolean isCasRequired() {
return casRequired;
}
/**
* @return Custom metadata.
* @since 1.3
*/
public Map<String, String> getCustomMetadata() {
return customMetadata;
}
/**
* @return time duration to delete version
* @since 1.3
*/
public String getDeleteVersionAfter() {
return deleteVersionAfter;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
SecretMetadata that = (SecretMetadata) o;
return Objects.equals(createdTime, that.createdTime) &&
Objects.equals(currentVersion, that.currentVersion) &&
Objects.equals(maxVersions, that.maxVersions) &&
Objects.equals(oldestVersion, that.oldestVersion) &&
Objects.equals(updatedTime, that.updatedTime) &&
Objects.equals(versions, that.versions) &&
Objects.equals(casRequired, that.casRequired) &&
Objects.equals(customMetadata, that.customMetadata) &&
Objects.equals(deleteVersionAfter, that.deleteVersionAfter);
}
@Override
public int hashCode() {
return Objects.hash(createdTime, currentVersion, maxVersions, oldestVersion, updatedTime, versions, casRequired,
customMetadata, deleteVersionAfter);
}
}

View File

@ -1,49 +0,0 @@
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
/**
* Wrapper object for secret data and metadata.
*
* @author Stefan Kalscheuer
* @since 1.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SecretWrapper implements Serializable {
private static final long serialVersionUID = 8600413181758893378L;
@JsonProperty("data")
private Map<String, Serializable> data;
@JsonProperty("metadata")
private VersionMetadata metadata;
public Map<String, Serializable> getData() {
return data;
}
public VersionMetadata getMetadata() {
return metadata;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
SecretWrapper that = (SecretWrapper) o;
return Objects.equals(data, that.data) && Objects.equals(metadata, that.metadata);
}
@Override
public int hashCode() {
return Objects.hash(data, metadata);
}
}

View File

@ -1,41 +1,16 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Embedded token information inside Vault response.
*
* @author Stefan Kalscheuer
* @since 0.1
* @since 1.1 implements {@link Serializable}
* @author Stefan Kalscheuer
* @since 0.1
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenData implements Serializable {
private static final long serialVersionUID = -5749716740973138916L;
public class TokenData {
@JsonProperty("accessor")
private String accessor;
@ -43,28 +18,16 @@ public final class TokenData implements Serializable {
private Integer creationTime;
@JsonProperty("creation_ttl")
private Integer creationTtl;
private Integer creatinTtl;
@JsonProperty("display_name")
private String name;
@JsonProperty("entity_id")
private String entityId;
@JsonProperty("expire_time")
private ZonedDateTime expireTime;
@JsonProperty("explicit_max_ttl")
private Integer explicitMaxTtl;
@JsonProperty("id")
private String id;
@JsonProperty("issue_time")
private ZonedDateTime issueTime;
@JsonProperty("meta")
private Map<String, Object> meta;
private String meta;
@JsonProperty("num_uses")
private Integer numUses;
@ -75,174 +38,53 @@ public final class TokenData implements Serializable {
@JsonProperty("path")
private String path;
@JsonProperty("policies")
private List<String> policies;
@JsonProperty("renewable")
private boolean renewable;
@JsonProperty("role")
private String role;
@JsonProperty("ttl")
private Integer ttl;
@JsonProperty("type")
private String type;
/**
* @return Token accessor
*/
public String getAccessor() {
return accessor;
}
/**
* @return Creation time
*/
public Integer getCreationTime() {
return creationTime;
}
/**
* @return Creation TTL (in seconds)
*/
public Integer getCreationTtl() {
return creationTtl;
public Integer getCreatinTtl() {
return creatinTtl;
}
/**
* @return Token name
*/
public String getName() {
return name;
}
/**
* @return Entity ID
* @since 0.9
*/
public String getEntityId() {
return entityId;
}
/**
* @return Expire time (parsed)
* @since 0.9
*/
public ZonedDateTime getExpireTime() {
return expireTime;
}
/**
* @return Explicit maximum TTL
* @since 0.9
*/
public Integer getExplicitMaxTtl() {
return explicitMaxTtl;
}
/**
* @return Token ID
*/
public String getId() {
return id;
}
/**
* @return Expire time (parsed)
* @since 0.9
*/
public ZonedDateTime getIssueTime() {
return issueTime;
}
/**
* @return Token type
* @since 0.9
*/
public String getType() {
return type;
}
/**
* @return Number of uses
*/
public Integer getNumUses() {
return numUses;
}
/**
* @return Token is orphan
*/
public boolean isOrphan() {
return orphan;
}
/**
* @return Token path
*/
public String getPath() {
return path;
}
/**
* @return Token policies
* @since 0.9
*/
public List<String> getPolicies() {
return policies;
public String getRole() {
return role;
}
/**
* @return Token is renewable
* @since 0.9
*/
public boolean isRenewable() {
return renewable;
}
/**
* @return Token TTL (in seconds)
*/
public Integer getTtl() {
return ttl;
}
/**
* @return Metadata
*/
public Map<String, Object> getMeta() {
public String getMeta() {
return meta;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
TokenData tokenData = (TokenData) o;
return orphan == tokenData.orphan &&
renewable == tokenData.renewable &&
Objects.equals(accessor, tokenData.accessor) &&
Objects.equals(creationTime, tokenData.creationTime) &&
Objects.equals(creationTtl, tokenData.creationTtl) &&
Objects.equals(name, tokenData.name) &&
Objects.equals(entityId, tokenData.entityId) &&
Objects.equals(expireTime, tokenData.expireTime) &&
Objects.equals(explicitMaxTtl, tokenData.explicitMaxTtl) &&
Objects.equals(id, tokenData.id) &&
Objects.equals(issueTime, tokenData.issueTime) &&
Objects.equals(meta, tokenData.meta) &&
Objects.equals(numUses, tokenData.numUses) &&
Objects.equals(path, tokenData.path) &&
Objects.equals(policies, tokenData.policies) &&
Objects.equals(ttl, tokenData.ttl) &&
Objects.equals(type, tokenData.type);
}
@Override
public int hashCode() {
return Objects.hash(accessor, creationTime, creationTtl, name, entityId, expireTime, explicitMaxTtl, id,
issueTime, meta, numUses, orphan, path, policies, renewable, ttl, type);
}
}
}

View File

@ -1,77 +0,0 @@
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.Objects;
/**
* Embedded user lockout config output.
*
* @author Stefan Kalscheuer
* @since 1.2
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class UserLockoutConfig implements Serializable {
private static final long serialVersionUID = -8051060041593140550L;
@JsonProperty("lockout_threshold")
private Integer lockoutThreshold;
@JsonProperty("lockout_duration")
private Integer lockoutDuration;
@JsonProperty("lockout_counter_reset_duration")
private Integer lockoutCounterResetDuration;
@JsonProperty("lockout_disable")
private Boolean lockoutDisable;
/**
* @return Lockout threshold
*/
public Integer getLockoutThreshold() {
return lockoutThreshold;
}
/**
* @return Lockout duration
*/
public Integer getLockoutDuration() {
return lockoutDuration;
}
/**
* @return Lockout counter reset duration
*/
public Integer getLockoutCounterResetDuration() {
return lockoutCounterResetDuration;
}
/**
* @return Lockout disabled?
*/
public Boolean getLockoutDisable() {
return lockoutDisable;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
UserLockoutConfig that = (UserLockoutConfig) o;
return Objects.equals(lockoutThreshold, that.lockoutThreshold) &&
Objects.equals(lockoutDuration, that.lockoutDuration) &&
Objects.equals(lockoutCounterResetDuration, that.lockoutCounterResetDuration) &&
Objects.equals(lockoutDisable, that.lockoutDisable);
}
@Override
public int hashCode() {
return Objects.hash(lockoutThreshold, lockoutDuration, lockoutCounterResetDuration, lockoutDisable);
}
}

View File

@ -1,109 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* Embedded metadata for a single Key-Value v2 version.
*
* @author Stefan Kalscheuer
* @since 0.8
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class VersionMetadata implements Serializable {
private static final long serialVersionUID = 8495687554714216478L;
@JsonProperty("created_time")
private ZonedDateTime createdTime;
@JsonProperty("deletion_time")
private ZonedDateTime deletionTime;
@JsonProperty("destroyed")
private boolean destroyed;
@JsonProperty("version")
private Integer version;
@JsonProperty("custom_metadata")
private HashMap<String, String> customMetadata;
/**
* @return Time of secret creation.
*/
public ZonedDateTime getCreatedTime() {
return createdTime;
}
/**
* @return Time for secret deletion.
*/
public ZonedDateTime getDeletionTime() {
return deletionTime;
}
/**
* @return Whether the secret is destroyed.
*/
public boolean isDestroyed() {
return destroyed;
}
/**
* @return Version of the entry.
*/
public Integer getVersion() {
return version;
}
/**
* @return Custom metadata.
* @since 1.3
*/
public Map<String, String> getCustomMetadata() {
return customMetadata;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
VersionMetadata that = (VersionMetadata) o;
return destroyed == that.destroyed &&
Objects.equals(createdTime, that.createdTime) &&
Objects.equals(deletionTime, that.deletionTime) &&
Objects.equals(version, that.version) &&
Objects.equals(customMetadata, that.customMetadata);
}
@Override
public int hashCode() {
return Objects.hash(createdTime, deletionTime, destroyed, version, customMetadata);
}
}

View File

@ -1,92 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.Objects;
/**
* Wrapping information object.
*
* @author Stefan Kalscheuer
* @since 1.1
*/
public class WrapInfo implements Serializable {
private static final long serialVersionUID = 4864973237090355607L;
@JsonProperty("token")
private String token;
@JsonProperty("ttl")
private Integer ttl;
@JsonProperty("creation_time")
private ZonedDateTime creationTime;
@JsonProperty("creation_path")
private String creationPath;
/**
* @return Token
*/
public String getToken() {
return token;
}
/**
* @return TTL (in seconds)
*/
public Integer getTtl() {
return ttl;
}
/**
* @return Creation time
*/
public ZonedDateTime getCreationTime() {
return creationTime;
}
/**
* @return Creation path
*/
public String getCreationPath() {
return creationPath;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
WrapInfo that = (WrapInfo) o;
return Objects.equals(token, that.token) &&
Objects.equals(ttl, that.ttl) &&
Objects.equals(creationTime, that.creationTime) &&
Objects.equals(creationPath, that.creationPath);
}
@Override
public int hashCode() {
return Objects.hash(token, ttl, creationTime, creationPath);
}
}

View File

@ -1,20 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Embedded data classes for responses from the Vault API.
*/
package de.stklcode.jvault.connector.model.response.embedded;

View File

@ -1,20 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Model classes for responses from the Vault API.
*/
package de.stklcode.jvault.connector.model.response;

View File

@ -1,21 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Java Vault Connector base package - contains {@link de.stklcode.jvault.connector.VaultConnector} interface and
* default implementation.
*/
package de.stklcode.jvault.connector;

View File

@ -1,37 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* JVaultConnector module.
*
* @author Stefan Kalscheuer
*/
module de.stklcode.jvault.connector {
exports de.stklcode.jvault.connector;
exports de.stklcode.jvault.connector.exception;
exports de.stklcode.jvault.connector.model;
exports de.stklcode.jvault.connector.model.response;
exports de.stklcode.jvault.connector.model.response.embedded;
opens de.stklcode.jvault.connector.model to com.fasterxml.jackson.databind;
opens de.stklcode.jvault.connector.model.response to com.fasterxml.jackson.databind;
opens de.stklcode.jvault.connector.model.response.embedded to com.fasterxml.jackson.databind;
requires java.net.http;
requires com.fasterxml.jackson.annotation;
requires com.fasterxml.jackson.databind;
requires com.fasterxml.jackson.datatype.jsr310;
}

View File

@ -1,13 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>API Overview</title>
</head>
<body>
<p>Java Vault Connector is a connector library for Vault by Hashicorp written in Java.</p>
<p>The connector allows simple usage of Vault's secret store in own applications.</p>
<p>It features a default implementation for the HTTP(S) interface and supports various authorization methods including
AppRole, token and secret handling.</p>
</body>
</html>

View File

@ -1,249 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector;
import com.github.stefanbirkner.systemlambda.SystemLambda;
import de.stklcode.jvault.connector.exception.ConnectionException;
import de.stklcode.jvault.connector.exception.TlsException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicReference;
import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit test for HTTP Vault connector factory
*
* @author Stefan Kalscheuer
* @since 0.8.0
*/
class HTTPVaultConnectorBuilderTest {
private static final String VAULT_ADDR = "https://localhost:8201";
private static final String VAULT_ADDR_2 = "http://localhost";
private static final String VAULT_ADDR_3 = "https://localhost/vault/";
private static final Integer VAULT_MAX_RETRIES = 13;
private static final String VAULT_TOKEN = "00001111-2222-3333-4444-555566667777";
@TempDir
File tempDir;
/**
* Test the builder.
*/
@Test
void builderTest() throws Exception {
// Minimal configuration.
HTTPVaultConnector connector = HTTPVaultConnector.builder().withHost("vault.example.com").build();
assertEquals("https://vault.example.com:8200/v1/", getRequestHelperPrivate(connector, "baseURL"), "URL not set correctly");
assertNull(getRequestHelperPrivate(connector, "trustedCaCert"), "Trusted CA cert set when no cert provided");
assertEquals(0, getRequestHelperPrivate(connector, "retries"), "Number of retries unexpectedly set");
// Specify all options.
HTTPVaultConnectorBuilder builder = HTTPVaultConnector.builder()
.withHost("vault2.example.com")
.withoutTLS()
.withPort(1234)
.withPrefix("/foo/")
.withTimeout(5678)
.withNumberOfRetries(9);
connector = builder.build();
assertEquals("http://vault2.example.com:1234/foo/", getRequestHelperPrivate(connector, "baseURL"), "URL not set correctly");
assertNull(getRequestHelperPrivate(connector, "trustedCaCert"), "Trusted CA cert set when no cert provided");
assertEquals(9, getRequestHelperPrivate(connector, "retries"), "Unexpected number of retries");
assertEquals(5678, getRequestHelperPrivate(connector, "timeout"), "Number timeout value");
assertThrows(ConnectionException.class, builder::buildAndAuth, "Immediate authentication should throw exception without token");
// Initialization from URL.
assertThrows(
URISyntaxException.class,
() -> HTTPVaultConnector.builder().withBaseURL("foo:/\\1nv4l1d_UrL"),
"Initialization from invalid URL should fail"
);
connector = assertDoesNotThrow(
() -> HTTPVaultConnector.builder().withBaseURL("https://vault3.example.com:5678/bar/").build(),
"Initialization from valid URL should not fail"
);
assertEquals("https://vault3.example.com:5678/bar/", getRequestHelperPrivate(connector, "baseURL"), "URL not set correctly");
// Port numbers.
assertThrows(IllegalArgumentException.class, () -> HTTPVaultConnector.builder().withPort(65536), "Too large port number should throw an exception");
assertThrows(IllegalArgumentException.class, () -> HTTPVaultConnector.builder().withPort(0), "Port number 0 should throw an exception");
builder = assertDoesNotThrow(() -> HTTPVaultConnector.builder().withPort(-1), "Port number -1 should not throw an exception");
assertNull(builder.getPort(), "Port number -1 should be omitted");
builder = assertDoesNotThrow(() -> HTTPVaultConnector.builder().withPort(null), "Port number NULL should not throw an exception");
assertNull(builder.getPort(), "Port number NULL should be passed through");
}
/**
* Test building from environment variables
*/
@Test
void testFromEnv() throws Exception {
// Provide address only should be enough.
withVaultEnv(VAULT_ADDR, null, null, null).execute(() -> {
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
() -> HTTPVaultConnector.builder().fromEnv(),
"Factory creation from minimal environment failed"
);
HTTPVaultConnector connector = builder.build();
assertEquals(VAULT_ADDR + "/v1/", getRequestHelperPrivate(connector, "baseURL"), "URL not set correctly");
assertNull(getRequestHelperPrivate(connector, "trustedCaCert"), "Trusted CA cert set when no cert provided");
assertEquals(0, getRequestHelperPrivate(connector, "retries"), "Non-default number of retries, when none set");
return null;
});
withVaultEnv(VAULT_ADDR_2, null, null, null).execute(() -> {
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
() -> HTTPVaultConnector.builder().fromEnv(),
"Factory creation from minimal environment failed"
);
assertEquals(VAULT_ADDR_2 + "/v1/", getRequestHelperPrivate(builder.build(), "baseURL"), "URL without port not set correctly");
return null;
});
withVaultEnv(VAULT_ADDR_3, null, null, null).execute(() -> {
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
() -> HTTPVaultConnector.builder().fromEnv(),
"Factory creation from minimal environment failed"
);
assertEquals(VAULT_ADDR_3, getRequestHelperPrivate(builder.build(), "baseURL"), "URL with custom path not set correctly");
return null;
});
// Provide address and number of retries.
withVaultEnv(VAULT_ADDR, null, VAULT_MAX_RETRIES.toString(), null).execute(() -> {
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
() -> HTTPVaultConnector.builder().fromEnv(),
"Factory creation from environment failed"
);
HTTPVaultConnector connector = builder.build();
assertEquals(VAULT_ADDR + "/v1/", getRequestHelperPrivate(connector, "baseURL"), "URL not set correctly");
assertNull(getRequestHelperPrivate(connector, "trustedCaCert"), "Trusted CA cert set when no cert provided");
assertEquals(VAULT_MAX_RETRIES, getRequestHelperPrivate(connector, "retries"), "Number of retries not set correctly");
return null;
});
// Automatic authentication.
withVaultEnv(VAULT_ADDR, null, VAULT_MAX_RETRIES.toString(), VAULT_TOKEN).execute(() -> {
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
() -> HTTPVaultConnector.builder().fromEnv(),
"Factory creation from minimal environment failed"
);
assertEquals(VAULT_TOKEN, getPrivate(builder, "token"), "Token not set correctly");
return null;
});
// Invalid URL.
withVaultEnv("This is not a valid URL!", null, VAULT_MAX_RETRIES.toString(), VAULT_TOKEN).execute(() -> {
assertThrows(
ConnectionException.class,
() -> HTTPVaultConnector.builder().fromEnv(),
"Invalid URL from environment should raise an exception"
);
return null;
});
}
/**
* Test CA certificate handling from environment variables
*/
@Test
void testCertificateFromEnv() throws Exception {
// From direct PEM content
String pem = Files.readString(Paths.get(getClass().getResource("/tls/ca.pem").toURI()));
AtomicReference<Object> certFromPem = new AtomicReference<>();
withVaultEnv(VAULT_ADDR, pem, null, null).execute(() -> {
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
() -> HTTPVaultConnector.builder().fromEnv(),
"Builder with PEM certificate from environment failed"
);
HTTPVaultConnector connector = builder.build();
certFromPem.set(getRequestHelperPrivate(connector, "trustedCaCert"));
assertNotNull(certFromPem.get(), "Trusted CA cert from PEM not set");
return null;
});
// From file path
String file = Paths.get(getClass().getResource("/tls/ca.pem").toURI()).toString();
AtomicReference<Object> certFromFile = new AtomicReference<>();
withVaultEnv(VAULT_ADDR, file, null, null).execute(() -> {
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
() -> HTTPVaultConnector.builder().fromEnv(),
"Builder with certificate path from environment failed"
);
HTTPVaultConnector connector = builder.build();
certFromFile.set(getRequestHelperPrivate(connector, "trustedCaCert"));
assertNotNull(certFromFile.get(), "Trusted CA cert from file not set");
return null;
});
assertEquals(certFromPem.get(), certFromFile.get(), "Certificates from PEM and file should be equal");
// Non-existing path CA certificate path
String doesNotExist = tempDir.toString() + "/doesnotexist";
withVaultEnv(VAULT_ADDR, doesNotExist, VAULT_MAX_RETRIES.toString(), null).execute(() -> {
TlsException e = assertThrows(
TlsException.class,
() -> HTTPVaultConnector.builder().fromEnv(),
"Creation with unknown cert path failed"
);
assertEquals(doesNotExist, assertInstanceOf(NoSuchFileException.class, e.getCause()).getFile());
return null;
});
}
private SystemLambda.WithEnvironmentVariables withVaultEnv(String vaultAddr, String vaultCacert, String vaultMaxRetries, String vaultToken) {
return withEnvironmentVariable("VAULT_ADDR", vaultAddr)
.and("VAULT_CACERT", vaultCacert)
.and("VAULT_MAX_RETRIES", vaultMaxRetries)
.and("VAULT_TOKEN", vaultToken);
}
private Object getRequestHelperPrivate(HTTPVaultConnector connector, String fieldName) throws NoSuchFieldException, IllegalAccessException {
return getPrivate(getPrivate(connector, "request"), fieldName);
}
private Object getPrivate(Object target, String fieldName) throws NoSuchFieldException, IllegalAccessException {
Field field = target.getClass().getDeclaredField(fieldName);
if (field.canAccess(target)) {
return field.get(target);
}
field.setAccessible(true);
Object value = field.get(target);
field.setAccessible(false);
return value;
}
}

View File

@ -1,314 +1,377 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
import de.stklcode.jvault.connector.exception.ConnectionException;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.test.VaultConfiguration;
import de.stklcode.jvault.connector.exception.InvalidRequestException;
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.function.Executable;
import de.stklcode.jvault.connector.factory.VaultConnectorFactory;
import de.stklcode.jvault.connector.model.AuthBackend;
import de.stklcode.jvault.connector.model.response.AuthResponse;
import de.stklcode.jvault.connector.model.response.SealResponse;
import de.stklcode.jvault.connector.model.response.SecretResponse;
import de.stklcode.jvault.connector.model.response.TokenResponse;
import org.junit.*;
import org.junit.rules.TemporaryFolder;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.ServerSocket;
import java.net.URISyntaxException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.List;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.*;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
/**
* JUnit test for HTTP Vault connector.
* This test suite contains tests that do not require connection to an actual Vault instance.
* JUnit Test for HTTP Vault connector.
*
* @author Stefan Kalscheuer
* @since 0.7.0
* @author Stefan Kalscheuer
* @since 0.1
*/
@WireMockTest
class HTTPVaultConnectorTest {
public class HTTPVaultConnectorTest {
private static String KEY = "81011a8061e5c028bd0d9503eeba40bd9054b9af0408d080cb24f57405c27a61";
private static String TOKEN_ROOT = "d1bd50e2-587b-6e68-d80b-a9a507625cb7";
private static String USER_VALID = "validUser";
private static String PASS_VALID = "validPass";
private static String APP_ID = "152AEA38-85FB-47A8-9CBD-612D645BFACA";
private static String USER_ID = "5ADF8218-D7FB-4089-9E38-287465DBF37E";
private static String SECRET_PATH = "userstore";
private static String SECRET_KEY = "foo";
private static String SECRET_VALUE = "bar";
private Process vaultProcess;
private VaultConnector connector;
@Rule
public TemporaryFolder tmpDir = new TemporaryFolder();
/**
* Test exceptions thrown during request.
* Initialize Vault instance with generated configuration and provided file backend.
* Requires "vault" binary to be in current user's executable path. Not using MLock, so no extended rights required.
*/
@Test
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"
);
assertEquals("Invalid response code", e.getMessage(), "Unexpected exception message");
assertEquals(responseCode, ((InvalidResponseException) e).getStatusCode(), "Unexpected status code in exception");
assertNull(((InvalidResponseException) e).getResponse(), "Response message where none was expected");
// Simulate permission denied response.
mockHttpResponse(responseCode, "{\"errors\":[\"permission denied\"]}", "application/json");
assertThrows(
PermissionDeniedException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
// Test exception thrown during request.
try (ServerSocket s = new ServerSocket(0)) {
connector = HTTPVaultConnector.builder("http://localst:" + s.getLocalPort() + "/").withTimeout(250).build();
}
e = assertThrows(
ConnectionException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
assertInstanceOf(IOException.class, e.getCause(), "Unexpected cause");
// Now simulate a failing request that succeeds on second try.
connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withNumberOfRetries(1).withTimeout(250).build();
stubFor(
WireMock.any(anyUrl())
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(200).withBody("{}").withHeader("Content-Type", "application/json"))
);
assertDoesNotThrow(connector::getHealth, "Request failed unexpectedly");
}
/**
* Test constructors of the {@link HTTPVaultConnector} class.
*/
@Test
void constructorTest() throws IOException, CertificateException, URISyntaxException {
final String url = "https://vault.example.net/test/";
final String hostname = "vault.example.com";
final Integer port = 1337;
final String prefix = "/custom/prefix/";
final int retries = 42;
final String expectedNoTls = "http://" + hostname + ":8200/v1/";
final String expectedCustomPort = "https://" + hostname + ":" + port + "/v1/";
final String expectedCustomPrefix = "https://" + hostname + ":" + port + prefix;
X509Certificate trustedCaCert;
try (InputStream is = getClass().getResourceAsStream("/tls/ca.pem")) {
trustedCaCert = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
}
// Most basic constructor expects complete URL.
HTTPVaultConnector connector = HTTPVaultConnector.builder(url).build();
assertEquals(url, getRequestHelperPrivate(connector, "baseURL"), "Unexpected base URL");
// Now override TLS usage.
connector = HTTPVaultConnector.builder().withHost(hostname).withoutTLS().build();
assertEquals(expectedNoTls, getRequestHelperPrivate(connector, "baseURL"), "Unexpected base URL with TLS disabled");
// Specify custom port.
connector = HTTPVaultConnector.builder().withHost(hostname).withTLS().withPort(port).build();
assertEquals(expectedCustomPort, getRequestHelperPrivate(connector, "baseURL"), "Unexpected base URL with custom port");
// Specify custom prefix.
connector = HTTPVaultConnector.builder().withHost(hostname).withTLS().withPort(port).withPrefix(prefix).build();
assertEquals(expectedCustomPrefix, getRequestHelperPrivate(connector, "baseURL"), "Unexpected base URL with custom prefix");
assertNull(getRequestHelperPrivate(connector, "trustedCaCert"), "Trusted CA cert set, but not specified");
// Specify number of retries.
connector = HTTPVaultConnector.builder(url).withTrustedCA(trustedCaCert).withNumberOfRetries(retries).build();
assertEquals(retries, getRequestHelperPrivate(connector, "retries"), "Number of retries not set correctly");
// Test TLS version (#22).
assertEquals("TLSv1.2", getRequestHelperPrivate(connector, "tlsVersion"), "TLS version should be 1.2 if not specified");
// Now override.
connector = HTTPVaultConnector.builder(url).withTrustedCA(trustedCaCert).withNumberOfRetries(retries).withTLS("TLSv1.1").build();
assertEquals("TLSv1.1", getRequestHelperPrivate(connector, "tlsVersion"), "Overridden TLS version 1.1 not correct");
}
/**
* This test is designed to test exceptions caught and thrown by seal-methods if Vault is not reachable.
*/
@Test
void sealExceptionTest() throws IOException, URISyntaxException {
// Simulate no connection.
VaultConnector connector;
try (ServerSocket s = new ServerSocket(0)) {
connector = HTTPVaultConnector.builder("http://localst:" + s.getLocalPort()).withTimeout(250).build();
}
ConnectionException e = assertThrows(
ConnectionException.class,
connector::sealStatus,
"Querying seal status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
}
/**
* This test is designed to test exceptions caught and thrown by seal-methods if Vault is not reachable.
*/
@Test
void healthExceptionTest() throws IOException, URISyntaxException {
// Simulate no connection.
HTTPVaultConnector connector;
try (ServerSocket s = new ServerSocket(0)) {
connector = HTTPVaultConnector.builder("http://localhost:" + s.getLocalPort() + "/").withTimeout(250).build();
}
ConnectionException e = assertThrows(
ConnectionException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
}
/**
* Test behavior on unparsable responses.
*/
@Test
void parseExceptionTest(WireMockRuntimeInfo wireMock) throws URISyntaxException {
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withTimeout(250).build();
// Mock authorization.
setPrivate(connector, "authorized", true);
// Mock response.
mockHttpResponse(200, "invalid", "application/json");
// Now test the methods.
assertParseError(connector::sealStatus, "sealStatus() succeeded on invalid instance");
assertParseError(() -> connector.unseal("key"), "unseal() succeeded on invalid instance");
assertParseError(connector::getHealth, "getHealth() succeeded on invalid instance");
assertParseError(connector::getAuthBackends, "getAuthBackends() succeeded on invalid instance");
assertParseError(() -> connector.authToken("token"), "authToken() succeeded on invalid instance");
assertParseError(() -> connector.lookupAppRole("roleName"), "lookupAppRole() succeeded on invalid instance");
assertParseError(() -> connector.getAppRoleID("roleName"), "getAppRoleID() succeeded on invalid instance");
assertParseError(() -> connector.createAppRoleSecret("roleName"), "createAppRoleSecret() succeeded on invalid instance");
assertParseError(() -> connector.lookupAppRoleSecret("roleName", "secretID"), "lookupAppRoleSecret() succeeded on invalid instance");
assertParseError(connector::listAppRoles, "listAppRoles() succeeded on invalid instance");
assertParseError(() -> connector.listAppRoleSecrets("roleName"), "listAppRoleSecrets() succeeded on invalid instance");
assertParseError(() -> connector.read("key"), "read() succeeded on invalid instance");
assertParseError(() -> connector.list("path"), "list() succeeded on invalid instance");
assertParseError(() -> connector.renew("leaseID"), "renew() succeeded on invalid instance");
assertParseError(() -> connector.lookupToken("token"), "lookupToken() succeeded on invalid instance");
}
private void assertParseError(Executable executable, String message) {
InvalidResponseException e = assertThrows(InvalidResponseException.class, executable, message);
assertEquals("Unable to parse response", e.getMessage(), "Unexpected exception message");
}
/**
* Test requests that expect an empty response with code 204, but receive a 200 body.
*/
@Test
void nonEmpty204ResponseTest(WireMockRuntimeInfo wireMock) throws URISyntaxException {
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withTimeout(250).build();
// Mock authorization.
setPrivate(connector, "authorized", true);
// Mock response.
mockHttpResponse(200, "{}", "application/json");
// Now test the methods expecting a 204.
assertThrows(
InvalidResponseException.class,
() -> connector.createAppRole("appID", Collections.singletonList("policy")),
"createAppRole() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.deleteAppRole("roleName"),
"deleteAppRole() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.setAppRoleID("roleName", "roleID"),
"setAppRoleID() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.destroyAppRoleSecret("roleName", "secretID"),
"destroyAppRoleSecret() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.destroyAppRoleSecret("roleName", "secretUD"),
"destroyAppRoleSecret() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.delete("key"),
"delete() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.revoke("leaseID"),
"destroyAppRoleSecret() with 200 response succeeded"
);
}
private Object getRequestHelperPrivate(HTTPVaultConnector connector, String fieldName) {
@Before
public void setUp() {
/* Initialize Vault */
VaultConfiguration config = initializeVault();
try {
return getPrivate(getPrivate(connector, "request"), fieldName);
} catch (NoSuchFieldException | IllegalAccessException e) {
return null;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/* Initialize connector */
connector = VaultConnectorFactory.httpFactory()
.withHost(config.getHost())
.withPort(config.getPort())
.withoutTLS()
.build();
/* Unseal Vault and check result */
SealResponse sealStatus = connector.unseal(KEY);
assumeNotNull(sealStatus);
assumeFalse(sealStatus.isSealed());
}
private Object getPrivate(Object target, String fieldName) throws NoSuchFieldException, IllegalAccessException {
Field field = target.getClass().getDeclaredField(fieldName);
if (field.canAccess(target)) {
return field.get(target);
}
field.setAccessible(true);
Object value = field.get(target);
field.setAccessible(false);
return value;
@After
public void tearDown() {
if (vaultProcess != null && vaultProcess.isAlive())
vaultProcess.destroy();
}
private void setPrivate(Object target, String fieldName, Object value) {
/**
* Test listing of authentication backends
*/
@Test
public void authMethodsTest() {
/* Authenticate as valid user */
try {
Field field = target.getClass().getDeclaredField(fieldName);
boolean accessible = field.canAccess(target);
field.setAccessible(true);
field.set(target, value);
field.setAccessible(accessible);
} catch (NoSuchFieldException | IllegalAccessException e) {
// Should not occur, to be taken care of in test code.
connector.authToken(TOKEN_ROOT);
}
catch(VaultConnectorException ignored) {
}
assumeTrue(connector.isAuthorized());
List<AuthBackend> supportedBackends = null;
try {
supportedBackends = connector.getAuthBackends();
} catch (VaultConnectorException e) {
fail("Could not list supported auth backends: " + e.getMessage());
}
assertThat(supportedBackends.size(), is(3));
assertThat(supportedBackends, hasItems(AuthBackend.TOKEN, AuthBackend.USERPASS, AuthBackend.APPID));
}
/**
* Test authentication using token.
*/
@Test
public void authTokenTest() {
TokenResponse res = null;
try {
res = connector.authToken("52135869df23a5e64c5d33a9785af5edb456b8a4a235d1fe135e6fba1c35edf6");
fail("Logged in with invalid token");
} catch (VaultConnectorException ignored) {
}
try {
res = connector.authToken(TOKEN_ROOT);
assertNotNull("Login failed with valid token", res);
assertThat("Login failed with valid token", connector.isAuthorized(), is(true));
} catch (VaultConnectorException ignored) {
fail("Login failed with valid token");
}
}
private void mockHttpResponse(int status, String body, String contentType) {
stubFor(
WireMock.any(anyUrl()).willReturn(
aResponse().withStatus(status).withBody(body).withHeader("Content-Type", contentType)
)
);
/**
* Test authentication using username and password.
*/
@Test
public void authUserPassTest() {
AuthResponse res = null;
try {
connector.authUserPass("foo", "bar");
fail("Logged in with invalid credentials");
}
catch(VaultConnectorException ignored) {
}
try {
res = connector.authUserPass(USER_VALID, PASS_VALID);
} catch (VaultConnectorException ignored) {
fail("Login failed with valid credentials: Exception thrown");
}
assertNotNull("Login failed with valid credentials: Response not available", res.getAuth());
assertThat("Login failed with valid credentials: Connector not authorized", connector.isAuthorized(), is(true));
}
/**
* App-ID authentication roundtrip.
*/
@Test
public void authAppIdTest() {
authRoot();
assumeTrue(connector.isAuthorized());
/* Register App-ID */
try {
boolean res = connector.registerAppId(APP_ID, "user", "App Name");
assertThat("Failed to register App-ID", res, is(true));
}
catch (VaultConnectorException e) {
fail("Failed to register App-ID: " + e.getMessage());
}
/* Register User-ID */
try {
boolean res = connector.registerUserId(APP_ID, USER_ID);
assertThat("Failed to register App-ID", res, is(true));
}
catch (VaultConnectorException e) {
fail("Failed to register App-ID: " + e.getMessage());
}
connector.resetAuth();
assumeFalse(connector.isAuthorized());
/* Authenticate with created credentials */
try {
AuthResponse res = connector.authAppId(APP_ID, USER_ID);
assertThat("Authorization flag not set after App-ID login.", connector.isAuthorized(), is(true));
} catch (VaultConnectorException e) {
fail("Failed to authenticate using App-ID: " + e.getMessage());
}
}
/**
* Test reading of secrets.
*/
@Test
public void readSecretTest() {
authUser();
assumeTrue(connector.isAuthorized());
/* Try to read path user has no permission to read */
SecretResponse res = null;
try {
res = connector.readSecret("invalid/path");
fail("Invalid secret path successfully read.");
} catch (VaultConnectorException e) {
assertThat(e, instanceOf(PermissionDeniedException.class));
}
/* Try to read accessible path with known value */
try {
res = connector.readSecret(SECRET_PATH + "/" + SECRET_KEY);
assertThat("Known secret returned invalid value.", res.getValue(), is(SECRET_VALUE));
} catch (VaultConnectorException e) {
fail("Valid secret path could not be read: " + e.getMessage());
}
}
/**
* Test listing secrets.
*/
@Test
public void listSecretsTest() {
authRoot();
assumeTrue(connector.isAuthorized());
/* Try to list secrets from valid path */
try {
List<String> secrets = connector.listSecrets(SECRET_PATH);
assertThat("Invalid nmber of secrets.", secrets.size(), greaterThan(0));
assertThat("Known secret key not found", secrets, hasItem(SECRET_KEY));
} catch (VaultConnectorException e) {
fail("Secrets could not be listed: " + e.getMessage());
}
}
/**
* Test writing secrets.
*/
@Test
public void writeSecretTest() {
authUser();
assumeTrue(connector.isAuthorized());
/* Try to write to null path */
try {
boolean res = connector.writeSecret(null, "someValue");
fail("Secret written to null path.");
} catch (VaultConnectorException e) {
assertThat(e, instanceOf(InvalidRequestException.class));
}
/* Try to write to invalid path */
try {
boolean res = connector.writeSecret("", "someValue");
fail("Secret written to invalid path.");
} catch (VaultConnectorException e) {
assertThat(e, instanceOf(InvalidRequestException.class));
}
/* Try to write to a path the user has no access for */
try {
boolean res = connector.writeSecret("invalid/path", "someValue");
fail("Secret written to inaccessible path.");
} catch (VaultConnectorException e) {
assertThat(e, instanceOf(PermissionDeniedException.class));
}
/* Perform a valid write/read roundtrip to valid path. Also check UTF8-encoding. */
try {
boolean res = connector.writeSecret(SECRET_PATH + "/temp", "Abc123äöü,!");
assertThat("Secret could not be written to valid path.", res, is(true));
} catch (VaultConnectorException e) {
fail("Secret written to inaccessible path.");
}
try {
SecretResponse res = connector.readSecret(SECRET_PATH + "/temp");
assertThat(res.getValue(), is("Abc123äöü,!"));
} catch (VaultConnectorException e) {
fail("Written secret could not be read.");
}
}
/**
* Initialize Vault with resource datastore and generated configuration.
* @return Vault Configuration
* @throws IllegalStateException
*/
private VaultConfiguration initializeVault() throws IllegalStateException {
String dataResource = getClass().getResource("/data_dir").getPath();
/* Generate vault local unencrypted configuration */
VaultConfiguration config = new VaultConfiguration()
.withHost("127.0.0.1")
.withPort(getFreePort())
.withDataLocation(dataResource)
.disableMlock();
/* Write configuration file */
BufferedWriter bw = null;
File configFIle = null;
try {
configFIle = tmpDir.newFile("vault.conf");
bw = new BufferedWriter(new FileWriter(configFIle));
bw.write(config.toString());
}
catch (IOException e) {
e.printStackTrace();
throw new IllegalStateException("Unable to generate config file.");
}
finally {
try {
if (bw != null)
bw.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
/* Start vault process */
try {
vaultProcess = Runtime.getRuntime().exec("vault server -config " + configFIle.toString());
} catch (IOException e) {
e.printStackTrace();
throw new IllegalStateException("Unable to start vault. Make sure vault binary is in your executable path.");
}
return config;
}
/**
* Authenticate with root token.
*/
private void authRoot() {
/* Authenticate as valid user */
try {
connector.authToken(TOKEN_ROOT);
}
catch(VaultConnectorException ignored) {
}
}
/**
* Authenticate with user credentials.
*/
private void authUser() {
try {
connector.authUserPass(USER_VALID, PASS_VALID);
}
catch(VaultConnectorException ignored) {
}
}
/**
* Find and return a free TCP port.
* @return port number
*/
private static Integer getFreePort() {
ServerSocket socket = null;
try {
socket = new ServerSocket(0);
socket.setReuseAddress(true);
int port = socket.getLocalPort();
try {
socket.close();
} catch (IOException e) {
// Ignore IOException on close()
}
return port;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
throw new IllegalStateException("Unable to find a free TCP port.");
}
}

View File

@ -1,152 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.exception;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
/**
* Common JUnit test for Exceptions extending {@link VaultConnectorException}.
*
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class VaultConnectorExceptionTest {
private static final String MSG = "This is a test exception!";
private static final Throwable CAUSE = new Exception("Test-Cause");
private static final Integer STATUS_CODE = 1337;
private static final String RESPONSE = "Dummy response";
@Test
void authorizationRequiredExceptionTest() {
assertEmptyConstructor(new AuthorizationRequiredException());
}
@Test
void connectionExceptionTest() {
assertEmptyConstructor(new ConnectionException());
assertMsgConstructor(new ConnectionException(MSG));
assertCauseConstructor(new ConnectionException(CAUSE));
assertMsgCauseConstructor(new ConnectionException(MSG, CAUSE));
}
@Test
void invalidRequestExceptionTest() {
assertEmptyConstructor(new InvalidRequestException());
assertMsgConstructor(new InvalidRequestException(MSG));
assertCauseConstructor(new InvalidRequestException(CAUSE));
assertMsgCauseConstructor(new InvalidRequestException(MSG, CAUSE));
}
@Test
void invalidResponseExceptionTest() {
assertEmptyConstructor(new InvalidResponseException());
assertMsgConstructor(new InvalidResponseException(MSG));
assertCauseConstructor(new InvalidResponseException(CAUSE));
assertMsgCauseConstructor(new InvalidResponseException(MSG, CAUSE));
// Constructor with message and status code.
InvalidResponseException e = new InvalidResponseException(MSG, STATUS_CODE);
assertEquals(MSG, e.getMessage());
assertNull(e.getCause());
assertEquals(STATUS_CODE, e.getStatusCode());
assertNull(e.getResponse());
// Constructor with message, status code and cause.
e = new InvalidResponseException(MSG, STATUS_CODE, CAUSE);
assertEquals(MSG, e.getMessage());
assertEquals(CAUSE, e.getCause());
assertEquals(STATUS_CODE, e.getStatusCode());
assertNull(e.getResponse());
// Constructor with message, status code and response.
e = new InvalidResponseException(MSG, STATUS_CODE, RESPONSE);
assertEquals(MSG, e.getMessage());
assertNull(e.getCause());
assertEquals(STATUS_CODE, e.getStatusCode());
assertEquals(RESPONSE, e.getResponse());
// Constructor with message, status code, response and cause.
e = new InvalidResponseException(MSG, STATUS_CODE, RESPONSE, CAUSE);
assertEquals(MSG, e.getMessage());
assertEquals(CAUSE, e.getCause());
assertEquals(STATUS_CODE, e.getStatusCode());
assertEquals(RESPONSE, e.getResponse());
}
@Test
void permissionDeniedExceptionTest() {
// Default message overwritten.
PermissionDeniedException e = new PermissionDeniedException();
assertEquals("Permission denied", e.getMessage());
assertNull(e.getCause());
assertMsgConstructor(new PermissionDeniedException(MSG));
assertCauseConstructor(new PermissionDeniedException(CAUSE));
assertMsgCauseConstructor(new PermissionDeniedException(MSG, CAUSE));
}
@Test
void tlsExceptionTest() {
assertEmptyConstructor(new TlsException());
assertMsgConstructor(new TlsException(MSG));
assertCauseConstructor(new TlsException(CAUSE));
assertMsgCauseConstructor(new TlsException(MSG, CAUSE));
}
/**
* Assertions for empty constructor.
*
* @param e the exception
*/
private void assertEmptyConstructor(VaultConnectorException e) {
assertNull(e.getMessage());
assertNull(e.getCause());
}
/**
* Assertions for constructor with message.
*
* @param e the exception
*/
private void assertMsgConstructor(VaultConnectorException e) {
assertEquals(MSG, e.getMessage());
assertNull(e.getCause());
}
/**
* Assertions for constructor with cause.
*
* @param e the exception
*/
private void assertCauseConstructor(VaultConnectorException e) {
assertEquals(CAUSE.toString(), e.getMessage());
assertEquals(CAUSE, e.getCause());
}
/**
* Assertions for constructor with message and cause.
*
* @param e the exception
*/
private void assertMsgCauseConstructor(VaultConnectorException e) {
assertEquals(MSG, e.getMessage());
assertEquals(CAUSE, e.getCause());
}
}

View File

@ -1,81 +0,0 @@
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import nl.jqno.equalsverifier.EqualsVerifier;
import org.junit.jupiter.api.Test;
import java.io.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
/**
* Abstract testcase for model classes.
*
* @author Stefan Kalscheuer
* @since 1.1
*/
public abstract class AbstractModelTest<T> {
protected final Class<?> modelClass;
protected final ObjectMapper objectMapper;
/**
* Test case constructor.
*
* @param modelClass Target class to test.
*/
protected AbstractModelTest(Class<T> modelClass) {
this.modelClass = modelClass;
this.objectMapper = JsonMapper.builder()
.addModule(new JavaTimeModule())
.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
.build();
}
/**
* Create a "full" model instance.
*
* @return Model instance.
*/
protected abstract T createFull();
/**
* Test if {@link Object#equals(Object)} and {@link Object#hashCode()} are implemented, s.t. all fields are covered.
*/
@Test
void testEqualsHashcode() {
EqualsVerifier.simple().forClass(modelClass).verify();
}
/**
* Test Java serialization of a full model instance.
* Serialization and deserialization must not fail and the resulting object should equal the original object.
*/
@Test
void serializationTest() {
T original = createFull();
byte[] bytes;
try (var bos = new ByteArrayOutputStream();
var oos = new ObjectOutputStream(bos)) {
oos.writeObject(original);
bytes = bos.toByteArray();
} catch (IOException e) {
fail("Serialization failed", e);
return;
}
try (var bis = new ByteArrayInputStream(bytes);
var ois = new ObjectInputStream(bis)) {
Object copy = ois.readObject();
assertEquals(modelClass, copy.getClass(), "Invalid class after deserialization");
assertEquals(original, copy, "Deserialized object should be equal to the original");
} catch (IOException | ClassNotFoundException e) {
fail("Deserialization failed", e);
}
}
}

View File

@ -1,186 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
/**
* JUnit Test for AppRoleSecret model.
*
* @author Stefan Kalscheuer
* @since 0.5.0
*/
class AppRoleSecretTest extends AbstractModelTest<AppRoleSecret> {
private static final String TEST_ID = "abc123";
private static final Map<String, Object> TEST_META = Map.of(
"foo", "bar",
"number", 1337
);
private static final List<String> TEST_CIDR = List.of("203.0.113.0/24", "198.51.100.0/24");
AppRoleSecretTest() {
super(AppRoleSecret.class);
}
@Override
protected AppRoleSecret createFull() {
return new AppRoleSecret(TEST_ID, TEST_META, TEST_CIDR);
}
/**
* Test constructors.
*/
@Test
void constructorTest() {
// Empty constructor.
AppRoleSecret secret = new AppRoleSecret();
assertNull(secret.getId());
assertNull(secret.getAccessor());
assertNull(secret.getMetadata());
assertNull(secret.getCidrList());
assertEquals("", secret.getCidrListString());
assertNull(secret.getCreationTime());
assertNull(secret.getExpirationTime());
assertNull(secret.getLastUpdatedTime());
assertNull(secret.getNumUses());
assertNull(secret.getTtl());
// Constructor with ID.
secret = new AppRoleSecret(TEST_ID);
assertEquals(TEST_ID, secret.getId());
assertNull(secret.getAccessor());
assertNull(secret.getMetadata());
assertNull(secret.getCidrList());
assertEquals("", secret.getCidrListString());
assertNull(secret.getCreationTime());
assertNull(secret.getExpirationTime());
assertNull(secret.getLastUpdatedTime());
assertNull(secret.getNumUses());
assertNull(secret.getTtl());
// Constructor with Metadata and CIDR bindings.
secret = new AppRoleSecret(TEST_ID, TEST_META, TEST_CIDR);
assertEquals(TEST_ID, secret.getId());
assertNull(secret.getAccessor());
assertEquals(TEST_META, secret.getMetadata());
assertEquals(TEST_CIDR, secret.getCidrList());
assertEquals(String.join(",", TEST_CIDR), secret.getCidrListString());
assertNull(secret.getCreationTime());
assertNull(secret.getExpirationTime());
assertNull(secret.getLastUpdatedTime());
assertNull(secret.getNumUses());
assertNull(secret.getTtl());
}
/**
* Test setter.
*/
@Test
void setterTest() {
AppRoleSecret secret = new AppRoleSecret(TEST_ID);
assertNull(secret.getCidrList());
assertEquals("", secret.getCidrListString());
secret.setCidrList(TEST_CIDR);
assertEquals(TEST_CIDR, secret.getCidrList());
assertEquals(String.join(",", TEST_CIDR), secret.getCidrListString());
secret.setCidrList(null);
assertNull(secret.getCidrList());
assertEquals("", secret.getCidrListString());
}
/**
* Test JSON (de)serialization.
*/
@Test
void jsonTest() throws NoSuchFieldException, IllegalAccessException {
// A simple roundtrip first. All set fields should be present afterward.
AppRoleSecret secret = new AppRoleSecret(TEST_ID, TEST_META, TEST_CIDR);
String secretJson = assertDoesNotThrow(() -> objectMapper.writeValueAsString(secret), "Serialization failed");
// CIDR list is comma-separated when used as input, but List otherwise, hence convert string to list.
String secretJson2 = commaSeparatedToList(secretJson);
AppRoleSecret secret2 = assertDoesNotThrow(
() -> objectMapper.readValue(secretJson2, AppRoleSecret.class),
"Deserialization failed"
);
assertEquals(secret2.getId(), secret.getId());
assertEquals(secret2.getMetadata(), secret.getMetadata());
assertEquals(secret2.getCidrList(), secret.getCidrList());
// Test fields, that should not be written to JSON.
setPrivateField(secret, "accessor", "TEST_ACCESSOR");
assumeTrue("TEST_ACCESSOR".equals(secret.getAccessor()));
setPrivateField(secret, "creationTime", "TEST_CREATION");
assumeTrue("TEST_CREATION".equals(secret.getCreationTime()));
setPrivateField(secret, "expirationTime", "TEST_EXPIRATION");
assumeTrue("TEST_EXPIRATION".equals(secret.getExpirationTime()));
setPrivateField(secret, "lastUpdatedTime", "TEST_UPDATETIME");
assumeTrue("TEST_UPDATETIME".equals(secret.getLastUpdatedTime()));
setPrivateField(secret, "numUses", 678);
assumeTrue(secret.getNumUses() == 678);
setPrivateField(secret, "ttl", 12345);
assumeTrue(secret.getTtl() == 12345);
String secretJson3 = assertDoesNotThrow(() -> objectMapper.writeValueAsString(secret), "Serialization failed");
secret2 = assertDoesNotThrow(
() -> objectMapper.readValue(commaSeparatedToList(secretJson3), AppRoleSecret.class),
"Deserialization failed"
);
assertEquals(secret2.getId(), secret.getId());
assertEquals(secret2.getMetadata(), secret.getMetadata());
assertEquals(secret2.getCidrList(), secret.getCidrList());
assertNull(secret2.getAccessor());
assertNull(secret2.getCreationTime());
assertNull(secret2.getExpirationTime());
assertNull(secret2.getLastUpdatedTime());
assertNull(secret2.getNumUses());
assertNull(secret2.getTtl());
// Those fields should be deserialized from JSON though.
String secretJson4 = "{\"secret_id\":\"abc123\",\"metadata\":{\"number\":1337,\"foo\":\"bar\"}," +
"\"cidr_list\":[\"203.0.113.0/24\",\"198.51.100.0/24\"],\"secret_id_accessor\":\"TEST_ACCESSOR\"," +
"\"creation_time\":\"TEST_CREATION\",\"expiration_time\":\"TEST_EXPIRATION\"," +
"\"last_updated_time\":\"TEST_LASTUPDATE\",\"secret_id_num_uses\":678,\"secret_id_ttl\":12345}";
secret2 = assertDoesNotThrow(() -> objectMapper.readValue(secretJson4, AppRoleSecret.class), "Deserialization failed");
assertEquals("TEST_ACCESSOR", secret2.getAccessor());
assertEquals("TEST_CREATION", secret2.getCreationTime());
assertEquals("TEST_EXPIRATION", secret2.getExpirationTime());
assertEquals("TEST_LASTUPDATE", secret2.getLastUpdatedTime());
assertEquals(678, secret2.getNumUses());
assertEquals(12345, secret2.getTtl());
}
private static void setPrivateField(Object object, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = object.getClass().getDeclaredField(fieldName);
boolean accessible = field.canAccess(object);
field.setAccessible(true);
field.set(object, value);
field.setAccessible(accessible);
}
private static String commaSeparatedToList(String json) {
return json.replaceAll("\"cidr_list\":\"([^\"]*)\"", "\"cidr_list\":[$1]")
.replaceAll("(\\d+\\.\\d+\\.\\d+\\.\\d+/\\d+)", "\"$1\"");
}
}

View File

@ -1,183 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link AppRole} and {@link AppRole.Builder}.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
class AppRoleTest extends AbstractModelTest<AppRole> {
private static final String NAME = "TestRole";
private static final String ID = "test-id";
private static final Boolean BIND_SECRET_ID = true;
private static final List<String> BOUND_CIDR_LIST = new ArrayList<>();
private static final String CIDR_1 = "192.168.1.0/24";
private static final String CIDR_2 = "172.16.0.0/16";
private static final List<String> POLICIES = new ArrayList<>();
private static final String POLICY = "policy";
private static final String POLICY_2 = "policy2";
private static final Integer SECRET_ID_NUM_USES = 10;
private static final Integer SECRET_ID_TTL = 7200;
private static final Boolean LOCAL_SECRET_IDS = false;
private static final Integer TOKEN_TTL = 4800;
private static final Integer TOKEN_MAX_TTL = 9600;
private static final Integer TOKEN_EXPLICIT_MAX_TTL = 14400;
private static final Boolean TOKEN_NO_DEFAULT_POLICY = false;
private static final Integer TOKEN_NUM_USES = 42;
private static final Integer TOKEN_PERIOD = 1234;
private static final Token.Type TOKEN_TYPE = Token.Type.DEFAULT_SERVICE;
private static final String JSON_MIN = "{\"role_name\":\"" + NAME + "\"}";
private static final String JSON_FULL = String.format("{\"role_name\":\"%s\",\"role_id\":\"%s\",\"bind_secret_id\":%s,\"secret_id_bound_cidrs\":\"%s\",\"secret_id_num_uses\":%d,\"secret_id_ttl\":%d,\"local_secret_ids\":%s,\"token_ttl\":%d,\"token_max_ttl\":%d,\"token_policies\":\"%s\",\"token_bound_cidrs\":\"%s\",\"token_explicit_max_ttl\":%d,\"token_no_default_policy\":%s,\"token_num_uses\":%d,\"token_period\":%d,\"token_type\":\"%s\"}",
NAME, ID, BIND_SECRET_ID, CIDR_1, SECRET_ID_NUM_USES, SECRET_ID_TTL, LOCAL_SECRET_IDS, TOKEN_TTL, TOKEN_MAX_TTL, POLICY, CIDR_1, TOKEN_EXPLICIT_MAX_TTL, TOKEN_NO_DEFAULT_POLICY, TOKEN_NUM_USES, TOKEN_PERIOD, TOKEN_TYPE.value());
AppRoleTest() {
super(AppRole.class);
}
@Override
protected AppRole createFull() {
return AppRole.builder(NAME)
.withId(ID)
.withBindSecretID(BIND_SECRET_ID)
.withSecretIdBoundCidrs(BOUND_CIDR_LIST)
.withTokenPolicies(POLICIES)
.withSecretIdNumUses(SECRET_ID_NUM_USES)
.withSecretIdTtl(SECRET_ID_TTL)
.withLocalSecretIds(LOCAL_SECRET_IDS)
.withTokenTtl(TOKEN_TTL)
.withTokenMaxTtl(TOKEN_MAX_TTL)
.withTokenBoundCidrs(BOUND_CIDR_LIST)
.withTokenExplicitMaxTtl(TOKEN_EXPLICIT_MAX_TTL)
.withTokenNoDefaultPolicy(TOKEN_NO_DEFAULT_POLICY)
.withTokenNumUses(TOKEN_NUM_USES)
.withTokenPeriod(TOKEN_PERIOD)
.withTokenType(TOKEN_TYPE)
.build();
}
@BeforeAll
static void init() {
BOUND_CIDR_LIST.add(CIDR_1);
POLICIES.add(POLICY);
}
/**
* Build role with only a name.
*/
@Test
void buildDefaultTest() throws JsonProcessingException {
AppRole role = AppRole.builder(NAME).build();
assertNull(role.getId());
assertNull(role.getBindSecretId());
assertNull(role.getSecretIdBoundCidrs());
assertNull(role.getTokenPolicies());
assertNull(role.getSecretIdNumUses());
assertNull(role.getSecretIdTtl());
assertNull(role.getLocalSecretIds());
assertNull(role.getTokenTtl());
assertNull(role.getTokenMaxTtl());
assertNull(role.getTokenBoundCidrs());
assertNull(role.getTokenExplicitMaxTtl());
assertNull(role.getTokenNoDefaultPolicy());
assertNull(role.getTokenNumUses());
assertNull(role.getTokenPeriod());
assertNull(role.getTokenType());
// Optional fields should be ignored, so JSON string should only contain role_name.
assertEquals(JSON_MIN, objectMapper.writeValueAsString(role));
}
/**
* Build token without all parameters set.
*/
@Test
void buildFullTest() throws JsonProcessingException {
AppRole role = createFull();
assertEquals(NAME, role.getName());
assertEquals(ID, role.getId());
assertEquals(BIND_SECRET_ID, role.getBindSecretId());
assertEquals(BOUND_CIDR_LIST, role.getSecretIdBoundCidrs());
assertEquals(POLICIES, role.getTokenPolicies());
assertEquals(SECRET_ID_NUM_USES, role.getSecretIdNumUses());
assertEquals(SECRET_ID_TTL, role.getSecretIdTtl());
assertEquals(LOCAL_SECRET_IDS, role.getLocalSecretIds());
assertEquals(TOKEN_TTL, role.getTokenTtl());
assertEquals(TOKEN_MAX_TTL, role.getTokenMaxTtl());
assertEquals(BOUND_CIDR_LIST, role.getTokenBoundCidrs());
assertEquals(TOKEN_EXPLICIT_MAX_TTL, role.getTokenExplicitMaxTtl());
assertEquals(TOKEN_NO_DEFAULT_POLICY, role.getTokenNoDefaultPolicy());
assertEquals(TOKEN_NUM_USES, role.getTokenNumUses());
assertEquals(TOKEN_PERIOD, role.getTokenPeriod());
assertEquals(TOKEN_TYPE.value(), role.getTokenType());
// Verify that all parameters are included in JSON string.
assertEquals(JSON_FULL, objectMapper.writeValueAsString(role));
}
/**
* Test convenience methods
*/
@Test
void convenienceMethodsTest() {
// bind_secret_id.
AppRole role = AppRole.builder(NAME).build();
assertNull(role.getBindSecretId());
role = AppRole.builder(NAME).withBindSecretID().build();
assertEquals(true, role.getBindSecretId());
role = AppRole.builder(NAME).withoutBindSecretID().build();
assertEquals(false, role.getBindSecretId());
// Add single CIDR subnet.
role = AppRole.builder(NAME).withSecretBoundCidr(CIDR_2).withTokenBoundCidr(CIDR_2).build();
assertEquals(1, role.getSecretIdBoundCidrs().size());
assertEquals(CIDR_2, role.getSecretIdBoundCidrs().get(0));
assertEquals(1, role.getTokenBoundCidrs().size());
assertEquals(CIDR_2, role.getTokenBoundCidrs().get(0));
role = AppRole.builder(NAME)
.withSecretIdBoundCidrs(BOUND_CIDR_LIST)
.withSecretBoundCidr(CIDR_2)
.withTokenBoundCidrs(BOUND_CIDR_LIST)
.withTokenBoundCidr(CIDR_2)
.build();
assertEquals(2, role.getSecretIdBoundCidrs().size());
assertTrue(role.getSecretIdBoundCidrs().containsAll(List.of(CIDR_1, CIDR_2)));
assertEquals(2, role.getTokenBoundCidrs().size());
assertTrue(role.getSecretIdBoundCidrs().containsAll(List.of(CIDR_1, CIDR_2)));
// Add single policy.
role = AppRole.builder(NAME).withTokenPolicy(POLICY_2).build();
assertEquals(1, role.getTokenPolicies().size());
assertEquals(POLICY_2, role.getTokenPolicies().get(0));
role = AppRole.builder(NAME)
.withTokenPolicies(POLICIES)
.withTokenPolicy(POLICY_2)
.build();
assertEquals(2, role.getTokenPolicies().size());
assertTrue(role.getTokenPolicies().containsAll(List.of(POLICY, POLICY_2)));
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* JUnit Test for AuthBackend model.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
class AuthBackendTest {
/**
* Test forType() method.
*/
@Test
void forTypeTest() {
assertEquals(AuthBackend.TOKEN, AuthBackend.forType("token"));
assertEquals(AuthBackend.USERPASS, AuthBackend.forType("userpass"));
assertEquals(AuthBackend.GITHUB, AuthBackend.forType("github"));
assertEquals(AuthBackend.UNKNOWN, AuthBackend.forType(""));
assertEquals(AuthBackend.UNKNOWN, AuthBackend.forType("foobar"));
}
}

View File

@ -1,212 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit Test for {@link TokenRole} and {@link TokenRole.Builder}.
*
* @author Stefan Kalscheuer
* @since 0.9
*/
class TokenRoleTest extends AbstractModelTest<TokenRole> {
private static final String NAME = "test-role";
private static final String ALLOWED_POLICY_1 = "apol-1";
private static final String ALLOWED_POLICY_2 = "apol-2";
private static final String ALLOWED_POLICY_3 = "apol-3";
private static final List<String> ALLOWED_POLICIES = Arrays.asList(ALLOWED_POLICY_1, ALLOWED_POLICY_2);
private static final String ALLOWED_POLICY_GLOB_1 = "apol-g1*";
private static final String ALLOWED_POLICY_GLOB_2 = "apol-g2*";
private static final String ALLOWED_POLICY_GLOB_3 = "apol-g3*";
private static final List<String> ALLOWED_POLICIES_GLOB = Arrays.asList(ALLOWED_POLICY_GLOB_2, ALLOWED_POLICY_GLOB_3);
private static final String DISALLOWED_POLICY_1 = "dpol-1";
private static final String DISALLOWED_POLICY_2 = "dpol-2";
private static final String DISALLOWED_POLICY_3 = "dpol-3";
private static final List<String> DISALLOWED_POLICIES = Arrays.asList(DISALLOWED_POLICY_2, DISALLOWED_POLICY_3);
private static final String DISALLOWED_POLICY_GLOB_1 = "dpol-g1*";
private static final String DISALLOWED_POLICY_GLOB_2 = "dpol-g2*";
private static final String DISALLOWED_POLICY_GLOB_3 = "dpol-g3*";
private static final List<String> DISALLOWED_POLICIES_GLOB = Arrays.asList(DISALLOWED_POLICY_GLOB_1, DISALLOWED_POLICY_GLOB_2);
private static final Boolean ORPHAN = false;
private static final Boolean RENEWABLE = true;
private static final String PATH_SUFFIX = "ps";
private static final String ALLOWED_ENTITY_ALIAS_1 = "alias-1";
private static final String ALLOWED_ENTITY_ALIAS_2 = "alias-2";
private static final String ALLOWED_ENTITY_ALIAS_3 = "alias-3";
private static final List<String> ALLOWED_ENTITY_ALIASES = Arrays.asList(ALLOWED_ENTITY_ALIAS_1, ALLOWED_ENTITY_ALIAS_3);
private static final String TOKEN_BOUND_CIDR_1 = "192.0.2.0/24";
private static final String TOKEN_BOUND_CIDR_2 = "198.51.100.0/24";
private static final String TOKEN_BOUND_CIDR_3 = "203.0.113.0/24";
private static final List<String> TOKEN_BOUND_CIDRS = Arrays.asList(TOKEN_BOUND_CIDR_2, TOKEN_BOUND_CIDR_1);
private static final Integer TOKEN_EXPLICIT_MAX_TTL = 1234;
private static final Boolean TOKEN_NO_DEFAULT_POLICY = false;
private static final Integer TOKEN_NUM_USES = 5;
private static final Integer TOKEN_PERIOD = 2345;
private static final Token.Type TOKEN_TYPE = Token.Type.SERVICE;
private static final String JSON_FULL = "{" +
"\"name\":\"" + NAME + "\"," +
"\"allowed_policies\":[\"" + ALLOWED_POLICY_1 + "\",\"" + ALLOWED_POLICY_2 + "\",\"" + ALLOWED_POLICY_3 + "\"]," +
"\"allowed_policies_glob\":[\"" + ALLOWED_POLICY_GLOB_1 + "\",\"" + ALLOWED_POLICY_GLOB_2 + "\",\"" + ALLOWED_POLICY_GLOB_3 + "\"]," +
"\"disallowed_policies\":[\"" + DISALLOWED_POLICY_1 + "\",\"" + DISALLOWED_POLICY_2 + "\",\"" + DISALLOWED_POLICY_3 + "\"]," +
"\"disallowed_policies_glob\":[\"" + DISALLOWED_POLICY_GLOB_1 + "\",\"" + DISALLOWED_POLICY_GLOB_2 + "\",\"" + DISALLOWED_POLICY_GLOB_3 + "\"]," +
"\"orphan\":" + ORPHAN + "," +
"\"renewable\":" + RENEWABLE + "," +
"\"path_suffix\":\"" + PATH_SUFFIX + "\"," +
"\"allowed_entity_aliases\":[\"" + ALLOWED_ENTITY_ALIAS_1 + "\",\"" + ALLOWED_ENTITY_ALIAS_3 + "\",\"" + ALLOWED_ENTITY_ALIAS_2 + "\"]," +
"\"token_bound_cidrs\":[\"" + TOKEN_BOUND_CIDR_3 + "\",\"" + TOKEN_BOUND_CIDR_2 + "\",\"" + TOKEN_BOUND_CIDR_1 + "\"]," +
"\"token_explicit_max_ttl\":" + TOKEN_EXPLICIT_MAX_TTL + "," +
"\"token_no_default_policy\":" + TOKEN_NO_DEFAULT_POLICY + "," +
"\"token_num_uses\":" + TOKEN_NUM_USES + "," +
"\"token_period\":" + TOKEN_PERIOD + "," +
"\"token_type\":\"" + TOKEN_TYPE.value() + "\"}";
TokenRoleTest() {
super(TokenRole.class);
}
@Override
protected TokenRole createFull() {
return TokenRole.builder()
.forName(NAME)
.withAllowedPolicies(ALLOWED_POLICIES)
.withAllowedPolicy(ALLOWED_POLICY_3)
.withAllowedPolicyGlob(ALLOWED_POLICY_GLOB_1)
.withAllowedPoliciesGlob(ALLOWED_POLICIES_GLOB)
.withDisallowedPolicy(DISALLOWED_POLICY_1)
.withDisallowedPolicies(DISALLOWED_POLICIES)
.withDisallowedPoliciesGlob(DISALLOWED_POLICIES_GLOB)
.withDisallowedPolicyGlob(DISALLOWED_POLICY_GLOB_3)
.orphan(ORPHAN)
.renewable(RENEWABLE)
.withPathSuffix(PATH_SUFFIX)
.withAllowedEntityAliases(ALLOWED_ENTITY_ALIASES)
.withAllowedEntityAlias(ALLOWED_ENTITY_ALIAS_2)
.withTokenBoundCidr(TOKEN_BOUND_CIDR_3)
.withTokenBoundCidrs(TOKEN_BOUND_CIDRS)
.withTokenExplicitMaxTtl(TOKEN_EXPLICIT_MAX_TTL)
.withTokenNoDefaultPolicy(TOKEN_NO_DEFAULT_POLICY)
.withTokenNumUses(TOKEN_NUM_USES)
.withTokenPeriod(TOKEN_PERIOD)
.withTokenType(TOKEN_TYPE)
.build();
}
/**
* Build token without any parameters.
*/
@Test
void buildDefaultTest() throws JsonProcessingException {
TokenRole role = TokenRole.builder().build();
assertNull(role.getAllowedPolicies());
assertNull(role.getDisallowedPolicies());
assertNull(role.getOrphan());
assertNull(role.getRenewable());
assertNull(role.getAllowedEntityAliases());
assertNull(role.getTokenBoundCidrs());
assertNull(role.getTokenExplicitMaxTtl());
assertNull(role.getTokenNoDefaultPolicy());
assertNull(role.getTokenNumUses());
assertNull(role.getTokenPeriod());
assertNull(role.getTokenType());
// Optional fields should be ignored, so JSON string should be empty.
assertEquals("{}", objectMapper.writeValueAsString(role));
}
/**
* Build token without all parameters NULL.
*/
@Test
void buildNullTest() throws JsonProcessingException {
TokenRole role = TokenRole.builder()
.forName(null)
.withAllowedPolicies(null)
.withAllowedPolicy(null)
.withDisallowedPolicy(null)
.withDisallowedPolicies(null)
.orphan(null)
.renewable(null)
.withPathSuffix(null)
.withAllowedEntityAliases(null)
.withAllowedEntityAlias(null)
.withTokenBoundCidr(null)
.withTokenBoundCidrs(null)
.withTokenExplicitMaxTtl(null)
.withTokenNoDefaultPolicy(null)
.withTokenNumUses(null)
.withTokenPeriod(null)
.withTokenType(null)
.build();
assertNull(role.getAllowedPolicies());
assertNull(role.getDisallowedPolicies());
assertNull(role.getOrphan());
assertNull(role.getRenewable());
assertNull(role.getAllowedEntityAliases());
assertNull(role.getTokenBoundCidrs());
assertNull(role.getTokenExplicitMaxTtl());
assertNull(role.getTokenNoDefaultPolicy());
assertNull(role.getTokenNumUses());
assertNull(role.getTokenPeriod());
assertNull(role.getTokenType());
// Empty builder should be equal to no-arg construction.
assertEquals(new TokenRole(), role);
// Optional fields should be ignored, so JSON string should be empty.
assertEquals("{}", objectMapper.writeValueAsString(role));
}
/**
* Build token without all parameters set.
*/
@Test
void buildFullTest() throws JsonProcessingException {
TokenRole role = createFull();
assertEquals(NAME, role.getName());
assertEquals(ALLOWED_POLICIES.size() + 1, role.getAllowedPolicies().size());
assertTrue(role.getAllowedPolicies().containsAll(List.of(ALLOWED_POLICY_1, ALLOWED_POLICY_2, ALLOWED_POLICY_3)));
assertEquals(ALLOWED_POLICIES_GLOB.size() + 1, role.getAllowedPoliciesGlob().size());
assertTrue(role.getAllowedPoliciesGlob().containsAll(List.of(ALLOWED_POLICY_GLOB_1, ALLOWED_POLICY_GLOB_2, ALLOWED_POLICY_GLOB_3)));
assertEquals(DISALLOWED_POLICIES.size() + 1, role.getDisallowedPolicies().size());
assertTrue(role.getDisallowedPolicies().containsAll(List.of(DISALLOWED_POLICY_1, DISALLOWED_POLICY_2, DISALLOWED_POLICY_3)));
assertEquals(DISALLOWED_POLICIES_GLOB.size() + 1, role.getDisallowedPoliciesGlob().size());
assertTrue(role.getDisallowedPoliciesGlob().containsAll(List.of(DISALLOWED_POLICY_GLOB_1, DISALLOWED_POLICY_GLOB_2, DISALLOWED_POLICY_GLOB_3)));
assertEquals(ORPHAN, role.getOrphan());
assertEquals(RENEWABLE, role.getRenewable());
assertEquals(PATH_SUFFIX, role.getPathSuffix());
assertEquals(ALLOWED_ENTITY_ALIASES.size() + 1, role.getAllowedEntityAliases().size());
assertTrue(role.getAllowedEntityAliases().containsAll(List.of(ALLOWED_ENTITY_ALIAS_1, ALLOWED_ENTITY_ALIAS_2, ALLOWED_ENTITY_ALIAS_3)));
assertEquals(TOKEN_BOUND_CIDRS.size() + 1, role.getTokenBoundCidrs().size());
assertTrue(role.getTokenBoundCidrs().containsAll(List.of(TOKEN_BOUND_CIDR_1, TOKEN_BOUND_CIDR_2, TOKEN_BOUND_CIDR_3)));
assertEquals(TOKEN_NO_DEFAULT_POLICY, role.getTokenNoDefaultPolicy());
assertEquals(TOKEN_NUM_USES, role.getTokenNumUses());
assertEquals(TOKEN_PERIOD, role.getTokenPeriod());
assertEquals(TOKEN_TYPE.value(), role.getTokenType());
// Verify that all parameters are included in JSON string.
assertEquals(JSON_FULL, objectMapper.writeValueAsString(role));
}
}

View File

@ -1,181 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link Token} and {@link Token.Builder}.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
class TokenTest extends AbstractModelTest<Token> {
private static final String ID = "test-id";
private static final String DISPLAY_NAME = "display-name";
private static final Boolean NO_PARENT = false;
private static final Boolean NO_DEFAULT_POLICY = false;
private static final Integer TTL = 123;
private static final Integer EXPLICIT_MAX_TTL = 456;
private static final Integer NUM_USES = 4;
private static final List<String> POLICIES = new ArrayList<>();
private static final String POLICY = "policy";
private static final String POLICY_2 = "policy2";
private static final String POLICY_3 = "policy3";
private static final Map<String, String> META = new HashMap<>();
private static final String META_KEY = "key";
private static final String META_VALUE = "value";
private static final String META_KEY_2 = "key2";
private static final String META_VALUE_2 = "value2";
private static final Boolean RENEWABLE = true;
private static final Integer PERIOD = 3600;
private static final String ENTITY_ALIAS = "alias-value";
private static final String JSON_FULL = "{\"id\":\"test-id\",\"type\":\"service\",\"display_name\":\"display-name\",\"no_parent\":false,\"no_default_policy\":false,\"ttl\":123,\"explicit_max_ttl\":456,\"num_uses\":4,\"policies\":[\"policy\"],\"meta\":{\"key\":\"value\"},\"renewable\":true,\"period\":3600,\"entity_alias\":\"alias-value\"}";
TokenTest() {
super(Token.class);
}
@Override
protected Token createFull() {
return Token.builder()
.withId(ID)
.withType(Token.Type.SERVICE)
.withDisplayName(DISPLAY_NAME)
.withNoParent(NO_PARENT)
.withNoDefaultPolicy(NO_DEFAULT_POLICY)
.withTtl(TTL)
.withExplicitMaxTtl(EXPLICIT_MAX_TTL)
.withNumUses(NUM_USES)
.withPolicies(POLICIES)
.withMeta(META)
.withRenewable(RENEWABLE)
.withPeriod(PERIOD)
.withEntityAlias(ENTITY_ALIAS)
.build();
}
@BeforeAll
static void init() {
POLICIES.add(POLICY);
META.put(META_KEY, META_VALUE);
}
/**
* Build token without any parameters.
*/
@Test
void buildDefaultTest() throws JsonProcessingException {
Token token = Token.builder().build();
assertNull(token.getId());
assertNull(token.getType());
assertNull(token.getDisplayName());
assertNull(token.getNoParent());
assertNull(token.getNoDefaultPolicy());
assertNull(token.getTtl());
assertNull(token.getExplicitMaxTtl());
assertNull(token.getNumUses());
assertNull(token.getPolicies());
assertNull(token.getMeta());
assertNull(token.isRenewable());
assertNull(token.getPeriod());
assertNull(token.getEntityAlias());
// Optional fields should be ignored, so JSON string should be empty.
assertEquals("{}", objectMapper.writeValueAsString(token));
// Empty builder should be equal to no-arg construction.
assertEquals(new Token(), token);
}
/**
* Build token without all parameters set.
*/
@Test
void buildFullTest() throws JsonProcessingException {
Token token = createFull();
assertEquals(ID, token.getId());
assertEquals(Token.Type.SERVICE.value(), token.getType());
assertEquals(DISPLAY_NAME, token.getDisplayName());
assertEquals(NO_PARENT, token.getNoParent());
assertEquals(NO_DEFAULT_POLICY, token.getNoDefaultPolicy());
assertEquals(TTL, token.getTtl());
assertEquals(EXPLICIT_MAX_TTL, token.getExplicitMaxTtl());
assertEquals(NUM_USES, token.getNumUses());
assertEquals(POLICIES, token.getPolicies());
assertEquals(META, token.getMeta());
assertEquals(RENEWABLE, token.isRenewable());
assertEquals(PERIOD, token.getPeriod());
// Verify that all parameters are included in JSON string.
assertEquals(JSON_FULL, objectMapper.writeValueAsString(token));
}
/**
* Test convenience methods
*/
@Test
void convenienceMethodsTest() {
// Parent.
Token token = Token.builder().asOrphan().build();
assertEquals(true, token.getNoParent());
token = Token.builder().withParent().build();
assertEquals(false, token.getNoParent());
// Default policy.
token = Token.builder().withDefaultPolicy().build();
assertEquals(false, token.getNoDefaultPolicy());
token = Token.builder().withoutDefaultPolicy().build();
assertEquals(true, token.getNoDefaultPolicy());
// Renewability.
token = Token.builder().renewable().build();
assertEquals(true, token.isRenewable());
token = Token.builder().notRenewable().build();
assertEquals(false, token.isRenewable());
// Add single policy.
token = Token.builder().withPolicy(POLICY_2).build();
assertEquals(1, token.getPolicies().size());
assertEquals(List.of(POLICY_2), token.getPolicies());
token = Token.builder()
.withPolicies(POLICY, POLICY_2)
.withPolicy(POLICY_3)
.build();
assertEquals(3, token.getPolicies().size());
assertTrue(token.getPolicies().containsAll(List.of(POLICY, POLICY_2, POLICY_3)));
// Add single metadata.
token = Token.builder().withMeta(META_KEY_2, META_VALUE_2).build();
assertEquals(1, token.getMeta().size());
assertEquals(Set.of(META_KEY_2), token.getMeta().keySet());
assertEquals(META_VALUE_2, token.getMeta().get(META_KEY_2));
token = Token.builder()
.withMeta(META)
.withMeta(META_KEY_2, META_VALUE_2)
.build();
assertEquals(2, token.getMeta().size());
assertEquals(META_VALUE, token.getMeta().get(META_KEY));
assertEquals(META_VALUE_2, token.getMeta().get(META_KEY_2));
}
}

View File

@ -1,111 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import de.stklcode.jvault.connector.model.AppRole;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link AppRoleResponse} model.
*
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class AppRoleResponseTest extends AbstractModelTest<AppRoleResponse> {
private static final Integer ROLE_TOKEN_TTL = 1200;
private static final Integer ROLE_TOKEN_MAX_TTL = 1800;
private static final Integer ROLE_SECRET_TTL = 600;
private static final Integer ROLE_SECRET_NUM_USES = 40;
private static final String ROLE_POLICY = "default";
private static final Integer ROLE_PERIOD = 0;
private static final Boolean ROLE_BIND_SECRET = true;
private static final String RES_JSON = "{\n" +
" \"auth\": null,\n" +
" \"warnings\": null,\n" +
" \"wrap_info\": null,\n" +
" \"data\": {\n" +
" \"token_ttl\": " + ROLE_TOKEN_TTL + ",\n" +
" \"token_max_ttl\": " + ROLE_TOKEN_MAX_TTL + ",\n" +
" \"secret_id_ttl\": " + ROLE_SECRET_TTL + ",\n" +
" \"secret_id_num_uses\": " + ROLE_SECRET_NUM_USES + ",\n" +
" \"token_policies\": [\n" +
" \"" + ROLE_POLICY + "\"\n" +
" ],\n" +
" \"token_period\": " + ROLE_PERIOD + ",\n" +
" \"bind_secret_id\": " + ROLE_BIND_SECRET + ",\n" +
" \"bound_cidr_list\": \"\"\n" +
" },\n" +
" \"lease_duration\": 0,\n" +
" \"renewable\": false,\n" +
" \"lease_id\": \"\"\n" +
"}";
AppRoleResponseTest() {
super(AppRoleResponse.class);
}
@Override
protected AppRoleResponse createFull() {
try {
return objectMapper.readValue(RES_JSON, AppRoleResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test getter, setter and get-methods for response data.
*/
@Test
void getDataRoundtrip() {
// Create empty Object.
AppRoleResponse res = new AppRoleResponse();
assertNull(res.getRole(), "Initial data should be empty");
}
/**
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
*/
@Test
void jsonRoundtrip() {
AppRoleResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(RES_JSON, AppRoleResponse.class),
"AuthResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
// Extract role data.
AppRole role = res.getRole();
assertNotNull(role, "Role data is NULL");
assertEquals(ROLE_TOKEN_TTL, role.getTokenTtl(), "Incorrect token TTL");
assertEquals(ROLE_TOKEN_MAX_TTL, role.getTokenMaxTtl(), "Incorrect token max TTL");
assertEquals(ROLE_SECRET_TTL, role.getSecretIdTtl(), "Incorrect secret ID TTL");
assertEquals(ROLE_SECRET_NUM_USES, role.getSecretIdNumUses(), "Incorrect secret ID umber of uses");
assertEquals(List.of(ROLE_POLICY), role.getTokenPolicies(), "Incorrect policies");
assertEquals(ROLE_PERIOD, role.getTokenPeriod(), "Incorrect role period");
assertEquals(ROLE_BIND_SECRET, role.getBindSecretId(), "Incorrect role bind secret ID flag");
assertNull(role.getTokenBoundCidrs(), "Incorrect bound CIDR list");
assertEquals("", role.getTokenBoundCidrsString(), "Incorrect bound CIDR list string");
}
}

View File

@ -1,161 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import de.stklcode.jvault.connector.model.AuthBackend;
import de.stklcode.jvault.connector.model.response.embedded.AuthMethod;
import org.junit.jupiter.api.Test;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link AuthMethodsResponse} model.
*
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class AuthMethodsResponseTest extends AbstractModelTest<AuthMethodsResponse> {
private static final String GH_PATH = "github/";
private static final String GH_TYPE = "github";
private static final String GH_UUID = "4b42d1a4-0a0d-3c88-ae90-997e0c8b41be";
private static final String GH_ACCESSOR = "auth_github_badd7fd0";
private static final String GH_DESCR = "GitHub auth";
private static final String TK_PATH = "token/";
private static final String TK_TYPE = "token";
private static final String TK_UUID = "32ea9681-6bd6-6cec-eec3-d11260ba9741";
private static final String TK_ACCESSOR = "auth_token_ac0dd95a";
private static final String TK_DESCR = "token based credentials";
private static final Integer TK_LEASE_TTL = 0;
private static final Boolean TK_FORCE_NO_CACHE = false;
private static final Integer TK_MAX_LEASE_TTL = 0;
private static final String TK_TOKEN_TYPE = "default-service";
private static final String TK_RUNNING_PLUGIN_VERSION = "v1.15.3+builtin.vault";
private static final String RES_JSON = "{\n" +
" \"data\": {" +
" \"" + GH_PATH + "\": {\n" +
" \"uuid\": \"" + GH_UUID + "\",\n" +
" \"type\": \"" + GH_TYPE + "\",\n" +
" \"accessor\": \"" + GH_ACCESSOR + "\",\n" +
" \"description\": \"" + GH_DESCR + "\",\n" +
" \"external_entropy_access\": false,\n" +
" \"local\": false,\n" +
" \"seal_wrap\": false\n" +
" },\n" +
" \"" + TK_PATH + "\": {\n" +
" \"config\": {\n" +
" \"default_lease_ttl\": " + TK_LEASE_TTL + ",\n" +
" \"force_no_cache\": " + TK_FORCE_NO_CACHE + ",\n" +
" \"max_lease_ttl\": " + TK_MAX_LEASE_TTL + ",\n" +
" \"token_type\": \"" + TK_TOKEN_TYPE + "\"\n" +
" },\n" +
" \"description\": \"" + TK_DESCR + "\",\n" +
" \"options\": null,\n" +
" \"plugin_version\": \"\",\n" +
" \"running_plugin_version\": \"" + TK_RUNNING_PLUGIN_VERSION + "\",\n" +
" \"running_sha256\": \"\",\n" +
" \"type\": \"" + TK_TYPE + "\",\n" +
" \"uuid\": \"" + TK_UUID + "\",\n" +
" \"accessor\": \"" + TK_ACCESSOR + "\",\n" +
" \"external_entropy_access\": false,\n" +
" \"local\": true,\n" +
" \"seal_wrap\": false\n" +
" }\n" +
" }\n" +
"}";
AuthMethodsResponseTest() {
super(AuthMethodsResponse.class);
}
@Override
protected AuthMethodsResponse createFull() {
try {
return objectMapper.readValue(RES_JSON, AuthMethodsResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test getter, setter and get-methods for response data.
*/
@Test
void getDataRoundtrip() {
// Create empty Object.
AuthMethodsResponse res = new AuthMethodsResponse();
assertEquals(Collections.emptyMap(), res.getSupportedMethods(), "Initial method map should be empty");
}
/**
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
*/
@Test
void jsonRoundtrip() {
AuthMethodsResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(RES_JSON, AuthMethodsResponse.class),
"AuthResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
// Extract auth data.
Map<String, AuthMethod> supported = res.getSupportedMethods();
assertNotNull(supported, "Auth data is NULL");
assertEquals(2, supported.size(), "Incorrect number of supported methods");
assertTrue(supported.keySet().containsAll(Set.of(GH_PATH, TK_PATH)), "Incorrect method paths");
// Verify first method.
AuthMethod method = supported.get(GH_PATH);
assertEquals(GH_TYPE, method.getRawType(), "Incorrect raw type for GitHub");
assertEquals(AuthBackend.GITHUB, method.getType(), "Incorrect parsed type for GitHub");
assertEquals(GH_DESCR, method.getDescription(), "Incorrect description for GitHub");
assertNull(method.getConfig(), "Unexpected config for GitHub");
assertEquals(GH_UUID, method.getUuid(), "Unexpected UUID for GitHub");
assertEquals(GH_ACCESSOR, method.getAccessor(), "Unexpected accessor for GitHub");
assertFalse(method.isLocal(), "Unexpected local flag for GitHub");
assertFalse(method.isExternalEntropyAccess(), "Unexpected external entropy flag for GitHub");
assertFalse(method.isSealWrap(), "Unexpected seal wrap flag for GitHub");
// Verify second method.
method = supported.get(TK_PATH);
assertEquals(TK_TYPE, method.getRawType(), "Incorrect raw type for Token");
assertEquals(AuthBackend.TOKEN, method.getType(), "Incorrect parsed type for Token");
assertEquals(TK_DESCR, method.getDescription(), "Incorrect description for Token");
assertEquals(TK_UUID, method.getUuid(), "Unexpected UUID for Token");
assertEquals(TK_ACCESSOR, method.getAccessor(), "Unexpected accessor for Token");
assertTrue(method.isLocal(), "Unexpected local flag for Token");
assertFalse(method.isExternalEntropyAccess(), "Unexpected external entropy flag for Token");
assertFalse(method.isSealWrap(), "Unexpected seal wrap flag for GitHub");
assertEquals("", method.getPluginVersion(), "Unexpected plugin version");
assertEquals(TK_RUNNING_PLUGIN_VERSION, method.getRunningPluginVersion(), "Unexpected running plugin version");
assertEquals("", method.getRunningSha256(), "Unexpected running SHA256");
assertNotNull(method.getConfig(), "Missing config for Token");
assertEquals(TK_LEASE_TTL, method.getConfig().getDefaultLeaseTtl(), "Unexpected default TTL");
assertEquals(TK_MAX_LEASE_TTL, method.getConfig().getMaxLeaseTtl(), "Unexpected max TTL");
assertEquals(TK_FORCE_NO_CACHE, method.getConfig().getForceNoCache(), "Unexpected force no cache flag");
assertEquals(TK_TOKEN_TYPE, method.getConfig().getTokenType(), "Unexpected token type");
assertNull(method.getOptions(), "Unexpected options");
}
}

View File

@ -1,155 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import de.stklcode.jvault.connector.model.response.embedded.AuthData;
import de.stklcode.jvault.connector.model.response.embedded.MfaConstraintAny;
import de.stklcode.jvault.connector.model.response.embedded.MfaMethodId;
import de.stklcode.jvault.connector.model.response.embedded.MfaRequirement;
import nl.jqno.equalsverifier.EqualsVerifier;
import org.junit.jupiter.api.Test;
import java.util.Map;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link AuthResponse} model.
*
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class AuthResponseTest extends AbstractModelTest<AuthResponse> {
private static final String AUTH_ACCESSOR = "2c84f488-2133-4ced-87b0-570f93a76830";
private static final String AUTH_CLIENT_TOKEN = "ABCD";
private static final String AUTH_POLICY_1 = "web";
private static final String AUTH_POLICY_2 = "stage";
private static final String AUTH_META_KEY = "user";
private static final String AUTH_META_VALUE = "armon";
private static final Integer AUTH_LEASE_DURATION = 3600;
private static final Boolean AUTH_RENEWABLE = true;
private static final String AUTH_ENTITY_ID = "";
private static final String AUTH_TOKEN_TYPE = "service";
private static final Boolean AUTH_ORPHAN = false;
private static final Integer AUTH_NUM_USES = 42;
private static final String MFA_REQUEST_ID = "d0c9eec7-6921-8cc0-be62-202b289ef163";
private static final String MFA_KEY = "enforcementConfigUserpass";
private static final String MFA_METHOD_TYPE = "totp";
private static final String MFA_METHOD_ID = "820997b3-110e-c251-7e8b-ff4aa428a6e1";
private static final Boolean MFA_METHOD_USES_PASSCODE = true;
private static final String MFA_METHOD_NAME = "sample_mfa_method_name";
private static final String RES_JSON = "{\n" +
" \"auth\": {\n" +
" \"accessor\": \"" + AUTH_ACCESSOR + "\",\n" +
" \"client_token\": \"" + AUTH_CLIENT_TOKEN + "\",\n" +
" \"policies\": [\n" +
" \"" + AUTH_POLICY_1 + "\", \n" +
" \"" + AUTH_POLICY_2 + "\"\n" +
" ],\n" +
" \"token_policies\": [\n" +
" \"" + AUTH_POLICY_2 + "\",\n" +
" \"" + AUTH_POLICY_1 + "\" \n" +
" ],\n" +
" \"metadata\": {\n" +
" \"" + AUTH_META_KEY + "\": \"" + AUTH_META_VALUE + "\"\n" +
" },\n" +
" \"lease_duration\": " + AUTH_LEASE_DURATION + ",\n" +
" \"renewable\": " + AUTH_RENEWABLE + ",\n" +
" \"entity_id\": \"" + AUTH_ENTITY_ID + "\",\n" +
" \"token_type\": \"" + AUTH_TOKEN_TYPE + "\",\n" +
" \"orphan\": " + AUTH_ORPHAN + ",\n" +
" \"num_uses\": " + AUTH_NUM_USES + ",\n" +
" \"mfa_requirement\": {\n" +
" \"mfa_request_id\": \"" + MFA_REQUEST_ID + "\",\n" +
" \"mfa_constraints\": {\n" +
" \"" + MFA_KEY + "\": {\n" +
" \"any\": [\n" +
" {\n" +
" \"type\": \"" + MFA_METHOD_TYPE + "\",\n" +
" \"id\": \"" + MFA_METHOD_ID + "\",\n" +
" \"uses_passcode\": " + MFA_METHOD_USES_PASSCODE + ",\n" +
" \"name\": \"" + MFA_METHOD_NAME + "\"\n" +
" }\n" +
" ]\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
"}";
AuthResponseTest() {
super(AuthResponse.class);
}
@Override
protected AuthResponse createFull() {
try {
return objectMapper.readValue(RES_JSON, AuthResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
@Test
void testEqualsHashcodeMfa() {
EqualsVerifier.simple().forClass(MfaRequirement.class).verify();
EqualsVerifier.simple().forClass(MfaConstraintAny.class).verify();
EqualsVerifier.simple().forClass(MfaMethodId.class).verify();
}
/**
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
*/
@Test
void jsonRoundtrip() {
AuthResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(RES_JSON, AuthResponse.class),
"AuthResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
// Extract auth data.
AuthData data = res.getAuth();
assertNotNull(data, "Auth data is NULL");
assertEquals(AUTH_ACCESSOR, data.getAccessor(), "Incorrect auth accessor");
assertEquals(AUTH_CLIENT_TOKEN, data.getClientToken(), "Incorrect auth client token");
assertEquals(AUTH_LEASE_DURATION, data.getLeaseDuration(), "Incorrect auth lease duration");
assertEquals(AUTH_RENEWABLE, data.isRenewable(), "Incorrect auth renewable flag");
assertEquals(AUTH_ORPHAN, data.isOrphan(), "Incorrect auth orphan flag");
assertEquals(AUTH_TOKEN_TYPE, data.getTokenType(), "Incorrect auth token type");
assertEquals(AUTH_ENTITY_ID, data.getEntityId(), "Incorrect auth entity id");
assertEquals(AUTH_NUM_USES, data.getNumUses(), "Incorrect auth num uses");
assertEquals(2, data.getPolicies().size(), "Incorrect number of policies");
assertTrue(data.getPolicies().containsAll(Set.of(AUTH_POLICY_1, AUTH_POLICY_2)));
assertEquals(2, data.getTokenPolicies().size(), "Incorrect number of token policies");
assertTrue(data.getTokenPolicies().containsAll(Set.of(AUTH_POLICY_2, AUTH_POLICY_1)), "Incorrect token policies");
assertEquals(Map.of(AUTH_META_KEY, AUTH_META_VALUE), data.getMetadata(), "Incorrect auth metadata");
assertEquals(MFA_REQUEST_ID, data.getMfaRequirement().getMfaRequestId(), "Incorrect MFA request ID");
assertEquals(Set.of(MFA_KEY), data.getMfaRequirement().getMfaConstraints().keySet(), "Incorrect MFA constraint keys");
var mfaConstraint = data.getMfaRequirement().getMfaConstraints().get(MFA_KEY);
assertEquals(1, mfaConstraint.getAny().size(), "Incorrect number of any constraints");
assertEquals(MFA_METHOD_TYPE, mfaConstraint.getAny().get(0).getType(), "Incorrect MFA method type");
assertEquals(MFA_METHOD_ID, mfaConstraint.getAny().get(0).getId(), "Incorrect MFA method type");
assertEquals(MFA_METHOD_USES_PASSCODE, mfaConstraint.getAny().get(0).getUsesPasscode(), "Incorrect MFA method uses passcode");
assertEquals(MFA_METHOD_NAME, mfaConstraint.getAny().get(0).getName(), "Incorrect MFA method uses passcode");
}
}

View File

@ -1,77 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link CredentialsResponse} model.
*
* @author Stefan Kalscheuer
* @since 0.8
*/
class CredentialsResponseTest extends AbstractModelTest<CredentialsResponse> {
private static final String VAL_USER = "testUserName";
private static final String VAL_PASS = "5up3r5ecr3tP455";
private static final String JSON = "{\n" +
" \"request_id\": \"68315073-6658-e3ff-2da7-67939fb91bbd\",\n" +
" \"lease_id\": \"\",\n" +
" \"lease_duration\": 2764800,\n" +
" \"renewable\": false,\n" +
" \"data\": {\n" +
" \"username\": \"" + VAL_USER + "\",\n" +
" \"password\": \"" + VAL_PASS + "\"\n" +
" },\n" +
" \"warnings\": null\n" +
"}";
CredentialsResponseTest() {
super(CredentialsResponse.class);
}
@Override
protected CredentialsResponse createFull() {
try {
return objectMapper.readValue(JSON, CredentialsResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test getter, setter and get-methods for response data.
*/
@Test
void getCredentialsTest() {
// Create empty Object.
CredentialsResponse res = new CredentialsResponse();
assertNull(res.getUsername(), "Username not present in data map should not return anything");
assertNull(res.getPassword(), "Password not present in data map should not return anything");
res = assertDoesNotThrow(
() -> objectMapper.readValue(JSON, CredentialsResponse.class),
"Deserialization of CredentialsResponse failed"
);
assertEquals(VAL_USER, res.getUsername(), "Incorrect username");
assertEquals(VAL_PASS, res.getPassword(), "Incorrect password");
}
}

View File

@ -1,88 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link ErrorResponse} model.
*
* @author Stefan Kalscheuer
*/
class ErrorResponseTest extends AbstractModelTest<ErrorResponse> {
private static final String ERROR_1 = "Error #1";
private static final String ERROR_2 = "Error #2";
private static final String JSON = "{\"errors\":[\"" + ERROR_1 + "\",\"" + ERROR_2 + "\"]}";
private static final String JSON_EMPTY = "{\"errors\":[]}";
ErrorResponseTest() {
super(ErrorResponse.class);
}
@Override
protected ErrorResponse createFull() {
try {
return objectMapper.readValue(JSON, ErrorResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test creation from JSON value as returned by Vault.
*/
@Test
void jsonRoundtrip() {
ErrorResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(JSON, ErrorResponse.class),
"ErrorResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
assertEquals(List.of(ERROR_1, ERROR_2), res.getErrors(), "Unexpected error messages");
assertEquals(
JSON,
assertDoesNotThrow(() -> objectMapper.writeValueAsString(res), "ErrorResponse serialization failed"),
"Unexpected JSON string after serialization"
);
}
@Test
void testToString() {
ErrorResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(JSON, ErrorResponse.class),
"ErrorResponse deserialization failed"
);
assertEquals(ERROR_1, res.toString());
res = assertDoesNotThrow(
() -> objectMapper.readValue(JSON_EMPTY, ErrorResponse.class),
"ErrorResponse deserialization failed with empty list"
);
assertEquals("error response", res.toString());
assertEquals("error response", new ErrorResponse().toString());
}
}

View File

@ -1,103 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link AuthResponse} model.
*
* @author Stefan Kalscheuer
* @since 0.7.0
*/
class HealthResponseTest extends AbstractModelTest<HealthResponse> {
private static final String CLUSTER_ID = "c9abceea-4f46-4dab-a688-5ce55f89e228";
private static final String CLUSTER_NAME = "vault-cluster-5515c810";
private static final String VERSION = "0.17.0";
private static final Long SERVER_TIME_UTC = 1469555798L;
private static final Boolean STANDBY = false;
private static final Boolean SEALED = false;
private static final Boolean INITIALIZED = true;
private static final Boolean PERF_STANDBY = false;
private static final String REPL_PERF_MODE = "disabled";
private static final String REPL_DR_MODE = "disabled";
private static final Long ECHO_DURATION = 1L;
private static final Long CLOCK_SKEW = 0L;
private static final Long REPL_PRIM_CANARY_AGE = 2L;
private static final Boolean ENTERPRISE = false;
private static final String RES_JSON = "{\n" +
" \"cluster_id\": \"" + CLUSTER_ID + "\",\n" +
" \"cluster_name\": \"" + CLUSTER_NAME + "\",\n" +
" \"version\": \"" + VERSION + "\",\n" +
" \"server_time_utc\": " + SERVER_TIME_UTC + ",\n" +
" \"standby\": " + STANDBY + ",\n" +
" \"sealed\": " + SEALED + ",\n" +
" \"initialized\": " + INITIALIZED + ",\n" +
" \"replication_performance_mode\": \"" + REPL_PERF_MODE + "\",\n" +
" \"replication_dr_mode\": \"" + REPL_DR_MODE + "\",\n" +
" \"performance_standby\": " + PERF_STANDBY + ",\n" +
" \"echo_duration_ms\": " + ECHO_DURATION + ",\n" +
" \"clock_skew_ms\": " + CLOCK_SKEW + ",\n" +
" \"replication_primary_canary_age_ms\": " + REPL_PRIM_CANARY_AGE + ",\n" +
" \"enterprise\": " + ENTERPRISE + "\n" +
"}";
HealthResponseTest() {
super(HealthResponse.class);
}
@Override
protected HealthResponse createFull() {
try {
return objectMapper.readValue(RES_JSON, HealthResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
*/
@Test
void jsonRoundtrip() {
HealthResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(RES_JSON, HealthResponse.class),
"Health deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
assertEquals(CLUSTER_ID, res.getClusterID(), "Incorrect cluster ID");
assertEquals(CLUSTER_NAME, res.getClusterName(), "Incorrect cluster name");
assertEquals(VERSION, res.getVersion(), "Incorrect version");
assertEquals(SERVER_TIME_UTC, res.getServerTimeUTC(), "Incorrect server time");
assertEquals(STANDBY, res.isStandby(), "Incorrect standby state");
assertEquals(SEALED, res.isSealed(), "Incorrect seal state");
assertEquals(INITIALIZED, res.isInitialized(), "Incorrect initialization state");
assertEquals(PERF_STANDBY, res.isPerformanceStandby(), "Incorrect performance standby state");
assertEquals(REPL_PERF_MODE, res.getReplicationPerfMode(), "Incorrect replication perf mode");
assertEquals(REPL_DR_MODE, res.getReplicationDrMode(), "Incorrect replication DR mode");
assertEquals(ECHO_DURATION, res.getEchoDurationMs(), "Incorrect echo duration");
assertEquals(CLOCK_SKEW, res.getClockSkewMs(), "Incorrect clock skew");
assertEquals(REPL_PRIM_CANARY_AGE, res.getReplicationPrimaryCanaryAgeMs(), "Incorrect canary age");
assertEquals(ENTERPRISE, res.isEnterprise(), "Incorrect enterprise flag");
}
}

View File

@ -1,66 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link HelpResponse} model.
*
* @author Stefan Kalscheuer
*/
class HelpResponseTest extends AbstractModelTest<HelpResponse> {
private static final String HELP = "Help Text.";
private static final String JSON = "{\"help\":\"" + HELP + "\"}";
HelpResponseTest() {
super(HelpResponse.class);
}
@Override
protected HelpResponse createFull() {
try {
return objectMapper.readValue(JSON, HelpResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test creation from JSON value as returned by Vault.
*/
@Test
void jsonRoundtrip() {
HelpResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(JSON, HelpResponse.class),
"HelpResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
assertEquals(HELP, res.getHelp(), "Unexpected help text");
assertEquals(
JSON,
assertDoesNotThrow(() -> objectMapper.writeValueAsString(res), "HelpResponse serialization failed"),
"Unexpected JSON string after serialization"
);
}
}

View File

@ -1,148 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link MetaSecretResponse} model.
*
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class MetaSecretResponseTest extends AbstractModelTest<MetaSecretResponse> {
private static final String SECRET_REQUEST_ID = "68315073-6658-e3ff-2da7-67939fb91bbd";
private static final String SECRET_LEASE_ID = "";
private static final Integer SECRET_LEASE_DURATION = 2764800;
private static final boolean SECRET_RENEWABLE = false;
private static final String SECRET_DATA_K1 = "excited";
private static final String SECRET_DATA_V1 = "yes";
private static final String SECRET_DATA_K2 = "value";
private static final String SECRET_DATA_V2 = "world";
private static final String SECRET_META_CREATED = "2018-03-22T02:24:06.945319214Z";
private static final String SECRET_META_DELETED = "2018-03-23T03:25:07.056420325Z";
private static final List<String> SECRET_WARNINGS = null;
private static final String CUSTOM_META_KEY = "foo";
private static final String CUSTOM_META_VAL = "bar";
private static final String SECRET_JSON_V2 = "{\n" +
" \"request_id\": \"" + SECRET_REQUEST_ID + "\",\n" +
" \"lease_id\": \"" + SECRET_LEASE_ID + "\",\n" +
" \"lease_duration\": " + SECRET_LEASE_DURATION + ",\n" +
" \"renewable\": " + SECRET_RENEWABLE + ",\n" +
" \"data\": {\n" +
" \"data\": {\n" +
" \"" + SECRET_DATA_K1 + "\": \"" + SECRET_DATA_V1 + "\",\n" +
" \"" + SECRET_DATA_K2 + "\": \"" + SECRET_DATA_V2 + "\"\n" +
" },\n" +
" \"metadata\": {\n" +
" \"created_time\": \"" + SECRET_META_CREATED + "\",\n" +
" \"custom_metadata\": null,\n" +
" \"deletion_time\": \"\",\n" +
" \"destroyed\": false,\n" +
" \"version\": 1\n" +
" }\n" +
" },\n" +
" \"warnings\": " + SECRET_WARNINGS + "\n" +
"}";
private static final String SECRET_JSON_V2_2 = "{\n" +
" \"request_id\": \"" + SECRET_REQUEST_ID + "\",\n" +
" \"lease_id\": \"" + SECRET_LEASE_ID + "\",\n" +
" \"lease_duration\": " + SECRET_LEASE_DURATION + ",\n" +
" \"renewable\": " + SECRET_RENEWABLE + ",\n" +
" \"data\": {\n" +
" \"data\": {\n" +
" \"" + SECRET_DATA_K1 + "\": \"" + SECRET_DATA_V1 + "\",\n" +
" \"" + SECRET_DATA_K2 + "\": \"" + SECRET_DATA_V2 + "\"\n" +
" },\n" +
" \"metadata\": {\n" +
" \"created_time\": \"" + SECRET_META_CREATED + "\",\n" +
" \"custom_metadata\": {" +
" \"" + CUSTOM_META_KEY + "\": \"" + CUSTOM_META_VAL + "\"" +
" },\n" +
" \"deletion_time\": \"" + SECRET_META_DELETED + "\",\n" +
" \"destroyed\": true,\n" +
" \"version\": 2\n" +
" }\n" +
" },\n" +
" \"warnings\": " + SECRET_WARNINGS + "\n" +
"}";
MetaSecretResponseTest() {
super(MetaSecretResponse.class);
}
@Override
protected MetaSecretResponse createFull() {
try {
return objectMapper.readValue(SECRET_JSON_V2, MetaSecretResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
*/
@Test
void jsonRoundtrip() {
// KV v2 secret.
MetaSecretResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(SECRET_JSON_V2, MetaSecretResponse.class),
"SecretResponse deserialization failed"
);
assertSecretData(res);
assertNotNull(res.getMetadata(), "SecretResponse does not contain metadata");
assertNotNull(res.getMetadata().getCreatedTime(), "Creation date parsing failed");
assertNull(res.getMetadata().getDeletionTime(), "Incorrect deletion date");
assertFalse(res.getMetadata().isDestroyed(), "Secret destroyed when not expected");
assertEquals(1, res.getMetadata().getVersion(), "Incorrect secret version");
assertNull(res.getMetadata().getCustomMetadata(), "Incorrect custom metadata");
// Deleted KV v2 secret.
res = assertDoesNotThrow(
() -> objectMapper.readValue(SECRET_JSON_V2_2, MetaSecretResponse.class),
"SecretResponse deserialization failed"
);
assertSecretData(res);
assertNotNull(res.getMetadata(), "SecretResponse does not contain metadata");
assertNotNull(res.getMetadata().getCreatedTime(), "Creation date parsing failed");
assertNotNull(res.getMetadata().getDeletionTime(), "Incorrect deletion date");
assertTrue(res.getMetadata().isDestroyed(), "Secret destroyed when not expected");
assertEquals(2, res.getMetadata().getVersion(), "Incorrect secret version");
assertEquals(Map.of(CUSTOM_META_KEY, CUSTOM_META_VAL), res.getMetadata().getCustomMetadata(), "Incorrect custom metadata");
}
private void assertSecretData(SecretResponse res) {
assertNotNull(res, "Parsed response is NULL");
assertEquals(SECRET_REQUEST_ID, res.getRequestId(), "Incorrect request ID");
assertEquals(SECRET_LEASE_ID, res.getLeaseId(), "Incorrect lease ID");
assertEquals(SECRET_LEASE_DURATION, res.getLeaseDuration(), "Incorrect lease duration");
assertEquals(SECRET_RENEWABLE, res.isRenewable(), "Incorrect renewable status");
assertEquals(SECRET_WARNINGS, res.getWarnings(), "Incorrect warnings");
assertEquals(SECRET_DATA_V1, res.get(SECRET_DATA_K1), "Response does not contain correct data");
assertEquals(SECRET_DATA_V2, res.get(SECRET_DATA_K2), "Response does not contain correct data");
}
}

View File

@ -1,116 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link MetadataResponse} model.
*
* @author Stefan Kalscheuer
* @since 0.8
*/
class MetadataResponseTest extends AbstractModelTest<MetadataResponse> {
private static final String V1_TIME = "2018-03-22T02:24:06.945319214Z";
private static final String V3_TIME = "2018-03-22T02:36:43.986212308Z";
private static final String V2_TIME = "2018-03-22T02:36:33.954880664Z";
private static final Integer CURRENT_VERSION = 3;
private static final Integer MAX_VERSIONS = 0;
private static final Integer OLDEST_VERSION = 1;
private static final Boolean CAS_REQUIRED = false;
private static final String CUSTOM_META_KEY = "test";
private static final String CUSTOM_META_VAL = "123";
private static final String DELETE_VERSION_AFTER = "0s";
private static final String META_JSON = "{\n" +
" \"data\": {\n" +
" \"cas_required\": " + CAS_REQUIRED + ",\n" +
" \"created_time\": \"" + V1_TIME + "\",\n" +
" \"current_version\": " + CURRENT_VERSION + ",\n" +
" \"custom_metadata\": {" +
" \"" + CUSTOM_META_KEY + "\": \"" + CUSTOM_META_VAL + "\"" +
" },\n" +
" \"delete_version_after\": \"" + DELETE_VERSION_AFTER + "\"," +
" \"max_versions\": " + MAX_VERSIONS + ",\n" +
" \"oldest_version\": " + OLDEST_VERSION + ",\n" +
" \"updated_time\": \"" + V3_TIME + "\",\n" +
" \"versions\": {\n" +
" \"1\": {\n" +
" \"created_time\": \"" + V1_TIME + "\",\n" +
" \"deletion_time\": \"" + V2_TIME + "\",\n" +
" \"destroyed\": true\n" +
" },\n" +
" \"2\": {\n" +
" \"created_time\": \"" + V2_TIME + "\",\n" +
" \"deletion_time\": \"\",\n" +
" \"destroyed\": false\n" +
" },\n" +
" \"3\": {\n" +
" \"created_time\": \"" + V3_TIME + "\",\n" +
" \"deletion_time\": \"\",\n" +
" \"destroyed\": false\n" +
" }\n" +
" }\n" +
" }\n" +
"}";
MetadataResponseTest() {
super(MetadataResponse.class);
}
@Override
protected MetadataResponse createFull() {
try {
return objectMapper.readValue(META_JSON, MetadataResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
*/
@Test
void jsonRoundtrip() {
MetadataResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(META_JSON, MetadataResponse.class),
"MetadataResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
assertNotNull(res.getMetadata(), "Parsed metadata is NULL");
assertEquals(CAS_REQUIRED, res.getMetadata().isCasRequired(), "Incorrect CAS required flag");
assertNotNull(res.getMetadata().getCreatedTime(), "Parting created time failed");
assertEquals(CURRENT_VERSION, res.getMetadata().getCurrentVersion(), "Incorrect current version");
assertEquals(MAX_VERSIONS, res.getMetadata().getMaxVersions(), "Incorrect max versions");
assertEquals(OLDEST_VERSION, res.getMetadata().getOldestVersion(), "Incorrect oldest version");
assertEquals(Map.of(CUSTOM_META_KEY, CUSTOM_META_VAL), res.getMetadata().getCustomMetadata(), "Incorrect custom metadata");
assertEquals(DELETE_VERSION_AFTER, res.getMetadata().getDeleteVersionAfter(), "Incorrect delete version after");
assertNotNull(res.getMetadata().getUpdatedTime(), "Parting updated time failed");
assertEquals(3, res.getMetadata().getVersions().size(), "Incorrect number of versions");
assertNotNull(res.getMetadata().getVersions().get(1).getDeletionTime(), "Parsing version delete time failed");
assertTrue(res.getMetadata().getVersions().get(1).isDestroyed(), "Incorrect version 1 destroyed state");
assertNotNull(res.getMetadata().getVersions().get(2).getCreatedTime(), "Parsing version created failed");
assertFalse(res.getMetadata().getVersions().get(3).isDestroyed(), "Incorrect version 3 destroyed state");
}
}

View File

@ -1,223 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link PlainSecretResponse} model.
*
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class PlainSecretResponseTest extends AbstractModelTest<PlainSecretResponse> {
private static final String SECRET_REQUEST_ID = "68315073-6658-e3ff-2da7-67939fb91bbd";
private static final String SECRET_LEASE_ID = "";
private static final Integer SECRET_LEASE_DURATION = 2764800;
private static final boolean SECRET_RENEWABLE = false;
private static final String SECRET_DATA_K1 = "excited";
private static final String SECRET_DATA_V1 = "yes";
private static final String SECRET_DATA_K2 = "value";
private static final String SECRET_DATA_V2 = "world";
private static final List<String> SECRET_WARNINGS = null;
private static final String SECRET_JSON = "{\n" +
" \"request_id\": \"" + SECRET_REQUEST_ID + "\",\n" +
" \"lease_id\": \"" + SECRET_LEASE_ID + "\",\n" +
" \"lease_duration\": " + SECRET_LEASE_DURATION + ",\n" +
" \"renewable\": " + SECRET_RENEWABLE + ",\n" +
" \"data\": {\n" +
" \"" + SECRET_DATA_K1 + "\": \"" + SECRET_DATA_V1 + "\",\n" +
" \"" + SECRET_DATA_K2 + "\": \"" + SECRET_DATA_V2 + "\"\n" +
" },\n" +
" \"warnings\": " + SECRET_WARNINGS + "\n" +
"}";
PlainSecretResponseTest() {
super(PlainSecretResponse.class);
}
@Override
protected PlainSecretResponse createFull() {
try {
return objectMapper.readValue(SECRET_JSON, PlainSecretResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
*/
@Test
void jsonRoundtrip() {
SecretResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(SECRET_JSON, PlainSecretResponse.class),
"SecretResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
assertEquals(SECRET_REQUEST_ID, res.getRequestId(), "Incorrect request ID");
assertEquals(SECRET_LEASE_ID, res.getLeaseId(), "Incorrect lease ID");
assertEquals(SECRET_LEASE_DURATION, res.getLeaseDuration(), "Incorrect lease duration");
assertEquals(SECRET_RENEWABLE, res.isRenewable(), "Incorrect renewable status");
assertEquals(SECRET_WARNINGS, res.getWarnings(), "Incorrect warnings");
assertEquals(SECRET_DATA_V1, res.get(SECRET_DATA_K1), "Response does not contain correct data");
assertEquals(SECRET_DATA_V2, res.get(SECRET_DATA_K2), "Response does not contain correct data");
}
/**
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
*/
@Test
void testGetter() {
final var stringKey = "string";
final var stringVal = "test";
final var numberKey = "number";
final var numberVal = 123.45;
final var listKey = "list";
final var listVal = List.of("foo", "bar");
final var complexKey = "complex";
final var complexVal = new ComplexType("val1", 678);
SecretResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(
"{\n" +
" \"request_id\": \"req-id\",\n" +
" \"lease_id\": \"lea-id\",\n" +
" \"lease_duration\": " + 123456 + ",\n" +
" \"renewable\": true,\n" +
" \"data\": {\n" +
" \"" + stringKey + "\": \"" + stringVal + "\",\n" +
" \"" + numberKey + "\": \"" + numberVal + "\",\n" +
" \"" + listKey + "\": [\"" + String.join("\", \"", listVal) + "\"],\n" +
" \"" + complexKey + "\": {" +
" \"field1\": \"" + complexVal.field1 + "\",\n" +
" \"field2\": " + complexVal.field2 + "\n" +
" },\n" +
" \"" + complexKey + "Json\": \"" + objectMapper.writeValueAsString(complexVal).replace("\"", "\\\"") + "\"\n" +
" }\n" +
"}",
PlainSecretResponse.class
),
"SecretResponse deserialization failed"
);
assertEquals(stringVal, res.get(stringKey), "unexpected value for string (implicit)");
assertEquals(
stringVal,
assertDoesNotThrow(() -> res.get(stringKey, String.class), "getting string failed"),
"unexpected value for string (explicit)"
);
assertEquals(String.valueOf(numberVal), res.get(numberKey), "unexpected value for number (implicit)");
assertEquals(
numberVal,
assertDoesNotThrow(() -> res.get(numberKey, Double.class), "getting number failed"),
"unexpected value for number (explicit)"
);
assertEquals(
String.valueOf(numberVal),
assertDoesNotThrow(() -> res.get(numberKey, String.class), "getting number as string failed"),
"unexpected value for number as string (explicit)"
);
assertEquals(listVal, res.get(listKey), "unexpected value for list (implicit)");
assertEquals(
listVal,
assertDoesNotThrow(() -> res.get(listKey, ArrayList.class), "getting list failed"),
"unexpected value for list (explicit)"
);
assertEquals(complexVal.toMap(), res.get(complexKey), "unexpected value for complex type (implicit)");
assertEquals(
complexVal.toMap(),
assertDoesNotThrow(() -> res.get(complexKey, HashMap.class), "getting complex type as map failed"),
"unexpected value for complex type as map (explicit)"
);
assertEquals(
complexVal,
assertDoesNotThrow(() -> res.get(complexKey, ComplexType.class), "getting complex type failed"),
"unexpected value for complex type (explicit)"
);
assertThrows(
InvalidResponseException.class,
() -> res.get(complexKey, Integer.class),
"getting complex type as integer should fail"
);
assertEquals(
complexVal,
assertDoesNotThrow(() -> res.get(complexKey + "Json", ComplexType.class), "getting complex type from JSON string failed"),
"unexpected value for complex type from JSON string"
);
}
/**
* Test class for complex field mapping.
*/
private static class ComplexType {
@JsonProperty("field1")
private String field1;
@JsonProperty("field2")
private Integer field2;
private ComplexType() {
// Required for JSON deserialization.
}
private ComplexType(String field1, Integer field2) {
this.field1 = field1;
this.field2 = field2;
}
private Map<String, Object> toMap() {
return Map.of(
"field1", field1,
"field2", field2
);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
ComplexType that = (ComplexType) o;
return Objects.equals(field1, that.field1) && Objects.equals(field2, that.field2);
}
@Override
public int hashCode() {
return Objects.hash(field1, field2);
}
}
}

View File

@ -1,143 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import java.time.ZonedDateTime;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link SealResponse} model.
*
* @author Stefan Kalscheuer
* @since 0.8
*/
class SealResponseTest extends AbstractModelTest<SealResponse> {
private static final String TYPE = "shamir";
private static final Integer THRESHOLD = 3;
private static final Integer SHARES = 5;
private static final Integer PROGRESS_SEALED = 2;
private static final Integer PROGRESS_UNSEALED = 0;
private static final String VERSION = "1.15.4";
private static final String BUILD_DATE = "2023-11-22T20:59:54Z";
private static final String CLUSTER_NAME = "vault-cluster-d6ec3c7f";
private static final String CLUSTER_ID = "3e8b3fec-3749-e056-ba41-b62a63b997e8";
private static final String NONCE = "ef05d55d-4d2c-c594-a5e8-55bc88604c24";
private static final Boolean MIGRATION = false;
private static final Boolean RECOVERY_SEAL = false;
private static final String STORAGE_TYPE = "file";
private static final String RES_SEALED = "{\n" +
" \"type\": \"" + TYPE + "\",\n" +
" \"sealed\": true,\n" +
" \"initialized\": true,\n" +
" \"t\": " + THRESHOLD + ",\n" +
" \"n\": " + SHARES + ",\n" +
" \"progress\": " + PROGRESS_SEALED + ",\n" +
" \"nonce\": \"\",\n" +
" \"version\": \"" + VERSION + "\",\n" +
" \"build_date\": \"" + BUILD_DATE + "\",\n" +
" \"migration\": \"" + MIGRATION + "\",\n" +
" \"recovery_seal\": \"" + RECOVERY_SEAL + "\",\n" +
" \"storage_type\": \"" + STORAGE_TYPE + "\"\n" +
"}";
private static final String RES_UNSEALED = "{\n" +
" \"type\": \"" + TYPE + "\",\n" +
" \"sealed\": false,\n" +
" \"initialized\": true,\n" +
" \"t\": " + THRESHOLD + ",\n" +
" \"n\": " + SHARES + ",\n" +
" \"progress\": " + PROGRESS_UNSEALED + ",\n" +
" \"version\": \"" + VERSION + "\",\n" +
" \"build_date\": \"" + BUILD_DATE + "\",\n" +
" \"cluster_name\": \"" + CLUSTER_NAME + "\",\n" +
" \"cluster_id\": \"" + CLUSTER_ID + "\",\n" +
" \"nonce\": \"" + NONCE + "\",\n" +
" \"migration\": \"" + MIGRATION + "\",\n" +
" \"recovery_seal\": \"" + RECOVERY_SEAL + "\",\n" +
" \"storage_type\": \"" + STORAGE_TYPE + "\"\n" +
"}";
SealResponseTest() {
super(SealResponse.class);
}
@Override
protected SealResponse createFull() {
try {
return objectMapper.readValue(RES_UNSEALED, SealResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test creation from JSON value as returned by Vault when sealed (JSON example close to Vault documentation).
*/
@Test
void jsonRoundtripSealed() {
// First test sealed Vault's response.
SealResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(RES_SEALED, SealResponse.class),
"SealResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
assertEquals(TYPE, res.getType(), "Incorrect seal type");
assertTrue(res.isSealed(), "Incorrect seal status");
assertTrue(res.isInitialized(), "Incorrect initialization status");
assertEquals(THRESHOLD, res.getThreshold(), "Incorrect threshold");
assertEquals(SHARES, res.getNumberOfShares(), "Incorrect number of shares");
assertEquals(PROGRESS_SEALED, res.getProgress(), "Incorrect progress");
assertEquals("", res.getNonce(), "Nonce not empty");
assertEquals(VERSION, res.getVersion(), "Incorrect version");
assertEquals(ZonedDateTime.parse(BUILD_DATE), res.getBuildDate(), "Incorrect build date");
assertEquals(MIGRATION, res.getMigration(), "Incorrect migration");
assertEquals(RECOVERY_SEAL, res.getRecoverySeal(), "Incorrect recovery seal");
assertEquals(STORAGE_TYPE, res.getStorageType(), "Incorrect storage type");
// And the fields, that should not be filled.
assertNull(res.getClusterName(), "Cluster name should not be populated");
assertNull(res.getClusterId(), "Cluster ID should not be populated");
// Not test unsealed Vault's response.
res = assertDoesNotThrow(
() -> objectMapper.readValue(RES_UNSEALED, SealResponse.class),
"SealResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
assertEquals(TYPE, res.getType(), "Incorrect seal type");
assertFalse(res.isSealed(), "Incorrect seal status");
assertTrue(res.isInitialized(), "Incorrect initialization status");
assertEquals(THRESHOLD, res.getThreshold(), "Incorrect threshold");
assertEquals(SHARES, res.getNumberOfShares(), "Incorrect number of shares");
assertEquals(PROGRESS_UNSEALED, res.getProgress(), "Incorrect progress");
assertEquals(NONCE, res.getNonce(), "Incorrect nonce");
assertEquals(VERSION, res.getVersion(), "Incorrect version");
assertEquals(ZonedDateTime.parse(BUILD_DATE), res.getBuildDate(), "Incorrect build date");
assertEquals(CLUSTER_NAME, res.getClusterName(), "Incorrect cluster name");
assertEquals(CLUSTER_ID, res.getClusterId(), "Incorrect cluster ID");
assertEquals(MIGRATION, res.getMigration(), "Incorrect migration");
assertEquals(RECOVERY_SEAL, res.getRecoverySeal(), "Incorrect recovery seal");
assertEquals(STORAGE_TYPE, res.getStorageType(), "Incorrect storage type");
}
}

View File

@ -1,75 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link SecretListResponse} model.
*
* @author Stefan Kalscheuer
* @since 0.8
*/
class SecretListResponseTest extends AbstractModelTest<SecretListResponse> {
private static final String KEY1 = "key1";
private static final String KEY2 = "key-2";
private static final String JSON = "{\n" +
" \"auth\": null,\n" +
" \"data\": {\n" +
" \"keys\": [" +
" \"" + KEY1 + "\",\n" +
" \"" + KEY2 + "\"\n" +
" ]\n" +
" },\n" +
" \"lease_duration\": 2764800,\n" +
" \"lease_id\": \"\",\n" +
" \"renewable\": false\n" +
"}";
SecretListResponseTest() {
super(SecretListResponse.class);
}
@Override
protected SecretListResponse createFull() {
try {
return objectMapper.readValue(JSON, SecretListResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test JSON deserialization and key getter.
*/
@Test
void getKeysTest() {
SecretListResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(JSON, SecretListResponse.class),
"SecretListResponse deserialization failed"
);
assertEquals(List.of(KEY1, KEY2), res.getKeys(), "Unexpected secret keys");
}
}

View File

@ -1,73 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link SecretVersionResponse} model.
*
* @author Stefan Kalscheuer
* @since 0.8
*/
class SecretVersionResponseTest extends AbstractModelTest<SecretVersionResponse> {
private static final String CREATION_TIME = "2018-03-22T02:24:06.945319214Z";
private static final String DELETION_TIME = "2018-03-22T02:36:43.986212308Z";
private static final Integer VERSION = 42;
private static final String META_JSON = "{\n" +
" \"data\": {\n" +
" \"created_time\": \"" + CREATION_TIME + "\",\n" +
" \"deletion_time\": \"" + DELETION_TIME + "\",\n" +
" \"destroyed\": false,\n" +
" \"version\": " + VERSION + "\n" +
" }\n" +
"}";
SecretVersionResponseTest() {
super(SecretVersionResponse.class);
}
@Override
protected SecretVersionResponse createFull() {
try {
return objectMapper.readValue(META_JSON, SecretVersionResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
*/
@Test
void jsonRoundtrip() {
SecretVersionResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(META_JSON, SecretVersionResponse.class),
"SecretVersionResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
assertNotNull(res.getMetadata(), "Parsed metadata is NULL");
assertFalse(res.getMetadata().isDestroyed(), "Incorrect destroyed state");
assertEquals(VERSION, res.getMetadata().getVersion(), "Incorrect version");
}
}

View File

@ -1,153 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
import org.junit.jupiter.api.Test;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link TokenResponse} model.
*
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class TokenResponseTest extends AbstractModelTest<TokenResponse> {
private static final Integer TOKEN_CREATION_TIME = 1457533232;
private static final Integer TOKEN_TTL = 2764800;
private static final Integer TOKEN_EXPLICIT_MAX_TTL = 0;
private static final String TOKEN_DISPLAY_NAME = "token";
private static final String TOKEN_META_KEY = "foo";
private static final String TOKEN_META_VALUE = "bar";
private static final Integer TOKEN_NUM_USES = 0;
private static final Boolean TOKEN_ORPHAN = false;
private static final Boolean TOKEN_RENEWABLE = true;
private static final String TOKEN_PATH = "auth/token/create";
private static final String TOKEN_POLICY_1 = "default";
private static final String TOKEN_POLICY_2 = "web";
private static final Boolean RES_RENEWABLE = false;
private static final Integer RES_TTL = 2591976;
private static final Integer RES_LEASE_DURATION = 0;
private static final String TOKEN_ACCESSOR = "VKvzT2fKHFsZFUus9LyoXCvu";
private static final String TOKEN_ENTITY_ID = "7d2e3179-f69b-450c-7179-ac8ee8bd8ca9";
private static final String TOKEN_EXPIRE_TIME = "2018-05-19T11:35:54.466476215-04:00";
private static final String TOKEN_ID = "my-token";
private static final String TOKEN_ISSUE_TIME = "2018-04-17T11:35:54.466476078-04:00";
private static final String TOKEN_TYPE = "service";
private static final String MOUNT_TYPE = "token";
private static final String RES_JSON = "{\n" +
" \"lease_id\": \"\",\n" +
" \"renewable\": " + RES_RENEWABLE + ",\n" +
" \"lease_duration\": " + RES_LEASE_DURATION + ",\n" +
" \"data\": {\n" +
" \"accessor\": \"" + TOKEN_ACCESSOR + "\",\n" +
" \"creation_time\": " + TOKEN_CREATION_TIME + ",\n" +
" \"creation_ttl\": " + TOKEN_TTL + ",\n" +
" \"display_name\": \"" + TOKEN_DISPLAY_NAME + "\",\n" +
" \"entity_id\": \"" + TOKEN_ENTITY_ID + "\",\n" +
" \"expire_time\": \"" + TOKEN_EXPIRE_TIME + "\",\n" +
" \"explicit_max_ttl\": \"" + TOKEN_EXPLICIT_MAX_TTL + "\",\n" +
" \"id\": \"" + TOKEN_ID + "\",\n" +
" \"issue_time\": \"" + TOKEN_ISSUE_TIME + "\",\n" +
" \"meta\": {\n" +
" \"" + TOKEN_META_KEY + "\": \"" + TOKEN_META_VALUE + "\"\n" +
" },\n" +
" \"num_uses\": " + TOKEN_NUM_USES + ",\n" +
" \"orphan\": " + TOKEN_ORPHAN + ",\n" +
" \"path\": \"" + TOKEN_PATH + "\",\n" +
" \"policies\": [\n" +
" \"" + TOKEN_POLICY_1 + "\", \n" +
" \"" + TOKEN_POLICY_2 + "\"\n" +
" ],\n" +
" \"renewable\": " + TOKEN_RENEWABLE + ",\n" +
" \"ttl\": " + RES_TTL + ",\n" +
" \"type\": \"" + TOKEN_TYPE + "\"\n" +
" },\n" +
" \"warnings\": null,\n" +
" \"auth\": null,\n" +
" \"mount_type\": \"" + MOUNT_TYPE + "\"\n" +
"}";
TokenResponseTest() {
super(TokenResponse.class);
}
@Override
protected TokenResponse createFull() {
try {
return objectMapper.readValue(RES_JSON, TokenResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test getter, setter and get-methods for response data.
*/
@Test
void getDataRoundtrip() {
// Create empty Object.
TokenResponse res = new TokenResponse();
assertNull(res.getData(), "Initial data should be empty");
}
/**
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
*/
@Test
void jsonRoundtrip() {
TokenResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(RES_JSON, TokenResponse.class),
"TokenResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
assertEquals(RES_LEASE_DURATION, res.getLeaseDuration(), "Incorrect lease duration");
assertEquals(RES_RENEWABLE, res.isRenewable(), "Incorrect response renewable flag");
assertEquals(RES_LEASE_DURATION, res.getLeaseDuration(), "Incorrect response lease duration");
assertEquals(MOUNT_TYPE, res.getMountType(), "Incorrect mount type");
// Extract token data.
TokenData data = res.getData();
assertNotNull(data, "Token data is NULL");
assertEquals(TOKEN_ACCESSOR, data.getAccessor(), "Incorrect token accessor");
assertEquals(TOKEN_CREATION_TIME, data.getCreationTime(), "Incorrect token creation time");
assertEquals(TOKEN_TTL, data.getCreationTtl(), "Incorrect token creation TTL");
assertEquals(TOKEN_DISPLAY_NAME, data.getName(), "Incorrect token display name");
assertEquals(TOKEN_ENTITY_ID, data.getEntityId(), "Incorrect token entity ID");
assertEquals(ZonedDateTime.parse(TOKEN_EXPIRE_TIME), data.getExpireTime(), "Incorrect parsed token expire time");
assertEquals(TOKEN_EXPLICIT_MAX_TTL, data.getExplicitMaxTtl(), "Incorrect token explicit max TTL");
assertEquals(TOKEN_ID, data.getId(), "Incorrect token ID");
assertEquals(ZonedDateTime.parse(TOKEN_ISSUE_TIME), data.getIssueTime(), "Incorrect parsed token issue time");
assertEquals(Map.of(TOKEN_META_KEY, TOKEN_META_VALUE), data.getMeta(), "Incorrect token metadata");
assertEquals(TOKEN_NUM_USES, data.getNumUses(), "Incorrect token number of uses");
assertEquals(TOKEN_ORPHAN, data.isOrphan(), "Incorrect token orphan flag");
assertEquals(TOKEN_PATH, data.getPath(), "Incorrect token path");
assertEquals(2, data.getPolicies().size(), "Incorrect number of token policies");
assertTrue(data.getPolicies().containsAll(List.of(TOKEN_POLICY_1, TOKEN_POLICY_2)), "Incorrect token policies");
assertEquals(TOKEN_RENEWABLE, data.isRenewable(), "Incorrect token renewable flag");
assertEquals(RES_TTL, data.getTtl(), "Incorrect token TTL");
assertEquals(TOKEN_TYPE, data.getType(), "Incorrect token type");
}
}

View File

@ -1,137 +0,0 @@
/*
* 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,103 +0,0 @@
package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit test for {@link MountConfig}.
*
* @author Stefan Kalscheuer
*/
class MountConfigTest extends AbstractModelTest<MountConfig> {
private static final Integer DEFAULT_LEASE_TTL = 1800;
private static final Integer MAX_LEASE_TTL = 3600;
private static final Boolean FORCE_NO_CACHE = false;
private static final String TOKEN_TYPE = "default-service";
private static final String AUDIT_NON_HMAC_REQ_KEYS_1 = "req1";
private static final String AUDIT_NON_HMAC_REQ_KEYS_2 = "req2";
private static final String AUDIT_NON_HMAC_RES_KEYS_1 = "res1";
private static final String AUDIT_NON_HMAC_RES_KEYS_2 = "res2";
private static final String LISTING_VISIBILITY = "unauth";
private static final String PT_REQ_HEADER_1 = "prh1";
private static final String PT_REQ_HEADER_2 = "prh2";
private static final String ALLOWED_RES_HEADER_1 = "arh1";
private static final String ALLOWED_RES_HEADER_2 = "arh2";
private static final String ALLOWED_MANAGED_KEY_1 = "amk1";
private static final String ALLOWED_MANAGED_KEY_2 = "amk2";
private static final String DEL_AUTH_ACCESSOR_1 = "daa1";
private static final String DEL_AUTH_ACCESSOR_2 = "daa2";
private static final Integer LOCKOUT_THRESH = 7200;
private static final Integer LOCKOUT_DURATION = 86400;
private static final Integer LOCKOUT_CNT_RESET_DURATION = 43200;
private static final Boolean LOCKOUT_DISABLE = false;
private static final String RES_JSON = "{\n" +
" \"default_lease_ttl\": " + DEFAULT_LEASE_TTL + ",\n" +
" \"force_no_cache\": " + FORCE_NO_CACHE + ",\n" +
" \"max_lease_ttl\": " + MAX_LEASE_TTL + ",\n" +
" \"token_type\": \"" + TOKEN_TYPE + "\",\n" +
" \"audit_non_hmac_request_keys\": [\"" + AUDIT_NON_HMAC_REQ_KEYS_1 + "\", \"" + AUDIT_NON_HMAC_REQ_KEYS_2 + "\"],\n" +
" \"audit_non_hmac_response_keys\": [\"" + AUDIT_NON_HMAC_RES_KEYS_1 + "\", \"" + AUDIT_NON_HMAC_RES_KEYS_2 + "\"],\n" +
" \"listing_visibility\": \"" + LISTING_VISIBILITY + "\",\n" +
" \"passthrough_request_headers\": [\"" + PT_REQ_HEADER_1 + "\", \"" + PT_REQ_HEADER_2 + "\"],\n" +
" \"allowed_response_headers\": [\"" + ALLOWED_RES_HEADER_1 + "\", \"" + ALLOWED_RES_HEADER_2 + "\"],\n" +
" \"allowed_managed_keys\": [\"" + ALLOWED_MANAGED_KEY_1 + "\", \"" + ALLOWED_MANAGED_KEY_2 + "\"],\n" +
" \"delegated_auth_accessors\": [\"" + DEL_AUTH_ACCESSOR_1 + "\", \"" + DEL_AUTH_ACCESSOR_2 + "\"],\n" +
" \"user_lockout_config\": {\n" +
" \"lockout_threshold\": " + LOCKOUT_THRESH + ",\n" +
" \"lockout_duration\": " + LOCKOUT_DURATION + ",\n" +
" \"lockout_counter_reset_duration\": " + LOCKOUT_CNT_RESET_DURATION + ",\n" +
" \"lockout_disable\": " + LOCKOUT_DISABLE + "\n" +
" }\n" +
"}";
MountConfigTest() {
super(MountConfig.class);
}
@Override
protected MountConfig createFull() {
try {
return objectMapper.readValue(RES_JSON, MountConfig.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
*/
@Test
void jsonRoundtrip() {
MountConfig mountConfig = assertDoesNotThrow(
() -> objectMapper.readValue(RES_JSON, MountConfig.class),
"MountConfig deserialization failed"
);
assertNotNull(mountConfig, "Parsed response is NULL");
// Verify data.
assertEquals(DEFAULT_LEASE_TTL, mountConfig.getDefaultLeaseTtl(), "Unexpected default lease TTL");
assertEquals(MAX_LEASE_TTL, mountConfig.getMaxLeaseTtl(), "Unexpected max lease TTL");
assertEquals(FORCE_NO_CACHE, mountConfig.getForceNoCache(), "Unexpected force no cache");
assertEquals(TOKEN_TYPE, mountConfig.getTokenType(), "Unexpected token type");
assertEquals(List.of(AUDIT_NON_HMAC_REQ_KEYS_1, AUDIT_NON_HMAC_REQ_KEYS_2), mountConfig.getAuditNonHmacRequestKeys(), "Unexpected audit no HMAC request keys");
assertEquals(List.of(AUDIT_NON_HMAC_RES_KEYS_1, AUDIT_NON_HMAC_RES_KEYS_2), mountConfig.getAuditNonHmacResponseKeys(), "Unexpected audit no HMAC response keys");
assertEquals(LISTING_VISIBILITY, mountConfig.getListingVisibility(), "Unexpected listing visibility");
assertEquals(List.of(PT_REQ_HEADER_1, PT_REQ_HEADER_2), mountConfig.getPassthroughRequestHeaders(), "Unexpected passthrough request headers");
assertEquals(List.of(ALLOWED_RES_HEADER_1, ALLOWED_RES_HEADER_2), mountConfig.getAllowedResponseHeaders(), "Unexpected allowed response headers");
assertEquals(List.of(ALLOWED_MANAGED_KEY_1, ALLOWED_MANAGED_KEY_2), mountConfig.getAllowedManagedKeys(), "Unexpected allowed managed keys");
assertEquals(List.of(DEL_AUTH_ACCESSOR_1, DEL_AUTH_ACCESSOR_2), mountConfig.getDelegatedAuthAccessors(), "Unexpected delegate auth accessors");
assertNotNull(mountConfig.getUserLockoutConfig(), "Missing user lockout config");
var ulc = mountConfig.getUserLockoutConfig();
assertEquals(LOCKOUT_THRESH, ulc.getLockoutThreshold(), "Unexpected lockout threshold");
assertEquals(LOCKOUT_DURATION, ulc.getLockoutDuration(), "Unexpected lockout duration");
assertEquals(LOCKOUT_CNT_RESET_DURATION, ulc.getLockoutCounterResetDuration(), "Unexpected lockout counter reset duration");
assertEquals(LOCKOUT_DISABLE, ulc.getLockoutDisable(), "Unexpected lockout disable");
}
}

View File

@ -1,41 +0,0 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.test;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Simple credentials class for JSON testing.
*
* @author Stefan Kalscheuer
* @since 0.1
*/
public class Credentials {
@JsonProperty("username")
private String username;
@JsonProperty("password")
private String password;
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
}

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