Compare commits

..

No commits in common. "main" and "v1.0.1" have entirely different histories.
main ... v1.0.1

109 changed files with 1548 additions and 5026 deletions

39
.drone.yml Normal file
View File

@ -0,0 +1,39 @@
kind: pipeline
name: default
steps:
- name: compile
image: maven:3-jdk-11
commands:
- mvn -B clean compile
when:
branch:
- main
- develop
- feature/*
- fix/*
- release/*
- name: unit-tests
image: maven:3-jdk-11
commands:
- mvn -B test
when:
branch:
- develop
- feature/*
- fix/*
- name: unit-integration-tests
image: maven:3-jdk-11
environment:
VAULT_VERSION: 1.9.0
commands:
- curl -s -o vault_1.9.0_linux_amd64.zip https://releases.hashicorp.com/vault/1.9.0/vault_1.9.0_linux_amd64.zip
- curl -s https://releases.hashicorp.com/vault/1.9.0/vault_1.9.0_SHA256SUMS | grep linux_amd64 | sha256sum -c
- unzip vault_1.9.0_linux_amd64.zip
- rm vault_1.9.0_linux_amd64.zip
- mv vault /bin/
- mvn -B -P integration-test verify
when:
branch:
- main
- release/*

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 +1,51 @@
name: CI
on:
push:
branches:
- '**'
- '!main'
pull_request:
branches:
- '**'
- '!main'
on: [ push, pull_request ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
jdk: [ 11, 17, 21 ]
jdk: [ 11, 17 ]
vault: [ '1.9.0' ]
include:
- jdk: 21
- jdk: 11
vault: '1.9.0'
analysis: true
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.jdk }}
distribution: 'temurin'
- name: Compile
run: ./mvnw -B clean compile
run: mvn -B clean compile
- name: Set up Vault
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')
run: |
wget -q "https://releases.hashicorp.com/vault/${{ matrix.vault }}/vault_${{ matrix.vault }}_linux_amd64.zip"
wget -q -O - "https://releases.hashicorp.com/vault/${{ matrix.vault }}/vault_${{ matrix.vault }}_SHA256SUMS" | grep linux_amd64 | sha256sum -c
unzip "vault_${{ matrix.vault }}_linux_amd64.zip"
rm "vault_${{ matrix.vault }}_linux_amd64.zip"
sudo mv vault /usr/bin/vault
- name: Test (Unit & Integration)
if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')
env:
VAULT_VERSION: ${{ matrix.vault }}
run: mvn -B -P coverage -P integration-test verify
- name: Test (Unit)
run: ./mvnw -B -P coverage verify
if: github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/heads/release/')
run: mvn -B -P coverage verify
- name: Analysis
if: matrix.analysis && env.SONAR_TOKEN != ''
if: matrix.analysis && github.event_name == 'push'
run: >
./mvnw -B sonar:sonar
mvn -B sonar:sonar
-Dsonar.host.url=https://sonarcloud.io
-Dsonar.organization=stklcode-github
-Dsonar.login=$SONAR_TOKEN
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

22
.gitignore vendored
View File

@ -1,17 +1,5 @@
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
*~
/target/
/*.iml
/.idea/
/*.project
*~

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,170 +1,3 @@
## 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
@ -262,7 +95,7 @@ Old builders will be removed in 1.0
* 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`,
* 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
@ -282,14 +115,14 @@ Old builders will be removed in 1.0
## 0.8.2 (2019-10-20)
### Fixes
* Fixed token lookup (#31)
* Fixed token lookup (#31)
### Improvements
* Updated dependencies
## 0.8.1 (2019-08-16)
### Fixes
* Removed compile dependency to JUnit library (#30)
* Removed compile dependency to JUnit library (#30)
### Improvements
* Updated dependencies
@ -381,7 +214,7 @@ Old builders will be removed in 1.0
### Fixes
* `SecretResponse` does not throw NPE on `get(key)` and `getData()`
### Test
### Test
* Tested against Vault 0.7.2

View File

@ -1,11 +1,11 @@
# Java Vault Connector
# 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)
[![CI Status](https://github.com/stklcode/jvaultconnector/actions/workflows/ci.yml/badge.svg)](https://github.com/stklcode/jvaultconnector/actions/workflows/ci.yml)
[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=de.stklcode.jvault%3Ajvault-connector&metric=alert_status)](https://sonarcloud.io/dashboard?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](https://img.shields.io/maven-central/v/de.stklcode.jvault/jvault-connector.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.stklcode.jvault%22%20AND%20a%3A%22jvault-connector%22)
![Logo](assets/logo.png)
![Logo](https://raw.githubusercontent.com/stklcode/jvaultconnector/main/assets/logo.png)
Java Vault Connector is a connector library for [Vault](https://www.vaultproject.io) by [Hashicorp](https://www.hashicorp.com) written in Java. The connector allows simple usage of Vault's secret store in own applications.
@ -18,6 +18,7 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
* Token
* Username/Password
* AppRole (register and authenticate)
* AppID (register and authenticate) [_deprecated_]
* Tokens
* Creation and lookup of tokens and token roles
* TokenBuilder for speaking creation of complex configurations
@ -28,11 +29,10 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
* Delete secrets
* Renew/revoke leases
* Raw secret content or JSON decoding
* SQL secret handling
* KV v1 and v2 support
* Database secret handling
* Transit API support
* Connector Factory with builder pattern
* Tested against Vault 1.2 to 1.19
* Tested against Vault 1.9.0
## Maven Artifact
@ -40,7 +40,7 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
<dependency>
<groupId>de.stklcode.jvault</groupId>
<artifactId>jvault-connector</artifactId>
<version>1.5.0</version>
<version>1.0.1</version>
</dependency>
```
@ -61,7 +61,7 @@ VaultConnector vault = HTTPVaultConnector.builder("https://example.com:8200/v1/"
.withTrustedCA(Paths.get("/path/to/CA.pem"))
.build();
// Initialization from environment variables
// Initialization from environment variables
VaultConnector vault = HTTPVaultConnector.builder()
.fromEnv()
.build();

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%

280
pom.xml
View File

@ -4,7 +4,7 @@
<groupId>de.stklcode.jvault</groupId>
<artifactId>jvault-connector</artifactId>
<version>1.5.1-SNAPSHOT</version>
<version>1.0.1</version>
<packaging>jar</packaging>
@ -21,11 +21,16 @@
</license>
</licenses>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<argLine></argLine>
</properties>
<developers>
<developer>
<name>Stefan Kalscheuer</name>
<email>stefan@stklcode.de</email>
<timezone>Europe/Berlin</timezone>
<timezone>+1</timezone>
</developer>
</developers>
@ -33,7 +38,6 @@
<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>
@ -41,123 +45,56 @@
<url>https://github.com/stklcode/jvaultconnector/issues</url>
</issueManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<argLine></argLine>
</properties>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.18.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.18.3</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.12.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.17.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-lambda</artifactId>
<version>1.2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId>
<version>3.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.19.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>3.19.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>4.3.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
<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>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.4</version>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.5.3</version>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<argLine>
@{argLine}
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.test=com.fasterxml.jackson.databind
</argLine>
<archive>
<manifestEntries>
<Automatic-Module-Name>de.stklcode.jvault.connector</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.4</version>
<version>2.5.2</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>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.3</version>
<version>2.22.2</version>
<configuration>
<argLine>
@{argLine}
@ -168,55 +105,63 @@
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.model.response=ALL-UNNAMED
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.model.response.embedded=ALL-UNNAMED
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.test=com.fasterxml.jackson.databind
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.test=com.fasterxml.jackson.datatype.jsr310
</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
<version>2.9.1</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.13</version>
</plugin>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>5.1.0.4751</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<id>enforce-versions</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireMavenVersion>
<version>[3.6.3,)</version>
</requireMavenVersion>
<requireJavaVersion>
<version>[11,)</version>
</requireJavaVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-lambda</artifactId>
<version>1.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>2.27.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.9.1.2184</version>
</dependency>
</dependencies>
</dependencyManagement>
<profiles>
<profile>
<id>sources</id>
@ -228,6 +173,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
@ -251,7 +197,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.11.2</version>
<version>3.3.1</version>
<configuration>
<source>11</source>
</configuration>
@ -268,29 +214,6 @@
</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>
@ -298,7 +221,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.7</version>
<version>3.0.1</version>
<executions>
<execution>
<id>sign-artifacts</id>
@ -323,6 +246,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.7</version>
<executions>
<execution>
<id>default-prepare-agent</id>
@ -349,6 +273,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
<executions>
<execution>
<goals>
@ -369,11 +294,7 @@
<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>
<version>6.5.0</version>
<executions>
<execution>
<goals>
@ -387,20 +308,17 @@
</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>
<id>sonatype</id>
<distributionManagement>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
</profile>
<profile>

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -41,62 +41,34 @@ import static java.util.Collections.singletonMap;
* @since 0.1
*/
public class HTTPVaultConnector implements VaultConnector {
private static final String PATH_SYS = "sys";
private static final String PATH_SYS_AUTH = PATH_SYS + "/auth";
private static final String PATH_RENEW = PATH_SYS + "/leases/renew";
private static final String PATH_REVOKE = PATH_SYS + "/leases/revoke/";
private static final String PATH_HEALTH = PATH_SYS + "/health";
private static final String PATH_SEAL = PATH_SYS + "/seal";
private static final String PATH_SEAL_STATUS = PATH_SYS + "/seal-status";
private static final String PATH_UNSEAL = PATH_SYS + "/unseal";
private static final String PATH_AUTH = "auth";
private static final String PATH_AUTH_TOKEN = PATH_AUTH + "/token";
private static final String PATH_SEAL_STATUS = "sys/seal-status";
private static final String PATH_SEAL = "sys/seal";
private static final String PATH_UNSEAL = "sys/unseal";
private static final String PATH_RENEW = "sys/leases/renew";
private static final String PATH_AUTH = "sys/auth";
private static final String PATH_TOKEN = "auth/token";
private static final String PATH_LOOKUP = "/lookup";
private static final String PATH_CREATE = "/create";
private static final String PATH_ROLES = "/roles";
private static final String PATH_CREATE_ORPHAN = "/create-orphan";
private static final String PATH_AUTH_USERPASS = PATH_AUTH + "/userpass/login/";
private static final String PATH_AUTH_APPROLE = PATH_AUTH + "/approle";
private static final String PATH_AUTH_APPROLE_ROLE = PATH_AUTH_APPROLE + "/role/%s%s";
private static final String PATH_AUTH_USERPASS = "auth/userpass/login/";
private static final String PATH_AUTH_APPID = "auth/app-id/";
private static final String PATH_AUTH_APPROLE = "auth/approle/";
private static final String PATH_AUTH_APPROLE_ROLE = "auth/approle/role/%s%s";
private static final String PATH_REVOKE = "sys/leases/revoke/";
private static final String PATH_HEALTH = "sys/health";
private static final String PATH_DATA = "/data/";
private static final String PATH_METADATA = "/metadata/";
private static final String PATH_LOGIN = "/login";
private static final String PATH_DELETE = "/delete/";
private static final String PATH_UNDELETE = "/undelete/";
private static final String PATH_DESTROY = "/destroy/";
private static final String PATH_TRANSIT = "transit";
private static final String PATH_TRANSIT_ENCRYPT = PATH_TRANSIT + "/encrypt/";
private static final String PATH_TRANSIT_DECRYPT = PATH_TRANSIT + "/decrypt/";
private static final String PATH_TRANSIT_HASH = PATH_TRANSIT + "/hash/";
private final RequestHelper request;
private boolean authorized = false; // Authorization status.
private String token; // Current token.
private long tokenTTL = 0; // Expiration time for current token.
/**
* Create connector using a {@link HTTPVaultConnectorBuilder}.
*
* @param builder The builder.
*/
HTTPVaultConnector(final HTTPVaultConnectorBuilder builder) {
this.request = new RequestHelper(
((builder.isWithTLS()) ? "https" : "http") + "://" +
builder.getHost() +
((builder.getPort() != null) ? ":" + builder.getPort() : "") +
builder.getPrefix(),
builder.getNumberOfRetries(),
builder.getTimeout(),
builder.getTlsVersion(),
builder.getTrustedCA()
);
}
/**
* Get a new builder for a connector.
*
@ -130,6 +102,24 @@ public class HTTPVaultConnector implements VaultConnector {
return new HTTPVaultConnectorBuilder().withBaseURL(baseURL);
}
/**
* Create connector using a {@link HTTPVaultConnectorBuilder}.
*
* @param builder The builder.
*/
HTTPVaultConnector(final HTTPVaultConnectorBuilder builder) {
this.request = new RequestHelper(
((builder.isWithTLS()) ? "https" : "http") + "://" +
builder.getHost() +
((builder.getPort() != null) ? ":" + builder.getPort() : "") +
builder.getPrefix(),
builder.getNumberOfRetries(),
builder.getTimeout(),
builder.getTlsVersion(),
builder.getTrustedCA()
);
}
@Override
public final void resetAuth() {
token = null;
@ -149,10 +139,11 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final SealResponse unseal(final String key, final Boolean reset) throws VaultConnectorException {
Map<String, String> param = mapOfStrings(
"key", key,
"reset", reset
);
Map<String, String> param = new HashMap<>(2, 1);
param.put("key", key);
if (reset != null) {
param.put("reset", reset.toString());
}
return request.put(PATH_UNSEAL, param, token, SealResponse.class);
}
@ -161,15 +152,15 @@ public class HTTPVaultConnector implements VaultConnector {
public HealthResponse getHealth() throws VaultConnectorException {
return request.get(
PATH_HEALTH,
// Force status code to be 200, so we don't need to modify the request sequence.
Map.of(
"standbycode", "200", // Default: 429.
"sealedcode", "200", // Default: 503.
"uninitcode", "200" // Default: 501.
),
token,
HealthResponse.class
PATH_HEALTH,
// Force status code to be 200, so we don't need to modify the request sequence.
Map.of(
"standbycode", "200", // Default: 429.
"sealedcode", "200", // Default: 503.
"uninitcode", "200" // Default: 501.
),
token,
HealthResponse.class
);
}
@ -181,7 +172,7 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final List<AuthBackend> getAuthBackends() throws VaultConnectorException {
/* Issue request and parse response */
AuthMethodsResponse amr = request.get(PATH_SYS_AUTH, emptyMap(), token, AuthMethodsResponse.class);
AuthMethodsResponse amr = request.get(PATH_AUTH, emptyMap(), token, AuthMethodsResponse.class);
return amr.getSupportedMethods().values().stream().map(AuthMethod::getType).collect(Collectors.toList());
}
@ -191,7 +182,7 @@ public class HTTPVaultConnector implements VaultConnector {
/* set token */
this.token = token;
this.tokenTTL = 0;
TokenResponse res = request.post(PATH_AUTH_TOKEN + PATH_LOOKUP, emptyMap(), token, TokenResponse.class);
TokenResponse res = request.post(PATH_TOKEN + PATH_LOOKUP, emptyMap(), token, TokenResponse.class);
authorized = true;
return res;
@ -199,18 +190,31 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final AuthResponse authUserPass(final String username, final String password)
throws VaultConnectorException {
throws VaultConnectorException {
final Map<String, String> payload = singletonMap("password", password);
return queryAuth(PATH_AUTH_USERPASS + username, payload);
}
@Override
public final AuthResponse authAppRole(final String roleID, final String secretID) throws VaultConnectorException {
final Map<String, String> payload = mapOfStrings(
"role_id", roleID,
"secret_id", secretID
@Deprecated(since = "0.4", forRemoval = false)
public final AuthResponse authAppId(final String appID, final String userID) throws VaultConnectorException {
return queryAuth(
PATH_AUTH_APPID + "login",
Map.of(
"app_id", appID,
"user_id", userID
)
);
return queryAuth(PATH_AUTH_APPROLE + PATH_LOGIN, payload);
}
@Override
public final AuthResponse authAppRole(final String roleID, final String secretID) throws VaultConnectorException {
final Map<String, String> payload = new HashMap<>(2, 1);
payload.put("role_id", roleID);
if (secretID != null) {
payload.put("secret_id", secretID);
}
return queryAuth(PATH_AUTH_APPROLE + "login", payload);
}
/**
@ -222,7 +226,7 @@ public class HTTPVaultConnector implements VaultConnector {
* @throws VaultConnectorException on errors
*/
private AuthResponse queryAuth(final String path, final Map<String, String> payload)
throws VaultConnectorException {
throws VaultConnectorException {
/* Issue request and parse response */
AuthResponse auth = request.post(path, payload, token, AuthResponse.class);
/* verify response */
@ -233,6 +237,40 @@ public class HTTPVaultConnector implements VaultConnector {
return auth;
}
@Override
@Deprecated(since = "0.4", forRemoval = false)
public final boolean registerAppId(final String appID, final String policy, final String displayName)
throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
PATH_AUTH_APPID + "map/app-id/" + appID,
Map.of(
"value", policy,
"display_name", displayName
),
token
);
return true;
}
@Override
@Deprecated(since = "0.4", forRemoval = false)
public final boolean registerUserId(final String appID, final String userID) throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
PATH_AUTH_APPID + "map/user-id/" + userID,
singletonMap("value", appID),
token
);
return true;
}
@Override
public final boolean createAppRole(final AppRole role) throws VaultConnectorException {
requireAuth();
@ -249,10 +287,10 @@ public class HTTPVaultConnector implements VaultConnector {
requireAuth();
/* Request HTTP response and parse Secret */
return request.get(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, ""),
emptyMap(),
token,
AppRoleResponse.class
String.format(PATH_AUTH_APPROLE_ROLE, roleName, ""),
emptyMap(),
token,
AppRoleResponse.class
);
}
@ -271,10 +309,10 @@ public class HTTPVaultConnector implements VaultConnector {
requireAuth();
/* Issue request, parse response and extract Role ID */
return request.get(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/role-id"),
emptyMap(),
token,
RawDataResponse.class
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/role-id"),
emptyMap(),
token,
RawDataResponse.class
).getData().get("role_id").toString();
}
@ -284,9 +322,9 @@ public class HTTPVaultConnector implements VaultConnector {
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/role-id"),
singletonMap("role_id", roleID),
token
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/role-id"),
singletonMap("role_id", roleID),
token
);
return true;
@ -294,49 +332,49 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final AppRoleSecretResponse createAppRoleSecret(final String roleName, final AppRoleSecret secret)
throws VaultConnectorException {
throws VaultConnectorException {
requireAuth();
if (secret.getId() != null && !secret.getId().isEmpty()) {
return request.post(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/custom-secret-id"),
secret,
token,
AppRoleSecretResponse.class
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/custom-secret-id"),
secret,
token,
AppRoleSecretResponse.class
);
} else {
return request.post(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id"),
secret, token,
AppRoleSecretResponse.class
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id"),
secret, token,
AppRoleSecretResponse.class
);
}
}
@Override
public final AppRoleSecretResponse lookupAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException {
throws VaultConnectorException {
requireAuth();
/* Issue request and parse secret response */
return request.post(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id/lookup"),
new AppRoleSecret(secretID),
token,
AppRoleSecretResponse.class
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id/lookup"),
new AppRoleSecret(secretID),
token,
AppRoleSecretResponse.class
);
}
@Override
public final boolean destroyAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException {
throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id/destroy"),
new AppRoleSecret(secretID),
token);
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id/destroy"),
new AppRoleSecret(secretID),
token);
return true;
}
@ -346,10 +384,10 @@ public class HTTPVaultConnector implements VaultConnector {
requireAuth();
SecretListResponse secrets = request.get(
PATH_AUTH_APPROLE + "/role?list=true",
emptyMap(),
token,
SecretListResponse.class
PATH_AUTH_APPROLE + "role?list=true",
emptyMap(),
token,
SecretListResponse.class
);
return secrets.getKeys();
@ -360,10 +398,10 @@ public class HTTPVaultConnector implements VaultConnector {
requireAuth();
SecretListResponse secrets = request.get(
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id?list=true"),
emptyMap(),
token,
SecretListResponse.class
String.format(PATH_AUTH_APPROLE_ROLE, roleName, "/secret-id?list=true"),
emptyMap(),
token,
SecretListResponse.class
);
return secrets.getKeys();
@ -373,22 +411,23 @@ public class HTTPVaultConnector implements VaultConnector {
public final SecretResponse read(final String key) throws VaultConnectorException {
requireAuth();
/* Issue request and parse secret response */
return request.get(key, emptyMap(), token, PlainSecretResponse.class);
return request.get(key, emptyMap(), token, SecretResponse.class);
}
@Override
public final SecretResponse readSecretVersion(final String mount, final String key, final Integer version)
throws VaultConnectorException {
public final SecretResponse readSecretVersion(final String mount, final String key, final Integer version) throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse secret metadata */
Map<String, String> args = mapOfStrings("version", version);
Map<String, String> args = new HashMap<>(1, 1);
if (version != null) {
args.put("version", version.toString());
}
return request.get(mount + PATH_DATA + key, args, token, MetaSecretResponse.class);
return request.get(mount + PATH_DATA + key, args, token, SecretResponse.class);
}
@Override
public final MetadataResponse readSecretMetadata(final String mount, final String key)
throws VaultConnectorException {
public final MetadataResponse readSecretMetadata(final String mount, final String key) throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse secret metadata */
@ -396,25 +435,20 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
public void updateSecretMetadata(final String mount,
final String key,
final Integer maxVersions,
final boolean casRequired) throws VaultConnectorException {
public void updateSecretMetadata(final String mount, final String key, final Integer maxVersions, final boolean casRequired) throws VaultConnectorException {
requireAuth();
Map<String, Object> payload = mapOf(
"max_versions", maxVersions,
"cas_required", casRequired
);
Map<String, Object> payload = new HashMap<>(2, 1);
if (maxVersions != null) {
payload.put("max_versions", maxVersions);
}
payload.put("cas_required", casRequired);
write(mount + PATH_METADATA + key, payload);
}
@Override
public final SecretVersionResponse writeSecretData(final String mount,
final String key,
final Map<String, Object> data,
final Integer cas) throws VaultConnectorException {
public final SecretVersionResponse writeSecretData(final String mount, final String key, final Map<String, Object> data, final Integer cas) throws VaultConnectorException {
requireAuth();
if (key == null || key.isEmpty()) {
@ -422,17 +456,22 @@ public class HTTPVaultConnector implements VaultConnector {
}
// Add CAS value to options map if present.
Map<String, Object> options = mapOf("cas", cas);
Map<String, Object> options;
if (cas != null) {
options = singletonMap("cas", cas);
} else {
options = emptyMap();
}
/* Issue request and parse metadata response */
return request.post(
mount + PATH_DATA + key,
Map.of(
"data", data,
"options", options
),
token,
SecretVersionResponse.class
mount + PATH_DATA + key,
Map.of(
"data", data,
"options", options
),
token,
SecretVersionResponse.class
);
}
@ -446,22 +485,21 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
public final void write(final String key, final Map<String, Object> data, final Map<String, Object> options)
throws VaultConnectorException {
public final void write(final String key, final Map<String, Object> data, final Map<String, Object> options) throws VaultConnectorException {
requireAuth();
if (key == null || key.isEmpty()) {
throw new InvalidRequestException("Secret path must not be empty.");
}
// By default, data is directly passed as payload.
// By default data is directly passed as payload.
Object payload = data;
// If options are given, split payload in two parts.
if (options != null) {
payload = Map.of(
"data", data,
"options", options
"data", data,
"options", options
);
}
@ -488,20 +526,17 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
public final void deleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
public final void deleteSecretVersions(final String mount, final String key, final int... versions) throws VaultConnectorException {
handleSecretVersions(mount, PATH_DELETE, key, versions);
}
@Override
public final void undeleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
public final void undeleteSecretVersions(final String mount, final String key, final int... versions) throws VaultConnectorException {
handleSecretVersions(mount, PATH_UNDELETE, key, versions);
}
@Override
public final void destroySecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
public final void destroySecretVersions(final String mount, final String key, final int... versions) throws VaultConnectorException {
handleSecretVersions(mount, PATH_DESTROY, key, versions);
}
@ -515,10 +550,7 @@ public class HTTPVaultConnector implements VaultConnector {
* @throws VaultConnectorException on error
* @since 0.8
*/
private void handleSecretVersions(final String mount,
final String pathPart,
final String key,
final int... versions) throws VaultConnectorException {
private void handleSecretVersions(final String mount, final String pathPart, final String key, final int... versions) throws VaultConnectorException {
requireAuth();
/* Request HTTP response and expect empty result */
@ -540,10 +572,11 @@ public class HTTPVaultConnector implements VaultConnector {
public final SecretResponse renew(final String leaseID, final Integer increment) throws VaultConnectorException {
requireAuth();
Map<String, String> payload = mapOfStrings(
"lease_id", leaseID,
"increment", increment
);
Map<String, String> payload = new HashMap<>(2, 1);
payload.put("lease_id", leaseID);
if (increment != null) {
payload.put("increment", increment.toString());
}
/* Issue request and parse secret response */
return request.put(PATH_RENEW, payload, token, SecretResponse.class);
@ -551,12 +584,12 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final AuthResponse createToken(final Token token) throws VaultConnectorException {
return createTokenInternal(token, PATH_AUTH_TOKEN + PATH_CREATE);
return createTokenInternal(token, PATH_TOKEN + PATH_CREATE);
}
@Override
public final AuthResponse createToken(final Token token, final boolean orphan) throws VaultConnectorException {
return createTokenInternal(token, PATH_AUTH_TOKEN + PATH_CREATE_ORPHAN);
return createTokenInternal(token, PATH_TOKEN + PATH_CREATE_ORPHAN);
}
@Override
@ -564,7 +597,7 @@ public class HTTPVaultConnector implements VaultConnector {
if (role == null || role.isEmpty()) {
throw new InvalidRequestException("No role name specified.");
}
return createTokenInternal(token, PATH_AUTH_TOKEN + PATH_CREATE + "/" + role);
return createTokenInternal(token, PATH_TOKEN + PATH_CREATE + "/" + role);
}
@Override
@ -599,10 +632,10 @@ public class HTTPVaultConnector implements VaultConnector {
/* Request HTTP response and parse Secret */
return request.get(
PATH_AUTH_TOKEN + PATH_LOOKUP,
singletonMap("token", token),
token,
TokenResponse.class
PATH_TOKEN + PATH_LOOKUP,
singletonMap("token", token),
token,
TokenResponse.class
);
}
@ -617,7 +650,7 @@ public class HTTPVaultConnector implements VaultConnector {
}
// Issue request and expect code 204 with empty response.
request.postWithoutResponse(PATH_AUTH_TOKEN + PATH_ROLES + "/" + name, role, token);
request.postWithoutResponse(PATH_TOKEN + PATH_ROLES + "/" + name, role, token);
return true;
}
@ -627,14 +660,14 @@ public class HTTPVaultConnector implements VaultConnector {
requireAuth();
// Request HTTP response and parse response.
return request.get(PATH_AUTH_TOKEN + PATH_ROLES + "/" + name, emptyMap(), token, TokenRoleResponse.class);
return request.get(PATH_TOKEN + PATH_ROLES + "/" + name, emptyMap(), token, TokenRoleResponse.class);
}
@Override
public List<String> listTokenRoles() throws VaultConnectorException {
requireAuth();
return list(PATH_AUTH_TOKEN + PATH_ROLES);
return list(PATH_TOKEN + PATH_ROLES);
}
@Override
@ -646,52 +679,11 @@ public class HTTPVaultConnector implements VaultConnector {
}
// Issue request and expect code 204 with empty response.
request.deleteWithoutResponse(PATH_AUTH_TOKEN + PATH_ROLES + "/" + name, token);
request.deleteWithoutResponse(PATH_TOKEN + PATH_ROLES + "/" + name, token);
return true;
}
@Override
public final TransitResponse transitEncrypt(final String keyName, final String plaintext)
throws VaultConnectorException {
requireAuth();
Map<String, Object> payload = mapOf(
"plaintext", plaintext
);
return request.post(PATH_TRANSIT_ENCRYPT + keyName, payload, token, TransitResponse.class);
}
@Override
public final TransitResponse transitDecrypt(final String keyName, final String ciphertext)
throws VaultConnectorException {
requireAuth();
Map<String, Object> payload = mapOf(
"ciphertext", ciphertext
);
return request.post(PATH_TRANSIT_DECRYPT + keyName, payload, token, TransitResponse.class);
}
@Override
public final TransitResponse transitHash(final String algorithm, final String input, final String format)
throws VaultConnectorException {
if (format != null && !"hex".equals(format) && !"base64".equals(format)) {
throw new IllegalArgumentException("Unsupported format " + format);
}
requireAuth();
Map<String, Object> payload = mapOf(
"input", input,
"format", format
);
return request.post(PATH_TRANSIT_HASH + algorithm, payload, token, TransitResponse.class);
}
/**
* Check for required authorization.
*
@ -703,42 +695,4 @@ public class HTTPVaultConnector implements VaultConnector {
throw new AuthorizationRequiredException();
}
}
/**
* Generate a map of non-null {@link String} keys and values
*
* @param keyValues Key-value tuples as vararg.
* @return The map of non-null keys and values.
*/
private static Map<String, String> mapOfStrings(Object... keyValues) {
Map<String, String> map = new HashMap<>(keyValues.length / 2, 1);
for (int i = 0; i < keyValues.length - 1; i = i + 2) {
Object key = keyValues[i];
Object val = keyValues[i + 1];
if (key instanceof String && val != null) {
map.put((String) key, val.toString());
}
}
return map;
}
/**
* Generate a map of non-null {@link String} keys and {@link Object} values
*
* @param keyValues Key-value tuples as vararg.
* @return The map of non-null keys and values.
*/
private static Map<String, Object> mapOf(Object... keyValues) {
Map<String, Object> map = new HashMap<>(keyValues.length / 2, 1);
for (int i = 0; i < keyValues.length; i = i + 2) {
Object key = keyValues[i];
Object val = keyValues[i + 1];
if (key instanceof String && val != null) {
map.put((String) key, val);
}
}
return map;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,17 +20,18 @@ import de.stklcode.jvault.connector.exception.ConnectionException;
import de.stklcode.jvault.connector.exception.TlsException;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Objects;
/**
* Vault Connector Builder implementation for HTTP Vault connectors.
@ -95,14 +96,10 @@ public final class HTTPVaultConnectorBuilder {
* @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);
return withTLS(!("http".equalsIgnoreCase(Objects.requireNonNullElse(baseURL.getScheme(), ""))))
.withHost(baseURL.getHost())
.withPort(baseURL.getPort())
.withPrefix(baseURL.getPath());
}
/**
@ -296,7 +293,7 @@ public final class HTTPVaultConnectorBuilder {
}
/**
* Build connector based on the {@code VAULT_ADDR} and {@code VAULT_CACERT} (optional) environment variables.
* 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
@ -304,10 +301,13 @@ public final class HTTPVaultConnectorBuilder {
*/
public HTTPVaultConnectorBuilder fromEnv() throws VaultConnectorException {
/* Parse URL from environment variable */
if (System.getenv(ENV_VAULT_ADDR) != null && !System.getenv(ENV_VAULT_ADDR).isBlank()) {
if (System.getenv(ENV_VAULT_ADDR) != null && !System.getenv(ENV_VAULT_ADDR).trim().isEmpty()) {
try {
withBaseURL(System.getenv(ENV_VAULT_ADDR));
} catch (URISyntaxException e) {
var url = new URL(System.getenv(ENV_VAULT_ADDR));
this.host = url.getHost();
this.port = url.getPort();
this.tls = url.getProtocol().equals("https");
} catch (MalformedURLException e) {
throw new ConnectionException("URL provided in environment variable malformed", e);
}
}
@ -315,7 +315,7 @@ public final class HTTPVaultConnectorBuilder {
/* Read number of retries */
if (System.getenv(ENV_VAULT_MAX_RETRIES) != null) {
try {
withNumberOfRetries(Integer.parseInt(System.getenv(ENV_VAULT_MAX_RETRIES)));
numberOfRetries = Integer.parseInt(System.getenv(ENV_VAULT_MAX_RETRIES));
} catch (NumberFormatException ignored) {
/* Ignore malformed values. */
}
@ -325,12 +325,8 @@ public final class HTTPVaultConnectorBuilder {
token = System.getenv(ENV_VAULT_TOKEN);
/* Parse certificate, if set */
if (System.getenv(ENV_VAULT_CACERT) != null && !System.getenv(ENV_VAULT_CACERT).isBlank()) {
X509Certificate cert = certificateFromString(System.getenv(ENV_VAULT_CACERT));
if (cert == null) {
cert = certificateFromFile(Paths.get(System.getenv(ENV_VAULT_CACERT)));
}
return withTrustedCA(cert);
if (System.getenv(ENV_VAULT_CACERT) != null && !System.getenv(ENV_VAULT_CACERT).trim().isEmpty()) {
return withTrustedCA(Paths.get(System.getenv(ENV_VAULT_CACERT)));
}
return this;
}
@ -402,28 +398,6 @@ public final class HTTPVaultConnectorBuilder {
return con;
}
/**
* Read given certificate file to X.509 certificate.
*
* @param cert Certificate string (optionally PEM)
* @return X.509 Certificate object if parseable, else {@code null}
* @throws TlsException on error
* @since 1.5.0
*/
private X509Certificate certificateFromString(final String cert) throws TlsException {
// Check if PEM header is present in given string
if (cert.contains("-BEGIN ") && cert.contains("-END")) {
try (var is = new ByteArrayInputStream(cert.getBytes(StandardCharsets.UTF_8))) {
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
} catch (IOException | CertificateException e) {
throw new TlsException("Unable to read certificate.", e);
}
}
// Not am PEM string, skip
return null;
}
/**
* Read given certificate file to X.509 certificate.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,7 +21,10 @@ import de.stklcode.jvault.connector.model.*;
import de.stklcode.jvault.connector.model.response.*;
import java.io.Serializable;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Vault Connector interface.
@ -109,6 +112,18 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
AuthResponse authUserPass(final String username, final String password) throws VaultConnectorException;
/**
* Authorize to Vault using AppID method.
*
* @param appID The App ID
* @param userID The User ID
* @return The {@link AuthResponse}
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. Consider using {@link #authAppRole} instead.
*/
@Deprecated(since = "0.4", forRemoval = false)
AuthResponse authAppId(final String appID, final String userID) throws VaultConnectorException;
/**
* Authorize to Vault using AppRole method without secret ID.
*
@ -132,6 +147,20 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
AuthResponse authAppRole(final String roleID, final String secretID) throws VaultConnectorException;
/**
* Register new App-ID with policy.
*
* @param appID The unique App-ID
* @param policy The policy to associate with
* @param displayName Arbitrary name to display
* @return {@code true} on success
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. Consider using {@link #createAppRole} instead.
*/
@Deprecated(since = "0.4", forRemoval = false)
boolean registerAppId(final String appID, final String policy, final String displayName)
throws VaultConnectorException;
/**
* Register a new AppRole role from given metamodel.
*
@ -191,7 +220,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @since 0.4.0
*/
default boolean createAppRole(final String roleName, final List<String> policies, final String roleID)
throws VaultConnectorException {
throws VaultConnectorException {
return createAppRole(AppRole.builder(roleName).withTokenPolicies(policies).withId(roleID).build());
}
@ -257,7 +286,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @since 0.4.0
*/
default AppRoleSecretResponse createAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException {
throws VaultConnectorException {
return createAppRoleSecret(roleName, new AppRoleSecret(secretID));
}
@ -271,7 +300,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @since 0.4.0
*/
AppRoleSecretResponse createAppRoleSecret(final String roleName, final AppRoleSecret secret)
throws VaultConnectorException;
throws VaultConnectorException;
/**
* Lookup an AppRole secret.
@ -283,7 +312,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @since 0.4.0
*/
AppRoleSecretResponse lookupAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException;
throws VaultConnectorException;
/**
* Destroy an AppRole secret.
@ -313,6 +342,38 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
List<String> listAppRoleSecrets(final String roleName) throws VaultConnectorException;
/**
* Register User-ID with App-ID.
*
* @param appID The App-ID
* @param userID The User-ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole.
* Consider using {@link #createAppRoleSecret} instead.
*/
@Deprecated(since = "0.4", forRemoval = false)
boolean registerUserId(final String appID, final String userID) throws VaultConnectorException;
/**
* Register new App-ID and User-ID at once.
*
* @param appID The App-ID
* @param policy The policy to associate with
* @param displayName Arbitrary name to display
* @param userID The User-ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole.
*/
@Deprecated(since = "0.4", forRemoval = false)
default boolean registerAppUserId(final String appID,
final String policy,
final String displayName,
final String userID) throws VaultConnectorException {
return registerAppId(appID, policy, userID) && registerUserId(appID, userID);
}
/**
* Get authorization status.
*
@ -359,9 +420,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @throws VaultConnectorException on error
* @since 0.8
*/
default SecretVersionResponse writeSecretData(final String mount,
final String key,
final Map<String, Object> data) throws VaultConnectorException {
default SecretVersionResponse writeSecretData(final String mount, final String key, final Map<String, Object> data) throws VaultConnectorException {
return writeSecretData(mount, key, data, null);
}
@ -379,10 +438,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @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;
SecretVersionResponse writeSecretData(final String mount, final String key, final Map<String, Object> data, final Integer cas) throws VaultConnectorException;
/**
* Retrieve secret data from Vault.
@ -397,8 +453,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @throws VaultConnectorException on error
* @since 0.8
*/
SecretResponse readSecretVersion(final String mount, final String key, final Integer version)
throws VaultConnectorException;
SecretResponse readSecretVersion(final String mount, final String key, final Integer version) throws VaultConnectorException;
/**
* Retrieve secret metadata from Vault.
@ -427,10 +482,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @throws VaultConnectorException on error
* @since 0.8
*/
void updateSecretMetadata(final String mount,
final String key,
final Integer maxVersions,
final boolean casRequired) throws VaultConnectorException;
void updateSecretMetadata(final String mount, final String key, final Integer maxVersions, final boolean casRequired) throws VaultConnectorException;
/**
* List available nodes from Vault.
@ -475,8 +527,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @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;
void write(final String key, final Map<String, Object> data, final Map<String, Object> options) throws VaultConnectorException;
/**
* Delete key from Vault.
@ -523,8 +574,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
void deleteSecretVersions(final String mount, final String key, final int... versions) throws VaultConnectorException;
/**
* Undelete (restore) secret versions from Vault.
@ -536,8 +586,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @throws VaultConnectorException on error
* @since 0.8
*/
void undeleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
void undeleteSecretVersions(final String mount, final String key, final int... versions) throws VaultConnectorException;
/**
* Destroy secret versions from Vault.
@ -549,8 +598,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @throws VaultConnectorException on error
* @since 0.8
*/
void destroySecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
void destroySecretVersions(final String mount, final String key, final int... versions) throws VaultConnectorException;
/**
* Revoke given lease immediately.
@ -671,82 +719,6 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
boolean deleteTokenRole(final String name) throws VaultConnectorException;
/**
* Encrypt plaintext via transit engine from Vault.
*
* @param keyName Transit key name
* @param plaintext Text to encrypt (Base64 encoded)
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse transitEncrypt(final String keyName, final String plaintext) throws VaultConnectorException;
/**
* Encrypt plaintext via transit engine from Vault.
*
* @param keyName Transit key name
* @param plaintext Binary data to encrypt
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse transitEncrypt(final String keyName, final byte[] plaintext)
throws VaultConnectorException {
return transitEncrypt(keyName, Base64.getEncoder().encodeToString(plaintext));
}
/**
* Decrypt ciphertext via transit engine from Vault.
*
* @param keyName Transit key name
* @param ciphertext Text to decrypt
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse transitDecrypt(final String keyName, final String ciphertext) throws VaultConnectorException;
/**
* Hash data in hex format via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse transitHash(final String algorithm, final String input) throws VaultConnectorException {
return transitHash(algorithm, input, "hex");
}
/**
* Hash data via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash (Base64 encoded)
* @param format Specifies the output encoding (hex/base64)
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse transitHash(final String algorithm, final String input, final String format)
throws VaultConnectorException;
/**
* Hash data via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse transitHash(final String algorithm, final byte[] input, final String format)
throws VaultConnectorException {
return transitHash(algorithm, Base64.getEncoder().encodeToString(input), format);
}
/**
* Read credentials for MySQL backend at default mount point.
*
@ -754,9 +726,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @return the credentials response
* @throws VaultConnectorException on error
* @since 0.5.0
* @deprecated use {@link #readDbCredentials(String, String)} your MySQL mountpoint
*/
@Deprecated(since = "1.5.0", forRemoval = true)
default CredentialsResponse readMySqlCredentials(final String role) throws VaultConnectorException {
return readDbCredentials(role, "mysql");
}
@ -768,9 +738,7 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @return the credentials response
* @throws VaultConnectorException on error
* @since 0.5.0
* @deprecated use {@link #readDbCredentials(String, String)} your PostgreSQL mountpoint
*/
@Deprecated(since = "1.5.0", forRemoval = true)
default CredentialsResponse readPostgreSqlCredentials(final String role) throws VaultConnectorException {
return readDbCredentials(role, "postgresql");
}
@ -782,38 +750,34 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @return the credentials response
* @throws VaultConnectorException on error
* @since 0.5.0
* @deprecated use {@link #readDbCredentials(String, String)} your MSSQL mountpoint
*/
@Deprecated(since = "1.5.0", forRemoval = true)
default CredentialsResponse readMsSqlCredentials(final String role) throws VaultConnectorException {
return readDbCredentials(role, "mssql");
}
/**
* Read credentials for MongoDB backend at default mount point.
* 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 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.
* Read credentials for SQL backends.
*
* @param role the role name
* @param mount mount point of the database backend
* @param mount mount point of the SQL backend
* @return the credentials response
* @throws VaultConnectorException on error
* @since 0.5.0
*/
default CredentialsResponse readDbCredentials(final String role, final String mount)
throws VaultConnectorException {
throws VaultConnectorException {
return (CredentialsResponse) read(mount + "/creds/" + role);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,5 +23,4 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public class AuthorizationRequiredException extends VaultConnectorException {
private static final long serialVersionUID = 2629577936657393880L;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,8 +23,6 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public class ConnectionException extends VaultConnectorException {
private static final long serialVersionUID = 3005430116002990418L;
/**
* Constructs a new empty exception.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,8 +23,6 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public class InvalidRequestException extends VaultConnectorException {
private static final long serialVersionUID = -6712239648281809159L;
/**
* Constructs a new empty exception.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -24,8 +24,6 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public final class InvalidResponseException extends VaultConnectorException {
private static final long serialVersionUID = 2003151038614163479L;
private final Integer statusCode;
private final String response;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,8 +23,6 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public class PermissionDeniedException extends VaultConnectorException {
private static final long serialVersionUID = -7149134015090750776L;
/**
* Constructs a new empty exception.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,8 +23,6 @@ package de.stklcode.jvault.connector.exception;
* @since 0.4.0
*/
public class TlsException extends VaultConnectorException {
private static final long serialVersionUID = -5139276834988258086L;
/**
* Constructs a new empty exception.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,8 +23,6 @@ package de.stklcode.jvault.connector.exception;
* @since 0.1
*/
public abstract class VaultConnectorException extends Exception {
private static final long serialVersionUID = -2612477894310906036L;
/**
* Constructs a new empty exception.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,10 +1,7 @@
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 com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.*;
import de.stklcode.jvault.connector.model.response.ErrorResponse;
@ -44,7 +41,7 @@ public final class RequestHelper implements Serializable {
private final int retries; // Number of retries on 5xx errors.
private final String tlsVersion; // TLS version (#22).
private final X509Certificate trustedCaCert; // Trusted CA certificate.
private final JsonMapper jsonMapper;
private final ObjectMapper jsonMapper;
/**
* Constructor of the request helper.
@ -65,11 +62,7 @@ public final class RequestHelper implements Serializable {
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();
this.jsonMapper = new ObjectMapper();
}
/**
@ -116,7 +109,7 @@ public final class RequestHelper implements Serializable {
* @since 0.8
*/
public <T> T post(final String path, final Object payload, final String token, final Class<T> target)
throws VaultConnectorException {
throws VaultConnectorException {
try {
String response = post(path, payload, token);
return jsonMapper.readValue(response, target);
@ -134,8 +127,7 @@ public final class RequestHelper implements Serializable {
* @throws VaultConnectorException on connection error
* @since 0.8
*/
public void postWithoutResponse(final String path, final Object payload, final String token)
throws VaultConnectorException {
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);
}
@ -151,8 +143,7 @@ public final class RequestHelper implements Serializable {
* @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 {
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));
@ -186,7 +177,7 @@ public final class RequestHelper implements Serializable {
* @since 0.8
*/
public <T> T put(final String path, final Map<String, String> payload, final String token, final Class<T> target)
throws VaultConnectorException {
throws VaultConnectorException {
try {
String response = put(path, payload, token);
return jsonMapper.readValue(response, target);
@ -205,7 +196,7 @@ public final class RequestHelper implements Serializable {
* @since 0.8
*/
public void putWithoutResponse(final String path, final Map<String, String> payload, final String token)
throws VaultConnectorException {
throws VaultConnectorException {
if (!put(path, payload, token).isEmpty()) {
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
}
@ -257,15 +248,15 @@ public final class RequestHelper implements Serializable {
* @since 0.8 Added {@code token} parameter.
*/
public String get(final String path, final Map<String, String> payload, final String token)
throws VaultConnectorException {
throws VaultConnectorException {
// Add parameters to URI.
var uriBuilder = new StringBuilder(baseURL + path);
if (!payload.isEmpty()) {
uriBuilder.append("?").append(
payload.entrySet().stream().map(par ->
URLEncoder.encode(par.getKey(), UTF_8) + "=" + URLEncoder.encode(par.getValue(), UTF_8)
).collect(Collectors.joining("&"))
payload.entrySet().stream().map(
par -> URLEncoder.encode(par.getKey(), UTF_8) + "=" + URLEncoder.encode(par.getValue(), UTF_8)
).collect(Collectors.joining("&"))
);
}
@ -298,7 +289,7 @@ public final class RequestHelper implements Serializable {
* @since 0.8
*/
public <T> T get(final String path, final Map<String, String> payload, final String token, final Class<T> target)
throws VaultConnectorException {
throws VaultConnectorException {
try {
String response = get(path, payload, token);
return jsonMapper.readValue(response, target);
@ -334,8 +325,8 @@ public final class RequestHelper implements Serializable {
// Execute request.
try {
HttpResponse<InputStream> response = client.sendAsync(
requestBuilder.build(),
HttpResponse.BodyHandlers.ofInputStream()
requestBuilder.build(),
HttpResponse.BodyHandlers.ofInputStream()
).join();
/* Check if response is valid */
@ -364,15 +355,6 @@ public final class RequestHelper implements Serializable {
}
} 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
}
}
}
}
@ -404,8 +386,7 @@ public final class RequestHelper implements Serializable {
}
return sslContext;
} catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException |
KeyManagementException e) {
} catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException | KeyManagementException e) {
throw new TlsException(Error.INIT_SSL_CONTEXT, e);
}
}
@ -418,7 +399,7 @@ public final class RequestHelper implements Serializable {
* @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))) {
try (var reader = new BufferedReader(new InputStreamReader(response.body()))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (IOException ignored) {
throw new InvalidResponseException(Error.READ_RESPONSE, 200);
@ -432,19 +413,18 @@ public final class RequestHelper implements Serializable {
* @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());
if (response.body() != null) {
try (var reader = new BufferedReader(new InputStreamReader(response.body()))) {
var responseString = reader.lines().collect(Collectors.joining("\n"));
ErrorResponse er = jsonMapper.readValue(responseString, ErrorResponse.class);
/* Check for "permission denied" response */
if (!er.getErrors().isEmpty() && er.getErrors().get(0).equals("permission denied")) {
throw new PermissionDeniedException();
}
throw new InvalidResponseException(Error.RESPONSE_CODE, response.statusCode(), er.toString());
} catch (IOException ignored) {
// Exception ignored.
}
} catch (IOException ignored) {
// Exception ignored.
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,21 +18,27 @@ 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;
public final class AppRole {
/**
* 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);
}
@JsonProperty("role_name")
private String name;
@ -55,9 +61,9 @@ public final class AppRole implements Serializable {
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer secretIdTtl;
@JsonProperty("local_secret_ids")
@JsonProperty("enable_local_secret_ids")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean localSecretIds;
private Boolean enableLocalSecretIds;
@JsonProperty("token_ttl")
@JsonInclude(JsonInclude.Include.NON_NULL)
@ -111,7 +117,7 @@ public final class AppRole implements Serializable {
this.secretIdBoundCidrs = builder.secretIdBoundCidrs;
this.secretIdNumUses = builder.secretIdNumUses;
this.secretIdTtl = builder.secretIdTtl;
this.localSecretIds = builder.localSecretIds;
this.enableLocalSecretIds = builder.enableLocalSecretIds;
this.tokenTtl = builder.tokenTtl;
this.tokenMaxTtl = builder.tokenMaxTtl;
this.tokenPolicies = builder.tokenPolicies;
@ -123,17 +129,6 @@ public final class AppRole implements Serializable {
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
*/
@ -262,10 +257,9 @@ public final class AppRole implements Serializable {
/**
* @return Enable local secret IDs?
* @since 0.9
* @since 1.3 renamed to {@code getLocalSecretIds()}
*/
public Boolean getLocalSecretIds() {
return localSecretIds;
public Boolean getEnableLocalSecretIds() {
return enableLocalSecretIds;
}
/**
@ -322,39 +316,6 @@ public final class AppRole implements Serializable {
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..
@ -371,7 +332,7 @@ public final class AppRole implements Serializable {
private List<String> tokenPolicies;
private Integer secretIdNumUses;
private Integer secretIdTtl;
private Boolean localSecretIds;
private Boolean enableLocalSecretIds;
private Integer tokenTtl;
private Integer tokenMaxTtl;
private List<String> tokenBoundCidrs;
@ -528,13 +489,12 @@ public final class AppRole implements Serializable {
/**
* Enable or disable local secret IDs.
*
* @param localSecretIds Enable local secret IDs?
* @param enableLocalSecretIds 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;
public Builder withEnableLocalSecretIds(final Boolean enableLocalSecretIds) {
this.enableLocalSecretIds = enableLocalSecretIds;
return this;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,22 +18,17 @@ 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;
public final class AppRoleSecret {
@JsonProperty("secret_id")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String id;
@ -171,29 +166,4 @@ public final class AppRoleSecret implements Serializable {
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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -24,6 +24,7 @@ package de.stklcode.jvault.connector.model;
*/
public enum AuthBackend {
TOKEN("token"),
APPID("app-id"),
APPROLE("approle"),
USERPASS("userpass"),
GITHUB("github"), // Not supported yet.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,7 +20,6 @@ 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.*;
/**
@ -28,11 +27,18 @@ import java.util.*;
*
* @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;
public final class Token {
/**
* Get {@link Builder} instance.
*
* @return Token Builder.
* @since 0.8
*/
public static Builder builder() {
return new Builder();
}
@JsonProperty("id")
@JsonInclude(JsonInclude.Include.NON_NULL)
@ -113,16 +119,6 @@ public final class Token implements Serializable {
this.entityAlias = builder.entityAlias;
}
/**
* Get {@link Builder} instance.
*
* @return Token Builder.
* @since 0.8
*/
public static Builder builder() {
return new Builder();
}
/**
* @return Token ID
*/
@ -218,35 +214,6 @@ public final class Token implements Serializable {
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.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,21 +20,25 @@ 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;
public final class TokenRole {
/**
* Get {@link Builder} instance.
*
* @return Token Role Builder.
*/
public static Builder builder() {
return new Builder();
}
@JsonProperty("name")
@JsonInclude(JsonInclude.Include.NON_NULL)
@ -44,18 +48,10 @@ public final class TokenRole implements Serializable {
@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;
@ -105,9 +101,7 @@ public final class TokenRole implements Serializable {
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;
@ -120,15 +114,6 @@ public final class TokenRole implements Serializable {
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
*/
@ -143,14 +128,6 @@ public final class TokenRole implements Serializable {
return allowedPolicies;
}
/**
* @return List of allowed policy glob patterns
* @since 1.1
*/
public List<String> getAllowedPoliciesGlob() {
return allowedPoliciesGlob;
}
/**
* @return List of disallowed policies
*/
@ -158,14 +135,6 @@ public final class TokenRole implements Serializable {
return disallowedPolicies;
}
/**
* @return List of disallowed policy glob patterns
* @since 1.1
*/
public List<String> getDisallowedPoliciesGlob() {
return disallowedPoliciesGlob;
}
/**
* @return Is Token Role orphan?
*/
@ -236,38 +205,6 @@ public final class TokenRole implements Serializable {
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.
*
@ -277,9 +214,7 @@ public final class TokenRole implements Serializable {
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;
@ -334,40 +269,6 @@ public final class TokenRole implements Serializable {
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.
*
@ -400,40 +301,6 @@ public final class TokenRole implements Serializable {
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.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,10 +17,13 @@
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.AppRole;
import java.util.Objects;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Vault response for AppRole lookup.
@ -30,31 +33,29 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRoleResponse extends VaultDataResponse {
private static final long serialVersionUID = -6536422219633829177L;
@JsonProperty("data")
private AppRole role;
@Override
public void setData(final Map<String, Object> data) throws InvalidResponseException {
var mapper = new ObjectMapper();
try {
/* null empty strings on list objects */
Map<String, Object> filteredData = new HashMap<>(data.size(), 1);
data.forEach((k, v) -> {
if (!(v instanceof String && ((String) v).isEmpty())) {
filteredData.put(k, v);
}
});
this.role = mapper.readValue(mapper.writeValueAsString(filteredData), AppRole.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
/**
* @return The role
*/
public AppRole getRole() {
return role;
}
@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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,10 +17,13 @@
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.AppRoleSecret;
import java.util.Objects;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Vault response for AppRole lookup.
@ -30,31 +33,29 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRoleSecretResponse extends VaultDataResponse {
private static final long serialVersionUID = -2484103304072370585L;
@JsonProperty("data")
private AppRoleSecret secret;
@Override
public void setData(final Map<String, Object> data) throws InvalidResponseException {
var mapper = new ObjectMapper();
try {
/* null empty strings on list objects */
Map<String, Object> filteredData = new HashMap<>(data.size(), 1);
data.forEach((k, v) -> {
if (!(v instanceof String && ((String) v).isEmpty())) {
filteredData.put(k, v);
}
});
this.secret = mapper.readValue(mapper.writeValueAsString(filteredData), AppRoleSecret.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
/**
* @return The secret
*/
public AppRoleSecret getSecret() {
return secret;
}
@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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,12 +17,13 @@
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.AuthMethod;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* Authentication method response.
@ -32,9 +33,6 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthMethodsResponse extends VaultDataResponse {
private static final long serialVersionUID = -1802724129533405375L;
@JsonProperty("data")
private Map<String, AuthMethod> supportedMethods;
/**
@ -44,26 +42,23 @@ public final class AuthMethodsResponse extends VaultDataResponse {
this.supportedMethods = new HashMap<>();
}
@Override
public void setData(final Map<String, Object> data) throws InvalidResponseException {
var mapper = new ObjectMapper();
for (Map.Entry<String, Object> entry : data.entrySet()) {
try {
this.supportedMethods.put(entry.getKey(),
mapper.readValue(mapper.writeValueAsString(entry.getValue()), AuthMethod.class));
} catch (IOException e) {
throw new InvalidResponseException();
}
}
}
/**
* @return Supported authentication methods
*/
public Map<String, AuthMethod> getSupportedMethods() {
return supportedMethods;
}
@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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,8 +17,14 @@
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.
*
@ -27,5 +33,42 @@ import de.stklcode.jvault.connector.model.response.embedded.AuthData;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthResponse extends VaultDataResponse {
private static final long serialVersionUID = 1628851361067456715L;
private Map<String, Object> data;
private AuthData auth;
/**
* Set authentication data. The input will be mapped to the {@link AuthData} model.
*
* @param auth Raw authentication data
* @throws InvalidResponseException on mapping errors
*/
@JsonProperty("auth")
public void setAuth(final Map<String, Object> auth) throws InvalidResponseException {
var mapper = new ObjectMapper();
try {
this.auth = mapper.readValue(mapper.writeValueAsString(auth), AuthData.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
@Override
public void setData(final Map<String, Object> data) {
this.data = data;
}
/**
* @return Raw data
*/
public Map<String, Object> getData() {
return data;
}
/**
* @return Authentication data
*/
public AuthData getAuth() {
return auth;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -25,8 +25,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
* @since 0.5.0
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class CredentialsResponse extends PlainSecretResponse {
private static final long serialVersionUID = -1439692963299045425L;
public final class CredentialsResponse extends SecretResponse {
/**
* @return Username

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,7 +20,6 @@ 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.
@ -30,8 +29,6 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class ErrorResponse implements VaultResponse {
private static final long serialVersionUID = -6227368087842549149L;
@JsonProperty("errors")
private List<String> errors;
@ -50,20 +47,4 @@ public final class ErrorResponse implements VaultResponse {
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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,8 +19,6 @@ 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.
*
@ -29,8 +27,6 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class HealthResponse implements VaultResponse {
private static final long serialVersionUID = 8675155916902904516L;
@JsonProperty("cluster_id")
private String clusterID;
@ -52,7 +48,7 @@ public final class HealthResponse implements VaultResponse {
@JsonProperty("initialized")
private Boolean initialized;
@JsonProperty("replication_performance_mode")
@JsonProperty("replication_perf_mode")
private String replicationPerfMode;
@JsonProperty("replication_dr_mode")
@ -61,18 +57,6 @@ public final class HealthResponse implements VaultResponse {
@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.
*/
@ -145,67 +129,4 @@ public final class HealthResponse implements VaultResponse {
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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,8 +19,6 @@ 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.
*
@ -29,8 +27,6 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class HelpResponse implements VaultResponse {
private static final long serialVersionUID = -1152070966642848490L;
@JsonProperty("help")
private String help;
@ -40,20 +36,4 @@ public final class HelpResponse implements VaultResponse {
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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,11 +17,12 @@
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.SecretMetadata;
import java.util.Objects;
import java.io.IOException;
import java.util.Map;
/**
* Vault response for secret metadata (KV v2).
@ -31,11 +32,19 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class MetadataResponse extends VaultDataResponse {
private static final long serialVersionUID = -3679762333630984679L;
@JsonProperty("data")
private SecretMetadata metadata;
@Override
public final void setData(final Map<String, Object> data) throws InvalidResponseException {
var mapper = new ObjectMapper();
try {
this.metadata = mapper.readValue(mapper.writeValueAsString(data), SecretMetadata.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
/**
* Get the actual metadata.
*
@ -44,20 +53,4 @@ public class MetadataResponse extends VaultDataResponse {
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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,11 +17,8 @@
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.
@ -31,31 +28,17 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class RawDataResponse extends VaultDataResponse {
private static final long serialVersionUID = -319727427792124071L;
private Map<String, Object> data;
@JsonProperty("data")
private Map<String, Serializable> data;
@Override
public void setData(final Map<String, Object> data) {
this.data = data;
}
/**
* @return Raw data {@link Map}
*/
public Map<String, Serializable> getData() {
public Map<String, Object> 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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,9 +19,6 @@ 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.
*
@ -30,8 +27,6 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class SealResponse implements VaultResponse {
private static final long serialVersionUID = -6000309255473305787L;
@JsonProperty("type")
private String type;
@ -53,9 +48,6 @@ public final class SealResponse implements VaultResponse {
@JsonProperty("version")
private String version;
@JsonProperty("build_date")
private ZonedDateTime buildDate;
@JsonProperty("nonce")
private String nonce;
@ -65,15 +57,6 @@ public final class SealResponse implements VaultResponse {
@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
@ -126,14 +109,6 @@ public final class SealResponse implements VaultResponse {
return version;
}
/**
* @return Vault build date.
* @since 1.2
*/
public ZonedDateTime getBuildDate() {
return buildDate;
}
/**
* @return A random nonce.
* @since 0.8
@ -157,58 +132,4 @@ public final class SealResponse implements VaultResponse {
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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,11 +18,10 @@ 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.
@ -32,34 +31,27 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class SecretListResponse extends VaultDataResponse {
private List<String> keys;
private static final long serialVersionUID = 8597121175002967213L;
/**
* Set data. Extracts list of keys from raw response data.
*
* @param data Raw data
* @throws InvalidResponseException on parsing errors
*/
@JsonProperty("data")
private SecretListWrapper data;
public void setData(final 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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,15 +17,12 @@
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 com.fasterxml.jackson.databind.ObjectMapper;
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.Collections;
import java.util.Map;
/**
@ -33,20 +30,46 @@ import java.util.Map;
*
* @author Stefan Kalscheuer
* @since 0.1
* @since 1.1 abstract
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public abstract class SecretResponse extends VaultDataResponse {
private static final long serialVersionUID = 5198088815871692951L;
public class SecretResponse extends VaultDataResponse {
private static final String KEY_DATA = "data";
private static final String KEY_METADATA = "metadata";
private Map<String, Object> data;
private VersionMetadata metadata;
@Override
public final void setData(final Map<String, Object> data) throws InvalidResponseException {
if (data.size() == 2
&& data.containsKey(KEY_DATA) && data.get(KEY_DATA) instanceof Map
&& data.containsKey(KEY_METADATA) && data.get(KEY_METADATA) instanceof Map) {
var mapper = new ObjectMapper();
try {
// This is apparently a KV v2 value.
this.data = (Map<String, Object>) data.get(KEY_DATA);
this.metadata = mapper.readValue(mapper.writeValueAsString(data.get(KEY_METADATA)), VersionMetadata.class);
} catch (ClassCastException | IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
} else {
// For KV v1 without metadata just store the data map.
this.data = data;
}
}
/**
* Get complete data object.
*
* @return data map
* @since 0.4.0
* @since 1.1 Serializable map value.
*/
public abstract Map<String, Serializable> getData();
public final Map<String, Object> getData() {
if (data == null) {
return Collections.emptyMap();
}
return data;
}
/**
* Get secret metadata. This is only available for KV v2 secrets.
@ -54,7 +77,9 @@ public abstract class SecretResponse extends VaultDataResponse {
* @return Metadata of the secret.
* @since 0.8
*/
public abstract VersionMetadata getMetadata();
public final VersionMetadata getMetadata() {
return metadata;
}
/**
* Get a single value for given key.
@ -64,6 +89,9 @@ public abstract class SecretResponse extends VaultDataResponse {
* @since 0.4.0
*/
public final Object get(final String key) {
if (data == null) {
return null;
}
return getData().get(key);
}
@ -72,31 +100,18 @@ public abstract class SecretResponse extends VaultDataResponse {
*
* @param key the key
* @param type Class to parse response
* @param <C> Class to parse response
* @param <T> Class to parse response
* @return Parsed object or {@code null} if absent
* @throws InvalidResponseException on parsing error
* @since 0.4.0
*/
public final <C> C get(final String key, final Class<C> type) throws InvalidResponseException {
public final <T> T get(final String key, final Class<T> type) 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);
}
}
return new ObjectMapper().readValue(rawValue.toString(), type);
} catch (IOException e) {
throw new InvalidResponseException("Unable to parse response payload: " + e.getMessage());
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,10 +17,12 @@
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.VersionMetadata;
import java.util.Objects;
import java.io.IOException;
import java.util.Map;
/**
* Vault response for a single secret version metadata, i.e. after update (KV v2).
@ -30,11 +32,19 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SecretVersionResponse extends VaultDataResponse {
private static final long serialVersionUID = 2748635005258576174L;
@JsonProperty("data")
private VersionMetadata metadata;
@Override
public final void setData(final Map<String, Object> data) throws InvalidResponseException {
var mapper = new ObjectMapper();
try {
this.metadata = mapper.readValue(mapper.writeValueAsString(data), VersionMetadata.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
/**
* Get the actual metadata.
*
@ -43,20 +53,4 @@ public class SecretVersionResponse extends VaultDataResponse {
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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,9 +18,12 @@ 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.
@ -30,32 +33,31 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenResponse extends VaultDataResponse {
private static final long serialVersionUID = -4341114947980033457L;
@JsonProperty("data")
private TokenData data;
@JsonProperty("auth")
private Boolean auth;
/**
* Set data. Parses response data map to {@link TokenData}.
*
* @param data Raw response data
* @throws InvalidResponseException on parsing errors
*/
@Override
public void setData(final Map<String, Object> data) throws InvalidResponseException {
var mapper = new ObjectMapper();
try {
this.data = mapper.readValue(mapper.writeValueAsString(data), TokenData.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
/**
* @return Token data
*/
public TokenData getData() {
return data;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
TokenResponse that = (TokenResponse) o;
return Objects.equals(data, that.data);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), data);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,11 +17,13 @@
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.TokenRole;
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 role lookup providing Token information in {@link TokenData} field.
@ -31,31 +33,28 @@ import java.util.Objects;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenRoleResponse extends VaultDataResponse {
private static final long serialVersionUID = 5265363857731948626L;
@JsonProperty("data")
private TokenRole data;
/**
* Set data. Parses response data map to {@link TokenRole}.
*
* @param data Raw response data
* @throws InvalidResponseException on parsing errors
*/
@Override
public void setData(final Map<String, Object> data) throws InvalidResponseException {
var mapper = new ObjectMapper();
try {
this.data = mapper.readValue(mapper.writeValueAsString(data), TokenRole.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
/**
* @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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,11 +17,10 @@
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.
@ -30,11 +29,6 @@ import java.util.Objects;
* @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,22 +41,14 @@ public abstract class VaultDataResponse implements VaultResponse {
@JsonProperty("warnings")
private List<String> warnings;
@JsonProperty("wrap_info")
private WrapInfo wrapInfo;
@JsonProperty("auth")
private AuthData auth;
@JsonProperty("mount_type")
private String mountType;
/**
* @return Request ID
* @since 1.1
* Set data. To be implemented in the specific subclasses, as data can be of arbitrary structure.
*
* @param data Raw response data
* @throws InvalidResponseException on parsing errors
*/
public final String getRequestId() {
return requestId;
}
@JsonProperty("data")
public abstract void setData(final Map<String, Object> data) throws InvalidResponseException;
/**
* @return Lease ID
@ -91,51 +77,4 @@ public abstract class VaultDataResponse implements VaultResponse {
public final List<String> getWarnings() {
return warnings;
}
/**
* @return Wrapping information
* @since 1.1
*/
public final WrapInfo getWrapInfo() {
return wrapInfo;
}
/**
* @return Authentication information for this response
* @since 1.3
*/
public final AuthData getAuth() {
return auth;
}
/**
* @return Information about the type of mount this secret is from (since Vault 1.17)
* @since 1.3
*/
public final String getMountType() {
return mountType;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
VaultDataResponse that = (VaultDataResponse) o;
return renewable == that.renewable &&
Objects.equals(requestId, that.requestId) &&
Objects.equals(leaseId, that.leaseId) &&
Objects.equals(leaseDuration, that.leaseDuration) &&
Objects.equals(warnings, that.warnings) &&
Objects.equals(wrapInfo, that.wrapInfo) &&
Objects.equals(auth, that.auth) &&
Objects.equals(mountType, that.mountType);
}
@Override
public int hashCode() {
return Objects.hash(requestId, leaseId, renewable, leaseDuration, warnings, wrapInfo, auth, mountType);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,14 +16,11 @@
package de.stklcode.jvault.connector.model.response;
import java.io.Serializable;
/**
* Marker interface for responses from Vault backend.
*
* @author Stefan Kalscheuer
* @since 0.1
* @since 1.1 extends {@link Serializable}
*/
public interface VaultResponse extends Serializable {
public interface VaultResponse {
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,22 +19,17 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Embedded authorization information inside Vault response.
*
* @author Stefan Kalscheuer
* @since 0.1
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthData implements Serializable {
private static final long serialVersionUID = 5969334512309655317L;
public final class AuthData {
@JsonProperty("client_token")
private String clientToken;
@ -65,12 +60,6 @@ public final class AuthData implements Serializable {
@JsonProperty("orphan")
private boolean orphan;
@JsonProperty("num_uses")
private Integer numUses;
@JsonProperty("mfa_requirement")
private MfaRequirement mfaRequirement;
/**
* @return Client token
*/
@ -137,14 +126,6 @@ public final class AuthData implements Serializable {
return accessor;
}
/**
* @return allowed number of uses for the issued token
* @since 1.3
*/
public Integer getNumUses() {
return numUses;
}
/**
* @return Token is orphan
* @since 0.9
@ -152,41 +133,4 @@ public final class AuthData implements Serializable {
public boolean isOrphan() {
return orphan;
}
/**
* @return multi-factor requirement
* @since 1.2
*/
public MfaRequirement getMfaRequirement() {
return mfaRequirement;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AuthData authData = (AuthData) o;
return renewable == authData.renewable &&
orphan == authData.orphan &&
Objects.equals(clientToken, authData.clientToken) &&
Objects.equals(accessor, authData.accessor) &&
Objects.equals(policies, authData.policies) &&
Objects.equals(tokenPolicies, authData.tokenPolicies) &&
Objects.equals(metadata, authData.metadata) &&
Objects.equals(leaseDuration, authData.leaseDuration) &&
Objects.equals(entityId, authData.entityId) &&
Objects.equals(tokenType, authData.tokenType) &&
Objects.equals(numUses, authData.numUses) &&
Objects.equals(mfaRequirement, authData.mfaRequirement);
}
@Override
public int hashCode() {
return Objects.hash(clientToken, accessor, policies, tokenPolicies, metadata, leaseDuration, renewable,
entityId, tokenType, orphan, numUses, mfaRequirement);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,60 +21,28 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import de.stklcode.jvault.connector.model.AuthBackend;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
/**
* Embedded authentication method response.
*
* @author Stefan Kalscheuer
* @since 0.1
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthMethod implements Serializable {
private static final long serialVersionUID = -439987082190917691L;
public final class AuthMethod {
private AuthBackend type;
private String rawType;
@JsonProperty("accessor")
private String accessor;
@JsonProperty("deprecation_status")
private String deprecationStatus;
@JsonProperty("description")
private String description;
@JsonProperty("config")
private MountConfig config;
@JsonProperty("external_entropy_access")
private boolean externalEntropyAccess;
private Map<String, String> config;
@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)}
*/
@ -98,22 +66,6 @@ public final class AuthMethod implements Serializable {
return rawType;
}
/**
* @return Accessor
* @since 1.1
*/
public String getAccessor() {
return accessor;
}
/**
* @return Deprecation status
* @since 1.2
*/
public String getDeprecationStatus() {
return deprecationStatus;
}
/**
* @return Description
*/
@ -123,103 +75,15 @@ public final class AuthMethod implements Serializable {
/**
* @return Configuration data
* @since 0.2
* @since 1.2 Returns {@link MountConfig} instead of {@link Map}
*/
public MountConfig getConfig() {
public Map<String, String> 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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,25 +19,23 @@ 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.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
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;
public final class SecretMetadata {
private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSX");
@JsonProperty("created_time")
private ZonedDateTime createdTime;
private String createdTimeString;
@JsonProperty("current_version")
private Integer currentVersion;
@ -49,25 +47,31 @@ public final class SecretMetadata implements Serializable {
private Integer oldestVersion;
@JsonProperty("updated_time")
private ZonedDateTime updatedTime;
private String 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 as raw string representation.
*/
public String getCreatedTimeString() {
return createdTimeString;
}
/**
* @return Time of secret creation.
*/
public ZonedDateTime getCreatedTime() {
return createdTime;
if (createdTimeString != null && !createdTimeString.isEmpty()) {
try {
return ZonedDateTime.parse(createdTimeString, TIME_FORMAT);
} catch (DateTimeParseException e) {
// Ignore.
}
}
return null;
}
/**
@ -92,10 +96,25 @@ public final class SecretMetadata implements Serializable {
}
/**
* @return Time of secret update.
* @return Time of secret update as raw string representation.
*/
public String getUpdatedTimeString() {
return updatedTime;
}
/**
* @return Time of secret update..
*/
public ZonedDateTime getUpdatedTime() {
return updatedTime;
if (updatedTime != null && !updatedTime.isEmpty()) {
try {
return ZonedDateTime.parse(updatedTime, TIME_FORMAT);
} catch (DateTimeParseException e) {
// Ignore.
}
}
return null;
}
/**
@ -105,52 +124,4 @@ public final class SecretMetadata implements Serializable {
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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,23 +19,18 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Embedded token information inside Vault response.
*
* @author Stefan Kalscheuer
* @since 0.1
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenData implements Serializable {
private static final long serialVersionUID = -5749716740973138916L;
public final class TokenData {
@JsonProperty("accessor")
private String accessor;
@ -52,7 +47,7 @@ public final class TokenData implements Serializable {
private String entityId;
@JsonProperty("expire_time")
private ZonedDateTime expireTime;
private String expireTime;
@JsonProperty("explicit_max_ttl")
private Integer explicitMaxTtl;
@ -61,7 +56,7 @@ public final class TokenData implements Serializable {
private String id;
@JsonProperty("issue_time")
private ZonedDateTime issueTime;
private String issueTime;
@JsonProperty("meta")
private Map<String, Object> meta;
@ -123,12 +118,24 @@ public final class TokenData implements Serializable {
return entityId;
}
/**
* @return Expire time as raw string value
* @since 0.9
*/
public String getExpireTimeString() {
return expireTime;
}
/**
* @return Expire time (parsed)
* @since 0.9
*/
public ZonedDateTime getExpireTime() {
return expireTime;
if (expireTime == null) {
return null;
} else {
return ZonedDateTime.parse(expireTime);
}
}
/**
@ -146,12 +153,24 @@ public final class TokenData implements Serializable {
return id;
}
/**
* @return Issue time as raw string value
* @since 0.9
*/
public String getIssueTimeString() {
return issueTime;
}
/**
* @return Expire time (parsed)
* @since 0.9
*/
public ZonedDateTime getIssueTime() {
return issueTime;
if (issueTime == null) {
return null;
} else {
return ZonedDateTime.parse(issueTime);
}
}
/**
@ -212,37 +231,4 @@ public final class TokenData implements Serializable {
public Map<String, Object> getMeta() {
return meta;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
TokenData tokenData = (TokenData) o;
return orphan == tokenData.orphan &&
renewable == tokenData.renewable &&
Objects.equals(accessor, tokenData.accessor) &&
Objects.equals(creationTime, tokenData.creationTime) &&
Objects.equals(creationTtl, tokenData.creationTtl) &&
Objects.equals(name, tokenData.name) &&
Objects.equals(entityId, tokenData.entityId) &&
Objects.equals(expireTime, tokenData.expireTime) &&
Objects.equals(explicitMaxTtl, tokenData.explicitMaxTtl) &&
Objects.equals(id, tokenData.id) &&
Objects.equals(issueTime, tokenData.issueTime) &&
Objects.equals(meta, tokenData.meta) &&
Objects.equals(numUses, tokenData.numUses) &&
Objects.equals(path, tokenData.path) &&
Objects.equals(policies, tokenData.policies) &&
Objects.equals(ttl, tokenData.ttl) &&
Objects.equals(type, tokenData.type);
}
@Override
public int hashCode() {
return Objects.hash(accessor, creationTime, creationTtl, name, entityId, expireTime, explicitMaxTtl, id,
issueTime, meta, numUses, orphan, path, policies, renewable, ttl, type);
}
}

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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,28 +19,25 @@ 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;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
/**
* 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;
public final class VersionMetadata {
private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSX");
@JsonProperty("created_time")
private ZonedDateTime createdTime;
private String createdTimeString;
@JsonProperty("deletion_time")
private ZonedDateTime deletionTime;
private String deletionTimeString;
@JsonProperty("destroyed")
private boolean destroyed;
@ -48,21 +45,48 @@ public final class VersionMetadata implements Serializable {
@JsonProperty("version")
private Integer version;
@JsonProperty("custom_metadata")
private HashMap<String, String> customMetadata;
/**
* @return Time of secret creation as raw string representation.
*/
public String getCreatedTimeString() {
return createdTimeString;
}
/**
* @return Time of secret creation.
*/
public ZonedDateTime getCreatedTime() {
return createdTime;
if (createdTimeString != null && !createdTimeString.isEmpty()) {
try {
return ZonedDateTime.parse(createdTimeString, TIME_FORMAT);
} catch (DateTimeParseException e) {
// Ignore.
}
}
return null;
}
/**
* @return Time for secret deletion as raw string representation.
*/
public String getDeletionTimeString() {
return deletionTimeString;
}
/**
* @return Time for secret deletion.
*/
public ZonedDateTime getDeletionTime() {
return deletionTime;
if (deletionTimeString != null && !deletionTimeString.isEmpty()) {
try {
return ZonedDateTime.parse(deletionTimeString, TIME_FORMAT);
} catch (DateTimeParseException e) {
// Ignore.
}
}
return null;
}
/**
@ -79,31 +103,4 @@ public final class VersionMetadata implements Serializable {
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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -30,8 +30,7 @@ module de.stklcode.jvault.connector {
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.base;
requires java.net.http;
requires com.fasterxml.jackson.annotation;
requires com.fasterxml.jackson.databind;
requires com.fasterxml.jackson.datatype.jsr310;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -25,10 +25,7 @@ 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.*;
@ -41,8 +38,6 @@ import static org.junit.jupiter.api.Assertions.*;
*/
class HTTPVaultConnectorBuilderTest {
private static final String VAULT_ADDR = "https://localhost:8201";
private static final String VAULT_ADDR_2 = "http://localhost";
private static final String VAULT_ADDR_3 = "https://localhost/vault/";
private static final Integer VAULT_MAX_RETRIES = 13;
private static final String VAULT_TOKEN = "00001111-2222-3333-4444-555566667777";
@ -117,22 +112,6 @@ class HTTPVaultConnectorBuilderTest {
return null;
});
withVaultEnv(VAULT_ADDR_2, null, null, null).execute(() -> {
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
() -> HTTPVaultConnector.builder().fromEnv(),
"Factory creation from minimal environment failed"
);
assertEquals(VAULT_ADDR_2 + "/v1/", getRequestHelperPrivate(builder.build(), "baseURL"), "URL without port not set correctly");
return null;
});
withVaultEnv(VAULT_ADDR_3, null, null, null).execute(() -> {
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
() -> HTTPVaultConnector.builder().fromEnv(),
"Factory creation from minimal environment failed"
);
assertEquals(VAULT_ADDR_3, getRequestHelperPrivate(builder.build(), "baseURL"), "URL with custom path not set correctly");
return null;
});
// Provide address and number of retries.
withVaultEnv(VAULT_ADDR, null, VAULT_MAX_RETRIES.toString(), null).execute(() -> {
@ -149,6 +128,20 @@ class HTTPVaultConnectorBuilderTest {
return null;
});
// Provide CA certificate.
String VAULT_CACERT = tempDir.toString() + "/doesnotexist";
withVaultEnv(VAULT_ADDR, VAULT_CACERT, VAULT_MAX_RETRIES.toString(), null).execute(() -> {
TlsException e = assertThrows(
TlsException.class,
() -> HTTPVaultConnector.builder().fromEnv(),
"Creation with unknown cert path failed"
);
assertTrue(e.getCause() instanceof NoSuchFileException);
assertEquals(VAULT_CACERT, ((NoSuchFileException) e.getCause()).getFile());
return null;
});
// Automatic authentication.
withVaultEnv(VAULT_ADDR, null, VAULT_MAX_RETRIES.toString(), VAULT_TOKEN).execute(() -> {
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
@ -172,64 +165,11 @@ class HTTPVaultConnectorBuilderTest {
});
}
/**
* Test CA certificate handling from environment variables
*/
@Test
void testCertificateFromEnv() throws Exception {
// From direct PEM content
String pem = Files.readString(Paths.get(getClass().getResource("/tls/ca.pem").toURI()));
AtomicReference<Object> certFromPem = new AtomicReference<>();
withVaultEnv(VAULT_ADDR, pem, null, null).execute(() -> {
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
() -> HTTPVaultConnector.builder().fromEnv(),
"Builder with PEM certificate from environment failed"
);
HTTPVaultConnector connector = builder.build();
certFromPem.set(getRequestHelperPrivate(connector, "trustedCaCert"));
assertNotNull(certFromPem.get(), "Trusted CA cert from PEM not set");
return null;
});
// From file path
String file = Paths.get(getClass().getResource("/tls/ca.pem").toURI()).toString();
AtomicReference<Object> certFromFile = new AtomicReference<>();
withVaultEnv(VAULT_ADDR, file, null, null).execute(() -> {
HTTPVaultConnectorBuilder builder = assertDoesNotThrow(
() -> HTTPVaultConnector.builder().fromEnv(),
"Builder with certificate path from environment failed"
);
HTTPVaultConnector connector = builder.build();
certFromFile.set(getRequestHelperPrivate(connector, "trustedCaCert"));
assertNotNull(certFromFile.get(), "Trusted CA cert from file not set");
return null;
});
assertEquals(certFromPem.get(), certFromFile.get(), "Certificates from PEM and file should be equal");
// Non-existing path CA certificate path
String doesNotExist = tempDir.toString() + "/doesnotexist";
withVaultEnv(VAULT_ADDR, doesNotExist, VAULT_MAX_RETRIES.toString(), null).execute(() -> {
TlsException e = assertThrows(
TlsException.class,
() -> HTTPVaultConnector.builder().fromEnv(),
"Creation with unknown cert path failed"
);
assertEquals(doesNotExist, assertInstanceOf(NoSuchFileException.class, e.getCause()).getFile());
return null;
});
}
private SystemLambda.WithEnvironmentVariables withVaultEnv(String vaultAddr, String vaultCacert, String vaultMaxRetries, String vaultToken) {
return withEnvironmentVariable("VAULT_ADDR", vaultAddr)
.and("VAULT_CACERT", vaultCacert)
.and("VAULT_MAX_RETRIES", vaultMaxRetries)
.and("VAULT_TOKEN", vaultToken);
private SystemLambda.WithEnvironmentVariables withVaultEnv(String vault_addr, String vault_cacert, String vault_max_retries, String vault_token) {
return withEnvironmentVariable("VAULT_ADDR", vault_addr)
.and("VAULT_CACERT", vault_cacert)
.and("VAULT_MAX_RETRIES", vault_max_retries)
.and("VAULT_TOKEN", vault_token);
}
private Object getRequestHelperPrivate(HTTPVaultConnector connector, String fieldName) throws NoSuchFieldException, IllegalAccessException {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -30,16 +30,13 @@ import org.junit.jupiter.api.io.TempDir;
import java.io.*;
import java.lang.reflect.Field;
import java.net.ServerSocket;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.singletonMap;
import static org.apache.commons.io.FileUtils.copyDirectory;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.assumeFalse;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
@ -52,7 +49,7 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
* @since 0.1
*/
class HTTPVaultConnectorIT {
private static String VAULT_VERSION = "1.19.0"; // The vault version this test is supposed to run against.
private static String VAULT_VERSION = "1.9.0"; // The vault version this test is supposed to run against.
private static final String KEY1 = "E38bkCm0VhUvpdCKGQpcohhD9XmcHJ/2hreOSY019Lho";
private static final String KEY2 = "O5OHwDleY3IiPdgw61cgHlhsrEm6tVJkrxhF6QAnILd1";
private static final String KEY3 = "mw7Bm3nbt/UWa/juDjjL2EPQ04kiJ0saC5JEXwJvXYsB";
@ -83,6 +80,11 @@ class HTTPVaultConnectorIT {
// Initialize Vault.
VaultConfiguration config = initializeVault(tempDir, isTls);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Initialize connector.
HTTPVaultConnectorBuilder builder = HTTPVaultConnector.builder()
@ -126,11 +128,13 @@ class HTTPVaultConnectorIT {
@Test
@Order(10)
@DisplayName("Read secrets")
@SuppressWarnings("deprecation")
void readSecretTest() {
authUser();
assumeTrue(connector.isAuthorized());
// Try to read path user has no permission to read.
SecretResponse res = null;
final String invalidPath = "secret/invalid/path";
VaultConnectorException e = assertThrows(
@ -146,7 +150,7 @@ class HTTPVaultConnectorIT {
assertFalse(Pattern.compile("[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}").matcher(stackTrace(e)).find());
// Try to read accessible path with known value.
SecretResponse res = assertDoesNotThrow(
res = assertDoesNotThrow(
() -> connector.read(SECRET_PATH + "/" + SECRET_KEY),
"Valid secret path could not be read"
);
@ -211,6 +215,7 @@ class HTTPVaultConnectorIT {
@Test
@Order(30)
@DisplayName("Write secrets")
@SuppressWarnings("deprecation")
void writeSecretTest() {
authUser();
assumeTrue(connector.isAuthorized());
@ -544,6 +549,73 @@ class HTTPVaultConnectorIT {
}
}
@Nested
@DisplayName("App-ID Tests")
class AppIdTests {
private static final String APP_ID = "152AEA38-85FB-47A8-9CBD-612D645BFACA";
private static final String USER_ID = "5ADF8218-D7FB-4089-9E38-287465DBF37E";
/**
* App-ID authentication roundtrip.
*/
@Test
@Order(10)
@DisplayName("Authenticate with App-ID")
@SuppressWarnings("deprecation")
void authAppIdTest() {
// Try unauthorized access first.
assumeFalse(connector.isAuthorized());
assertThrows(
AuthorizationRequiredException.class,
() -> connector.registerAppId("", "", ""),
"Expected exception not thrown"
);
assertThrows(
AuthorizationRequiredException.class,
() -> connector.registerUserId("", ""),
"Expected exception not thrown"
);
}
/**
* App-ID authentication roundtrip.
*/
@Test
@Order(20)
@DisplayName("Register App-ID")
@SuppressWarnings("deprecation")
void registerAppIdTest() {
// Authorize.
authRoot();
assumeTrue(connector.isAuthorized());
// Register App-ID.
boolean res = assertDoesNotThrow(
() -> connector.registerAppId(APP_ID, "user", "App Name"),
"Failed to register App-ID"
);
assertTrue(res, "Failed to register App-ID");
// Register User-ID.
res = assertDoesNotThrow(
() -> connector.registerUserId(APP_ID, USER_ID),
"Failed to register App-ID"
);
assertTrue(res, "Failed to register App-ID");
connector.resetAuth();
assumeFalse(connector.isAuthorized());
// Authenticate with created credentials.
AuthResponse resp = assertDoesNotThrow(
() -> connector.authAppId(APP_ID, USER_ID),
"Failed to authenticate using App-ID"
);
assertTrue(connector.isAuthorized(), "Authorization flag not set after App-ID login");
}
}
@Nested
@DisplayName("AppRole Tests")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ -835,9 +907,8 @@ class HTTPVaultConnectorIT {
assertFalse(res.getAuth().isRenewable(), "Root token should not be renewable");
assertFalse(res.getAuth().isOrphan(), "Root token should not be orphan");
// Starting with Vault 1.0 a warning "custom ID uses weaker SHA1..." is given.
// Starting with Vault 1.11 a second warning "Endpoint ignored unrecognized parameters" is given.
assertFalse(res.getWarnings().isEmpty(), "Token creation did not return expected warning");
// Starting with Vault 1.0 a warning "custom ID uses weaker SHA1.." is given.
assertEquals(1, res.getWarnings().size(), "Token creation did not return expected warning");
// Create token with attributes.
Token token2 = Token.builder()
@ -881,11 +952,7 @@ class HTTPVaultConnectorIT {
.withType(Token.Type.BATCH)
.build();
res = assertDoesNotThrow(() -> connector.createToken(token4), "Token creation failed");
assertTrue(
// Expecting batch token. "hvb." Prefix as of Vault 1.10, "b." before.
res.getAuth().getClientToken().startsWith("b.") || res.getAuth().getClientToken().startsWith("hvb."),
"Unexpected token prefix"
);
assertTrue(res.getAuth().getClientToken().startsWith("b"), "Unexpected token prefix");
assertEquals(1, res.getAuth().getPolicies().size(), "Invalid number of policies returned");
assertTrue(res.getAuth().getPolicies().contains("batchpolicy"), "Custom policy policy not set");
assertFalse(res.getAuth().isRenewable(), "Token should not be renewable");
@ -989,75 +1056,6 @@ class HTTPVaultConnectorIT {
}
}
@Nested
@DisplayName("Transit Tests")
class TransitTests {
@Test
@DisplayName("Transit encryption")
void transitEncryptTest() {
assertDoesNotThrow(() -> connector.authToken(TOKEN_ROOT));
assumeTrue(connector.isAuthorized());
TransitResponse transitResponse = assertDoesNotThrow(
() -> connector.transitEncrypt("my-key", "dGVzdCBtZQ=="),
"Failed to encrypt via transit"
);
assertNotNull(transitResponse.getCiphertext());
assertTrue(transitResponse.getCiphertext().startsWith("vault:v1:"));
transitResponse = assertDoesNotThrow(
() -> connector.transitEncrypt("my-key", "test me".getBytes(UTF_8)),
"Failed to encrypt binary data via transit"
);
assertNotNull(transitResponse.getCiphertext());
assertTrue(transitResponse.getCiphertext().startsWith("vault:v1:"));
}
@Test
@DisplayName("Transit decryption")
void transitDecryptTest() {
assertDoesNotThrow(() -> connector.authToken(TOKEN_ROOT));
assumeTrue(connector.isAuthorized());
TransitResponse transitResponse = assertDoesNotThrow(
() -> connector.transitDecrypt("my-key", "vault:v1:1mhLVkBAR2nrFtIkJF/qg57DWfRj0FWgR6tvkGO8XOnL6sw="),
"Failed to decrypt via transit"
);
assertEquals("dGVzdCBtZQ==", transitResponse.getPlaintext());
}
@Test
@DisplayName("Transit hash")
void transitHashText() {
assertDoesNotThrow(() -> connector.authToken(TOKEN_ROOT));
assumeTrue(connector.isAuthorized());
TransitResponse transitResponse = assertDoesNotThrow(
() -> connector.transitHash("sha2-512", "dGVzdCBtZQ=="),
"Failed to hash via transit"
);
assertEquals("7677af0ee4effaa9f35e9b1e82d182f79516ab8321786baa23002de7c06851059492dd37d5fc3791f17d81d4b58198d24a6fd8bbd62c42c1c30b371da500f193", transitResponse.getSum());
TransitResponse transitResponseBase64 = assertDoesNotThrow(
() -> connector.transitHash("sha2-256", "dGVzdCBtZQ==", "base64"),
"Failed to hash via transit with base64 output"
);
assertEquals("5DfYkW7cvGLkfy36cXhqmZcygEy9HpnFNB4WWXKOl1M=", transitResponseBase64.getSum());
transitResponseBase64 = assertDoesNotThrow(
() -> connector.transitHash("sha2-256", "test me".getBytes(UTF_8), "base64"),
"Failed to hash binary data via transit"
);
assertEquals("5DfYkW7cvGLkfy36cXhqmZcygEy9HpnFNB4WWXKOl1M=", transitResponseBase64.getSum());
}
}
@Nested
@DisplayName("Misc Tests")
class MiscTests {
@ -1075,9 +1073,8 @@ class HTTPVaultConnectorIT {
() -> connector.getAuthBackends(),
"Could not list supported auth backends"
);
assertEquals(3, supportedBackends.size());
assertTrue(supportedBackends.containsAll(List.of(AuthBackend.TOKEN, AuthBackend.USERPASS, AuthBackend.APPROLE)));
assertEquals(4, supportedBackends.size());
assertTrue(supportedBackends.containsAll(List.of(AuthBackend.TOKEN, AuthBackend.USERPASS, AuthBackend.APPID, AuthBackend.APPROLE)));
}
/**
@ -1220,39 +1217,30 @@ class HTTPVaultConnectorIT {
}
// Write configuration file.
File configFile = new File(dir, "vault.conf");
BufferedWriter bw = null;
File configFile;
try {
Files.write(configFile.toPath(), config.toString().getBytes(UTF_8));
configFile = new File(dir, "vault.conf");
bw = new BufferedWriter(new FileWriter(configFile));
bw.write(config.toString());
} catch (IOException e) {
throw new IllegalStateException("Unable to generate config file", e);
} finally {
try {
if (bw != null)
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// Start vault process.
try {
vaultProcess = new ProcessBuilder("vault", "server", "-config", configFile.toString())
.directory(dir)
.start();
vaultProcess = Runtime.getRuntime().exec("vault server -config " + configFile.toString());
} catch (IOException e) {
throw new IllegalStateException("Unable to start vault. Make sure vault binary is in your executable path", e);
}
await().atMost(5, TimeUnit.SECONDS).until(() -> {
try (InputStream stdout = vaultProcess.getInputStream();
InputStreamReader reader = new InputStreamReader(stdout);
BufferedReader br = new BufferedReader(reader)) {
String line = br.readLine();
while (line != null) {
if (line.contains("Vault server started")) {
return true;
} else {
line = br.readLine();
}
}
return false;
}
});
return config;
}
@ -1277,14 +1265,28 @@ class HTTPVaultConnectorIT {
* @return port number
*/
private static Integer getFreePort() {
try (ServerSocket socket = new ServerSocket(0)) {
ServerSocket socket = null;
try {
socket = new ServerSocket(0);
socket.setReuseAddress(true);
return socket.getLocalPort();
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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +16,15 @@
package de.stklcode.jvault.connector;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import de.stklcode.jvault.connector.exception.ConnectionException;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.exception.PermissionDeniedException;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
@ -36,7 +38,8 @@ import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collections;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
import static org.junit.jupiter.api.Assertions.*;
/**
@ -46,23 +49,37 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.7.0
*/
@WireMockTest
class HTTPVaultConnectorTest {
private static WireMockServer wireMock;
@BeforeAll
static void prepare() {
// Initialize HTTP mock.
wireMock = new WireMockServer(WireMockConfiguration.options().dynamicPort());
wireMock.start();
WireMock.configureFor("localhost", wireMock.port());
}
@AfterAll
static void tearDown() {
wireMock.stop();
wireMock = null;
}
/**
* Test exceptions thrown during request.
*/
@Test
void requestExceptionTest(WireMockRuntimeInfo wireMock) throws IOException, URISyntaxException {
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withTimeout(250).build();
void requestExceptionTest() throws IOException, URISyntaxException {
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.url("/")).withTimeout(250).build();
// Test invalid response code.
final int responseCode = 400;
mockHttpResponse(responseCode, "", "application/json");
VaultConnectorException e = assertThrows(
InvalidResponseException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
InvalidResponseException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
assertEquals("Invalid response code", e.getMessage(), "Unexpected exception message");
assertEquals(responseCode, ((InvalidResponseException) e).getStatusCode(), "Unexpected status code in exception");
@ -71,9 +88,9 @@ class HTTPVaultConnectorTest {
// Simulate permission denied response.
mockHttpResponse(responseCode, "{\"errors\":[\"permission denied\"]}", "application/json");
assertThrows(
PermissionDeniedException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
PermissionDeniedException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
// Test exception thrown during request.
@ -81,22 +98,22 @@ class HTTPVaultConnectorTest {
connector = HTTPVaultConnector.builder("http://localst:" + s.getLocalPort() + "/").withTimeout(250).build();
}
e = assertThrows(
ConnectionException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
ConnectionException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
assertInstanceOf(IOException.class, e.getCause(), "Unexpected cause");
assertTrue(e.getCause() instanceof IOException, "Unexpected cause");
// Now simulate a failing request that succeeds on second try.
connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withNumberOfRetries(1).withTimeout(250).build();
connector = HTTPVaultConnector.builder(wireMock.url("/")).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"))
WireMock.stubFor(
WireMock.any(anyUrl())
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(200).withBody("{}").withHeader("Content-Type", "application/json"))
);
assertDoesNotThrow(connector::getHealth, "Request failed unexpectedly");
}
@ -159,9 +176,9 @@ class HTTPVaultConnectorTest {
connector = HTTPVaultConnector.builder("http://localst:" + s.getLocalPort()).withTimeout(250).build();
}
ConnectionException e = assertThrows(
ConnectionException.class,
connector::sealStatus,
"Querying seal status succeeded on invalid instance"
ConnectionException.class,
connector::sealStatus,
"Querying seal status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
}
@ -177,9 +194,9 @@ class HTTPVaultConnectorTest {
connector = HTTPVaultConnector.builder("http://localhost:" + s.getLocalPort() + "/").withTimeout(250).build();
}
ConnectionException e = assertThrows(
ConnectionException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
ConnectionException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
}
@ -188,8 +205,8 @@ class HTTPVaultConnectorTest {
* Test behavior on unparsable responses.
*/
@Test
void parseExceptionTest(WireMockRuntimeInfo wireMock) throws URISyntaxException {
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withTimeout(250).build();
void parseExceptionTest() throws URISyntaxException {
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.url("/")).withTimeout(250).build();
// Mock authorization.
setPrivate(connector, "authorized", true);
// Mock response.
@ -222,8 +239,8 @@ class HTTPVaultConnectorTest {
* 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();
void nonEmpty204ResponseTest() throws URISyntaxException {
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.url("/")).withTimeout(250).build();
// Mock authorization.
setPrivate(connector, "authorized", true);
// Mock response.
@ -231,45 +248,57 @@ class HTTPVaultConnectorTest {
// Now test the methods expecting a 204.
assertThrows(
InvalidResponseException.class,
() -> connector.createAppRole("appID", Collections.singletonList("policy")),
"createAppRole() with 200 response succeeded"
InvalidResponseException.class,
() -> connector.registerAppId("appID", "policy", "displayName"),
"registerAppId() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.deleteAppRole("roleName"),
"deleteAppRole() with 200 response succeeded"
InvalidResponseException.class,
() -> connector.registerUserId("appID", "userID"),
"registerUserId() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.setAppRoleID("roleName", "roleID"),
"setAppRoleID() with 200 response succeeded"
InvalidResponseException.class,
() -> connector.createAppRole("appID", Collections.singletonList("policy")),
"createAppRole() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.destroyAppRoleSecret("roleName", "secretID"),
"destroyAppRoleSecret() with 200 response succeeded"
InvalidResponseException.class,
() -> connector.deleteAppRole("roleName"),
"deleteAppRole() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.destroyAppRoleSecret("roleName", "secretUD"),
"destroyAppRoleSecret() with 200 response succeeded"
InvalidResponseException.class,
() -> connector.setAppRoleID("roleName", "roleID"),
"setAppRoleID() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.delete("key"),
"delete() with 200 response succeeded"
InvalidResponseException.class,
() -> connector.destroyAppRoleSecret("roleName", "secretID"),
"destroyAppRoleSecret() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.revoke("leaseID"),
"destroyAppRoleSecret() with 200 response succeeded"
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"
);
}
@ -283,7 +312,7 @@ class HTTPVaultConnectorTest {
private Object getPrivate(Object target, String fieldName) throws NoSuchFieldException, IllegalAccessException {
Field field = target.getClass().getDeclaredField(fieldName);
if (field.canAccess(target)) {
if (field.isAccessible()) {
return field.get(target);
}
field.setAccessible(true);
@ -295,7 +324,7 @@ class HTTPVaultConnectorTest {
private void setPrivate(Object target, String fieldName, Object value) {
try {
Field field = target.getClass().getDeclaredField(fieldName);
boolean accessible = field.canAccess(target);
boolean accessible = field.isAccessible();
field.setAccessible(true);
field.set(target, value);
field.setAccessible(accessible);
@ -305,10 +334,10 @@ class HTTPVaultConnectorTest {
}
private void mockHttpResponse(int status, String body, String contentType) {
stubFor(
WireMock.any(anyUrl()).willReturn(
aResponse().withStatus(status).withBody(body).withHeader("Content-Type", contentType)
)
WireMock.stubFor(
WireMock.any(anyUrl()).willReturn(
aResponse().withStatus(status).withBody(body).withHeader("Content-Type", contentType)
)
);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,9 +16,12 @@
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -32,21 +35,14 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
* @author Stefan Kalscheuer
* @since 0.5.0
*/
class AppRoleSecretTest extends AbstractModelTest<AppRoleSecret> {
class AppRoleSecretTest {
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");
private static final Map<String, Object> TEST_META = new HashMap<>();
private static final List<String> TEST_CIDR = Arrays.asList("203.0.113.0/24", "198.51.100.0/24");
AppRoleSecretTest() {
super(AppRoleSecret.class);
}
@Override
protected AppRoleSecret createFull() {
return new AppRoleSecret(TEST_ID, TEST_META, TEST_CIDR);
static {
TEST_META.put("foo", "bar");
TEST_META.put("number", 1337);
}
/**
@ -115,14 +111,16 @@ class AppRoleSecretTest extends AbstractModelTest<AppRoleSecret> {
*/
@Test
void jsonTest() throws NoSuchFieldException, IllegalAccessException {
// A simple roundtrip first. All set fields should be present afterward.
ObjectMapper mapper = new ObjectMapper();
// A simple roundtrip first. All set fields should be present afterwards..
AppRoleSecret secret = new AppRoleSecret(TEST_ID, TEST_META, TEST_CIDR);
String secretJson = assertDoesNotThrow(() -> objectMapper.writeValueAsString(secret), "Serialization failed");
String secretJson = assertDoesNotThrow(() -> mapper.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),
() -> mapper.readValue(secretJson2, AppRoleSecret.class),
"Deserialization failed"
);
assertEquals(secret2.getId(), secret.getId());
@ -142,9 +140,9 @@ class AppRoleSecretTest extends AbstractModelTest<AppRoleSecret> {
assumeTrue(secret.getNumUses() == 678);
setPrivateField(secret, "ttl", 12345);
assumeTrue(secret.getTtl() == 12345);
String secretJson3 = assertDoesNotThrow(() -> objectMapper.writeValueAsString(secret), "Serialization failed");
String secretJson3 = assertDoesNotThrow(() -> mapper.writeValueAsString(secret), "Serialization failed");
secret2 = assertDoesNotThrow(
() -> objectMapper.readValue(commaSeparatedToList(secretJson3), AppRoleSecret.class),
() -> mapper.readValue(commaSeparatedToList(secretJson3), AppRoleSecret.class),
"Deserialization failed"
);
assertEquals(secret2.getId(), secret.getId());
@ -162,25 +160,27 @@ class AppRoleSecretTest extends AbstractModelTest<AppRoleSecret> {
"\"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");
secret2 = assertDoesNotThrow(() -> mapper.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);
boolean accessible = field.isAccessible();
field.setAccessible(true);
field.set(object, value);
field.setAccessible(accessible);
}
private static String commaSeparatedToList(String json) {
return json.replaceAll("\"cidr_list\":\"([^\"]*)\"", "\"cidr_list\":[$1]")
return json.replaceAll("\"cidr_list\":\"([^\"]*)\"", "\"cidr_list\":\\[$1\\]")
.replaceAll("(\\d+\\.\\d+\\.\\d+\\.\\d+/\\d+)", "\"$1\"");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@ -31,7 +32,7 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.4.0
*/
class AppRoleTest extends AbstractModelTest<AppRole> {
class AppRoleTest {
private static final String NAME = "TestRole";
private static final String ID = "test-id";
private static final Boolean BIND_SECRET_ID = true;
@ -43,7 +44,7 @@ class AppRoleTest extends AbstractModelTest<AppRole> {
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 Boolean ENABLE_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;
@ -52,33 +53,8 @@ class AppRoleTest extends AbstractModelTest<AppRole> {
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();
}
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,\"enable_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, ENABLE_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());
@BeforeAll
static void init() {
@ -98,7 +74,7 @@ class AppRoleTest extends AbstractModelTest<AppRole> {
assertNull(role.getTokenPolicies());
assertNull(role.getSecretIdNumUses());
assertNull(role.getSecretIdTtl());
assertNull(role.getLocalSecretIds());
assertNull(role.getEnableLocalSecretIds());
assertNull(role.getTokenTtl());
assertNull(role.getTokenMaxTtl());
assertNull(role.getTokenBoundCidrs());
@ -109,7 +85,7 @@ class AppRoleTest extends AbstractModelTest<AppRole> {
assertNull(role.getTokenType());
// Optional fields should be ignored, so JSON string should only contain role_name.
assertEquals(JSON_MIN, objectMapper.writeValueAsString(role));
assertEquals(JSON_MIN, new ObjectMapper().writeValueAsString(role));
}
/**
@ -117,7 +93,23 @@ class AppRoleTest extends AbstractModelTest<AppRole> {
*/
@Test
void buildFullTest() throws JsonProcessingException {
AppRole role = createFull();
AppRole role = AppRole.builder(NAME)
.withId(ID)
.withBindSecretID(BIND_SECRET_ID)
.withSecretIdBoundCidrs(BOUND_CIDR_LIST)
.withTokenPolicies(POLICIES)
.withSecretIdNumUses(SECRET_ID_NUM_USES)
.withSecretIdTtl(SECRET_ID_TTL)
.withEnableLocalSecretIds(ENABLE_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();
assertEquals(NAME, role.getName());
assertEquals(ID, role.getId());
assertEquals(BIND_SECRET_ID, role.getBindSecretId());
@ -125,7 +117,7 @@ class AppRoleTest extends AbstractModelTest<AppRole> {
assertEquals(POLICIES, role.getTokenPolicies());
assertEquals(SECRET_ID_NUM_USES, role.getSecretIdNumUses());
assertEquals(SECRET_ID_TTL, role.getSecretIdTtl());
assertEquals(LOCAL_SECRET_IDS, role.getLocalSecretIds());
assertEquals(ENABLE_LOCAL_SECRET_IDS, role.getEnableLocalSecretIds());
assertEquals(TOKEN_TTL, role.getTokenTtl());
assertEquals(TOKEN_MAX_TTL, role.getTokenMaxTtl());
assertEquals(BOUND_CIDR_LIST, role.getTokenBoundCidrs());
@ -136,7 +128,7 @@ class AppRoleTest extends AbstractModelTest<AppRole> {
assertEquals(TOKEN_TYPE.value(), role.getTokenType());
// Verify that all parameters are included in JSON string.
assertEquals(JSON_FULL, objectMapper.writeValueAsString(role));
assertEquals(JSON_FULL, new ObjectMapper().writeValueAsString(role));
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -35,6 +35,7 @@ class AuthBackendTest {
@Test
void forTypeTest() {
assertEquals(AuthBackend.TOKEN, AuthBackend.forType("token"));
assertEquals(AuthBackend.APPID, AuthBackend.forType("app-id"));
assertEquals(AuthBackend.USERPASS, AuthBackend.forType("userpass"));
assertEquals(AuthBackend.GITHUB, AuthBackend.forType("github"));
assertEquals(AuthBackend.UNKNOWN, AuthBackend.forType(""));

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
@ -25,29 +26,21 @@ import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit Test for {@link TokenRole} and {@link TokenRole.Builder}.
* Unit Test for {@link Token.Builder}
*
* @author Stefan Kalscheuer
* @since 0.9
*/
class TokenRoleTest extends AbstractModelTest<TokenRole> {
class TokenRoleBuilderTest {
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";
@ -68,9 +61,7 @@ class TokenRoleTest extends AbstractModelTest<TokenRole> {
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 + "\"," +
@ -82,37 +73,6 @@ class TokenRoleTest extends AbstractModelTest<TokenRole> {
"\"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.
*/
@ -132,7 +92,7 @@ class TokenRoleTest extends AbstractModelTest<TokenRole> {
assertNull(role.getTokenType());
// Optional fields should be ignored, so JSON string should be empty.
assertEquals("{}", objectMapper.writeValueAsString(role));
assertEquals("{}", new ObjectMapper().writeValueAsString(role));
}
/**
@ -172,11 +132,8 @@ class TokenRoleTest extends AbstractModelTest<TokenRole> {
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));
assertEquals("{}", new ObjectMapper().writeValueAsString(role));
}
/**
@ -184,16 +141,30 @@ class TokenRoleTest extends AbstractModelTest<TokenRole> {
*/
@Test
void buildFullTest() throws JsonProcessingException {
TokenRole role = createFull();
TokenRole role = TokenRole.builder()
.forName(NAME)
.withAllowedPolicies(ALLOWED_POLICIES)
.withAllowedPolicy(ALLOWED_POLICY_3)
.withDisallowedPolicy(DISALLOWED_POLICY_1)
.withDisallowedPolicies(DISALLOWED_POLICIES)
.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();
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());
@ -207,6 +178,6 @@ class TokenRoleTest extends AbstractModelTest<TokenRole> {
assertEquals(TOKEN_TYPE.value(), role.getTokenType());
// Verify that all parameters are included in JSON string.
assertEquals(JSON_FULL, objectMapper.writeValueAsString(role));
assertEquals(JSON_FULL, new ObjectMapper().writeValueAsString(role));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@ -30,7 +31,7 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.4.0
*/
class TokenTest extends AbstractModelTest<Token> {
class TokenTest {
private static final String ID = "test-id";
private static final String DISPLAY_NAME = "display-name";
private static final Boolean NO_PARENT = false;
@ -52,29 +53,6 @@ class TokenTest extends AbstractModelTest<Token> {
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);
@ -102,10 +80,7 @@ class TokenTest extends AbstractModelTest<Token> {
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);
assertEquals("{}", new ObjectMapper().writeValueAsString(token));
}
/**
@ -113,7 +88,21 @@ class TokenTest extends AbstractModelTest<Token> {
*/
@Test
void buildFullTest() throws JsonProcessingException {
Token token = createFull();
Token token = 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();
assertEquals(ID, token.getId());
assertEquals(Token.Type.SERVICE.value(), token.getType());
assertEquals(DISPLAY_NAME, token.getDisplayName());
@ -128,7 +117,7 @@ class TokenTest extends AbstractModelTest<Token> {
assertEquals(PERIOD, token.getPeriod());
// Verify that all parameters are included in JSON string.
assertEquals(JSON_FULL, objectMapper.writeValueAsString(token));
assertEquals(JSON_FULL, new ObjectMapper().writeValueAsString(token));
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,12 +16,14 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.AppRole;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
@ -31,7 +33,7 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class AppRoleResponseTest extends AbstractModelTest<AppRoleResponse> {
class AppRoleResponseTest {
private static final Integer ROLE_TOKEN_TTL = 1200;
private static final Integer ROLE_TOKEN_MAX_TTL = 1800;
private static final Integer ROLE_SECRET_TTL = 600;
@ -61,18 +63,10 @@ class AppRoleResponseTest extends AbstractModelTest<AppRoleResponse> {
" \"lease_id\": \"\"\n" +
"}";
AppRoleResponseTest() {
super(AppRoleResponse.class);
}
private static final Map<String, Object> INVALID_DATA = new HashMap<>();
@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;
}
static {
INVALID_DATA.put("token_policies", "fancy-policy");
}
/**
@ -83,6 +77,13 @@ class AppRoleResponseTest extends AbstractModelTest<AppRoleResponse> {
// Create empty Object.
AppRoleResponse res = new AppRoleResponse();
assertNull(res.getRole(), "Initial data should be empty");
// Parsing invalid auth data map should fail.
assertThrows(
InvalidResponseException.class,
() -> res.setData(INVALID_DATA),
"Parsing invalid data succeeded"
);
}
/**
@ -91,7 +92,7 @@ class AppRoleResponseTest extends AbstractModelTest<AppRoleResponse> {
@Test
void jsonRoundtrip() {
AppRoleResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(RES_JSON, AppRoleResponse.class),
() -> new ObjectMapper().readValue(RES_JSON, AppRoleResponse.class),
"AuthResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +16,14 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.AuthBackend;
import de.stklcode.jvault.connector.model.response.embedded.AuthMethod;
import org.junit.jupiter.api.Test;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@ -34,68 +35,37 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class AuthMethodsResponseTest extends AbstractModelTest<AuthMethodsResponse> {
class AuthMethodsResponseTest {
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" +
" \"description\": \"" + GH_DESCR + "\"\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" +
" \"max_lease_ttl\": " + TK_MAX_LEASE_TTL + "\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" +
" \"type\": \"" + TK_TYPE + "\"\n" +
" }\n" +
" }\n" +
"}";
AuthMethodsResponseTest() {
super(AuthMethodsResponse.class);
}
private static final Map<String, Object> INVALID_DATA = new HashMap<>();
@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;
}
static {
INVALID_DATA.put("dummy/", new Dummy());
}
/**
@ -106,6 +76,13 @@ class AuthMethodsResponseTest extends AbstractModelTest<AuthMethodsResponse> {
// Create empty Object.
AuthMethodsResponse res = new AuthMethodsResponse();
assertEquals(Collections.emptyMap(), res.getSupportedMethods(), "Initial method map should be empty");
// Parsing invalid data map should fail.
assertThrows(
InvalidResponseException.class,
() -> res.setData(INVALID_DATA),
"Parsing invalid data succeeded"
);
}
/**
@ -114,7 +91,7 @@ class AuthMethodsResponseTest extends AbstractModelTest<AuthMethodsResponse> {
@Test
void jsonRoundtrip() {
AuthMethodsResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(RES_JSON, AuthMethodsResponse.class),
() -> new ObjectMapper().readValue(RES_JSON, AuthMethodsResponse.class),
"AuthResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
@ -130,32 +107,19 @@ class AuthMethodsResponseTest extends AbstractModelTest<AuthMethodsResponse> {
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.
// Verify first 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");
assertEquals(2, method.getConfig().size(), "Unexpected config size for Token");
assertEquals(TK_LEASE_TTL.toString(), method.getConfig().get("default_lease_ttl"), "Incorrect lease TTL config");
assertEquals(TK_MAX_LEASE_TTL.toString(), method.getConfig().get("max_lease_ttl"), "Incorrect max lease TTL config");
}
private static class Dummy {
assertNull(method.getOptions(), "Unexpected options");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,15 +16,12 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
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.HashMap;
import java.util.Map;
import java.util.Set;
@ -36,7 +33,7 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class AuthResponseTest extends AbstractModelTest<AuthResponse> {
class AuthResponseTest {
private static final String AUTH_ACCESSOR = "2c84f488-2133-4ced-87b0-570f93a76830";
private static final String AUTH_CLIENT_TOKEN = "ABCD";
private static final String AUTH_POLICY_1 = "web";
@ -48,72 +45,55 @@ class AuthResponseTest extends AbstractModelTest<AuthResponse> {
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" +
"}";
" \"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" +
" }\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;
}
private static final Map<String, Object> INVALID_AUTH_DATA = new HashMap<>();
static {
INVALID_AUTH_DATA.put("policies", "fancy-policy");
}
/**
* Test getter, setter and get-methods for response data.
*/
@Test
void testEqualsHashcodeMfa() {
EqualsVerifier.simple().forClass(MfaRequirement.class).verify();
EqualsVerifier.simple().forClass(MfaConstraintAny.class).verify();
EqualsVerifier.simple().forClass(MfaMethodId.class).verify();
void getDataRoundtrip() {
// Create empty Object.
AuthResponse res = new AuthResponse();
assertNull(res.getData(), "Initial data should be empty");
// Parsing invalid auth data map should fail.
assertThrows(
InvalidResponseException.class,
() -> res.setAuth(INVALID_AUTH_DATA),
"Parsing invalid auth data succeeded"
);
// Data method should be agnostic.
res.setData(INVALID_AUTH_DATA);
assertEquals(INVALID_AUTH_DATA, res.getData(), "Data not passed through");
}
/**
@ -122,7 +102,7 @@ class AuthResponseTest extends AbstractModelTest<AuthResponse> {
@Test
void jsonRoundtrip() {
AuthResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(RES_JSON, AuthResponse.class),
() -> new ObjectMapper().readValue(RES_JSON, AuthResponse.class),
"AuthResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
@ -136,20 +116,10 @@ class AuthResponseTest extends AbstractModelTest<AuthResponse> {
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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,11 +16,14 @@
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.exception.InvalidResponseException;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
/**
* JUnit Test for {@link CredentialsResponse} model.
@ -28,49 +31,31 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.8
*/
class CredentialsResponseTest extends AbstractModelTest<CredentialsResponse> {
class CredentialsResponseTest {
private static final Map<String, Object> DATA = new HashMap<>();
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;
}
static {
DATA.put("username", VAL_USER);
DATA.put("password", VAL_PASS);
}
/**
* Test getter, setter and get-methods for response data.
*
* @throws InvalidResponseException Should not occur
*/
@Test
void getCredentialsTest() {
@SuppressWarnings("unchecked")
void getCredentialsTest() throws InvalidResponseException {
// 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"
);
// Fill data map.
res.setData(DATA);
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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,8 +16,7 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
@ -28,10 +27,10 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.7.0
*/
class HealthResponseTest extends AbstractModelTest<HealthResponse> {
class HealthResponseTest {
private static final String CLUSTER_ID = "c9abceea-4f46-4dab-a688-5ce55f89e228";
private static final String CLUSTER_NAME = "vault-cluster-5515c810";
private static final String VERSION = "0.17.0";
private static final String VERSION = "0.9.2";
private static final Long SERVER_TIME_UTC = 1469555798L;
private static final Boolean STANDBY = false;
private static final Boolean SEALED = false;
@ -39,10 +38,6 @@ class HealthResponseTest extends AbstractModelTest<HealthResponse> {
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" +
@ -52,36 +47,18 @@ class HealthResponseTest extends AbstractModelTest<HealthResponse> {
" \"standby\": " + STANDBY + ",\n" +
" \"sealed\": " + SEALED + ",\n" +
" \"initialized\": " + INITIALIZED + ",\n" +
" \"replication_performance_mode\": \"" + REPL_PERF_MODE + "\",\n" +
" \"replication_perf_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" +
" \"performance_standby\": " + PERF_STANDBY + "\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),
() -> new ObjectMapper().readValue(RES_JSON, HealthResponse.class),
"Health deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
@ -95,9 +72,5 @@ class HealthResponseTest extends AbstractModelTest<HealthResponse> {
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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,12 +16,9 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
/**
@ -30,27 +27,18 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.8
*/
class MetadataResponseTest extends AbstractModelTest<MetadataResponse> {
class MetadataResponseTest {
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" +
@ -74,42 +62,29 @@ class MetadataResponseTest extends AbstractModelTest<MetadataResponse> {
" }\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),
() -> new 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");
assertEquals(V1_TIME, res.getMetadata().getCreatedTimeString(), "Incorrect created time");
assertNotNull(res.getMetadata().getCreatedTime(), "Parting created time failed");
assertEquals(CURRENT_VERSION, res.getMetadata().getCurrentVersion(), "Incorrect current version");
assertEquals(MAX_VERSIONS, res.getMetadata().getMaxVersions(), "Incorrect max versions");
assertEquals(OLDEST_VERSION, res.getMetadata().getOldestVersion(), "Incorrect oldest version");
assertEquals(Map.of(CUSTOM_META_KEY, CUSTOM_META_VAL), res.getMetadata().getCustomMetadata(), "Incorrect custom metadata");
assertEquals(DELETE_VERSION_AFTER, res.getMetadata().getDeleteVersionAfter(), "Incorrect delete version after");
assertEquals(V3_TIME, res.getMetadata().getUpdatedTimeString(), "Incorrect updated time");
assertNotNull(res.getMetadata().getUpdatedTime(), "Parting updated time failed");
assertEquals(3, res.getMetadata().getVersions().size(), "Incorrect number of versions");
assertEquals(V2_TIME, res.getMetadata().getVersions().get(1).getDeletionTimeString(), "Incorrect version 1 delete time");
assertNotNull(res.getMetadata().getVersions().get(1).getDeletionTime(), "Parsing version delete time failed");
assertTrue(res.getMetadata().getVersions().get(1).isDestroyed(), "Incorrect version 1 destroyed state");
assertEquals(V2_TIME, res.getMetadata().getVersions().get(2).getCreatedTimeString(), "Incorrect version 2 created time");
assertNotNull(res.getMetadata().getVersions().get(2).getCreatedTime(), "Parsing version created failed");
assertFalse(res.getMetadata().getVersions().get(3).isDestroyed(), "Incorrect version 3 destroyed state");
}

View File

@ -1,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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,12 +16,9 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import java.time.ZonedDateTime;
import static org.junit.jupiter.api.Assertions.*;
/**
@ -30,20 +27,16 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.8
*/
class SealResponseTest extends AbstractModelTest<SealResponse> {
class SealResponseTest {
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 VERSION = "0.11.2";
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" +
@ -53,11 +46,7 @@ class SealResponseTest extends AbstractModelTest<SealResponse> {
" \"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" +
" \"version\": \"" + VERSION + "\"\n" +
"}";
private static final String RES_UNSEALED = "{\n" +
@ -68,29 +57,11 @@ class SealResponseTest extends AbstractModelTest<SealResponse> {
" \"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" +
" \"nonce\": \"" + NONCE + "\"\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).
*/
@ -98,8 +69,8 @@ class SealResponseTest extends AbstractModelTest<SealResponse> {
void jsonRoundtripSealed() {
// First test sealed Vault's response.
SealResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(RES_SEALED, SealResponse.class),
"SealResponse deserialization failed"
() -> new ObjectMapper().readValue(RES_SEALED, SealResponse.class),
"TokenResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
assertEquals(TYPE, res.getType(), "Incorrect seal type");
@ -110,10 +81,6 @@ class SealResponseTest extends AbstractModelTest<SealResponse> {
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");
@ -121,8 +88,8 @@ class SealResponseTest extends AbstractModelTest<SealResponse> {
// Not test unsealed Vault's response.
res = assertDoesNotThrow(
() -> objectMapper.readValue(RES_UNSEALED, SealResponse.class),
"SealResponse deserialization failed"
() -> new ObjectMapper().readValue(RES_UNSEALED, SealResponse.class),
"TokenResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
assertEquals(TYPE, res.getType(), "Incorrect seal type");
@ -133,11 +100,7 @@ class SealResponseTest extends AbstractModelTest<SealResponse> {
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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,11 +16,10 @@
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.exception.InvalidResponseException;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
@ -30,46 +29,40 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.8
*/
class SecretListResponseTest extends AbstractModelTest<SecretListResponse> {
class SecretListResponseTest {
private static final Map<String, Object> DATA = new HashMap<>();
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" +
"}";
private static final List<String> KEYS = Arrays.asList(KEY1, KEY2);
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;
}
static {
DATA.put("keys", KEYS);
}
/**
* Test JSON deserialization and key getter.
* Test getter, setter and get-methods for response data.
*
* @throws InvalidResponseException Should not occur
*/
@Test
void getKeysTest() {
SecretListResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(JSON, SecretListResponse.class),
"SecretListResponse deserialization failed"
void getKeysTest() throws InvalidResponseException {
// Create empty Object.
SecretListResponse res = new SecretListResponse();
assertNull(res.getKeys(), "Keys should be null without initialization");
// Provoke internal ClassCastException.
Map<String, Object> invalidData = new HashMap<>();
invalidData.put("keys", "some string");
assertThrows(
InvalidResponseException.class,
() -> res.setData(invalidData),
"Setting incorrect class succeeded"
);
assertEquals(List.of(KEY1, KEY2), res.getKeys(), "Unexpected secret keys");
// Fill correct data.
res.setData(DATA);
assertNotNull(res.getKeys(), "Keys should be filled here");
assertEquals(2, res.getKeys().size(), "Unexpected number of keys");
assertTrue(res.getKeys().containsAll(Set.of(KEY1, KEY2)), "Unexpected keys");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,22 +16,33 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link MetaSecretResponse} model.
* JUnit Test for {@link SecretResponse} model.
*
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class MetaSecretResponseTest extends AbstractModelTest<MetaSecretResponse> {
class SecretResponseTest {
private static final Map<String, Object> DATA = new HashMap<>();
private static final String KEY_UNKNOWN = "unknown";
private static final String KEY_STRING = "test1";
private static final String VAL_STRING = "testvalue";
private static final String KEY_INTEGER = "test2";
private static final Integer VAL_INTEGER = 42;
private static final String KEY_LIST = "list";
private static final String VAL_LIST = "[\"first\",\"second\"]";
private static final String SECRET_REQUEST_ID = "68315073-6658-e3ff-2da7-67939fb91bbd";
private static final String SECRET_LEASE_ID = "";
private static final Integer SECRET_LEASE_DURATION = 2764800;
@ -43,9 +54,17 @@ class MetaSecretResponseTest extends AbstractModelTest<MetaSecretResponse> {
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 = "{\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" +
"}";
private static final String SECRET_JSON_V2 = "{\n" +
" \"request_id\": \"" + SECRET_REQUEST_ID + "\",\n" +
" \"lease_id\": \"" + SECRET_LEASE_ID + "\",\n" +
@ -58,7 +77,6 @@ class MetaSecretResponseTest extends AbstractModelTest<MetaSecretResponse> {
" },\n" +
" \"metadata\": {\n" +
" \"created_time\": \"" + SECRET_META_CREATED + "\",\n" +
" \"custom_metadata\": null,\n" +
" \"deletion_time\": \"\",\n" +
" \"destroyed\": false,\n" +
" \"version\": 1\n" +
@ -78,9 +96,6 @@ class MetaSecretResponseTest extends AbstractModelTest<MetaSecretResponse> {
" },\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" +
@ -89,18 +104,49 @@ class MetaSecretResponseTest extends AbstractModelTest<MetaSecretResponse> {
" \"warnings\": " + SECRET_WARNINGS + "\n" +
"}";
MetaSecretResponseTest() {
super(MetaSecretResponse.class);
static {
DATA.put(KEY_STRING, VAL_STRING);
DATA.put(KEY_INTEGER, VAL_INTEGER);
DATA.put(KEY_LIST, VAL_LIST);
}
@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 getter, setter and get-methods for response data.
*
* @throws InvalidResponseException Should not occur
*/
@Test
@SuppressWarnings("unchecked")
void getDataRoundtrip() throws InvalidResponseException {
// Create empty Object.
SecretResponse res = new SecretResponse();
assertNotNull(res.getData(), "Initial data should be Map");
assertTrue(res.getData().isEmpty(), "Initial data should be empty");
assertNull(res.get(KEY_STRING), "Getter should return NULL on empty data map");
// Fill data map.
res.setData(DATA);
assertEquals(DATA, res.getData(), "Data setter/getter not transparent");
assertEquals(DATA.size(), res.getData().keySet().size(), "Data size modified");
assertTrue(res.getData().keySet().containsAll(Set.of(KEY_STRING, KEY_INTEGER, KEY_LIST)), "Data keys not passed correctly");
assertEquals(VAL_STRING, res.get(KEY_STRING), "Data values not passed correctly");
assertEquals(VAL_INTEGER, res.get(KEY_INTEGER), "Data values not passed correctly");
assertNull(res.get(KEY_UNKNOWN), "Non-Null returned on unknown key");
// Try explicit JSON conversion.
final List<?> list = res.get(KEY_LIST, List.class);
assertNotNull(list, "JSON parsing of list failed");
assertEquals(2, list.size(), "JSON parsing of list returned incorrect size");
assertTrue(list.containsAll(List.of("first", "second")), "JSON parsing of list returned incorrect elements");
assertNull(res.get(KEY_UNKNOWN, Object.class), "Non-Null returned on unknown key");
// Requesting invalid class should result in Exception.
assertThrows(
InvalidResponseException.class,
() -> res.get(KEY_LIST, Double.class),
"JSON parsing to incorrect type succeeded"
);
}
/**
@ -108,36 +154,43 @@ class MetaSecretResponseTest extends AbstractModelTest<MetaSecretResponse> {
*/
@Test
void jsonRoundtrip() {
SecretResponse res = assertDoesNotThrow(
() -> new ObjectMapper().readValue(SECRET_JSON, SecretResponse.class),
"SecretResponse deserialization failed"
);
assertSecretData(res);
// KV v2 secret.
MetaSecretResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(SECRET_JSON_V2, MetaSecretResponse.class),
res = assertDoesNotThrow(
() -> new ObjectMapper().readValue(SECRET_JSON_V2, SecretResponse.class),
"SecretResponse deserialization failed"
);
assertSecretData(res);
assertNotNull(res.getMetadata(), "SecretResponse does not contain metadata");
assertEquals(SECRET_META_CREATED, res.getMetadata().getCreatedTimeString(), "Incorrect creation date string");
assertNotNull(res.getMetadata().getCreatedTime(), "Creation date parsing failed");
assertEquals("", res.getMetadata().getDeletionTimeString(), "Incorrect deletion date string");
assertNull(res.getMetadata().getDeletionTime(), "Incorrect deletion date");
assertFalse(res.getMetadata().isDestroyed(), "Secret destroyed when not expected");
assertEquals(false, 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),
() -> new ObjectMapper().readValue(SECRET_JSON_V2_2, SecretResponse.class),
"SecretResponse deserialization failed"
);
assertSecretData(res);
assertNotNull(res.getMetadata(), "SecretResponse does not contain metadata");
assertEquals(SECRET_META_CREATED, res.getMetadata().getCreatedTimeString(), "Incorrect creation date string");
assertNotNull(res.getMetadata().getCreatedTime(), "Creation date parsing failed");
assertEquals(SECRET_META_DELETED, res.getMetadata().getDeletionTimeString(), "Incorrect deletion date string");
assertNotNull(res.getMetadata().getDeletionTime(), "Incorrect deletion date");
assertTrue(res.getMetadata().isDestroyed(), "Secret destroyed when not expected");
assertEquals(true, 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");

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,8 +16,7 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
@ -28,7 +27,7 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.8
*/
class SecretVersionResponseTest extends AbstractModelTest<SecretVersionResponse> {
class SecretVersionResponseTest {
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;
@ -42,32 +41,20 @@ class SecretVersionResponseTest extends AbstractModelTest<SecretVersionResponse>
" }\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),
() -> new 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(CREATION_TIME, res.getMetadata().getCreatedTimeString(), "Incorrect created time");
assertEquals(DELETION_TIME, res.getMetadata().getDeletionTimeString(), "Incorrect deletion time");
assertEquals(false, res.getMetadata().isDestroyed(), "Incorrect destroyed state");
assertEquals(VERSION, res.getMetadata().getVersion(), "Incorrect version");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,12 +16,13 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
import org.junit.jupiter.api.Test;
import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -33,7 +34,7 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class TokenResponseTest extends AbstractModelTest<TokenResponse> {
class TokenResponseTest {
private static final Integer TOKEN_CREATION_TIME = 1457533232;
private static final Integer TOKEN_TTL = 2764800;
private static final Integer TOKEN_EXPLICIT_MAX_TTL = 0;
@ -55,7 +56,6 @@ class TokenResponseTest extends AbstractModelTest<TokenResponse> {
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" +
@ -86,22 +86,13 @@ class TokenResponseTest extends AbstractModelTest<TokenResponse> {
" \"type\": \"" + TOKEN_TYPE + "\"\n" +
" },\n" +
" \"warnings\": null,\n" +
" \"auth\": null,\n" +
" \"mount_type\": \"" + MOUNT_TYPE + "\"\n" +
" \"auth\": null\n" +
"}";
TokenResponseTest() {
super(TokenResponse.class);
}
private static final Map<String, Object> INVALID_TOKEN_DATA = new HashMap<>();
@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;
}
static {
INVALID_TOKEN_DATA.put("num_uses", "fourtytwo");
}
/**
@ -112,6 +103,13 @@ class TokenResponseTest extends AbstractModelTest<TokenResponse> {
// Create empty Object.
TokenResponse res = new TokenResponse();
assertNull(res.getData(), "Initial data should be empty");
// Parsing invalid data map should fail.
assertThrows(
InvalidResponseException.class,
() -> res.setData(INVALID_TOKEN_DATA),
"Parsing invalid token data succeeded"
);
}
/**
@ -120,14 +118,13 @@ class TokenResponseTest extends AbstractModelTest<TokenResponse> {
@Test
void jsonRoundtrip() {
TokenResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(RES_JSON, TokenResponse.class),
() -> new 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");
@ -136,9 +133,11 @@ class TokenResponseTest extends AbstractModelTest<TokenResponse> {
assertEquals(TOKEN_TTL, data.getCreationTtl(), "Incorrect token creation TTL");
assertEquals(TOKEN_DISPLAY_NAME, data.getName(), "Incorrect token display name");
assertEquals(TOKEN_ENTITY_ID, data.getEntityId(), "Incorrect token entity ID");
assertEquals(TOKEN_EXPIRE_TIME, data.getExpireTimeString(), "Incorrect token expire time");
assertEquals(ZonedDateTime.parse(TOKEN_EXPIRE_TIME), data.getExpireTime(), "Incorrect parsed token expire time");
assertEquals(TOKEN_EXPLICIT_MAX_TTL, data.getExplicitMaxTtl(), "Incorrect token explicit max TTL");
assertEquals(TOKEN_ID, data.getId(), "Incorrect token ID");
assertEquals(TOKEN_ISSUE_TIME, data.getIssueTimeString(), "Incorrect token issue time");
assertEquals(ZonedDateTime.parse(TOKEN_ISSUE_TIME), data.getIssueTime(), "Incorrect parsed token issue time");
assertEquals(Map.of(TOKEN_META_KEY, TOKEN_META_VALUE), data.getMeta(), "Incorrect token metadata");
assertEquals(TOKEN_NUM_USES, data.getNumUses(), "Incorrect token number of uses");

View File

@ -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,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
* Copyright 2016-2021 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -103,4 +103,4 @@ public class VaultConfiguration {
"}\n" +
((disableMlock) ? "disable_mlock = true" : "");
}
}
}

View File

@ -0,0 +1 @@
{"Value":"AAAAAQK5U1GclNj+Tga7D4bQ5wExYfVu2y+djHlAlhiJ/JHOS1gS0G/kDrjR8gCdg/Aw2UunrObAq/mrKw0HEe1wo2qA"}

View File

@ -0,0 +1 @@
{"Value":"AAAAAQLbvc+neI458Mqhl2WUUjY5HMC1Ast0KjZ5pslwW+5TtjVHcqdzls4whrrYHGUWv+nTg6wxJaS46j5+FER+4gsgWVJE1S33ZqvGtmmueCVpac5ZM0biBDXOvE/YFQ=="}

View File

@ -0,0 +1 @@
{"Value":"AAAAAQIK4FkvUHPiWUfHY7l9lGW1qf+sU2mAIWbjlfSvEIecbg94Mu4KAPxY3E2YLwOs7VyPZtWNZrZAZDMJJJzxM/pLux2o/IctJ5oXGtfPPjTjwNRRJ4U62wpRqBnBGX4="}

View File

@ -1 +1 @@
{"Value":"AAAAAQK788ueZMqWkxK0+QrdrSU6/fJE0BHpMFCmXuZch21YdFNQSxZwgbTTH6uAyzxlEpHvAa4v9ScNyYXqRCLFK4X0DtDmpheIr/Ow6BPU8yxNglfI+qW5SKZKeYAYMHal0jX1MYsaIdYp8LJm52VMa+CdjTRx1J7ZhrNqiNHXbVJr6uOM+FDbGU4W8LyDy1ZhBKo17fwMnOycl5vBHu7b964iVHAIDkZHBq/4N1R/w7Sne7K/JvNPfuBNd1evRSErRNJRPp4DEkpK2v8lgIAXFjemE+aOysWYjGh/XVi8EzP09K1QFwfsvgIeIX0XVP4wMNn2xHedDyWQV55FJbD1LcrM2Q54HAHM0YGItI+MwPPzmP06Udoq3PZNRMWRI3l1rdjnIT+3FtbJr43EF8mf6SuYCzf9QWkGkixWAPAsMO+ZYCkHfsp8Ebq5IQmgK2IXzR7Dw8+tizs+8jaXB5JJ1vru0dZJa3b1oV9eizW5U53yIWNhC2v/d0rVxivvMbZ2deAP9OaqXm+oFukIjaFHDNbAskqvpHh8/7e91fqDFla2ZNEEPtVSsBBmyKHO0gDiDHKC3T2hrvvSRHsMHplIpD1mnppE2E4BlngIDgrfAe3G2jKUHg9eYLq9dMXBeysfzc8UtBI="}
{"Value":"AAAAAQKHd7fFuNKfj/RnIQoxQEOTorNNl1NfcVtynLwYvtvZGDvhAO34YmOFKJSQVSiT4Js08ik48DWWnZHCZzAyMlK0HqNGYQRzCkuHkzYpH0uLrTcddXLuKyc7j6IiRTl3qYb1pzdlTzDtlwsi4J7s+7orETS146yY/GnGPWM/Tmet7p5qOECRq7m04gBX0pnwZl12iRqWG4aHHY5D4aFp9KjKUBKCIhz2Tb9wcSKV/Aa/ct1d0K0k8pyu1r1OkaJqCQXQeIaJR/WBMECR4omezvg7IGCoBIkMjwFR1urSaB0xNdgk+ByZE0C5zeDfmVRylYlypPAlIBrGL/Q/d6+NWiiOzXdoQoqAa/Pyg7e2gClsKDBFDvSL1QVBdsnBIskDeig2t46Ew5qM00wY58BWlUxqjlCgsNm3nPHtWpc6+XiR4ZkEZ9VeEIQhwC/R+NxS+QCDKeuSfyZM3OqQBwOx22mTL0i86YzlUph0alBmDF1b1FkDbg46MSWTANrkov1LPDnOvvNet7pb0L6exN5Q+HKitmxn36E0KAiqj1hEaHMZF6Pe+IIScLPClgPNeMkZWLeD5kvLv9kfObTYneHVHqj8O9jGtk03T4vOoaUNJY9U0irBGzlV+GkneJUgBL1QBspfK4GvFvUrd0Ds/teayJba8HDxlpCEWr6h062BXsNPg5gUn4H/uvginsFng02M8IyrDA1QOb4XS1zdfrvq"}

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