12 Commits

Author SHA1 Message Date
1072e9b4a9 split VaultConnector interface into clients per module
All checks were successful
CI / build (11) (push) Successful in 33s
CI / build (17) (push) Successful in 31s
CI / build (true, 21) (push) Successful in 25s
The connector interface has grown quite big and does not even cover all
potential APIs. We now extract functionality into submodules and group
them to handle each area in separate interfaces. Provide fluent access,
strip prefixes from methods and preserve a 1:1 migration path.

Examples:

* connector.unseal() => connector.sys().unseal()
* connector.readSecretVersion() => connector.kv2().readVersion()
* connector.createToken() => connector.token().create()
* connector.lookupAppRole() => connector.appRole().lookup()
* connector.transitHash() => connector.transit().hash()
2025-09-02 15:35:18 +02:00
e96ece3385 build: update maven-wrapper to 3.3.3
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 49s
CI / build-with-it (11, 1.20.0) (push) Successful in 1m6s
CI / build-with-it (21, 1.2.0) (push) Successful in 49s
CI / build-with-it (17, 1.2.0) (push) Successful in 48s
CI / build-with-it (17, 1.20.0) (push) Successful in 1m5s
CI / build-with-it (true, 21, 1.20.0) (push) Successful in 59s
2025-09-02 13:27:29 +02:00
41eeae6687 refactor: extract API paths into a utility class (#108)
Some checks failed
CI / build-with-it (11, 1.2.0) (push) Successful in 50s
CI / build-with-it (11, 1.20.0) (push) Successful in 1m8s
CI / build-with-it (17, 1.2.0) (push) Successful in 46s
CI / build-with-it (true, 21, 1.20.0) (push) Has been cancelled
CI / build-with-it (17, 1.20.0) (push) Has been cancelled
CI / build-with-it (21, 1.2.0) (push) Has been cancelled
Extract some static String constants from HTTPVaultConnector, which is
quite long already, into an internal utility class VaultApiPath.
We just reorganize some constants that should not change any behavior.
2025-08-30 09:53:46 +02:00
bac06c5d19 fix: prevent potential off-by-1 error in internal mapOf() helper (#107)
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 43s
CI / build-with-it (11, 1.20.0) (push) Successful in 53s
CI / build-with-it (17, 1.2.0) (push) Successful in 40s
CI / build-with-it (17, 1.20.0) (push) Successful in 52s
CI / build-with-it (21, 1.2.0) (push) Successful in 41s
CI / build-with-it (true, 21, 1.20.0) (push) Successful in 45s
2025-08-30 09:41:09 +02:00
e30a3bd93a build: update sonar-maven-plugin to 5.2.0.4988
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 44s
CI / build-with-it (11, 1.20.0) (push) Successful in 51s
CI / build-with-it (17, 1.2.0) (push) Successful in 40s
CI / build-with-it (17, 1.20.0) (push) Successful in 49s
CI / build-with-it (21, 1.2.0) (push) Successful in 39s
CI / build-with-it (true, 21, 1.20.0) (push) Successful in 46s
2025-08-30 09:11:21 +02:00
8447b572b4 build: update maven-javadoc-plugin to 3.11.3 2025-08-30 09:10:26 +02:00
a95b05ba0e build: update GitHub actions 2025-08-30 09:08:30 +02:00
29517b9d78 deps: update jackson to 2.20.0 (#106)
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 47s
CI / build-with-it (11, 1.20.0) (push) Successful in 54s
CI / build-with-it (17, 1.2.0) (push) Successful in 43s
CI / build-with-it (17, 1.20.0) (push) Successful in 53s
CI / build-with-it (21, 1.2.0) (push) Successful in 44s
CI / build-with-it (true, 21, 1.20.0) (push) Successful in 51s
2025-08-29 17:36:24 +02:00
1536c23cf0 test(deps): update mockito-core to 5.19.0
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 47s
CI / build-with-it (11, 1.20.0) (push) Successful in 1m0s
CI / build-with-it (17, 1.2.0) (push) Successful in 46s
CI / build-with-it (17, 1.20.0) (push) Successful in 57s
CI / build-with-it (21, 1.2.0) (push) Successful in 46s
CI / build-with-it (true, 21, 1.20.0) (push) Successful in 54s
2025-08-16 10:23:36 +02:00
a7a435b420 test(deps): update junit-jupiter to 5.13.3
All checks were successful
CI / build-with-it (11, 1.2.0) (push) Successful in 57s
CI / build-with-it (11, 1.20.0) (push) Successful in 1m13s
CI / build-with-it (17, 1.2.0) (push) Successful in 52s
CI / build-with-it (17, 1.20.0) (push) Successful in 1m11s
CI / build-with-it (21, 1.2.0) (push) Successful in 50s
CI / build-with-it (true, 21, 1.20.0) (push) Successful in 1m4s
2025-07-20 15:47:32 +02:00
d1b8b12ffe test(deps): update commons-io to 2.20.0 2025-07-20 15:47:31 +02:00
27c94870d3 deps: update jackson to 2.19.2 (#105) 2025-07-20 15:47:30 +02:00
18 changed files with 1869 additions and 1606 deletions

View File

@@ -22,11 +22,11 @@ jobs:
analysis: true
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
java-version: ${{ matrix.jdk }}
distribution: 'temurin'

View File

@@ -21,11 +21,11 @@ jobs:
analysis: true
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
java-version: ${{ matrix.jdk }}
distribution: 'temurin'

View File

@@ -1,2 +1,2 @@
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar

View File

@@ -1,3 +1,14 @@
## unreleased
### Dependencies
* Updated Jackson to 2.20.0 (#106)
### Improvements
* Extract API paths into a utility class (#108)
### Fix
* Prevent potential off-by-1 error in internal `mapOf()` helper (#107)
## 1.5.2 (2025-07-16)
### Dependencies

View File

@@ -109,11 +109,11 @@ Token token = Token.builder()
.withDisplayName("new test token")
.withPolicies("pol1", "pol2")
.build();
vault.createToken(token);
vault.token().create(token);
// Create AppRole credentials
vault.createAppRole("testrole", policyList);
AppRoleSecretResponse secret = vault.createAppRoleSecret("testrole");
vault.appRole().create("testrole", policyList);
AppRoleSecretResponse secret = vault.appRole().createSecret("testrole");
```
## Links

493
mvnw vendored
View File

@@ -19,314 +19,277 @@
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Apache Maven Wrapper startup batch script, version 3.3.2
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
# Apache Maven Wrapper startup batch script, version 3.3.3
#
# 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
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
# MVNW_REPOURL - repo url base for downloading maven distribution
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ]; then
set -euf
[ "${MVNW_VERBOSE-}" != debug ] || set -x
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
# OS specific support.
native_path() { printf %s\\n "$1"; }
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
CYGWIN* | MINGW*)
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
native_path() { cygpath --path --windows "$1"; }
;;
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
# set JAVACMD and JAVACCMD
set_java_home() {
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
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"
JAVACCMD="$JAVA_HOME/jre/sh/javac"
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACCMD="$JAVA_HOME/bin/javac"
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
return 1
fi
fi
else
JAVACMD="$(
\unset -f command 2>/dev/null
\command -v java
)"
fi
fi
'set' +e
'unset' -f command 2>/dev/null
'command' -v java
)" || :
JAVACCMD="$(
'set' +e
'unset' -f command 2>/dev/null
'command' -v javac
)" || :
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
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
return 1
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=$(
cd "$wdir/.." || exit 1
pwd
)
fi
# end of workaround
fi
}
# hash string like Java String::hashCode
hash_string() {
str="${1:-}" h=0
while [ -n "$str" ]; do
char="${str%"${str#?}"}"
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
str="${str#?}"
done
printf '%s' "$(
cd "$basedir" || exit 1
pwd
)"
printf %x\\n $h
}
# 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
}
verbose() { :; }
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
log() {
if [ "$MVNW_VERBOSE" = true ]; then
printf '%s\n' "$1"
fi
}
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
if [ -z "$BASE_DIR" ]; then
die() {
printf %s\\n "$1" >&2
exit 1
fi
}
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
export MAVEN_PROJECTBASEDIR
log "$MAVEN_PROJECTBASEDIR"
trim() {
# MWRAPPER-139:
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
# Needed for removing poorly interpreted newline sequences when running in more
# exotic environments such as mingw bash on Windows.
printf "%s" "${1}" | tr -d '[:space:]'
}
##########################################################################################
# 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 ..."
scriptDir="$(dirname "$0")"
scriptName="$(basename "$0")"
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=""
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
while IFS="=" read -r key value; do
case "$key" in wrapperSha256Sum)
wrapperSha256Sum=$value
break
case "${key-}" in
distributionUrl) distributionUrl=$(trim "${value-}") ;;
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
esac
done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties"
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
case "${distributionUrl##*/}" in
maven-mvnd-*bin.*)
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
*)
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
distributionPlatform=linux-amd64
;;
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
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
;;
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
esac
# apply MVNW_REPOURL and calculate MAVEN_HOME
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
distributionUrlName="${distributionUrl##*/}"
distributionUrlNameMain="${distributionUrlName%.*}"
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
exec_maven() {
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
}
if [ -d "$MAVEN_HOME" ]; then
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
exec_maven "$@"
fi
case "${distributionUrl-}" in
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
esac
# prepare tmp dir
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
trap clean HUP INT TERM EXIT
else
die "cannot create temp dir"
fi
mkdir -p -- "${MAVEN_HOME%/*}"
# Download and Install Apache Maven
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
verbose "Downloading from: $distributionUrl"
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
# select .zip or .tar.gz
if ! command -v unzip >/dev/null; then
distributionUrl="${distributionUrl%.zip}.tar.gz"
distributionUrlName="${distributionUrl##*/}"
fi
# verbose opt
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
# normalize http auth
case "${MVNW_PASSWORD:+has-password}" in
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
esac
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
verbose "Found wget ... using wget"
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
verbose "Found curl ... using curl"
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
elif set_java_home; then
verbose "Falling back to use Java to download"
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
cat >"$javaSource" <<-END
public class Downloader extends java.net.Authenticator
{
protected java.net.PasswordAuthentication getPasswordAuthentication()
{
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
}
public static void main( String[] args ) throws Exception
{
setDefault( new Downloader() );
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
}
}
END
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
verbose " - Compiling Downloader.java ..."
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
verbose " - Running Downloader.java ..."
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
fi
# If specified, validate the SHA-256 sum of the Maven distribution zip file
if [ -n "${distributionSha256Sum-}" ]; then
distributionSha256Result=false
if [ "$MVN_CMD" = mvnd.sh ]; then
echo "Checksum validation is not supported for maven-mvnd." >&2
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
exit 1
elif command -v sha256sum >/dev/null; then
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then
distributionSha256Result=true
fi
elif command -v shasum >/dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c >/dev/null 2>&1; then
wrapperSha256Result=true
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
distributionSha256Result=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
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' 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
if [ $distributionSha256Result = false ]; then
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum 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")
# unzip and move
if command -v unzip >/dev/null; then
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
else
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
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
# Find the actual extracted directory name (handles snapshots where filename != directory name)
actualDistributionDir=""
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
# First try the expected directory name (for regular distributions)
if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then
if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then
actualDistributionDir="$distributionUrlNameMain"
fi
fi
# 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 "$@"
# If not found, search for any directory with the Maven executable (for snapshots)
if [ -z "$actualDistributionDir" ]; then
# enable globbing to iterate over items
set +f
for dir in "$TMP_DOWNLOAD_DIR"/*; do
if [ -d "$dir" ]; then
if [ -f "$dir/bin/$MVN_CMD" ]; then
actualDistributionDir="$(basename "$dir")"
break
fi
fi
done
set -f
fi
if [ -z "$actualDistributionDir" ]; then
verbose "Contents of $TMP_DOWNLOAD_DIR:"
verbose "$(ls -la "$TMP_DOWNLOAD_DIR")"
die "Could not find Maven distribution directory in extracted archive"
fi
verbose "Found extracted Maven distribution directory: $actualDistributionDir"
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url"
mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
clean || :
exec_maven "$@"

323
mvnw.cmd vendored
View File

@@ -1,3 +1,4 @@
<# : batch portion
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@@ -18,189 +19,171 @@
@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 Apache Maven Wrapper startup batch script, version 3.3.3
@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 MVNW_REPOURL - repo url base for downloading maven distribution
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
@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
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
@SET __MVNW_CMD__=
@SET __MVNW_ERROR__=
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
@SET PSModulePath=
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
)
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
@SET __MVNW_PSMODULEP_SAVE=
@SET __MVNW_ARG0_NAME__=
@SET MVNW_USERNAME=
@SET MVNW_PASSWORD=
@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*)
@echo Cannot start maven from wrapper >&2 && exit /b 1
@GOTO :EOF
: end batch / begin powershell #>
@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%
)
$ErrorActionPreference = "Stop"
if ($env:MVNW_VERBOSE -eq "true") {
$VerbosePreference = "Continue"
}
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
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
if (!$distributionUrl) {
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
}
@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
)
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
"maven-mvnd-*" {
$USE_MVND = $true
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
$MVN_CMD = "mvnd.cmd"
break
}
default {
$USE_MVND = $false
$MVN_CMD = $script -replace '^mvnw','mvn'
break
}
}
@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=%*
# apply MVNW_REPOURL and calculate MAVEN_HOME
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
if ($env:MVNW_REPOURL) {
$MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" }
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')"
}
$distributionUrlName = $distributionUrl -replace '^.*/',''
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
%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
$MAVEN_M2_PATH = "$HOME/.m2"
if ($env:MAVEN_USER_HOME) {
$MAVEN_M2_PATH = "$env:MAVEN_USER_HOME"
}
:error
set ERROR_CODE=1
if (-not (Test-Path -Path $MAVEN_M2_PATH)) {
New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null
}
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
$MAVEN_WRAPPER_DISTS = $null
if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) {
$MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists"
} else {
$MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists"
}
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
$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain"
$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%"=="on" pause
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
exit $?
}
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
}
cmd /C exit /B %ERROR_CODE%
# prepare tmp dir
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
trap {
if ($TMP_DOWNLOAD_DIR.Exists) {
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}
}
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
# Download and Install Apache Maven
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
Write-Verbose "Downloading from: $distributionUrl"
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
$webclient = New-Object System.Net.WebClient
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
# If specified, validate the SHA-256 sum of the Maven distribution zip file
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
if ($distributionSha256Sum) {
if ($USE_MVND) {
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
}
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
}
}
# unzip and move
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
# Find the actual extracted directory name (handles snapshots where filename != directory name)
$actualDistributionDir = ""
# First try the expected directory name (for regular distributions)
$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain"
$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD"
if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) {
$actualDistributionDir = $distributionUrlNameMain
}
# If not found, search for any directory with the Maven executable (for snapshots)
if (!$actualDistributionDir) {
Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object {
$testPath = Join-Path $_.FullName "bin/$MVN_CMD"
if (Test-Path -Path $testPath -PathType Leaf) {
$actualDistributionDir = $_.Name
}
}
}
if (!$actualDistributionDir) {
Write-Error "Could not find Maven distribution directory in extracted archive"
}
Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir"
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null
try {
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
} catch {
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
Write-Error "fail to move MAVEN_HOME"
}
} finally {
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"

16
pom.xml
View File

@@ -3,7 +3,7 @@
<groupId>de.stklcode.jvault</groupId>
<artifactId>jvault-connector</artifactId>
<version>1.5.3-SNAPSHOT</version>
<version>2.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
@@ -49,24 +49,24 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.19.1</version>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.19.1</version>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.13.2</version>
<version>5.13.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.18.0</version>
<version>5.19.0</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -84,7 +84,7 @@
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.19.0</version>
<version>2.20.0</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -178,7 +178,7 @@
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>5.1.0.4751</version>
<version> 5.2.0.4988</version>
</plugin>
</plugins>
</pluginManagement>
@@ -244,7 +244,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.11.2</version>
<version>3.11.3</version>
<configuration>
<source>11</source>
</configuration>

View File

@@ -0,0 +1,217 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import de.stklcode.jvault.connector.model.AppRole;
import de.stklcode.jvault.connector.model.AppRoleSecret;
import de.stklcode.jvault.connector.model.Token;
import de.stklcode.jvault.connector.model.TokenRole;
import de.stklcode.jvault.connector.model.response.*;
import java.util.ArrayList;
import java.util.List;
/**
* AppRole client interface.
* Provides methods to interact with Vault's AppRole API.
*
* @since 2.0.0 extracted from {@link VaultConnector}
*/
public interface AppRoleClient {
/**
* Register a new AppRole role from given metamodel.
*
* @param role The role
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean create(final AppRole role) throws VaultConnectorException;
/**
* Register new AppRole role with default policy.
*
* @param roleName The role name
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean create(final String roleName) throws VaultConnectorException {
return create(roleName, new ArrayList<>());
}
/**
* Register new AppRole role with policies.
*
* @param roleName The role name
* @param policies The policies to associate with
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean create(final String roleName, final List<String> policies) throws VaultConnectorException {
return create(roleName, policies, null);
}
/**
* Register new AppRole role with default policy and custom ID.
*
* @param roleName The role name
* @param roleID A custom role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean create(final String roleName, final String roleID) throws VaultConnectorException {
return create(roleName, new ArrayList<>(), roleID);
}
/**
* Register new AppRole role with policies and custom ID.
*
* @param roleName The role name
* @param policies The policies to associate with
* @param roleID A custom role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean create(final String roleName, final List<String> policies, final String roleID)
throws VaultConnectorException {
return create(AppRole.builder(roleName).withTokenPolicies(policies).withId(roleID).build());
}
/**
* Delete AppRole role from Vault.
*
* @param roleName The role name
* @return {@code true} on success
* @throws VaultConnectorException on error
*/
boolean delete(final String roleName) throws VaultConnectorException;
/**
* Lookup an AppRole role.
*
* @param roleName The role name
* @return Result of the lookup
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleResponse lookup(final String roleName) throws VaultConnectorException;
/**
* Retrieve ID for an AppRole role.
*
* @param roleName The role name
* @return The role ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
String getRoleID(final String roleName) throws VaultConnectorException;
/**
* Set custom ID for an AppRole role.
*
* @param roleName The role name
* @param roleID The role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean setRoleID(final String roleName, final String roleID) throws VaultConnectorException;
/**
* Register new random generated AppRole secret.
*
* @param roleName The role name
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default AppRoleSecretResponse createSecret(final String roleName) throws VaultConnectorException {
return createSecret(roleName, new AppRoleSecret());
}
/**
* Register new AppRole secret with custom ID.
*
* @param roleName The role name
* @param secretID A custom secret ID
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default AppRoleSecretResponse createSecret(final String roleName, final String secretID)
throws VaultConnectorException {
return createSecret(roleName, new AppRoleSecret(secretID));
}
/**
* Register new AppRole secret with custom ID.
*
* @param roleName The role name
* @param secret The secret meta object
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleSecretResponse createSecret(final String roleName, final AppRoleSecret secret)
throws VaultConnectorException;
/**
* Lookup an AppRole secret.
*
* @param roleName The role name
* @param secretID The secret ID
* @return Result of the lookup
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleSecretResponse lookupSecret(final String roleName, final String secretID)
throws VaultConnectorException;
/**
* Destroy an AppRole secret.
*
* @param roleName The role name
* @param secretID The secret meta object
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean destroySecret(final String roleName, final String secretID) throws VaultConnectorException;
/**
* List existing (accessible) AppRole roles.
*
* @return List of roles
* @throws VaultConnectorException on error
*/
List<String> listRoles() throws VaultConnectorException;
/**
* List existing (accessible) secret IDs for AppRole role.
*
* @param roleName The role name
* @return List of roles
* @throws VaultConnectorException on error
*/
List<String> listSecrets(final String roleName) throws VaultConnectorException;
}

View File

@@ -0,0 +1,200 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import de.stklcode.jvault.connector.model.response.MetadataResponse;
import de.stklcode.jvault.connector.model.response.SecretResponse;
import de.stklcode.jvault.connector.model.response.SecretVersionResponse;
import java.util.Map;
/**
* KV v2 client interface.
* Provides methods to interact with Vault's KV v2 API.
*
* @since 2.0.0 extracted from {@link VaultConnector}
*/
public interface KV2Client {
/**
* Retrieve the latest secret data for specific version from Vault.
* <br>
* Path {@code <mount>/data/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @return Secret response
* @throws VaultConnectorException on error
* @since 0.8
*/
default SecretResponse readData(final String mount, final String key) throws VaultConnectorException {
return readVersion(mount, key, null);
}
/**
* Write secret to Vault.
* <br>
* Path {@code <mount>/data/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @param data Secret content. Value must be be JSON serializable.
* @return Metadata for the created/updated secret.
* @throws VaultConnectorException on error
* @since 0.8
*/
default SecretVersionResponse writeData(final String mount,
final String key,
final Map<String, Object> data) throws VaultConnectorException {
return writeData(mount, key, data, null);
}
/**
* Write secret to Vault.
* <br>
* Path {@code <mount>/data/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @param data Secret content. Value must be be JSON serializable.
* @param cas Use Check-And-Set operation, i.e. only allow writing if current version matches this value.
* @return Metadata for the created/updated secret.
* @throws VaultConnectorException on error
* @since 0.8
*/
SecretVersionResponse writeData(final String mount,
final String key,
final Map<String, Object> data,
final Integer cas) throws VaultConnectorException;
/**
* Retrieve secret data from Vault.
* <br>
* Path {@code <mount>/data/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @param version Version to read. If {@code null} or zero, the latest version will be returned.
* @return Secret response.
* @throws VaultConnectorException on error
* @since 0.8
*/
SecretResponse readVersion(final String mount, final String key, final Integer version)
throws VaultConnectorException;
/**
* Retrieve secret metadata from Vault.
* <br>
* Path {@code <mount>/metadata/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @return Metadata response
* @throws VaultConnectorException on error
* @since 0.8
*/
MetadataResponse readMetadata(final String mount, final String key) throws VaultConnectorException;
/**
* Update secret metadata.
* <br>
* Path {@code <mount>/metadata/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @param maxVersions Maximum number of versions (fallback to backend default if {@code null})
* @param casRequired Specify if Check-And-Set is required for this secret.
* @throws VaultConnectorException on error
* @since 0.8
*/
void updateMetadata(final String mount,
final String key,
final Integer maxVersions,
final boolean casRequired) throws VaultConnectorException;
/**
* Delete latest version of a secret from Vault.
* <br>
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteLatestVersion(final String mount, final String key) throws VaultConnectorException;
/**
* Delete latest version of a secret from Vault.
* <br>
* Prefix {@code secret/} is automatically added to path.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteAllVersions(final String mount, final String key) throws VaultConnectorException;
/**
* Delete secret versions from Vault.
* <br>
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to delete.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Undelete (restore) secret versions from Vault.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to undelete.
* @throws VaultConnectorException on error
* @since 0.8
*/
void undeleteVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Destroy secret versions from Vault.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to destroy.
* @throws VaultConnectorException on error
* @since 0.8
*/
void destroyVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import de.stklcode.jvault.connector.model.AuthBackend;
import de.stklcode.jvault.connector.model.Token;
import de.stklcode.jvault.connector.model.TokenRole;
import de.stklcode.jvault.connector.model.response.*;
import java.util.List;
/**
* Sys client interface.
* Provides methods to interact with Vault's system API.
*
* @since 2.0.0 extracted from {@link VaultConnector}
*/
public interface SysClient {
/**
* Retrieve status of vault seal.
*
* @return Seal status
* @throws VaultConnectorException on error
*/
SealResponse sealStatus() throws VaultConnectorException;
/**
* Seal vault.
*
* @throws VaultConnectorException on error
*/
void seal() throws VaultConnectorException;
/**
* Unseal vault.
*
* @param key A single master share key
* @param reset Discard previously provided keys (optional)
* @return Response with seal status
* @throws VaultConnectorException on error
*/
SealResponse unseal(final String key, final Boolean reset) throws VaultConnectorException;
/**
* Unseal vault.
*
* @param key A single master share key
* @return Response with seal status
* @throws VaultConnectorException on error
*/
default SealResponse unseal(final String key) throws VaultConnectorException {
return unseal(key, null);
}
/**
* Query server health information.
*
* @return Health information.
* @throws VaultConnectorException on error
* @since 0.7.0
*/
HealthResponse getHealth() throws VaultConnectorException;
/**
* Get all available authentication backends.
*
* @return List of backends
* @throws VaultConnectorException on error
*/
List<AuthBackend> getAuthBackends() throws VaultConnectorException;
}

View File

@@ -0,0 +1,125 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import de.stklcode.jvault.connector.model.Token;
import de.stklcode.jvault.connector.model.TokenRole;
import de.stklcode.jvault.connector.model.response.AuthResponse;
import de.stklcode.jvault.connector.model.response.TokenResponse;
import de.stklcode.jvault.connector.model.response.TokenRoleResponse;
import java.util.List;
/**
* Token client interface.
* Provides methods to interact with Vault's token API.
*
* @since 2.0.0 extracted from {@link VaultConnector}
*/
public interface TokenClient {
/**
* Create a new token.
*
* @param token the token
* @return the result response
* @throws VaultConnectorException on error
*/
AuthResponse create(final Token token) throws VaultConnectorException;
/**
* Create a new token.
*
* @param token the token
* @param orphan create orphan token
* @return the result response
* @throws VaultConnectorException on error
*/
AuthResponse create(final Token token, boolean orphan) throws VaultConnectorException;
/**
* Create a new token for specific role.
*
* @param token the token
* @param role the role name
* @return the result response
* @throws VaultConnectorException on error
*/
AuthResponse create(final Token token, final String role) throws VaultConnectorException;
/**
* Lookup token information.
*
* @param token the token
* @return the result response
* @throws VaultConnectorException on error
*/
TokenResponse lookup(final String token) throws VaultConnectorException;
/**
* Create a new or update an existing token role.
*
* @param role the role entity (name must be set)
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
*/
default boolean createOrUpdateRole(final TokenRole role) throws VaultConnectorException {
return createOrUpdateRole(role.getName(), role);
}
/**
* Create a new or update an existing token role.
*
* @param name the role name (overrides name possibly set in role entity)
* @param role the role entity
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
*/
boolean createOrUpdateRole(final String name, final TokenRole role) throws VaultConnectorException;
/**
* Lookup token information.
*
* @param name the role name
* @return the result response
* @throws VaultConnectorException on error
* @since 0.9
*/
TokenRoleResponse readRole(final String name) throws VaultConnectorException;
/**
* List available token roles from Vault.
*
* @return List of token roles
* @throws VaultConnectorException on error
* @since 0.9
*/
List<String> listRoles() throws VaultConnectorException;
/**
* Delete a token role.
*
* @param name the role name to delete
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
*/
boolean deleteRole(final String name) throws VaultConnectorException;
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import de.stklcode.jvault.connector.model.response.TransitResponse;
import java.util.Base64;
/**
* Transit client interface.
* Provides methods to interact with Vault's transit API.
*
* @since 2.0.0 extracted from {@link VaultConnector}
*/
public interface TransitClient {
/**
* 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 encrypt(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 encrypt(final String keyName, final byte[] plaintext)
throws VaultConnectorException {
return encrypt(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 decrypt(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 hash(final String algorithm, final String input) throws VaultConnectorException {
return hash(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 hash(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 hash(final String algorithm, final byte[] input, final String format)
throws VaultConnectorException {
return hash(algorithm, Base64.getEncoder().encodeToString(input), format);
}
}

View File

@@ -37,59 +37,6 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
void resetAuth();
/**
* Retrieve status of vault seal.
*
* @return Seal status
* @throws VaultConnectorException on error
*/
SealResponse sealStatus() throws VaultConnectorException;
/**
* Seal vault.
*
* @throws VaultConnectorException on error
*/
void seal() throws VaultConnectorException;
/**
* Unseal vault.
*
* @param key A single master share key
* @param reset Discard previously provided keys (optional)
* @return Response with seal status
* @throws VaultConnectorException on error
*/
SealResponse unseal(final String key, final Boolean reset) throws VaultConnectorException;
/**
* Unseal vault.
*
* @param key A single master share key
* @return Response with seal status
* @throws VaultConnectorException on error
*/
default SealResponse unseal(final String key) throws VaultConnectorException {
return unseal(key, null);
}
/**
* Query server health information.
*
* @return Health information.
* @throws VaultConnectorException on error
* @since 0.7.0
*/
HealthResponse getHealth() throws VaultConnectorException;
/**
* Get all available authentication backends.
*
* @return List of backends
* @throws VaultConnectorException on error
*/
List<AuthBackend> getAuthBackends() throws VaultConnectorException;
/**
* Authorize to Vault using token.
*
@@ -132,187 +79,6 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
AuthResponse authAppRole(final String roleID, final String secretID) throws VaultConnectorException;
/**
* Register a new AppRole role from given metamodel.
*
* @param role The role
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean createAppRole(final AppRole role) throws VaultConnectorException;
/**
* Register new AppRole role with default policy.
*
* @param roleName The role name
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName) throws VaultConnectorException {
return createAppRole(roleName, new ArrayList<>());
}
/**
* Register new AppRole role with policies.
*
* @param roleName The role name
* @param policies The policies to associate with
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName, final List<String> policies) throws VaultConnectorException {
return createAppRole(roleName, policies, null);
}
/**
* Register new AppRole role with default policy and custom ID.
*
* @param roleName The role name
* @param roleID A custom role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName, final String roleID) throws VaultConnectorException {
return createAppRole(roleName, new ArrayList<>(), roleID);
}
/**
* Register new AppRole role with policies and custom ID.
*
* @param roleName The role name
* @param policies The policies to associate with
* @param roleID A custom role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default boolean createAppRole(final String roleName, final List<String> policies, final String roleID)
throws VaultConnectorException {
return createAppRole(AppRole.builder(roleName).withTokenPolicies(policies).withId(roleID).build());
}
/**
* Delete AppRole role from Vault.
*
* @param roleName The role name
* @return {@code true} on success
* @throws VaultConnectorException on error
*/
boolean deleteAppRole(final String roleName) throws VaultConnectorException;
/**
* Lookup an AppRole role.
*
* @param roleName The role name
* @return Result of the lookup
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleResponse lookupAppRole(final String roleName) throws VaultConnectorException;
/**
* Retrieve ID for an AppRole role.
*
* @param roleName The role name
* @return The role ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
String getAppRoleID(final String roleName) throws VaultConnectorException;
/**
* Set custom ID for an AppRole role.
*
* @param roleName The role name
* @param roleID The role ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean setAppRoleID(final String roleName, final String roleID) throws VaultConnectorException;
/**
* Register new random generated AppRole secret.
*
* @param roleName The role name
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default AppRoleSecretResponse createAppRoleSecret(final String roleName) throws VaultConnectorException {
return createAppRoleSecret(roleName, new AppRoleSecret());
}
/**
* Register new AppRole secret with custom ID.
*
* @param roleName The role name
* @param secretID A custom secret ID
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
default AppRoleSecretResponse createAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException {
return createAppRoleSecret(roleName, new AppRoleSecret(secretID));
}
/**
* Register new AppRole secret with custom ID.
*
* @param roleName The role name
* @param secret The secret meta object
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleSecretResponse createAppRoleSecret(final String roleName, final AppRoleSecret secret)
throws VaultConnectorException;
/**
* Lookup an AppRole secret.
*
* @param roleName The role name
* @param secretID The secret ID
* @return Result of the lookup
* @throws VaultConnectorException on error
* @since 0.4.0
*/
AppRoleSecretResponse lookupAppRoleSecret(final String roleName, final String secretID)
throws VaultConnectorException;
/**
* Destroy an AppRole secret.
*
* @param roleName The role name
* @param secretID The secret meta object
* @return The secret ID
* @throws VaultConnectorException on error
* @since 0.4.0
*/
boolean destroyAppRoleSecret(final String roleName, final String secretID) throws VaultConnectorException;
/**
* List existing (accessible) AppRole roles.
*
* @return List of roles
* @throws VaultConnectorException on error
*/
List<String> listAppRoles() throws VaultConnectorException;
/**
* List existing (accessible) secret IDs for AppRole role.
*
* @param roleName The role name
* @return List of roles
* @throws VaultConnectorException on error
*/
List<String> listAppRoleSecrets(final String roleName) throws VaultConnectorException;
/**
* Get authorization status.
*
@@ -330,108 +96,6 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
SecretResponse read(final String key) throws VaultConnectorException;
/**
* Retrieve the latest secret data for specific version from Vault.
* <br>
* Path {@code <mount>/data/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @return Secret response
* @throws VaultConnectorException on error
* @since 0.8
*/
default SecretResponse readSecretData(final String mount, final String key) throws VaultConnectorException {
return readSecretVersion(mount, key, null);
}
/**
* Write secret to Vault.
* <br>
* Path {@code <mount>/data/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @param data Secret content. Value must be be JSON serializable.
* @return Metadata for the created/updated secret.
* @throws VaultConnectorException on error
* @since 0.8
*/
default SecretVersionResponse writeSecretData(final String mount,
final String key,
final Map<String, Object> data) throws VaultConnectorException {
return writeSecretData(mount, key, data, null);
}
/**
* Write secret to Vault.
* <br>
* Path {@code <mount>/data/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @param data Secret content. Value must be be JSON serializable.
* @param cas Use Check-And-Set operation, i.e. only allow writing if current version matches this value.
* @return Metadata for the created/updated secret.
* @throws VaultConnectorException on error
* @since 0.8
*/
SecretVersionResponse writeSecretData(final String mount,
final String key,
final Map<String, Object> data,
final Integer cas) throws VaultConnectorException;
/**
* Retrieve secret data from Vault.
* <br>
* Path {@code <mount>/data/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @param version Version to read. If {@code null} or zero, the latest version will be returned.
* @return Secret response.
* @throws VaultConnectorException on error
* @since 0.8
*/
SecretResponse readSecretVersion(final String mount, final String key, final Integer version)
throws VaultConnectorException;
/**
* Retrieve secret metadata from Vault.
* <br>
* Path {@code <mount>/metadata/<key>} is read here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @return Metadata response
* @throws VaultConnectorException on error
* @since 0.8
*/
MetadataResponse readSecretMetadata(final String mount, final String key) throws VaultConnectorException;
/**
* Update secret metadata.
* <br>
* Path {@code <mount>/metadata/<key>} is written here.
* Only available for KV v2 secrets.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret identifier
* @param maxVersions Maximum number of versions (fallback to backend default if {@code null})
* @param casRequired Specify if Check-And-Set is required for this secret.
* @throws VaultConnectorException on error
* @since 0.8
*/
void updateSecretMetadata(final String mount,
final String key,
final Integer maxVersions,
final boolean casRequired) throws VaultConnectorException;
/**
* List available nodes from Vault.
*
@@ -487,71 +151,6 @@ public interface VaultConnector extends AutoCloseable, Serializable {
*/
void delete(final String key) throws VaultConnectorException;
/**
* Delete latest version of a secret from Vault.
* <br>
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteLatestSecretVersion(final String mount, final String key) throws VaultConnectorException;
/**
* Delete latest version of a secret from Vault.
* <br>
* Prefix {@code secret/} is automatically added to path.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteAllSecretVersions(final String mount, final String key) throws VaultConnectorException;
/**
* Delete secret versions from Vault.
* <br>
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to delete.
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Undelete (restore) secret versions from Vault.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to undelete.
* @throws VaultConnectorException on error
* @since 0.8
*/
void undeleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Destroy secret versions from Vault.
* Only available for KV v2 stores.
*
* @param mount Secret store mount point (without leading or trailing slash).
* @param key Secret path.
* @param versions Versions of the secret to destroy.
* @throws VaultConnectorException on error
* @since 0.8
*/
void destroySecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Revoke given lease immediately.
*
@@ -582,170 +181,44 @@ public interface VaultConnector extends AutoCloseable, Serializable {
SecretResponse renew(final String leaseID, final Integer increment) throws VaultConnectorException;
/**
* Create a new token.
* Get client for KV v2 API.
*
* @param token the token
* @return the result response
* @throws VaultConnectorException on error
* @return KV v2 client
* @since 2.0.0
*/
AuthResponse createToken(final Token token) throws VaultConnectorException;
KV2Client kv2();
/**
* Create a new token.
* Get client for token API.
*
* @param token the token
* @param orphan create orphan token
* @return the result response
* @throws VaultConnectorException on error
* @return Token client
* @since 2.0.0
*/
AuthResponse createToken(final Token token, boolean orphan) throws VaultConnectorException;
TokenClient token();
/**
* Create a new token for specific role.
* Get client for AppRole API.
*
* @param token the token
* @param role the role name
* @return the result response
* @throws VaultConnectorException on error
* @return AppRole client
* @since 2.0.0
*/
AuthResponse createToken(final Token token, final String role) throws VaultConnectorException;
AppRoleClient appRole();
/**
* Lookup token information.
* Get client for transit API.
*
* @param token the token
* @return the result response
* @throws VaultConnectorException on error
* @return Transit client
* @since 2.0.0
*/
TokenResponse lookupToken(final String token) throws VaultConnectorException;
TransitClient transit();
/**
* Create a new or update an existing token role.
* Get client for system API.
*
* @param role the role entity (name must be set)
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
* @return System client
* @since 2.0.0
*/
default boolean createOrUpdateTokenRole(final TokenRole role) throws VaultConnectorException {
return createOrUpdateTokenRole(role.getName(), role);
}
/**
* Create a new or update an existing token role.
*
* @param name the role name (overrides name possibly set in role entity)
* @param role the role entity
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
*/
boolean createOrUpdateTokenRole(final String name, final TokenRole role) throws VaultConnectorException;
/**
* Lookup token information.
*
* @param name the role name
* @return the result response
* @throws VaultConnectorException on error
* @since 0.9
*/
TokenRoleResponse readTokenRole(final String name) throws VaultConnectorException;
/**
* List available token roles from Vault.
*
* @return List of token roles
* @throws VaultConnectorException on error
* @since 0.9
*/
List<String> listTokenRoles() throws VaultConnectorException;
/**
* Delete a token role.
*
* @param name the role name to delete
* @return {@code true} on success
* @throws VaultConnectorException on error
* @since 0.9
*/
boolean deleteTokenRole(final String name) throws VaultConnectorException;
/**
* Encrypt plaintext via transit engine from Vault.
*
* @param keyName Transit key name
* @param plaintext Text to encrypt (Base64 encoded)
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse transitEncrypt(final String keyName, final String plaintext) throws VaultConnectorException;
/**
* Encrypt plaintext via transit engine from Vault.
*
* @param keyName Transit key name
* @param plaintext Binary data to encrypt
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse transitEncrypt(final String keyName, final byte[] plaintext)
throws VaultConnectorException {
return transitEncrypt(keyName, Base64.getEncoder().encodeToString(plaintext));
}
/**
* Decrypt ciphertext via transit engine from Vault.
*
* @param keyName Transit key name
* @param ciphertext Text to decrypt
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse transitDecrypt(final String keyName, final String ciphertext) throws VaultConnectorException;
/**
* Hash data in hex format via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse transitHash(final String algorithm, final String input) throws VaultConnectorException {
return transitHash(algorithm, input, "hex");
}
/**
* Hash data via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash (Base64 encoded)
* @param format Specifies the output encoding (hex/base64)
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
TransitResponse transitHash(final String algorithm, final String input, final String format)
throws VaultConnectorException;
/**
* Hash data via transit engine from Vault.
*
* @param algorithm Specifies the hash algorithm to use
* @param input Data to hash
* @return Transit response
* @throws VaultConnectorException on error
* @since 1.5.0
*/
default TransitResponse transitHash(final String algorithm, final byte[] input, final String format)
throws VaultConnectorException {
return transitHash(algorithm, Base64.getEncoder().encodeToString(input), format);
}
SysClient sys();
/**
* Read credentials for MySQL backend at default mount point.
@@ -816,4 +289,5 @@ public interface VaultConnector extends AutoCloseable, Serializable {
throws VaultConnectorException {
return (CredentialsResponse) read(mount + "/creds/" + role);
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2016-2025 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.internal;
/**
* Vault API path constants.
*
* @author Stefan Kalscheuer
* @since 1.5.3
*/
public final class VaultApiPath {
// Base paths
private static final String SYS = "sys";
private static final String AUTH = "auth";
private static final String TRANSIT = "transit";
// System paths
public static final String SYS_AUTH = SYS + "/auth";
public static final String SYS_LEASES_RENEW = SYS + "/leases/renew";
public static final String SYS_LEASES_REVOKE = SYS + "/leases/revoke/";
public static final String SYS_HEALTH = SYS + "/health";
public static final String SYS_SEAL = SYS + "/seal";
public static final String SYS_SEAL_STATUS = SYS + "/seal-status";
public static final String SYS_UNSEAL = SYS + "/unseal";
// Auth paths
public static final String AUTH_TOKEN = AUTH + "/token";
public static final String AUTH_USERPASS_LOGIN = AUTH + "/userpass/login/";
public static final String AUTH_APPROLE = AUTH + "/approle";
public static final String AUTH_APPROLE_ROLE = AUTH_APPROLE + "/role/%s%s";
// Token operations
public static final String TOKEN_LOOKUP = "/lookup";
public static final String TOKEN_LOOKUP_SELF = "/lookup-self";
public static final String TOKEN_CREATE = "/create";
public static final String TOKEN_CREATE_ORPHAN = "/create-orphan";
public static final String TOKEN_ROLES = "/roles";
// Secret engine paths
public static final String SECRET_DATA = "/data/";
public static final String SECRET_METADATA = "/metadata/";
public static final String SECRET_DELETE = "/delete/";
public static final String SECRET_UNDELETE = "/undelete/";
public static final String SECRET_DESTROY = "/destroy/";
// Generic paths
public static final String LOGIN = "/login";
// Transit engine paths
public static final String TRANSIT_ENCRYPT = TRANSIT + "/encrypt/";
public static final String TRANSIT_DECRYPT = TRANSIT + "/decrypt/";
public static final String TRANSIT_HASH = TRANSIT + "/hash/";
/**
* Private constructor to prevent instantiation.
*/
private VaultApiPath() {
// Utility class
}
}

View File

@@ -95,10 +95,10 @@ class HTTPVaultConnectorIT {
connector = builder.build();
// Unseal Vault and check result.
SealResponse sealStatus = connector.unseal(KEY1);
SealResponse sealStatus = connector.sys().unseal(KEY1);
assumeTrue(sealStatus != null, "Seal status could not be determined after startup");
assumeTrue(sealStatus.isSealed(), "Vault is not sealed after startup");
sealStatus = connector.unseal(KEY2);
sealStatus = connector.sys().unseal(KEY2);
assumeTrue(sealStatus != null, "Seal status could not be determined");
assumeFalse(sealStatus.isSealed(), "Vault is not unsealed");
assumeTrue(sealStatus.isInitialized(), "Vault is not initialized"); // Initialized flag of Vault 0.11.2 (#20).
@@ -337,7 +337,7 @@ class HTTPVaultConnectorIT {
// Try to read accessible path with known value.
SecretResponse res = assertDoesNotThrow(
() -> connector.readSecretData(MOUNT_KV2, SECRET2_KEY),
() -> connector.kv2().readData(MOUNT_KV2, SECRET2_KEY),
"Valid secret path could not be read"
);
assertNotNull(res.getMetadata(), "Metadata not populated for KV v2 secret");
@@ -346,7 +346,7 @@ class HTTPVaultConnectorIT {
// Try to read different version of same secret.
res = assertDoesNotThrow(
() -> connector.readSecretVersion(MOUNT_KV2, SECRET2_KEY, 1),
() -> connector.kv2().readVersion(MOUNT_KV2, SECRET2_KEY, 1),
"Valid secret version could not be read"
);
assertEquals(1, res.getMetadata().getVersion(), "Unexpected secret version");
@@ -365,7 +365,7 @@ class HTTPVaultConnectorIT {
// First get the current version of the secret.
MetadataResponse res = assertDoesNotThrow(
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading secret metadata failed"
);
int currentVersion = res.getMetadata().getCurrentVersion();
@@ -374,7 +374,7 @@ class HTTPVaultConnectorIT {
Map<String, Object> data = new HashMap<>();
data.put("value", SECRET2_VALUE3);
SecretVersionResponse res2 = assertDoesNotThrow(
() -> connector.writeSecretData(MOUNT_KV2, SECRET2_KEY, data),
() -> connector.kv2().writeData(MOUNT_KV2, SECRET2_KEY, data),
"Writing secret to KV v2 store failed"
);
assertEquals(currentVersion + 1, res2.getMetadata().getVersion(), "Version not updated after writing secret");
@@ -382,7 +382,7 @@ class HTTPVaultConnectorIT {
// Verify the content.
SecretResponse res3 = assertDoesNotThrow(
() -> connector.readSecretData(MOUNT_KV2, SECRET2_KEY),
() -> connector.kv2().readData(MOUNT_KV2, SECRET2_KEY),
"Reading secret from KV v2 store failed"
);
assertEquals(SECRET2_VALUE3, res3.get("value"), "Data not updated correctly");
@@ -391,13 +391,13 @@ class HTTPVaultConnectorIT {
Map<String, Object> data4 = singletonMap("value", SECRET2_VALUE4);
assertThrows(
InvalidResponseException.class,
() -> connector.writeSecretData(MOUNT_KV2, SECRET2_KEY, data4, currentVersion2 - 1),
() -> connector.kv2().writeData(MOUNT_KV2, SECRET2_KEY, data4, currentVersion2 - 1),
"Writing secret to KV v2 with invalid CAS value succeeded"
);
// And finally with a correct CAS value.
Map<String, Object> data5 = singletonMap("value", SECRET2_VALUE4);
assertDoesNotThrow(() -> connector.writeSecretData(MOUNT_KV2, SECRET2_KEY, data5, currentVersion2));
assertDoesNotThrow(() -> connector.kv2().writeData(MOUNT_KV2, SECRET2_KEY, data5, currentVersion2));
}
/**
@@ -412,7 +412,7 @@ class HTTPVaultConnectorIT {
// Read current metadata first.
MetadataResponse res = assertDoesNotThrow(
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading secret metadata failed"
);
Integer maxVersions = res.getMetadata().getMaxVersions();
@@ -420,13 +420,13 @@ class HTTPVaultConnectorIT {
// Now update the metadata.
assertDoesNotThrow(
() -> connector.updateSecretMetadata(MOUNT_KV2, SECRET2_KEY, maxVersions + 1, true),
() -> connector.kv2().updateMetadata(MOUNT_KV2, SECRET2_KEY, maxVersions + 1, true),
"Updating secret metadata failed"
);
// And verify the result.
res = assertDoesNotThrow(
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading secret metadata failed"
);
assertEquals(maxVersions + 1, res.getMetadata().getMaxVersions(), "Unexpected maximum number of versions");
@@ -444,7 +444,7 @@ class HTTPVaultConnectorIT {
// Try to read accessible path with known value.
MetadataResponse res = assertDoesNotThrow(
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
"Valid secret path could not be read"
);
assertNotNull(res.getMetadata(), "Metadata not populated for KV v2 secret");
@@ -467,21 +467,21 @@ class HTTPVaultConnectorIT {
// Try to delete non-existing versions.
assertDoesNotThrow(
() -> connector.deleteSecretVersions(MOUNT_KV2, SECRET2_KEY, 5, 42),
() -> connector.kv2().deleteVersions(MOUNT_KV2, SECRET2_KEY, 5, 42),
"Revealed non-existence of secret versions"
);
assertDoesNotThrow(
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
"Revealed non-existence of secret versions"
);
// Now delete existing version and verify.
assertDoesNotThrow(
() -> connector.deleteSecretVersions(MOUNT_KV2, SECRET2_KEY, 1),
() -> connector.kv2().deleteVersions(MOUNT_KV2, SECRET2_KEY, 1),
"Deleting existing version failed"
);
MetadataResponse meta = assertDoesNotThrow(
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading deleted secret metadata failed"
);
assertNotNull(
@@ -491,11 +491,11 @@ class HTTPVaultConnectorIT {
// Undelete the just deleted version.
assertDoesNotThrow(
() -> connector.undeleteSecretVersions(MOUNT_KV2, SECRET2_KEY, 1),
() -> connector.kv2().undeleteVersions(MOUNT_KV2, SECRET2_KEY, 1),
"Undeleting existing version failed"
);
meta = assertDoesNotThrow(
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading deleted secret metadata failed"
);
assertNull(
@@ -505,11 +505,11 @@ class HTTPVaultConnectorIT {
// Now destroy it.
assertDoesNotThrow(
() -> connector.destroySecretVersions(MOUNT_KV2, SECRET2_KEY, 1),
() -> connector.kv2().destroyVersions(MOUNT_KV2, SECRET2_KEY, 1),
"Destroying existing version failed"
);
meta = assertDoesNotThrow(
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading destroyed secret metadata failed"
);
assertTrue(
@@ -519,11 +519,11 @@ class HTTPVaultConnectorIT {
// Delete latest version.
assertDoesNotThrow(
() -> connector.deleteLatestSecretVersion(MOUNT_KV2, SECRET2_KEY),
() -> connector.kv2().deleteLatestVersion(MOUNT_KV2, SECRET2_KEY),
"Deleting latest version failed"
);
meta = assertDoesNotThrow(
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading deleted secret metadata failed"
);
assertNotNull(
@@ -533,12 +533,12 @@ class HTTPVaultConnectorIT {
// Delete all versions.
assertDoesNotThrow(
() -> connector.deleteAllSecretVersions(MOUNT_KV2, SECRET2_KEY),
() -> connector.kv2().deleteAllVersions(MOUNT_KV2, SECRET2_KEY),
"Deleting latest version failed"
);
assertThrows(
InvalidResponseException.class,
() -> connector.readSecretMetadata(MOUNT_KV2, SECRET2_KEY),
() -> connector.kv2().readMetadata(MOUNT_KV2, SECRET2_KEY),
"Reading metadata of deleted secret should not succeed"
);
}
@@ -620,21 +620,21 @@ class HTTPVaultConnectorIT {
// Try unauthorized access first.
assumeFalse(connector.isAuthorized());
assertThrows(AuthorizationRequiredException.class, () -> connector.listAppRoles());
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().listRoles());
assertThrows(AuthorizationRequiredException.class, () -> connector.listAppRoleSecrets(""));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().listSecrets(""));
// Authorize.
authRoot();
assumeTrue(connector.isAuthorized());
// Verify pre-existing rules.
List<String> res = assertDoesNotThrow(() -> connector.listAppRoles(), "Role listing failed");
List<String> res = assertDoesNotThrow(() -> connector.appRole().listRoles(), "Role listing failed");
assertEquals(2, res.size(), "Unexpected number of AppRoles");
assertTrue(res.containsAll(List.of(APPROLE_ROLE_NAME, APPROLE_ROLE2_NAME)), "Pre-configured roles not listed");
// Check secret IDs.
res = assertDoesNotThrow(() -> connector.listAppRoleSecrets(APPROLE_ROLE_NAME), "AppRole secret listing failed");
res = assertDoesNotThrow(() -> connector.appRole().listSecrets(APPROLE_ROLE_NAME), "AppRole secret listing failed");
assertEquals(List.of(APPROLE_SECRET_ACCESSOR), res, "Pre-configured AppRole secret not listed");
}
@@ -647,14 +647,14 @@ class HTTPVaultConnectorIT {
void createAppRoleTest() {
// Try unauthorized access first.
assumeFalse(connector.isAuthorized());
assertThrows(AuthorizationRequiredException.class, () -> connector.createAppRole(new AppRole()));
assertThrows(AuthorizationRequiredException.class, () -> connector.lookupAppRole(""));
assertThrows(AuthorizationRequiredException.class, () -> connector.deleteAppRole(""));
assertThrows(AuthorizationRequiredException.class, () -> connector.getAppRoleID(""));
assertThrows(AuthorizationRequiredException.class, () -> connector.setAppRoleID("", ""));
assertThrows(AuthorizationRequiredException.class, () -> connector.createAppRoleSecret("", ""));
assertThrows(AuthorizationRequiredException.class, () -> connector.lookupAppRoleSecret("", ""));
assertThrows(AuthorizationRequiredException.class, () -> connector.destroyAppRoleSecret("", ""));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().create(new AppRole()));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().lookup(""));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().delete(""));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().getRoleID(""));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().setRoleID("", ""));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().createSecret("", ""));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().lookupSecret("", ""));
assertThrows(AuthorizationRequiredException.class, () -> connector.appRole().destroySecret("", ""));
// Authorize.
authRoot();
@@ -666,23 +666,23 @@ class HTTPVaultConnectorIT {
AppRole role = AppRole.builder(roleName).build();
// Create role.
boolean createRes = assertDoesNotThrow(() -> connector.createAppRole(role), "Role creation failed");
boolean createRes = assertDoesNotThrow(() -> connector.appRole().create(role), "Role creation failed");
assertTrue(createRes, "Role creation failed");
// Lookup role.
AppRoleResponse res = assertDoesNotThrow(() -> connector.lookupAppRole(roleName), "Role lookup failed");
AppRoleResponse res = assertDoesNotThrow(() -> connector.appRole().lookup(roleName), "Role lookup failed");
assertNotNull(res.getRole(), "Role lookup returned no role");
// Lookup role ID.
String roleID = assertDoesNotThrow(() -> connector.getAppRoleID(roleName), "Role ID lookup failed");
String roleID = assertDoesNotThrow(() -> connector.appRole().getRoleID(roleName), "Role ID lookup failed");
assertNotEquals("", roleID, "Role ID lookup returned empty ID");
// Set custom role ID.
String roleID2 = "custom-role-id";
assertDoesNotThrow(() -> connector.setAppRoleID(roleName, roleID2), "Setting custom role ID failed");
assertDoesNotThrow(() -> connector.appRole().setRoleID(roleName, roleID2), "Setting custom role ID failed");
// Verify role ID.
String res2 = assertDoesNotThrow(() -> connector.getAppRoleID(roleName), "Role ID lookup failed");
String res2 = assertDoesNotThrow(() -> connector.appRole().getRoleID(roleName), "Role ID lookup failed");
assertEquals(roleID2, res2, "Role ID lookup returned wrong ID");
// Update role model with custom flags.
@@ -691,44 +691,44 @@ class HTTPVaultConnectorIT {
.build();
// Create role.
boolean res3 = assertDoesNotThrow(() -> connector.createAppRole(role2), "Role creation failed");
boolean res3 = assertDoesNotThrow(() -> connector.appRole().create(role2), "Role creation failed");
assertTrue(res3, "No result given");
// Lookup updated role.
res = assertDoesNotThrow(() -> connector.lookupAppRole(roleName), "Role lookup failed");
res = assertDoesNotThrow(() -> connector.appRole().lookup(roleName), "Role lookup failed");
assertNotNull(res.getRole(), "Role lookup returned no role");
assertEquals(321, res.getRole().getTokenPeriod(), "Token period not set for role");
// Create role by name.
String roleName2 = "RoleByName";
assertDoesNotThrow(() -> connector.createAppRole(roleName2), "Creation of role by name failed");
res = assertDoesNotThrow(() -> connector.lookupAppRole(roleName2), "Creation of role by name failed");
assertDoesNotThrow(() -> connector.appRole().create(roleName2), "Creation of role by name failed");
res = assertDoesNotThrow(() -> connector.appRole().lookup(roleName2), "Creation of role by name failed");
assertNotNull(res.getRole(), "Role lookuo returned not value");
// Create role by name with custom ID.
String roleName3 = "RoleByName";
String roleID3 = "RolyByNameID";
assertDoesNotThrow(() -> connector.createAppRole(roleName3, roleID3), "Creation of role by name failed");
res = assertDoesNotThrow(() -> connector.lookupAppRole(roleName3), "Creation of role by name failed");
assertDoesNotThrow(() -> connector.appRole().create(roleName3, roleID3), "Creation of role by name failed");
res = assertDoesNotThrow(() -> connector.appRole().lookup(roleName3), "Creation of role by name failed");
assertNotNull(res.getRole(), "Role lookuo returned not value");
res2 = assertDoesNotThrow(() -> connector.getAppRoleID(roleName3), "Creation of role by name failed");
res2 = assertDoesNotThrow(() -> connector.appRole().getRoleID(roleName3), "Creation of role by name failed");
assertEquals(roleID3, res2, "Role lookuo returned wrong ID");
// Create role by name with policies.
assertDoesNotThrow(
() -> connector.createAppRole(roleName3, Collections.singletonList("testpolicy")),
() -> connector.appRole().create(roleName3, Collections.singletonList("testpolicy")),
"Creation of role by name failed"
);
res = assertDoesNotThrow(() -> connector.lookupAppRole(roleName3), "Creation of role by name failed");
res = assertDoesNotThrow(() -> connector.appRole().lookup(roleName3), "Creation of role by name failed");
// Note: As of Vault 0.8.3 default policy is not added automatically, so this test should return 1, not 2.
assertEquals(List.of("testpolicy"), res.getRole().getTokenPolicies(), "Role lookup returned unexpected policies");
// Delete role.
assertDoesNotThrow(() -> connector.deleteAppRole(roleName3), "Deletion of role failed");
assertDoesNotThrow(() -> connector.appRole().delete(roleName3), "Deletion of role failed");
assertThrows(
InvalidResponseException.class,
() -> connector.lookupAppRole(roleName3),
() -> connector.appRole().lookup(roleName3),
"Deleted role could be looked up"
);
}
@@ -745,7 +745,7 @@ class HTTPVaultConnectorIT {
// Create default (random) secret for existing role.
AppRoleSecretResponse res = assertDoesNotThrow(
() -> connector.createAppRoleSecret(APPROLE_ROLE_NAME),
() -> connector.appRole().createSecret(APPROLE_ROLE_NAME),
"AppRole secret creation failed"
);
assertNotNull(res.getSecret(), "No secret returned");
@@ -753,26 +753,26 @@ class HTTPVaultConnectorIT {
// Create secret with custom ID.
String secretID = "customSecretId";
res = assertDoesNotThrow(
() -> connector.createAppRoleSecret(APPROLE_ROLE_NAME, secretID),
() -> connector.appRole().createSecret(APPROLE_ROLE_NAME, secretID),
"AppRole secret creation failed"
);
assertEquals(secretID, res.getSecret().getId(), "Unexpected secret ID returned");
// Lookup secret.
res = assertDoesNotThrow(
() -> connector.lookupAppRoleSecret(APPROLE_ROLE_NAME, secretID),
() -> connector.appRole().lookupSecret(APPROLE_ROLE_NAME, secretID),
"AppRole secret lookup failed"
);
assertNotNull(res.getSecret(), "No secret information returned");
// Destroy secret.
assertDoesNotThrow(
() -> connector.destroyAppRoleSecret(APPROLE_ROLE_NAME, secretID),
() -> connector.appRole().destroySecret(APPROLE_ROLE_NAME, secretID),
"AppRole secret destruction failed"
);
assertThrows(
InvalidResponseException.class,
() -> connector.lookupAppRoleSecret(APPROLE_ROLE_NAME, secretID),
() -> connector.appRole().lookupSecret(APPROLE_ROLE_NAME, secretID),
"Destroyed AppRole secret successfully read"
);
}
@@ -825,7 +825,7 @@ class HTTPVaultConnectorIT {
.build();
// Create token.
AuthResponse res = assertDoesNotThrow(() -> connector.createToken(token), "Token creation failed");
AuthResponse res = assertDoesNotThrow(() -> connector.token().create(token), "Token creation failed");
assertNotNull(res, "No result given");
assertEquals("test-id", res.getAuth().getClientToken(), "Invalid token ID returned");
assertEquals(List.of("root"), res.getAuth().getPolicies(), "Expected inherited root policy");
@@ -847,7 +847,7 @@ class HTTPVaultConnectorIT {
.withoutDefaultPolicy()
.withMeta("foo", "bar")
.build();
res = assertDoesNotThrow(() -> connector.createToken(token2), "Token creation failed");
res = assertDoesNotThrow(() -> connector.token().create(token2), "Token creation failed");
assertEquals("test-id2", res.getAuth().getClientToken(), "Invalid token ID returned");
assertEquals(List.of("testpolicy"), res.getAuth().getPolicies(), "Invalid policies returned");
assertNotNull(res.getAuth().getMetadata(), "Metadata not given");
@@ -866,7 +866,7 @@ class HTTPVaultConnectorIT {
.build();
InvalidResponseException e = assertThrows(
InvalidResponseException.class,
() -> connector.createToken(token3),
() -> connector.token().create(token3),
"Overwriting token should fail as of Vault 0.8.0"
);
assertEquals(400, e.getStatusCode());
@@ -880,7 +880,7 @@ class HTTPVaultConnectorIT {
.withoutDefaultPolicy()
.withType(Token.Type.BATCH)
.build();
res = assertDoesNotThrow(() -> connector.createToken(token4), "Token creation failed");
res = assertDoesNotThrow(() -> connector.token().create(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."),
@@ -908,12 +908,12 @@ class HTTPVaultConnectorIT {
.withId("my-token")
.withType(Token.Type.SERVICE)
.build();
assertDoesNotThrow(() -> connector.createToken(token), "Token creation failed");
assertDoesNotThrow(() -> connector.token().create(token), "Token creation failed");
authRoot();
assumeTrue(connector.isAuthorized());
TokenResponse res = assertDoesNotThrow(() -> connector.lookupToken("my-token"), "Token creation failed");
TokenResponse res = assertDoesNotThrow(() -> connector.token().lookup("my-token"), "Token creation failed");
assertEquals(token.getId(), res.getData().getId(), "Unexpected token ID");
assertEquals(1, res.getData().getPolicies().size(), "Unexpected number of policies");
assertTrue(res.getData().getPolicies().contains("root"), "Unexpected policy");
@@ -936,14 +936,14 @@ class HTTPVaultConnectorIT {
final TokenRole role = TokenRole.builder().build();
boolean creationRes = assertDoesNotThrow(
() -> connector.createOrUpdateTokenRole(roleName, role),
() -> connector.token().createOrUpdateRole(roleName, role),
"Token role creation failed"
);
assertTrue(creationRes, "Token role creation failed");
// Read the role.
TokenRoleResponse res = assertDoesNotThrow(
() -> connector.readTokenRole(roleName),
() -> connector.token().readRole(roleName),
"Reading token role failed"
);
assertNotNull(res, "Token role response must not be null");
@@ -963,12 +963,12 @@ class HTTPVaultConnectorIT {
.build();
creationRes = assertDoesNotThrow(
() -> connector.createOrUpdateTokenRole(role2),
() -> connector.token().createOrUpdateRole(role2),
"Token role update failed"
);
assertTrue(creationRes, "Token role update failed");
res = assertDoesNotThrow(() -> connector.readTokenRole(roleName), "Reading token role failed");
res = assertDoesNotThrow(() -> connector.token().readRole(roleName), "Reading token role failed");
assertNotNull(res, "Token role response must not be null");
assertNotNull(res.getData(), "Token role must not be null");
assertEquals(roleName, res.getData().getName(), "Token role name not as expected");
@@ -977,15 +977,15 @@ class HTTPVaultConnectorIT {
assertEquals(42, res.getData().getTokenNumUses(), "Unexpected number of token uses after update");
// List roles.
List<String> listRes = assertDoesNotThrow(() -> connector.listTokenRoles(), "Listing token roles failed");
List<String> listRes = assertDoesNotThrow(() -> connector.token().listRoles(), "Listing token roles failed");
assertNotNull(listRes, "Token role list must not be null");
assertEquals(List.of(roleName), listRes, "Unexpected token role list");
// Delete the role.
creationRes = assertDoesNotThrow(() -> connector.deleteTokenRole(roleName), "Token role deletion failed");
creationRes = assertDoesNotThrow(() -> connector.token().deleteRole(roleName), "Token role deletion failed");
assertTrue(creationRes, "Token role deletion failed");
assertThrows(InvalidResponseException.class, () -> connector.readTokenRole(roleName), "Reading nonexistent token role should fail");
assertThrows(InvalidResponseException.class, () -> connector.listTokenRoles(), "Listing nonexistent token roles should fail");
assertThrows(InvalidResponseException.class, () -> connector.token().readRole(roleName), "Reading nonexistent token role should fail");
assertThrows(InvalidResponseException.class, () -> connector.token().listRoles(), "Listing nonexistent token roles should fail");
}
}
@@ -1000,14 +1000,14 @@ class HTTPVaultConnectorIT {
assumeTrue(connector.isAuthorized());
TransitResponse transitResponse = assertDoesNotThrow(
() -> connector.transitEncrypt("my-key", "dGVzdCBtZQ=="),
() -> connector.transit().encrypt("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)),
() -> connector.transit().encrypt("my-key", "test me".getBytes(UTF_8)),
"Failed to encrypt binary data via transit"
);
assertNotNull(transitResponse.getCiphertext());
@@ -1022,7 +1022,7 @@ class HTTPVaultConnectorIT {
assumeTrue(connector.isAuthorized());
TransitResponse transitResponse = assertDoesNotThrow(
() -> connector.transitDecrypt("my-key", "vault:v1:1mhLVkBAR2nrFtIkJF/qg57DWfRj0FWgR6tvkGO8XOnL6sw="),
() -> connector.transit().decrypt("my-key", "vault:v1:1mhLVkBAR2nrFtIkJF/qg57DWfRj0FWgR6tvkGO8XOnL6sw="),
"Failed to decrypt via transit"
);
@@ -1036,21 +1036,21 @@ class HTTPVaultConnectorIT {
assumeTrue(connector.isAuthorized());
TransitResponse transitResponse = assertDoesNotThrow(
() -> connector.transitHash("sha2-512", "dGVzdCBtZQ=="),
() -> connector.transit().hash("sha2-512", "dGVzdCBtZQ=="),
"Failed to hash via transit"
);
assertEquals("7677af0ee4effaa9f35e9b1e82d182f79516ab8321786baa23002de7c06851059492dd37d5fc3791f17d81d4b58198d24a6fd8bbd62c42c1c30b371da500f193", transitResponse.getSum());
TransitResponse transitResponseBase64 = assertDoesNotThrow(
() -> connector.transitHash("sha2-256", "dGVzdCBtZQ==", "base64"),
() -> connector.transit().hash("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"),
() -> connector.transit().hash("sha2-256", "test me".getBytes(UTF_8), "base64"),
"Failed to hash binary data via transit"
);
@@ -1072,7 +1072,7 @@ class HTTPVaultConnectorIT {
assumeTrue(connector.isAuthorized());
List<AuthBackend> supportedBackends = assertDoesNotThrow(
() -> connector.getAuthBackends(),
() -> connector.sys().getAuthBackends(),
"Could not list supported auth backends"
);
@@ -1132,22 +1132,22 @@ class HTTPVaultConnectorIT {
@Test
@DisplayName("Seal test")
void sealTest() throws VaultConnectorException {
SealResponse sealStatus = connector.sealStatus();
SealResponse sealStatus = connector.sys().sealStatus();
assumeFalse(sealStatus.isSealed());
// Unauthorized sealing should fail.
assertThrows(VaultConnectorException.class, connector::seal, "Unauthorized sealing succeeded");
assertThrows(VaultConnectorException.class, () -> connector.sys().seal(), "Unauthorized sealing succeeded");
assertFalse(sealStatus.isSealed(), "Vault sealed, although sealing failed");
// Root user should be able to seal.
authRoot();
assumeTrue(connector.isAuthorized());
assertDoesNotThrow(connector::seal, "Sealing failed");
sealStatus = connector.sealStatus();
assertDoesNotThrow(() -> connector.sys().seal(), "Sealing failed");
sealStatus = connector.sys().sealStatus();
assertTrue(sealStatus.isSealed(), "Vault not sealed");
sealStatus = connector.unseal(KEY2);
sealStatus = connector.sys().unseal(KEY2);
assertTrue(sealStatus.isSealed(), "Vault unsealed with only 1 key");
sealStatus = connector.unseal(KEY3);
sealStatus = connector.sys().unseal(KEY3);
assertFalse(sealStatus.isSealed(), "Vault not unsealed");
}
@@ -1157,7 +1157,7 @@ class HTTPVaultConnectorIT {
@Test
@DisplayName("Health test")
void healthTest() {
HealthResponse res = assertDoesNotThrow(connector::getHealth, "Retrieving health status failed");
HealthResponse res = assertDoesNotThrow(() -> connector.sys().getHealth(), "Retrieving health status failed");
assertNotNull(res, "Health response should be set");
assertEquals(VAULT_VERSION, res.getVersion(), "Unexpected version");
assertTrue(res.isInitialized(), "Unexpected init status");
@@ -1166,11 +1166,11 @@ class HTTPVaultConnectorIT {
// No seal vault and verify correct status.
authRoot();
assertDoesNotThrow(connector::seal, "Unexpected exception on sealing");
SealResponse sealStatus = assertDoesNotThrow(connector::sealStatus);
assertDoesNotThrow(() -> connector.sys().seal(), "Unexpected exception on sealing");
SealResponse sealStatus = assertDoesNotThrow(() -> connector.sys().sealStatus());
assumeTrue(sealStatus.isSealed());
connector.resetAuth(); // Should work unauthenticated
res = assertDoesNotThrow(connector::getHealth, "Retrieving health status failed when sealed");
res = assertDoesNotThrow(() -> connector.sys().getHealth(), "Retrieving health status failed when sealed");
assertTrue(res.isSealed(), "Unexpected seal status");
}

View File

@@ -54,51 +54,51 @@ class HTTPVaultConnectorTest {
*/
@Test
void requestExceptionTest(WireMockRuntimeInfo wireMock) throws IOException, URISyntaxException {
HTTPVaultConnector connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withTimeout(250).build();
try (var connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withTimeout(250).build()) {
// Test invalid response code.
final int responseCode = 400;
mockHttpResponse(responseCode, "", "application/json");
VaultConnectorException e = assertThrows(
InvalidResponseException.class,
() -> connector.sys().getHealth(),
"Querying health status succeeded on invalid instance"
);
assertEquals("Invalid response code", e.getMessage(), "Unexpected exception message");
assertEquals(responseCode, ((InvalidResponseException) e).getStatusCode(), "Unexpected status code in exception");
assertNull(((InvalidResponseException) e).getResponse(), "Response message where none was expected");
// Test invalid response code.
final int responseCode = 400;
mockHttpResponse(responseCode, "", "application/json");
VaultConnectorException e = assertThrows(
InvalidResponseException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
assertEquals("Invalid response code", e.getMessage(), "Unexpected exception message");
assertEquals(responseCode, ((InvalidResponseException) e).getStatusCode(), "Unexpected status code in exception");
assertNull(((InvalidResponseException) e).getResponse(), "Response message where none was expected");
// Simulate permission denied response.
mockHttpResponse(responseCode, "{\"errors\":[\"permission denied\"]}", "application/json");
assertThrows(
PermissionDeniedException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
// Simulate permission denied response.
mockHttpResponse(responseCode, "{\"errors\":[\"permission denied\"]}", "application/json");
assertThrows(
PermissionDeniedException.class,
() -> connector.sys().getHealth(),
"Querying health status succeeded on invalid instance"
);
}
// Test exception thrown during request.
try (ServerSocket s = new ServerSocket(0)) {
connector = HTTPVaultConnector.builder("http://localst:" + s.getLocalPort() + "/").withTimeout(250).build();
try (ServerSocket s = new ServerSocket(0);
var connector = HTTPVaultConnector.builder("http://localst:" + s.getLocalPort() + "/").withTimeout(250).build()) {
var e = assertThrows(
ConnectionException.class,
() -> connector.sys().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");
}
e = assertThrows(
ConnectionException.class,
connector::getHealth,
"Querying health status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
assertInstanceOf(IOException.class, e.getCause(), "Unexpected cause");
// Now simulate a failing request that succeeds on second try.
connector = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withNumberOfRetries(1).withTimeout(250).build();
stubFor(
WireMock.any(anyUrl())
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(200).withBody("{}").withHeader("Content-Type", "application/json"))
);
assertDoesNotThrow(connector::getHealth, "Request failed unexpectedly");
try (var connector3 = HTTPVaultConnector.builder(wireMock.getHttpBaseUrl()).withNumberOfRetries(1).withTimeout(250).build()) {
stubFor(
WireMock.any(anyUrl())
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(200).withBody("{}").withHeader("Content-Type", "application/json"))
);
assertDoesNotThrow(() -> connector3.sys().getHealth(), "Request failed unexpectedly");
}
}
/**
@@ -160,7 +160,7 @@ class HTTPVaultConnectorTest {
}
ConnectionException e = assertThrows(
ConnectionException.class,
connector::sealStatus,
() -> connector.sys().sealStatus(),
"Querying seal status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
@@ -178,7 +178,7 @@ class HTTPVaultConnectorTest {
}
ConnectionException e = assertThrows(
ConnectionException.class,
connector::getHealth,
() -> connector.sys().getHealth(),
"Querying health status succeeded on invalid instance"
);
assertEquals("Unable to connect to Vault server", e.getMessage(), "Unexpected exception message");
@@ -196,21 +196,21 @@ class HTTPVaultConnectorTest {
mockHttpResponse(200, "invalid", "application/json");
// Now test the methods.
assertParseError(connector::sealStatus, "sealStatus() succeeded on invalid instance");
assertParseError(() -> connector.unseal("key"), "unseal() succeeded on invalid instance");
assertParseError(connector::getHealth, "getHealth() succeeded on invalid instance");
assertParseError(connector::getAuthBackends, "getAuthBackends() succeeded on invalid instance");
assertParseError(() -> connector.sys().sealStatus(), "sys().sealStatus() succeeded on invalid instance");
assertParseError(() -> connector.sys().unseal("key"), "sys().unseal() succeeded on invalid instance");
assertParseError(() -> connector.sys().getHealth(), "sys().getHealth() succeeded on invalid instance");
assertParseError(() -> connector.sys().getAuthBackends(), "sys().getAuthBackends() succeeded on invalid instance");
assertParseError(() -> connector.authToken("token"), "authToken() succeeded on invalid instance");
assertParseError(() -> connector.lookupAppRole("roleName"), "lookupAppRole() succeeded on invalid instance");
assertParseError(() -> connector.getAppRoleID("roleName"), "getAppRoleID() succeeded on invalid instance");
assertParseError(() -> connector.createAppRoleSecret("roleName"), "createAppRoleSecret() succeeded on invalid instance");
assertParseError(() -> connector.lookupAppRoleSecret("roleName", "secretID"), "lookupAppRoleSecret() succeeded on invalid instance");
assertParseError(connector::listAppRoles, "listAppRoles() succeeded on invalid instance");
assertParseError(() -> connector.listAppRoleSecrets("roleName"), "listAppRoleSecrets() succeeded on invalid instance");
assertParseError(() -> connector.appRole().lookup("roleName"), "appRole().lookup() succeeded on invalid instance");
assertParseError(() -> connector.appRole().getRoleID("roleName"), "appRole().getRoleID() succeeded on invalid instance");
assertParseError(() -> connector.appRole().createSecret("roleName"), "appRole().createSecret() succeeded on invalid instance");
assertParseError(() -> connector.appRole().lookupSecret("roleName", "secretID"), "appRole().lookupSecret() succeeded on invalid instance");
assertParseError(() -> connector.appRole().listRoles(), "appRole().listRoles() succeeded on invalid instance");
assertParseError(() -> connector.appRole().listSecrets("roleName"), "appRole().listSecrets() succeeded on invalid instance");
assertParseError(() -> connector.read("key"), "read() succeeded on invalid instance");
assertParseError(() -> connector.list("path"), "list() succeeded on invalid instance");
assertParseError(() -> connector.renew("leaseID"), "renew() succeeded on invalid instance");
assertParseError(() -> connector.lookupToken("token"), "lookupToken() succeeded on invalid instance");
assertParseError(() -> connector.token().lookup("token"), "token().lookup() succeeded on invalid instance");
}
private void assertParseError(Executable executable, String message) {
@@ -232,32 +232,32 @@ class HTTPVaultConnectorTest {
// Now test the methods expecting a 204.
assertThrows(
InvalidResponseException.class,
() -> connector.createAppRole("appID", Collections.singletonList("policy")),
"createAppRole() with 200 response succeeded"
() -> connector.appRole().create("appID", Collections.singletonList("policy")),
"appRole().create() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.deleteAppRole("roleName"),
"deleteAppRole() with 200 response succeeded"
() -> connector.delete("roleName"),
"appRole().delete() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.setAppRoleID("roleName", "roleID"),
"setAppRoleID() with 200 response succeeded"
() -> connector.appRole().setRoleID("roleName", "roleID"),
"appRole().setRoleID() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.destroyAppRoleSecret("roleName", "secretID"),
"destroyAppRoleSecret() with 200 response succeeded"
() -> connector.appRole().destroySecret("roleName", "secretID"),
"appRole().destroySecret() with 200 response succeeded"
);
assertThrows(
InvalidResponseException.class,
() -> connector.destroyAppRoleSecret("roleName", "secretUD"),
"destroyAppRoleSecret() with 200 response succeeded"
() -> connector.appRole().destroySecret("roleName", "secretUD"),
"appRole().destroySecret() with 200 response succeeded"
);
assertThrows(