55 Commits

Author SHA1 Message Date
be23129441 prepare release of v1.1.5
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-19 11:10:57 +02:00
199dfd30ca update test dependencies and plugins
All checks were successful
continuous-integration/drone/push Build is passing
2023-08-19 11:06:43 +02:00
b72298f2a8 bump Vault versions in integration tests to 1.14.0 and 1.11.12
All checks were successful
continuous-integration/drone/push Build is passing
2023-06-23 17:43:22 +02:00
226b6ad6c4 split lines above 120 characters
All checks were successful
continuous-integration/drone/push Build is passing
2023-06-17 15:17:06 +02:00
d81fc4e5af reorder members and elements to comply with language recommendations 2023-06-17 15:23:49 +02:00
1195b447a2 fix regression from redundant String mapping in SecretResponse getter
All checks were successful
continuous-integration/drone/push Build is passing
Mapping a JSON string into String using a JSON parser will fail, so we
should use the string directly instead of applying double conversion.

Fixes: f3e1f01e38
2023-06-16 18:18:55 +02:00
f3e1f01e38 fix type conversion in SecretResponse getter method (#67)
Some checks failed
continuous-integration/drone/push Build is failing
Converting the payload using toString() is not an appropriate way to
feed a JSON parser. We now use JSON roundtrip for type mapping and
introduce shortcuts of the type already matches the target type.
2023-06-16 17:43:30 +02:00
622b13f508 prepare release of v1.1.4
All checks were successful
continuous-integration/drone/push Build is passing
2023-06-15 18:08:24 +02:00
0f0b008f2f bump Vault versions in integration tests to 1.13.3 and 1.11.1
All checks were successful
continuous-integration/drone/push Build is passing
2023-06-15 18:03:59 +02:00
34322b389c fix timezone pattern in datetime parsing 2023-06-15 17:58:41 +02:00
7a813cdda3 use common ObjectMapper instance in model unit tests
All checks were successful
continuous-integration/drone/push Build is passing
2023-06-13 21:12:36 +02:00
d9dbdad75b use explicit utf-8 encoding for parsing responses
All checks were successful
continuous-integration/drone/push Build is passing
2023-06-13 18:51:07 +02:00
c97308fb4f deps: update jackson to 2.15.2
Plus some minor dev-dependency updates
2023-06-13 18:51:05 +02:00
fea27910bb minor dev-dependency updates
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-18 18:35:59 +02:00
4d79ef6634 ci: use SONAR_TOKEN env variable instead of sonar.login property
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-29 10:22:53 +02:00
402567a0db deps: update jackson to 2.15.0 2023-04-29 10:21:34 +02:00
00422ea00c ci: build and test with JDK 20
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-06 17:32:50 +02:00
01e1c6e8c7 minor dev-dependency updates 2023-04-06 17:32:01 +02:00
e322a74818 test against Vault 1.13.0
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-03 20:25:14 +01:00
f9fe57230f prepare release of v1.1.3
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-31 13:56:17 +01:00
e0c33b51e4 update .gitignore
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-29 11:51:52 +01:00
5e6dcc64cd test against Vault 1.12.2
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-29 11:25:00 +01:00
70b7338f3e update copyright notice to 2023 2023-01-29 11:20:59 +01:00
489e450dc8 deps: update jackson to 2.14.2 and mockito to 5.0.0
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-29 11:16:58 +01:00
909eab762c mark deprecated AppID components for removal
All checks were successful
continuous-integration/drone/push Build is passing
The AppID backend is no longer available in the latest Vault releases,
so we plan removal with a following major release.
2022-11-21 12:01:26 +01:00
abba4dff93 ci: enable SonarQube analysis for pull requests
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-21 11:48:11 +01:00
712fab04e1 combine payload map creation into subroutines
We create payload maps with conditional argument sets in several
places. Combine the generation into subroutines, to keep the actual
endpoint calls short and clear.
2022-11-21 11:40:53 +01:00
39ac32a2f6 minor rework of internal path constants 2022-11-21 11:33:47 +01:00
31e20385d4 prepare release of v1.1.2
All checks were successful
continuous-integration/drone/push Build is passing
2022-10-26 10:18:39 +02:00
30996e9fc9 ci: build and test with JDK 19
All checks were successful
continuous-integration/drone/push Build is passing
2022-10-26 10:14:11 +02:00
81decd1a4c deps: update jackson dependency to 2.13.4.2 2022-10-26 10:11:19 +02:00
adedc277fa test against older Vault versions to provide a supported range
Some checks reported errors
continuous-integration/drone/push Build was killed
We've only tested the connector against the latest Vault version
available at release time. However, we do support a wider range.
Test against the oldest supported release, the latest with AppID
and the actual latest.
2022-10-13 11:01:14 +02:00
0c56813121 test against Vault 1.12.0, conditionally disable AppID tests
The AppID auth backend is removed in Vault 1.12 and prevents the process
from starting. We now enable the legacy tests conditionally depending on
the actual Vault version.
2022-10-13 10:46:45 +02:00
2412a291f6 prepare release of v1.1.1
All checks were successful
continuous-integration/drone/push Build is passing
2022-08-29 10:02:41 +02:00
b5ed7704e3 test: scan for "Vault server started" instead of fixed delay
All checks were successful
continuous-integration/drone/push Build is passing
2022-08-29 09:42:23 +02:00
a1626aa1c7 ci: fix drone CI pipeline
All checks were successful
continuous-integration/drone/push Build is passing
The Ubuntu Focal base image does not ship "unzip" by default, so using
the current Maven/JDK image we cannot extract the Vault binary.
Add an additional setup step to solve this problem.
2022-08-16 16:56:28 +02:00
3fb8454711 ci: update CI pipelines and test dependencies
Some checks failed
continuous-integration/drone/push Build is failing
2022-08-14 20:35:54 +02:00
ecf18881b9 test: extend assertion for warnings creating token with custom ID
All checks were successful
continuous-integration/drone/push Build is passing
With Vault 1.11 a second warning is raised. We accept "at least one"
for now.
2022-06-23 18:29:23 +02:00
69287f7196 deps: update jackson dependency to 2.13.2 2022-06-23 18:28:17 +02:00
4b1b4399e1 test against Vault 1.11.0 2022-06-23 18:16:40 +02:00
9ce819b1d0 prepare release of v1.1.0
All checks were successful
continuous-integration/drone/push Build is passing
2022-04-24 17:54:04 +02:00
64e55eddd8 model: add request ID to data response models
All checks were successful
continuous-integration/drone/push Build is passing
2022-04-24 16:44:50 +02:00
feb6e147fe model: add support for (dis)allowed policy glob patterns in TokenRole
All checks were successful
continuous-integration/drone/push Build is passing
2022-04-24 16:40:33 +02:00
b0d2b038eb model: add missing fields to AuthMethod model
All checks were successful
continuous-integration/drone/push Build is passing
2022-04-24 16:32:49 +02:00
f3cc16f44a test: bundle serialization tests into abstract test case
All checks were successful
continuous-integration/drone/push Build is passing
2022-04-19 17:24:17 +02:00
4f3cb4b330 model: eliminate double-mapping of generic data in response classes
Explicitly declare mapping of the "data" field in response classes.
Therefore, the JSON setter setData() is no longer used. SecretResponse
is split into subclasses for secret with and without metadata.
2022-04-19 17:24:16 +02:00
021421a54c model: implement Serializable with model classes
implement equals() and hashCode()
2022-04-19 17:24:09 +02:00
18cb89ace4 test: update to JRE8+ version of Wiremock with Junit5 extension
All checks were successful
continuous-integration/drone/push Build is passing
2022-04-12 21:01:40 +02:00
85aa5c3c30 deps: update Jackson Databind to 2.13.2.2 + minor plugin updates
All checks were successful
continuous-integration/drone/push Build is passing
2022-04-02 10:25:23 +02:00
912b9ec61b test: minor adjustments for integration tests against Vault 1.10
All checks were successful
continuous-integration/drone/push Build is passing
Accept token prefixes "hvb." and "b." as valid results for creation
without specific preferences.
2022-03-24 20:43:00 +01:00
bd0c5b08fe model: add wrap_info to data response model
All checks were successful
continuous-integration/drone/push Build is passing
2022-03-06 18:11:31 +01:00
5f3a36e2c5 update copyright notice to 2022 2022-03-06 18:10:33 +01:00
deb03cc2b0 minor dependency updates 2022-03-06 17:56:52 +01:00
f6180c4f90 model: add migration, recovery and storage type fields to seal status
All checks were successful
continuous-integration/drone/push Build is passing
2022-02-05 13:01:57 +01:00
dc4b62496a model: use correct "replication_performance_mode" JSON field
All checks were successful
continuous-integration/drone/push Build is passing
The official docs incorrectly state "replication_perf_mode" which was
renamed to "replication_performance_mode" way back in Vault 0.9. We now
use the correct field name that is emitted by the API.
2021-12-27 18:54:49 +01:00
130 changed files with 2672 additions and 934 deletions

View File

@ -3,7 +3,7 @@ name: default
steps:
- name: compile
image: maven:3-jdk-11
image: maven:3-eclipse-temurin-17
commands:
- mvn -B clean compile
when:
@ -14,7 +14,7 @@ steps:
- fix/*
- release/*
- name: unit-tests
image: maven:3-jdk-11
image: maven:3-eclipse-temurin-17
commands:
- mvn -B test
when:
@ -22,16 +22,27 @@ steps:
- develop
- feature/*
- fix/*
- name: unit-integration-tests
image: maven:3-jdk-11
- name: setup-vault
image: alpine:latest
environment:
VAULT_VERSION: 1.9.0
VAULT_VERSION: 1.14.0
commands:
- curl -s -o vault_1.9.0_linux_amd64.zip https://releases.hashicorp.com/vault/1.9.0/vault_1.9.0_linux_amd64.zip
- curl -s https://releases.hashicorp.com/vault/1.9.0/vault_1.9.0_SHA256SUMS | grep linux_amd64 | sha256sum -c
- unzip vault_1.9.0_linux_amd64.zip
- rm vault_1.9.0_linux_amd64.zip
- mv vault /bin/
- wget -q -O vault_$${VAULT_VERSION}_linux_amd64.zip https://releases.hashicorp.com/vault/$${VAULT_VERSION}/vault_$${VAULT_VERSION}_linux_amd64.zip
- wget -q -O - https://releases.hashicorp.com/vault/$${VAULT_VERSION}/vault_$${VAULT_VERSION}_SHA256SUMS | grep linux_amd64 | sha256sum -c
- unzip vault_$${VAULT_VERSION}_linux_amd64.zip
- rm vault_$${VAULT_VERSION}_linux_amd64.zip
- mkdir -p .bin
- mv vault .bin/
when:
branch:
- main
- release/*
- name: unit-integration-tests
image: maven:3-eclipse-temurin-17
environment:
VAULT_VERSION: 1.14.0
commands:
- export PATH=.bin:$${PATH}
- mvn -B -P integration-test verify
when:
branch:

View File

@ -5,19 +5,19 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
jdk: [ 11, 17 ]
vault: [ '1.9.0' ]
jdk: [ 11, 17, 20 ]
vault: [ '1.2.0', '1.11.12', '1.14.0' ]
include:
- jdk: 11
vault: '1.9.0'
- jdk: 17
vault: '1.11.12'
analysis: true
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Java
uses: actions/setup-java@v2
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.jdk }}
distribution: 'temurin'
@ -40,12 +40,11 @@ jobs:
if: github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/heads/release/')
run: mvn -B -P coverage verify
- name: Analysis
if: matrix.analysis && github.event_name == 'push'
if: matrix.analysis
run: >
mvn -B sonar:sonar
-Dsonar.host.url=https://sonarcloud.io
-Dsonar.organization=stklcode-github
-Dsonar.login=$SONAR_TOKEN
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

21
.gitignore vendored
View File

@ -1,5 +1,16 @@
/target/
/*.iml
/.idea/
/*.project
*~
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.idea
*.iml
.bin
*~

View File

@ -1,3 +1,79 @@
## 1.1.5 (2023-08-19)
### Fix
* Fixed JSON type conversion in `SecretResponse#get(String, Class)` (#67)
## 1.1.4 (2023-06-15)
### Fix
* Use `[+-]XX:XX` notation for timezone in date/time parsing
### Improvements
* Use explicit UTF-8 encoding for parsing responses
### Dependencies
* Updated Jackson to 2.15.2
### Test
* Tested against Vault 1.2.0 to 1.13.3
## 1.1.3 (2023-01-31)
### Deprecations
* AppID components (deprecated since 0.4) are marked for removal with the next major release
### Dependencies
* Updated Jackson to 2.14.2
### Improvements
* Minor internal refactoring
### Test
* Tested against Vault 1.2.0 to 1.12.2
## 1.1.2 (2022-10-26)
### Dependencies
* Updated Jackson to 2.13.4.2
### Test
* Tested against Vault 1.2.0 to 1.12.0
* Disable AppID tests for Vault 1.12 and above (auth method removed)
* Tested with Java 19
## 1.1.1 (2022-08-29)
### Dependencies
* Updated Jackson to 2.13.3
### Test
* Tested against Vault 1.11.2
* Tested with Java 18
## 1.1.0 (2022-04-24)
### Fix
* Use `replication_performance_mode` instead of `replication_perf_mode` in health response.
### Improvements
* Add `migration`, `recovery_seal` and `storage_type` fields to `SealReponse` model
* Add support for `wrap_info` in data response models
* Dependency updates
* Model and response classes implement `Serializable` (#57)
* Split `SercretResponse` into `PlainSecretResponse` and `MetaSecretResponse` subclasses (common API unchanged)
* Add missing fields to `AuthMethod` model
* Add support for (dis)allowed policy glob patterns in `TokenRole`
* Add request ID to data response models
### Test
* Tested against Vault 1.10.1
## 1.0.1 (2021-11-21)
### Fix

View File

@ -32,7 +32,7 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
* SQL secret handling
* KV v1 and v2 support
* Connector Factory with builder pattern
* Tested against Vault 1.9.0
* Tested against Vault 1.2 to 1.14
## Maven Artifact
@ -40,7 +40,7 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject
<dependency>
<groupId>de.stklcode.jvault</groupId>
<artifactId>jvault-connector</artifactId>
<version>1.0.1</version>
<version>1.1.5</version>
</dependency>
```

190
pom.xml
View File

@ -4,7 +4,7 @@
<groupId>de.stklcode.jvault</groupId>
<artifactId>jvault-connector</artifactId>
<version>1.0.1</version>
<version>1.1.5</version>
<packaging>jar</packaging>
@ -21,16 +21,11 @@
</license>
</licenses>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<argLine></argLine>
</properties>
<developers>
<developer>
<name>Stefan Kalscheuer</name>
<email>stefan@stklcode.de</email>
<timezone>+1</timezone>
<timezone>Europe/Berlin</timezone>
</developer>
</developers>
@ -45,34 +40,104 @@
<url>https://github.com/stklcode/jvaultconnector/issues</url>
</issueManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<argLine></argLine>
</properties>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-lambda</artifactId>
<version>1.2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<version>2.35.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>3.15.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>4.2.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<artifactId>maven-clean-plugin</artifactId>
<version>3.3.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<argLine>
@{argLine}
--add-opens de.stklcode.jvault.connector/de.stklcode.jvault.connector.test=com.fasterxml.jackson.databind
</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
<configuration>
<archive>
<manifestEntries>
@ -83,18 +148,18 @@
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<version>3.1.2</version>
<configuration>
<argLine>
@{argLine}
@ -108,60 +173,20 @@
</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.10</version>
</plugin>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.9.1.2184</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-lambda</artifactId>
<version>1.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>2.27.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.9.1.2184</version>
</dependency>
</dependencies>
</dependencyManagement>
<profiles>
<profile>
<id>sources</id>
@ -173,7 +198,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
@ -197,7 +221,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.1</version>
<version>3.5.0</version>
<configuration>
<source>11</source>
</configuration>
@ -221,7 +245,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.0.1</version>
<version>3.1.0</version>
<executions>
<execution>
<id>sign-artifacts</id>
@ -246,7 +270,6 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.7</version>
<executions>
<execution>
<id>default-prepare-agent</id>
@ -273,7 +296,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
<executions>
<execution>
<goals>
@ -294,7 +316,7 @@
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>6.5.0</version>
<version>8.3.1</version>
<executions>
<execution>
<goals>

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -41,24 +41,30 @@ import static java.util.Collections.singletonMap;
* @since 0.1
*/
public class HTTPVaultConnector implements VaultConnector {
private static final String PATH_SEAL_STATUS = "sys/seal-status";
private static final String PATH_SEAL = "sys/seal";
private static final String PATH_UNSEAL = "sys/unseal";
private static final String PATH_RENEW = "sys/leases/renew";
private static final String PATH_AUTH = "sys/auth";
private static final String PATH_TOKEN = "auth/token";
private static final String PATH_SYS = "sys";
private static final String PATH_SYS_AUTH = PATH_SYS + "/auth";
private static final String PATH_RENEW = PATH_SYS + "/leases/renew";
private static final String PATH_REVOKE = PATH_SYS + "/leases/revoke/";
private static final String PATH_HEALTH = PATH_SYS + "/health";
private static final String PATH_SEAL = PATH_SYS + "/seal";
private static final String PATH_SEAL_STATUS = PATH_SYS + "/seal-status";
private static final String PATH_UNSEAL = PATH_SYS + "/unseal";
private static final String PATH_AUTH = "auth";
private static final String PATH_AUTH_TOKEN = PATH_AUTH + "/token";
private static final String PATH_LOOKUP = "/lookup";
private static final String PATH_CREATE = "/create";
private static final String PATH_ROLES = "/roles";
private static final String PATH_CREATE_ORPHAN = "/create-orphan";
private static final String PATH_AUTH_USERPASS = "auth/userpass/login/";
private static final String PATH_AUTH_APPID = "auth/app-id/";
private static final String PATH_AUTH_APPROLE = "auth/approle/";
private static final String PATH_AUTH_APPROLE_ROLE = "auth/approle/role/%s%s";
private static final String PATH_REVOKE = "sys/leases/revoke/";
private static final String PATH_HEALTH = "sys/health";
private static final String PATH_AUTH_USERPASS = PATH_AUTH + "/userpass/login/";
private static final String PATH_AUTH_APPID = PATH_AUTH + "/app-id";
private static final String PATH_AUTH_APPROLE = PATH_AUTH + "/approle";
private static final String PATH_AUTH_APPROLE_ROLE = PATH_AUTH_APPROLE + "/role/%s%s";
private static final String PATH_DATA = "/data/";
private static final String PATH_METADATA = "/metadata/";
private static final String PATH_LOGIN = "/login";
private static final String PATH_DELETE = "/delete/";
private static final String PATH_UNDELETE = "/undelete/";
private static final String PATH_DESTROY = "/destroy/";
@ -69,6 +75,24 @@ public class HTTPVaultConnector implements VaultConnector {
private String token; // Current token.
private long tokenTTL = 0; // Expiration time for current token.
/**
* Create connector using a {@link HTTPVaultConnectorBuilder}.
*
* @param builder The builder.
*/
HTTPVaultConnector(final HTTPVaultConnectorBuilder builder) {
this.request = new RequestHelper(
((builder.isWithTLS()) ? "https" : "http") + "://" +
builder.getHost() +
((builder.getPort() != null) ? ":" + builder.getPort() : "") +
builder.getPrefix(),
builder.getNumberOfRetries(),
builder.getTimeout(),
builder.getTlsVersion(),
builder.getTrustedCA()
);
}
/**
* Get a new builder for a connector.
*
@ -102,24 +126,6 @@ public class HTTPVaultConnector implements VaultConnector {
return new HTTPVaultConnectorBuilder().withBaseURL(baseURL);
}
/**
* Create connector using a {@link HTTPVaultConnectorBuilder}.
*
* @param builder The builder.
*/
HTTPVaultConnector(final HTTPVaultConnectorBuilder builder) {
this.request = new RequestHelper(
((builder.isWithTLS()) ? "https" : "http") + "://" +
builder.getHost() +
((builder.getPort() != null) ? ":" + builder.getPort() : "") +
builder.getPrefix(),
builder.getNumberOfRetries(),
builder.getTimeout(),
builder.getTlsVersion(),
builder.getTrustedCA()
);
}
@Override
public final void resetAuth() {
token = null;
@ -139,11 +145,10 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final SealResponse unseal(final String key, final Boolean reset) throws VaultConnectorException {
Map<String, String> param = new HashMap<>(2, 1);
param.put("key", key);
if (reset != null) {
param.put("reset", reset.toString());
}
Map<String, String> param = mapOfStrings(
"key", key,
"reset", reset
);
return request.put(PATH_UNSEAL, param, token, SealResponse.class);
}
@ -172,7 +177,7 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final List<AuthBackend> getAuthBackends() throws VaultConnectorException {
/* Issue request and parse response */
AuthMethodsResponse amr = request.get(PATH_AUTH, emptyMap(), token, AuthMethodsResponse.class);
AuthMethodsResponse amr = request.get(PATH_SYS_AUTH, emptyMap(), token, AuthMethodsResponse.class);
return amr.getSupportedMethods().values().stream().map(AuthMethod::getType).collect(Collectors.toList());
}
@ -182,7 +187,7 @@ public class HTTPVaultConnector implements VaultConnector {
/* set token */
this.token = token;
this.tokenTTL = 0;
TokenResponse res = request.post(PATH_TOKEN + PATH_LOOKUP, emptyMap(), token, TokenResponse.class);
TokenResponse res = request.post(PATH_AUTH_TOKEN + PATH_LOOKUP, emptyMap(), token, TokenResponse.class);
authorized = true;
return res;
@ -196,10 +201,10 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
@Deprecated(since = "0.4", forRemoval = false)
@Deprecated(since = "0.4", forRemoval = true)
public final AuthResponse authAppId(final String appID, final String userID) throws VaultConnectorException {
return queryAuth(
PATH_AUTH_APPID + "login",
PATH_AUTH_APPID + PATH_LOGIN,
Map.of(
"app_id", appID,
"user_id", userID
@ -209,12 +214,11 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final AuthResponse authAppRole(final String roleID, final String secretID) throws VaultConnectorException {
final Map<String, String> payload = new HashMap<>(2, 1);
payload.put("role_id", roleID);
if (secretID != null) {
payload.put("secret_id", secretID);
}
return queryAuth(PATH_AUTH_APPROLE + "login", payload);
final Map<String, String> payload = mapOfStrings(
"role_id", roleID,
"secret_id", secretID
);
return queryAuth(PATH_AUTH_APPROLE + PATH_LOGIN, payload);
}
/**
@ -238,14 +242,14 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
@Deprecated(since = "0.4", forRemoval = false)
@Deprecated(since = "0.4", forRemoval = true)
public final boolean registerAppId(final String appID, final String policy, final String displayName)
throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
PATH_AUTH_APPID + "map/app-id/" + appID,
PATH_AUTH_APPID + "/map/app-id/" + appID,
Map.of(
"value", policy,
"display_name", displayName
@ -257,13 +261,13 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
@Deprecated(since = "0.4", forRemoval = false)
@Deprecated(since = "0.4", forRemoval = true)
public final boolean registerUserId(final String appID, final String userID) throws VaultConnectorException {
requireAuth();
/* Issue request and expect code 204 with empty response */
request.postWithoutResponse(
PATH_AUTH_APPID + "map/user-id/" + userID,
PATH_AUTH_APPID + "/map/user-id/" + userID,
singletonMap("value", appID),
token
);
@ -384,7 +388,7 @@ public class HTTPVaultConnector implements VaultConnector {
requireAuth();
SecretListResponse secrets = request.get(
PATH_AUTH_APPROLE + "role?list=true",
PATH_AUTH_APPROLE + "/role?list=true",
emptyMap(),
token,
SecretListResponse.class
@ -411,23 +415,22 @@ public class HTTPVaultConnector implements VaultConnector {
public final SecretResponse read(final String key) throws VaultConnectorException {
requireAuth();
/* Issue request and parse secret response */
return request.get(key, emptyMap(), token, SecretResponse.class);
return request.get(key, emptyMap(), token, PlainSecretResponse.class);
}
@Override
public final SecretResponse readSecretVersion(final String mount, final String key, final Integer version) throws VaultConnectorException {
public final SecretResponse readSecretVersion(final String mount, final String key, final Integer version)
throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse secret metadata */
Map<String, String> args = new HashMap<>(1, 1);
if (version != null) {
args.put("version", version.toString());
}
Map<String, String> args = mapOfStrings("version", version);
return request.get(mount + PATH_DATA + key, args, token, SecretResponse.class);
return request.get(mount + PATH_DATA + key, args, token, MetaSecretResponse.class);
}
@Override
public final MetadataResponse readSecretMetadata(final String mount, final String key) throws VaultConnectorException {
public final MetadataResponse readSecretMetadata(final String mount, final String key)
throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse secret metadata */
@ -435,20 +438,25 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
public void updateSecretMetadata(final String mount, final String key, final Integer maxVersions, final boolean casRequired) throws VaultConnectorException {
public void updateSecretMetadata(final String mount,
final String key,
final Integer maxVersions,
final boolean casRequired) throws VaultConnectorException {
requireAuth();
Map<String, Object> payload = new HashMap<>(2, 1);
if (maxVersions != null) {
payload.put("max_versions", maxVersions);
}
payload.put("cas_required", casRequired);
Map<String, Object> payload = mapOf(
"max_versions", maxVersions,
"cas_required", casRequired
);
write(mount + PATH_METADATA + key, payload);
}
@Override
public final SecretVersionResponse writeSecretData(final String mount, final String key, final Map<String, Object> data, final Integer cas) throws VaultConnectorException {
public final SecretVersionResponse writeSecretData(final String mount,
final String key,
final Map<String, Object> data,
final Integer cas) throws VaultConnectorException {
requireAuth();
if (key == null || key.isEmpty()) {
@ -456,12 +464,7 @@ public class HTTPVaultConnector implements VaultConnector {
}
// Add CAS value to options map if present.
Map<String, Object> options;
if (cas != null) {
options = singletonMap("cas", cas);
} else {
options = emptyMap();
}
Map<String, Object> options = mapOf("cas", cas);
/* Issue request and parse metadata response */
return request.post(
@ -485,7 +488,8 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
public final void write(final String key, final Map<String, Object> data, final Map<String, Object> options) throws VaultConnectorException {
public final void write(final String key, final Map<String, Object> data, final Map<String, Object> options)
throws VaultConnectorException {
requireAuth();
if (key == null || key.isEmpty()) {
@ -526,17 +530,20 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
public final void deleteSecretVersions(final String mount, final String key, final int... versions) throws VaultConnectorException {
public final void deleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
handleSecretVersions(mount, PATH_DELETE, key, versions);
}
@Override
public final void undeleteSecretVersions(final String mount, final String key, final int... versions) throws VaultConnectorException {
public final void undeleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
handleSecretVersions(mount, PATH_UNDELETE, key, versions);
}
@Override
public final void destroySecretVersions(final String mount, final String key, final int... versions) throws VaultConnectorException {
public final void destroySecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException {
handleSecretVersions(mount, PATH_DESTROY, key, versions);
}
@ -550,7 +557,10 @@ public class HTTPVaultConnector implements VaultConnector {
* @throws VaultConnectorException on error
* @since 0.8
*/
private void handleSecretVersions(final String mount, final String pathPart, final String key, final int... versions) throws VaultConnectorException {
private void handleSecretVersions(final String mount,
final String pathPart,
final String key,
final int... versions) throws VaultConnectorException {
requireAuth();
/* Request HTTP response and expect empty result */
@ -572,11 +582,10 @@ public class HTTPVaultConnector implements VaultConnector {
public final SecretResponse renew(final String leaseID, final Integer increment) throws VaultConnectorException {
requireAuth();
Map<String, String> payload = new HashMap<>(2, 1);
payload.put("lease_id", leaseID);
if (increment != null) {
payload.put("increment", increment.toString());
}
Map<String, String> payload = mapOfStrings(
"lease_id", leaseID,
"increment", increment
);
/* Issue request and parse secret response */
return request.put(PATH_RENEW, payload, token, SecretResponse.class);
@ -584,12 +593,12 @@ public class HTTPVaultConnector implements VaultConnector {
@Override
public final AuthResponse createToken(final Token token) throws VaultConnectorException {
return createTokenInternal(token, PATH_TOKEN + PATH_CREATE);
return createTokenInternal(token, PATH_AUTH_TOKEN + PATH_CREATE);
}
@Override
public final AuthResponse createToken(final Token token, final boolean orphan) throws VaultConnectorException {
return createTokenInternal(token, PATH_TOKEN + PATH_CREATE_ORPHAN);
return createTokenInternal(token, PATH_AUTH_TOKEN + PATH_CREATE_ORPHAN);
}
@Override
@ -597,7 +606,7 @@ public class HTTPVaultConnector implements VaultConnector {
if (role == null || role.isEmpty()) {
throw new InvalidRequestException("No role name specified.");
}
return createTokenInternal(token, PATH_TOKEN + PATH_CREATE + "/" + role);
return createTokenInternal(token, PATH_AUTH_TOKEN + PATH_CREATE + "/" + role);
}
@Override
@ -632,7 +641,7 @@ public class HTTPVaultConnector implements VaultConnector {
/* Request HTTP response and parse Secret */
return request.get(
PATH_TOKEN + PATH_LOOKUP,
PATH_AUTH_TOKEN + PATH_LOOKUP,
singletonMap("token", token),
token,
TokenResponse.class
@ -650,7 +659,7 @@ public class HTTPVaultConnector implements VaultConnector {
}
// Issue request and expect code 204 with empty response.
request.postWithoutResponse(PATH_TOKEN + PATH_ROLES + "/" + name, role, token);
request.postWithoutResponse(PATH_AUTH_TOKEN + PATH_ROLES + "/" + name, role, token);
return true;
}
@ -660,14 +669,14 @@ public class HTTPVaultConnector implements VaultConnector {
requireAuth();
// Request HTTP response and parse response.
return request.get(PATH_TOKEN + PATH_ROLES + "/" + name, emptyMap(), token, TokenRoleResponse.class);
return request.get(PATH_AUTH_TOKEN + PATH_ROLES + "/" + name, emptyMap(), token, TokenRoleResponse.class);
}
@Override
public List<String> listTokenRoles() throws VaultConnectorException {
requireAuth();
return list(PATH_TOKEN + PATH_ROLES);
return list(PATH_AUTH_TOKEN + PATH_ROLES);
}
@Override
@ -679,7 +688,7 @@ public class HTTPVaultConnector implements VaultConnector {
}
// Issue request and expect code 204 with empty response.
request.deleteWithoutResponse(PATH_TOKEN + PATH_ROLES + "/" + name, token);
request.deleteWithoutResponse(PATH_AUTH_TOKEN + PATH_ROLES + "/" + name, token);
return true;
}
@ -695,4 +704,42 @@ public class HTTPVaultConnector implements VaultConnector {
throw new AuthorizationRequiredException();
}
}
/**
* Generate a map of non-null {@link String} keys and values
*
* @param keyValues Key-value tuples as vararg.
* @return The map of non-null keys and values.
*/
private static Map<String, String> mapOfStrings(Object... keyValues) {
Map<String, String> map = new HashMap<>(keyValues.length / 2, 1);
for (int i = 0; i < keyValues.length - 1; i = i + 2) {
Object key = keyValues[i];
Object val = keyValues[i + 1];
if (key instanceof String && val != null) {
map.put((String) key, val.toString());
}
}
return map;
}
/**
* Generate a map of non-null {@link String} keys and {@link Object} values
*
* @param keyValues Key-value tuples as vararg.
* @return The map of non-null keys and values.
*/
private static Map<String, Object> mapOf(Object... keyValues) {
Map<String, Object> map = new HashMap<>(keyValues.length / 2, 1);
for (int i = 0; i < keyValues.length; i = i + 2) {
Object key = keyValues[i];
Object val = keyValues[i + 1];
if (key instanceof String && val != null) {
map.put((String) key, val);
}
}
return map;
}
}

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -119,9 +119,10 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @param userID The User ID
* @return The {@link AuthResponse}
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. Consider using {@link #authAppRole} instead.
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. App-ID was removed in Vault 1.12.
* Consider using {@link #authAppRole} instead.
*/
@Deprecated(since = "0.4", forRemoval = false)
@Deprecated(since = "0.4", forRemoval = true)
AuthResponse authAppId(final String appID, final String userID) throws VaultConnectorException;
/**
@ -155,9 +156,10 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @param displayName Arbitrary name to display
* @return {@code true} on success
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. Consider using {@link #createAppRole} instead.
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. App-ID was removed in Vault 1.12.
* Consider using {@link #createAppRole} instead.
*/
@Deprecated(since = "0.4", forRemoval = false)
@Deprecated(since = "0.4", forRemoval = true)
boolean registerAppId(final String appID, final String policy, final String displayName)
throws VaultConnectorException;
@ -349,10 +351,10 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @param userID The User-ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole.
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. App-ID was removed in Vault 1.12.
* Consider using {@link #createAppRoleSecret} instead.
*/
@Deprecated(since = "0.4", forRemoval = false)
@Deprecated(since = "0.4", forRemoval = true)
boolean registerUserId(final String appID, final String userID) throws VaultConnectorException;
/**
@ -364,9 +366,9 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @param userID The User-ID
* @return {@code true} on success
* @throws VaultConnectorException on error
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole.
* @deprecated As of Vault 0.6.1 App-ID is superseded by AppRole. App-ID was removed in Vault 1.12.
*/
@Deprecated(since = "0.4", forRemoval = false)
@Deprecated(since = "0.4", forRemoval = true)
default boolean registerAppUserId(final String appID,
final String policy,
final String displayName,
@ -420,7 +422,9 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @throws VaultConnectorException on error
* @since 0.8
*/
default SecretVersionResponse writeSecretData(final String mount, final String key, final Map<String, Object> data) throws VaultConnectorException {
default SecretVersionResponse writeSecretData(final String mount,
final String key,
final Map<String, Object> data) throws VaultConnectorException {
return writeSecretData(mount, key, data, null);
}
@ -438,7 +442,10 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @throws VaultConnectorException on error
* @since 0.8
*/
SecretVersionResponse writeSecretData(final String mount, final String key, final Map<String, Object> data, final Integer cas) throws VaultConnectorException;
SecretVersionResponse writeSecretData(final String mount,
final String key,
final Map<String, Object> data,
final Integer cas) throws VaultConnectorException;
/**
* Retrieve secret data from Vault.
@ -453,7 +460,8 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @throws VaultConnectorException on error
* @since 0.8
*/
SecretResponse readSecretVersion(final String mount, final String key, final Integer version) throws VaultConnectorException;
SecretResponse readSecretVersion(final String mount, final String key, final Integer version)
throws VaultConnectorException;
/**
* Retrieve secret metadata from Vault.
@ -482,7 +490,10 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @throws VaultConnectorException on error
* @since 0.8
*/
void updateSecretMetadata(final String mount, final String key, final Integer maxVersions, final boolean casRequired) throws VaultConnectorException;
void updateSecretMetadata(final String mount,
final String key,
final Integer maxVersions,
final boolean casRequired) throws VaultConnectorException;
/**
* List available nodes from Vault.
@ -527,7 +538,8 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @throws VaultConnectorException on error
* @since 0.8 {@code options} parameter added
*/
void write(final String key, final Map<String, Object> data, final Map<String, Object> options) throws VaultConnectorException;
void write(final String key, final Map<String, Object> data, final Map<String, Object> options)
throws VaultConnectorException;
/**
* Delete key from Vault.
@ -574,7 +586,8 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @throws VaultConnectorException on error
* @since 0.8
*/
void deleteSecretVersions(final String mount, final String key, final int... versions) throws VaultConnectorException;
void deleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Undelete (restore) secret versions from Vault.
@ -586,7 +599,8 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @throws VaultConnectorException on error
* @since 0.8
*/
void undeleteSecretVersions(final String mount, final String key, final int... versions) throws VaultConnectorException;
void undeleteSecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Destroy secret versions from Vault.
@ -598,7 +612,8 @@ public interface VaultConnector extends AutoCloseable, Serializable {
* @throws VaultConnectorException on error
* @since 0.8
*/
void destroySecretVersions(final String mount, final String key, final int... versions) throws VaultConnectorException;
void destroySecretVersions(final String mount, final String key, final int... versions)
throws VaultConnectorException;
/**
* Revoke given lease immediately.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -127,7 +127,8 @@ public final class RequestHelper implements Serializable {
* @throws VaultConnectorException on connection error
* @since 0.8
*/
public void postWithoutResponse(final String path, final Object payload, final String token) throws VaultConnectorException {
public void postWithoutResponse(final String path, final Object payload, final String token)
throws VaultConnectorException {
if (!post(path, payload, token).isEmpty()) {
throw new InvalidResponseException(Error.UNEXPECTED_RESPONSE);
}
@ -143,7 +144,8 @@ public final class RequestHelper implements Serializable {
* @throws VaultConnectorException on connection error
* @since 0.8 Added {@code token} parameter.
*/
public String put(final String path, final Map<String, String> payload, final String token) throws VaultConnectorException {
public String put(final String path, final Map<String, String> payload, final String token)
throws VaultConnectorException {
// Initialize PUT.
var req = HttpRequest.newBuilder(URI.create(baseURL + path));
@ -254,8 +256,8 @@ public final class RequestHelper implements Serializable {
if (!payload.isEmpty()) {
uriBuilder.append("?").append(
payload.entrySet().stream().map(
par -> URLEncoder.encode(par.getKey(), UTF_8) + "=" + URLEncoder.encode(par.getValue(), UTF_8)
payload.entrySet().stream().map(par ->
URLEncoder.encode(par.getKey(), UTF_8) + "=" + URLEncoder.encode(par.getValue(), UTF_8)
).collect(Collectors.joining("&"))
);
}
@ -386,7 +388,8 @@ public final class RequestHelper implements Serializable {
}
return sslContext;
} catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException | KeyManagementException e) {
} catch (CertificateException | NoSuchAlgorithmException | KeyStoreException | IOException |
KeyManagementException e) {
throw new TlsException(Error.INIT_SSL_CONTEXT, e);
}
}
@ -399,7 +402,7 @@ public final class RequestHelper implements Serializable {
* @throws InvalidResponseException on reading errors
*/
private String handleResult(final HttpResponse<InputStream> response) throws InvalidResponseException {
try (var reader = new BufferedReader(new InputStreamReader(response.body()))) {
try (var reader = new BufferedReader(new InputStreamReader(response.body(), UTF_8))) {
return reader.lines().collect(Collectors.joining("\n"));
} catch (IOException ignored) {
throw new InvalidResponseException(Error.READ_RESPONSE, 200);
@ -414,7 +417,7 @@ public final class RequestHelper implements Serializable {
*/
private void handleError(final HttpResponse<InputStream> response) throws VaultConnectorException {
if (response.body() != null) {
try (var reader = new BufferedReader(new InputStreamReader(response.body()))) {
try (var reader = new BufferedReader(new InputStreamReader(response.body(), UTF_8))) {
var responseString = reader.lines().collect(Collectors.joining("\n"));
ErrorResponse er = jsonMapper.readValue(responseString, ErrorResponse.class);
/* Check for "permission denied" response */

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,27 +18,21 @@ package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.annotation.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Vault AppRole role metamodel.
*
* @author Stefan Kalscheuer
* @since 0.4.0
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRole {
/**
* Get {@link Builder} instance.
*
* @param name Role name.
* @return AppRole Builder.
* @since 0.8
*/
public static Builder builder(final String name) {
return new Builder(name);
}
public final class AppRole implements Serializable {
private static final long serialVersionUID = -6248529625864573990L;
@JsonProperty("role_name")
private String name;
@ -129,6 +123,17 @@ public final class AppRole {
this.tokenType = builder.tokenType != null ? builder.tokenType.value() : null;
}
/**
* Get {@link Builder} instance.
*
* @param name Role name.
* @return AppRole Builder.
* @since 0.8
*/
public static Builder builder(final String name) {
return new Builder(name);
}
/**
* @return the role name
*/
@ -316,6 +321,39 @@ public final class AppRole {
return tokenType;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
AppRole appRole = (AppRole) o;
return Objects.equals(name, appRole.name) &&
Objects.equals(id, appRole.id) &&
Objects.equals(bindSecretId, appRole.bindSecretId) &&
Objects.equals(secretIdBoundCidrs, appRole.secretIdBoundCidrs) &&
Objects.equals(secretIdNumUses, appRole.secretIdNumUses) &&
Objects.equals(secretIdTtl, appRole.secretIdTtl) &&
Objects.equals(enableLocalSecretIds, appRole.enableLocalSecretIds) &&
Objects.equals(tokenTtl, appRole.tokenTtl) &&
Objects.equals(tokenMaxTtl, appRole.tokenMaxTtl) &&
Objects.equals(tokenPolicies, appRole.tokenPolicies) &&
Objects.equals(tokenBoundCidrs, appRole.tokenBoundCidrs) &&
Objects.equals(tokenExplicitMaxTtl, appRole.tokenExplicitMaxTtl) &&
Objects.equals(tokenNoDefaultPolicy, appRole.tokenNoDefaultPolicy) &&
Objects.equals(tokenNumUses, appRole.tokenNumUses) &&
Objects.equals(tokenPeriod, appRole.tokenPeriod) &&
Objects.equals(tokenType, appRole.tokenType);
}
@Override
public int hashCode() {
return Objects.hash(name, id, bindSecretId, secretIdBoundCidrs, secretIdNumUses, secretIdTtl,
enableLocalSecretIds, tokenTtl, tokenMaxTtl, tokenPolicies, tokenBoundCidrs, tokenExplicitMaxTtl,
tokenNoDefaultPolicy, tokenNumUses, tokenPeriod, tokenType);
}
/**
* A builder for vault AppRole roles..

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,17 +18,22 @@ package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.annotation.*;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Vault AppRole role metamodel.
*
* @author Stefan Kalscheuer
* @since 0.4.0
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRoleSecret {
public final class AppRoleSecret implements Serializable {
private static final long serialVersionUID = -3401074170145792641L;
@JsonProperty("secret_id")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String id;
@ -166,4 +171,29 @@ public final class AppRoleSecret {
public Integer getTtl() {
return ttl;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
AppRoleSecret that = (AppRoleSecret) o;
return Objects.equals(id, that.id) &&
Objects.equals(accessor, that.accessor) &&
Objects.equals(metadata, that.metadata) &&
Objects.equals(cidrList, that.cidrList) &&
Objects.equals(creationTime, that.creationTime) &&
Objects.equals(expirationTime, that.expirationTime) &&
Objects.equals(lastUpdatedTime, that.lastUpdatedTime) &&
Objects.equals(numUses, that.numUses) &&
Objects.equals(ttl, that.ttl);
}
@Override
public int hashCode() {
return Objects.hash(id, accessor, metadata, cidrList, creationTime, expirationTime, lastUpdatedTime, numUses,
ttl);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -24,6 +24,7 @@ package de.stklcode.jvault.connector.model;
*/
public enum AuthBackend {
TOKEN("token"),
@Deprecated(since = "1.1.3", forRemoval = true)
APPID("app-id"),
APPROLE("approle"),
USERPASS("userpass"),

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.*;
/**
@ -27,18 +28,11 @@ import java.util.*;
*
* @author Stefan Kalscheuer
* @since 0.4.0
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class Token {
/**
* Get {@link Builder} instance.
*
* @return Token Builder.
* @since 0.8
*/
public static Builder builder() {
return new Builder();
}
public final class Token implements Serializable {
private static final long serialVersionUID = 5208508683665365287L;
@JsonProperty("id")
@JsonInclude(JsonInclude.Include.NON_NULL)
@ -119,6 +113,16 @@ public final class Token {
this.entityAlias = builder.entityAlias;
}
/**
* Get {@link Builder} instance.
*
* @return Token Builder.
* @since 0.8
*/
public static Builder builder() {
return new Builder();
}
/**
* @return Token ID
*/
@ -214,6 +218,35 @@ public final class Token {
return entityAlias;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
Token token = (Token) o;
return Objects.equals(id, token.id) &&
Objects.equals(type, token.type) &&
Objects.equals(displayName, token.displayName) &&
Objects.equals(noParent, token.noParent) &&
Objects.equals(noDefaultPolicy, token.noDefaultPolicy) &&
Objects.equals(ttl, token.ttl) &&
Objects.equals(explicitMaxTtl, token.explicitMaxTtl) &&
Objects.equals(numUses, token.numUses) &&
Objects.equals(policies, token.policies) &&
Objects.equals(meta, token.meta) &&
Objects.equals(renewable, token.renewable) &&
Objects.equals(period, token.period) &&
Objects.equals(entityAlias, token.entityAlias);
}
@Override
public int hashCode() {
return Objects.hash(id, type, displayName, noParent, noDefaultPolicy, ttl, explicitMaxTtl, numUses, policies,
meta, renewable, period, entityAlias);
}
/**
* Constants for token types.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,25 +20,21 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Vault Token Role metamodel.
*
* @author Stefan Kalscheuer
* @since 0.9
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenRole {
/**
* Get {@link Builder} instance.
*
* @return Token Role Builder.
*/
public static Builder builder() {
return new Builder();
}
public final class TokenRole implements Serializable {
private static final long serialVersionUID = -3505215215838576321L;
@JsonProperty("name")
@JsonInclude(JsonInclude.Include.NON_NULL)
@ -48,10 +44,18 @@ public final class TokenRole {
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<String> allowedPolicies;
@JsonProperty("allowed_policies_glob")
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<String> allowedPoliciesGlob;
@JsonProperty("disallowed_policies")
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<String> disallowedPolicies;
@JsonProperty("disallowed_policies_glob")
@JsonInclude(JsonInclude.Include.NON_NULL)
private List<String> disallowedPoliciesGlob;
@JsonProperty("orphan")
@JsonInclude(JsonInclude.Include.NON_NULL)
private Boolean orphan;
@ -101,7 +105,9 @@ public final class TokenRole {
public TokenRole(final Builder builder) {
this.name = builder.name;
this.allowedPolicies = builder.allowedPolicies;
this.allowedPoliciesGlob = builder.allowedPoliciesGlob;
this.disallowedPolicies = builder.disallowedPolicies;
this.disallowedPoliciesGlob = builder.disallowedPoliciesGlob;
this.orphan = builder.orphan;
this.renewable = builder.renewable;
this.pathSuffix = builder.pathSuffix;
@ -114,6 +120,15 @@ public final class TokenRole {
this.tokenType = builder.tokenType != null ? builder.tokenType.value() : null;
}
/**
* Get {@link Builder} instance.
*
* @return Token Role Builder.
*/
public static Builder builder() {
return new Builder();
}
/**
* @return Token Role name
*/
@ -128,6 +143,14 @@ public final class TokenRole {
return allowedPolicies;
}
/**
* @return List of allowed policy glob patterns
* @since 1.1
*/
public List<String> getAllowedPoliciesGlob() {
return allowedPoliciesGlob;
}
/**
* @return List of disallowed policies
*/
@ -135,6 +158,14 @@ public final class TokenRole {
return disallowedPolicies;
}
/**
* @return List of disallowed policy glob patterns
* @since 1.1
*/
public List<String> getDisallowedPoliciesGlob() {
return disallowedPoliciesGlob;
}
/**
* @return Is Token Role orphan?
*/
@ -205,6 +236,38 @@ public final class TokenRole {
return tokenType;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
TokenRole tokenRole = (TokenRole) o;
return Objects.equals(name, tokenRole.name) &&
Objects.equals(allowedPolicies, tokenRole.allowedPolicies) &&
Objects.equals(allowedPoliciesGlob, tokenRole.allowedPoliciesGlob) &&
Objects.equals(disallowedPolicies, tokenRole.disallowedPolicies) &&
Objects.equals(disallowedPoliciesGlob, tokenRole.disallowedPoliciesGlob) &&
Objects.equals(orphan, tokenRole.orphan) &&
Objects.equals(renewable, tokenRole.renewable) &&
Objects.equals(pathSuffix, tokenRole.pathSuffix) &&
Objects.equals(allowedEntityAliases, tokenRole.allowedEntityAliases) &&
Objects.equals(tokenBoundCidrs, tokenRole.tokenBoundCidrs) &&
Objects.equals(tokenExplicitMaxTtl, tokenRole.tokenExplicitMaxTtl) &&
Objects.equals(tokenNoDefaultPolicy, tokenRole.tokenNoDefaultPolicy) &&
Objects.equals(tokenNumUses, tokenRole.tokenNumUses) &&
Objects.equals(tokenPeriod, tokenRole.tokenPeriod) &&
Objects.equals(tokenType, tokenRole.tokenType);
}
@Override
public int hashCode() {
return Objects.hash(name, allowedPolicies, allowedPoliciesGlob, disallowedPolicies, disallowedPoliciesGlob,
orphan, renewable, pathSuffix, allowedEntityAliases, tokenBoundCidrs, tokenExplicitMaxTtl,
tokenNoDefaultPolicy, tokenNumUses, tokenPeriod, tokenType);
}
/**
* A builder for vault token roles.
*
@ -214,7 +277,9 @@ public final class TokenRole {
public static final class Builder {
private String name;
private List<String> allowedPolicies;
private List<String> allowedPoliciesGlob;
private List<String> disallowedPolicies;
private List<String> disallowedPoliciesGlob;
private Boolean orphan;
private Boolean renewable;
private String pathSuffix;
@ -269,6 +334,40 @@ public final class TokenRole {
return this;
}
/**
* Add an allowed policy glob pattern.
*
* @param allowedPolicyGlob allowed policy glob pattern to add
* @return self
* @since 1.1
*/
public Builder withAllowedPolicyGlob(final String allowedPolicyGlob) {
if (allowedPolicyGlob != null) {
if (this.allowedPoliciesGlob == null) {
this.allowedPoliciesGlob = new ArrayList<>();
}
this.allowedPoliciesGlob.add(allowedPolicyGlob);
}
return this;
}
/**
* Add allowed policy glob patterns.
*
* @param allowedPoliciesGlob list of allowed policy glob patterns
* @return self
* @since 1.1
*/
public Builder withAllowedPoliciesGlob(final List<String> allowedPoliciesGlob) {
if (allowedPoliciesGlob != null) {
if (this.allowedPoliciesGlob == null) {
this.allowedPoliciesGlob = new ArrayList<>();
}
this.allowedPoliciesGlob.addAll(allowedPoliciesGlob);
}
return this;
}
/**
* Add a disallowed policy.
*
@ -301,6 +400,40 @@ public final class TokenRole {
return this;
}
/**
* Add an allowed policy glob pattern.
*
* @param disallowedPolicyGlob disallowed policy glob pattern to add
* @return self
* @since 1.1
*/
public Builder withDisallowedPolicyGlob(final String disallowedPolicyGlob) {
if (disallowedPolicyGlob != null) {
if (this.disallowedPoliciesGlob == null) {
this.disallowedPoliciesGlob = new ArrayList<>();
}
this.disallowedPoliciesGlob.add(disallowedPolicyGlob);
}
return this;
}
/**
* Add disallowed policy glob patterns.
*
* @param disallowedPoliciesGlob list of disallowed policy glob patterns
* @return self
* @since 1.1
*/
public Builder withDisallowedPoliciesGlob(final List<String> disallowedPoliciesGlob) {
if (disallowedPoliciesGlob != null) {
if (this.disallowedPoliciesGlob == null) {
this.disallowedPoliciesGlob = new ArrayList<>();
}
this.disallowedPoliciesGlob.addAll(disallowedPoliciesGlob);
}
return this;
}
/**
* Set TRUE if the token role should be created orphan.
*

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,13 +17,10 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.AppRole;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* Vault response for AppRole lookup.
@ -33,24 +30,10 @@ import java.util.Map;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRoleResponse extends VaultDataResponse {
private AppRole role;
private static final long serialVersionUID = -6536422219633829177L;
@Override
public void setData(final Map<String, Object> data) throws InvalidResponseException {
var mapper = new ObjectMapper();
try {
/* null empty strings on list objects */
Map<String, Object> filteredData = new HashMap<>(data.size(), 1);
data.forEach((k, v) -> {
if (!(v instanceof String && ((String) v).isEmpty())) {
filteredData.put(k, v);
}
});
this.role = mapper.readValue(mapper.writeValueAsString(filteredData), AppRole.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
@JsonProperty("data")
private AppRole role;
/**
* @return The role
@ -58,4 +41,20 @@ public final class AppRoleResponse extends VaultDataResponse {
public AppRole getRole() {
return role;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
AppRoleResponse that = (AppRoleResponse) o;
return Objects.equals(role, that.role);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), role);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,13 +17,10 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.AppRoleSecret;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* Vault response for AppRole lookup.
@ -33,24 +30,10 @@ import java.util.Map;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AppRoleSecretResponse extends VaultDataResponse {
private AppRoleSecret secret;
private static final long serialVersionUID = -2484103304072370585L;
@Override
public void setData(final Map<String, Object> data) throws InvalidResponseException {
var mapper = new ObjectMapper();
try {
/* null empty strings on list objects */
Map<String, Object> filteredData = new HashMap<>(data.size(), 1);
data.forEach((k, v) -> {
if (!(v instanceof String && ((String) v).isEmpty())) {
filteredData.put(k, v);
}
});
this.secret = mapper.readValue(mapper.writeValueAsString(filteredData), AppRoleSecret.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
@JsonProperty("data")
private AppRoleSecret secret;
/**
* @return The secret
@ -58,4 +41,20 @@ public final class AppRoleSecretResponse extends VaultDataResponse {
public AppRoleSecret getSecret() {
return secret;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
AppRoleSecretResponse that = (AppRoleSecretResponse) o;
return Objects.equals(secret, that.secret);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), secret);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,13 +17,12 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.AuthMethod;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* Authentication method response.
@ -33,6 +32,9 @@ import java.util.Map;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthMethodsResponse extends VaultDataResponse {
private static final long serialVersionUID = -1802724129533405375L;
@JsonProperty("data")
private Map<String, AuthMethod> supportedMethods;
/**
@ -42,23 +44,26 @@ public final class AuthMethodsResponse extends VaultDataResponse {
this.supportedMethods = new HashMap<>();
}
@Override
public void setData(final Map<String, Object> data) throws InvalidResponseException {
var mapper = new ObjectMapper();
for (Map.Entry<String, Object> entry : data.entrySet()) {
try {
this.supportedMethods.put(entry.getKey(),
mapper.readValue(mapper.writeValueAsString(entry.getValue()), AuthMethod.class));
} catch (IOException e) {
throw new InvalidResponseException();
}
}
}
/**
* @return Supported authentication methods
*/
public Map<String, AuthMethod> getSupportedMethods() {
return supportedMethods;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
AuthMethodsResponse that = (AuthMethodsResponse) o;
return Objects.equals(supportedMethods, that.supportedMethods);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), supportedMethods);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,12 +18,9 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.AuthData;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
/**
* Vault response for authentication providing auth info in {@link AuthData} field.
@ -33,37 +30,10 @@ import java.util.Map;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthResponse extends VaultDataResponse {
private Map<String, Object> data;
private static final long serialVersionUID = 1628851361067456715L;
private AuthData auth;
/**
* Set authentication data. The input will be mapped to the {@link AuthData} model.
*
* @param auth Raw authentication data
* @throws InvalidResponseException on mapping errors
*/
@JsonProperty("auth")
public void setAuth(final Map<String, Object> auth) throws InvalidResponseException {
var mapper = new ObjectMapper();
try {
this.auth = mapper.readValue(mapper.writeValueAsString(auth), AuthData.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
@Override
public void setData(final Map<String, Object> data) {
this.data = data;
}
/**
* @return Raw data
*/
public Map<String, Object> getData() {
return data;
}
private AuthData auth;
/**
* @return Authentication data
@ -71,4 +41,20 @@ public final class AuthResponse extends VaultDataResponse {
public AuthData getAuth() {
return auth;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
AuthResponse that = (AuthResponse) o;
return Objects.equals(auth, that.auth);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), auth);
}
}

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import java.util.Objects;
/**
* Vault response in case of errors.
@ -29,6 +30,8 @@ import java.util.List;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class ErrorResponse implements VaultResponse {
private static final long serialVersionUID = -6227368087842549149L;
@JsonProperty("errors")
private List<String> errors;
@ -47,4 +50,20 @@ public final class ErrorResponse implements VaultResponse {
return errors.get(0);
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
ErrorResponse that = (ErrorResponse) o;
return Objects.equals(errors, that.errors);
}
@Override
public int hashCode() {
return Objects.hash(errors);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,6 +19,8 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Objects;
/**
* Vault response for health query.
*
@ -27,6 +29,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class HealthResponse implements VaultResponse {
private static final long serialVersionUID = 6483840078694294401L;
@JsonProperty("cluster_id")
private String clusterID;
@ -48,7 +52,7 @@ public final class HealthResponse implements VaultResponse {
@JsonProperty("initialized")
private Boolean initialized;
@JsonProperty("replication_perf_mode")
@JsonProperty("replication_performance_mode")
private String replicationPerfMode;
@JsonProperty("replication_dr_mode")
@ -129,4 +133,30 @@ public final class HealthResponse implements VaultResponse {
public Boolean isPerformanceStandby() {
return performanceStandby;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
HealthResponse that = (HealthResponse) o;
return Objects.equals(clusterID, that.clusterID) &&
Objects.equals(clusterName, that.clusterName) &&
Objects.equals(version, that.version) &&
Objects.equals(serverTimeUTC, that.serverTimeUTC) &&
Objects.equals(standby, that.standby) &&
Objects.equals(sealed, that.sealed) &&
Objects.equals(initialized, that.initialized) &&
Objects.equals(replicationPerfMode, that.replicationPerfMode) &&
Objects.equals(replicationDrMode, that.replicationDrMode) &&
Objects.equals(performanceStandby, that.performanceStandby);
}
@Override
public int hashCode() {
return Objects.hash(clusterID, clusterName, version, serverTimeUTC, standby, sealed, initialized,
replicationPerfMode, replicationDrMode, performanceStandby);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,6 +19,8 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Objects;
/**
* Vault response for help request.
*
@ -27,6 +29,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class HelpResponse implements VaultResponse {
private static final long serialVersionUID = -1152070966642848490L;
@JsonProperty("help")
private String help;
@ -36,4 +40,20 @@ public final class HelpResponse implements VaultResponse {
public String getHelp() {
return help;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
HelpResponse that = (HelpResponse) o;
return Objects.equals(help, that.help);
}
@Override
public int hashCode() {
return Objects.hash(help);
}
}

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,12 +17,11 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.SecretMetadata;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
/**
* Vault response for secret metadata (KV v2).
@ -32,19 +31,11 @@ import java.util.Map;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class MetadataResponse extends VaultDataResponse {
private static final long serialVersionUID = -3679762333630984679L;
@JsonProperty("data")
private SecretMetadata metadata;
@Override
public final void setData(final Map<String, Object> data) throws InvalidResponseException {
var mapper = new ObjectMapper();
try {
this.metadata = mapper.readValue(mapper.writeValueAsString(data), SecretMetadata.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
/**
* Get the actual metadata.
*
@ -53,4 +44,20 @@ public class MetadataResponse extends VaultDataResponse {
public SecretMetadata getMetadata() {
return metadata;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
MetadataResponse that = (MetadataResponse) o;
return Objects.equals(metadata, that.metadata);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), metadata);
}
}

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,8 +17,11 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
/**
* Simple Vault data response.
@ -28,17 +31,31 @@ import java.util.Map;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class RawDataResponse extends VaultDataResponse {
private Map<String, Object> data;
private static final long serialVersionUID = -319727427792124071L;
@Override
public void setData(final Map<String, Object> data) {
this.data = data;
}
@JsonProperty("data")
private Map<String, Serializable> data;
/**
* @return Raw data {@link Map}
*/
public Map<String, Object> getData() {
public Map<String, Serializable> getData() {
return data;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
RawDataResponse that = (RawDataResponse) o;
return Objects.equals(data, that.data);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), data);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,6 +19,8 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Objects;
/**
* Vault response for seal status or unseal request.
*
@ -27,6 +29,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class SealResponse implements VaultResponse {
private static final long serialVersionUID = -3661916639367542617L;
@JsonProperty("type")
private String type;
@ -57,6 +61,15 @@ public final class SealResponse implements VaultResponse {
@JsonProperty("cluster_id")
private String clusterId;
@JsonProperty("migration")
private Boolean migration;
@JsonProperty("recovery_seal")
private Boolean recoverySeal;
@JsonProperty("storage_type")
private String storageType;
/**
* @return Seal type.
* @since 0.8
@ -132,4 +145,57 @@ public final class SealResponse implements VaultResponse {
public String getClusterId() {
return clusterId;
}
/**
* @return Migration status (since Vault 1.4)
* @since 1.1
*/
public Boolean getMigration() {
return migration;
}
/**
* @return Recovery seal status.
* @since 1.1
*/
public Boolean getRecoverySeal() {
return recoverySeal;
}
/**
* @return Storage type (since Vault 1.3).
* @since 1.1
*/
public String getStorageType() {
return storageType;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
SealResponse that = (SealResponse) o;
return sealed == that.sealed &&
initialized == that.initialized &&
Objects.equals(type, that.type) &&
Objects.equals(threshold, that.threshold) &&
Objects.equals(numberOfShares, that.numberOfShares) &&
Objects.equals(progress, that.progress) &&
Objects.equals(version, that.version) &&
Objects.equals(nonce, that.nonce) &&
Objects.equals(clusterName, that.clusterName) &&
Objects.equals(clusterId, that.clusterId) &&
Objects.equals(migration, that.migration) &&
Objects.equals(recoverySeal, that.recoverySeal) &&
Objects.equals(storageType, that.storageType);
}
@Override
public int hashCode() {
return Objects.hash(type, sealed, initialized, threshold, numberOfShares, progress, version, nonce,
clusterName, clusterId, migration, recoverySeal, storageType);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,10 +18,11 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.SecretListWrapper;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Vault response for secret list request.
@ -31,27 +32,34 @@ import java.util.Map;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class SecretListResponse extends VaultDataResponse {
private List<String> keys;
/**
* Set data. Extracts list of keys from raw response data.
*
* @param data Raw data
* @throws InvalidResponseException on parsing errors
*/
private static final long serialVersionUID = 8597121175002967213L;
@JsonProperty("data")
public void setData(final Map<String, Object> data) throws InvalidResponseException {
try {
this.keys = (List<String>) data.get("keys");
} catch (ClassCastException e) {
throw new InvalidResponseException("Keys could not be parsed from data.", e);
}
}
private SecretListWrapper data;
/**
* @return List of secret keys
*/
public List<String> getKeys() {
return keys;
if (data == null) {
return Collections.emptyList();
}
return Objects.requireNonNullElseGet(data.getKeys(), Collections::emptyList);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
SecretListResponse that = (SecretListResponse) o;
return Objects.equals(data, that.data);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), data);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -22,7 +22,7 @@ import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
import java.io.IOException;
import java.util.Collections;
import java.io.Serializable;
import java.util.Map;
/**
@ -30,46 +30,20 @@ import java.util.Map;
*
* @author Stefan Kalscheuer
* @since 0.1
* @since 1.1 abstract
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SecretResponse extends VaultDataResponse {
private static final String KEY_DATA = "data";
private static final String KEY_METADATA = "metadata";
private Map<String, Object> data;
private VersionMetadata metadata;
@Override
public final void setData(final Map<String, Object> data) throws InvalidResponseException {
if (data.size() == 2
&& data.containsKey(KEY_DATA) && data.get(KEY_DATA) instanceof Map
&& data.containsKey(KEY_METADATA) && data.get(KEY_METADATA) instanceof Map) {
var mapper = new ObjectMapper();
try {
// This is apparently a KV v2 value.
this.data = (Map<String, Object>) data.get(KEY_DATA);
this.metadata = mapper.readValue(mapper.writeValueAsString(data.get(KEY_METADATA)), VersionMetadata.class);
} catch (ClassCastException | IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
} else {
// For KV v1 without metadata just store the data map.
this.data = data;
}
}
public abstract class SecretResponse extends VaultDataResponse {
private static final long serialVersionUID = 5198088815871692951L;
/**
* Get complete data object.
*
* @return data map
* @since 0.4.0
* @since 1.1 Serializable map value.
*/
public final Map<String, Object> getData() {
if (data == null) {
return Collections.emptyMap();
}
return data;
}
public abstract Map<String, Serializable> getData();
/**
* Get secret metadata. This is only available for KV v2 secrets.
@ -77,9 +51,7 @@ public class SecretResponse extends VaultDataResponse {
* @return Metadata of the secret.
* @since 0.8
*/
public final VersionMetadata getMetadata() {
return metadata;
}
public abstract VersionMetadata getMetadata();
/**
* Get a single value for given key.
@ -89,9 +61,6 @@ public class SecretResponse extends VaultDataResponse {
* @since 0.4.0
*/
public final Object get(final String key) {
if (data == null) {
return null;
}
return getData().get(key);
}
@ -100,18 +69,26 @@ public class SecretResponse extends VaultDataResponse {
*
* @param key the key
* @param type Class to parse response
* @param <T> Class to parse response
* @param <C> Class to parse response
* @return Parsed object or {@code null} if absent
* @throws InvalidResponseException on parsing error
* @since 0.4.0
*/
public final <T> T get(final String key, final Class<T> type) throws InvalidResponseException {
public final <C> C get(final String key, final Class<C> type) throws InvalidResponseException {
try {
Object rawValue = get(key);
if (rawValue == null) {
return null;
} else if (type.isInstance(rawValue)) {
return type.cast(rawValue);
} else {
var om = new ObjectMapper();
if (rawValue instanceof String) {
return om.readValue((String) rawValue, type);
} else {
return om.readValue(om.writeValueAsString(rawValue), type);
}
}
return new ObjectMapper().readValue(rawValue.toString(), type);
} catch (IOException e) {
throw new InvalidResponseException("Unable to parse response payload: " + e.getMessage());
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,12 +17,10 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
/**
* Vault response for a single secret version metadata, i.e. after update (KV v2).
@ -32,19 +30,11 @@ import java.util.Map;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SecretVersionResponse extends VaultDataResponse {
private static final long serialVersionUID = 2748635005258576174L;
@JsonProperty("data")
private VersionMetadata metadata;
@Override
public final void setData(final Map<String, Object> data) throws InvalidResponseException {
var mapper = new ObjectMapper();
try {
this.metadata = mapper.readValue(mapper.writeValueAsString(data), VersionMetadata.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
/**
* Get the actual metadata.
*
@ -53,4 +43,20 @@ public class SecretVersionResponse extends VaultDataResponse {
public VersionMetadata getMetadata() {
return metadata;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
SecretVersionResponse that = (SecretVersionResponse) o;
return Objects.equals(metadata, that.metadata);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), metadata);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,12 +18,9 @@ package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
/**
* Vault response from token lookup providing Token information in {@link TokenData} field.
@ -33,31 +30,41 @@ import java.util.Map;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenResponse extends VaultDataResponse {
private static final long serialVersionUID = -4053126653764241197L;
@JsonProperty("data")
private TokenData data;
@JsonProperty("auth")
private Boolean auth;
/**
* Set data. Parses response data map to {@link TokenData}.
*
* @param data Raw response data
* @throws InvalidResponseException on parsing errors
*/
@Override
public void setData(final Map<String, Object> data) throws InvalidResponseException {
var mapper = new ObjectMapper();
try {
this.data = mapper.readValue(mapper.writeValueAsString(data), TokenData.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
/**
* @return Token data
*/
public TokenData getData() {
return data;
}
/**
* @return Auth data
*/
public Boolean getAuth() {
return auth;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
TokenResponse that = (TokenResponse) o;
return Objects.equals(data, that.data) && Objects.equals(auth, that.auth);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), data, auth);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,13 +17,11 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.model.TokenRole;
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
/**
* Vault response from token role lookup providing Token information in {@link TokenData} field.
@ -33,23 +31,10 @@ import java.util.Map;
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenRoleResponse extends VaultDataResponse {
private TokenRole data;
private static final long serialVersionUID = 5265363857731948626L;
/**
* Set data. Parses response data map to {@link TokenRole}.
*
* @param data Raw response data
* @throws InvalidResponseException on parsing errors
*/
@Override
public void setData(final Map<String, Object> data) throws InvalidResponseException {
var mapper = new ObjectMapper();
try {
this.data = mapper.readValue(mapper.writeValueAsString(data), TokenRole.class);
} catch (IOException e) {
throw new InvalidResponseException("Failed deserializing response", e);
}
}
@JsonProperty("data")
private TokenRole data;
/**
* @return TokenRole data
@ -57,4 +42,20 @@ public final class TokenRoleResponse extends VaultDataResponse {
public TokenRole getData() {
return data;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass() || !super.equals(o)) {
return false;
}
TokenRoleResponse that = (TokenRoleResponse) o;
return Objects.equals(data, that.data);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), data);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,10 +17,10 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.response.embedded.WrapInfo;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Abstract Vault response with default payload fields.
@ -29,6 +29,11 @@ import java.util.Map;
* @since 0.1
*/
public abstract class VaultDataResponse implements VaultResponse {
private static final long serialVersionUID = 7486270767477652184L;
@JsonProperty("request_id")
private String requestId;
@JsonProperty("lease_id")
private String leaseId;
@ -41,14 +46,16 @@ public abstract class VaultDataResponse implements VaultResponse {
@JsonProperty("warnings")
private List<String> warnings;
@JsonProperty("wrap_info")
private WrapInfo wrapInfo;
/**
* Set data. To be implemented in the specific subclasses, as data can be of arbitrary structure.
*
* @param data Raw response data
* @throws InvalidResponseException on parsing errors
* @return Request ID
* @since 1.1
*/
@JsonProperty("data")
public abstract void setData(final Map<String, Object> data) throws InvalidResponseException;
public final String getRequestId() {
return requestId;
}
/**
* @return Lease ID
@ -77,4 +84,33 @@ public abstract class VaultDataResponse implements VaultResponse {
public final List<String> getWarnings() {
return warnings;
}
/**
* @return Wrapping information
* @since 1.1
*/
public final WrapInfo getWrapInfo() {
return wrapInfo;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
VaultDataResponse that = (VaultDataResponse) o;
return renewable == that.renewable &&
Objects.equals(requestId, that.requestId) &&
Objects.equals(leaseId, that.leaseId) &&
Objects.equals(leaseDuration, that.leaseDuration) &&
Objects.equals(warnings, that.warnings) &&
Objects.equals(wrapInfo, that.wrapInfo);
}
@Override
public int hashCode() {
return Objects.hash(requestId, leaseId, renewable, leaseDuration, warnings, wrapInfo);
}
}

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,17 +19,22 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Embedded authorization information inside Vault response.
*
* @author Stefan Kalscheuer
* @since 0.1
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthData {
public final class AuthData implements Serializable {
private static final long serialVersionUID = -6962244199229885869L;
@JsonProperty("client_token")
private String clientToken;
@ -133,4 +138,31 @@ public final class AuthData {
public boolean isOrphan() {
return orphan;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AuthData authData = (AuthData) o;
return renewable == authData.renewable &&
orphan == authData.orphan &&
Objects.equals(clientToken, authData.clientToken) &&
Objects.equals(accessor, authData.accessor) &&
Objects.equals(policies, authData.policies) &&
Objects.equals(tokenPolicies, authData.tokenPolicies) &&
Objects.equals(metadata, authData.metadata) &&
Objects.equals(leaseDuration, authData.leaseDuration) &&
Objects.equals(entityId, authData.entityId) &&
Objects.equals(tokenType, authData.tokenType);
}
@Override
public int hashCode() {
return Objects.hash(clientToken, accessor, policies, tokenPolicies, metadata, leaseDuration, renewable,
entityId, tokenType, orphan);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,28 +21,45 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import de.stklcode.jvault.connector.model.AuthBackend;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
/**
* Embedded authentication method response.
*
* @author Stefan Kalscheuer
* @since 0.1
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class AuthMethod {
public final class AuthMethod implements Serializable {
private static final long serialVersionUID = -2718660627880077335L;
private AuthBackend type;
private String rawType;
@JsonProperty("accessor")
private String accessor;
@JsonProperty("description")
private String description;
@JsonProperty("config")
private Map<String, String> config;
@JsonProperty("external_entropy_access")
private boolean externalEntropyAccess;
@JsonProperty("local")
private boolean local;
@JsonProperty("seal_wrap")
private boolean sealWrap;
@JsonProperty("uuid")
private String uuid;
/**
* @param type Backend type, passed to {@link AuthBackend#forType(String)}
*/
@ -66,6 +83,14 @@ public final class AuthMethod {
return rawType;
}
/**
* @return Accessor
* @since 1.1
*/
public String getAccessor() {
return accessor;
}
/**
* @return Description
*/
@ -80,10 +105,58 @@ public final class AuthMethod {
return config;
}
/**
* @return Backend has access to external entropy source
* @since 1.1
*/
public boolean isExternalEntropyAccess() {
return externalEntropyAccess;
}
/**
* @return Is local backend
*/
public boolean isLocal() {
return local;
}
/**
* @return Seal wrapping enabled
* @since 1.1
*/
public boolean isSealWrap() {
return sealWrap;
}
/**
* @return Backend UUID
* @since 1.1
*/
public String getUuid() {
return uuid;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
AuthMethod that = (AuthMethod) o;
return local == that.local &&
type == that.type &&
externalEntropyAccess == that.externalEntropyAccess &&
sealWrap == that.sealWrap &&
Objects.equals(rawType, that.rawType) &&
Objects.equals(accessor, that.accessor) &&
Objects.equals(description, that.description) &&
Objects.equals(config, that.config) &&
Objects.equals(uuid, that.uuid);
}
@Override
public int hashCode() {
return Objects.hash(type, rawType, accessor, description, config, externalEntropyAccess, local, sealWrap, uuid);
}
}

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,20 +19,26 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Map;
import java.util.Objects;
/**
* Embedded metadata for Key-Value v2 secrets.
*
* @author Stefan Kalscheuer
* @since 0.8
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class SecretMetadata {
private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSX");
public final class SecretMetadata implements Serializable {
private static final long serialVersionUID = 1684891108903409038L;
private static final DateTimeFormatter TIME_FORMAT =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX");
@JsonProperty("created_time")
private String createdTimeString;
@ -124,4 +130,24 @@ public final class SecretMetadata {
return versions;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
SecretMetadata that = (SecretMetadata) o;
return Objects.equals(createdTimeString, that.createdTimeString) &&
Objects.equals(currentVersion, that.currentVersion) &&
Objects.equals(maxVersions, that.maxVersions) &&
Objects.equals(oldestVersion, that.oldestVersion) &&
Objects.equals(updatedTime, that.updatedTime) &&
Objects.equals(versions, that.versions);
}
@Override
public int hashCode() {
return Objects.hash(createdTimeString, currentVersion, maxVersions, oldestVersion, updatedTime, versions);
}
}

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,18 +19,23 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* Embedded token information inside Vault response.
*
* @author Stefan Kalscheuer
* @since 0.1
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class TokenData {
public final class TokenData implements Serializable {
private static final long serialVersionUID = 2915180734313753649L;
@JsonProperty("accessor")
private String accessor;
@ -231,4 +236,37 @@ public final class TokenData {
public Map<String, Object> getMeta() {
return meta;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
TokenData tokenData = (TokenData) o;
return orphan == tokenData.orphan &&
renewable == tokenData.renewable &&
Objects.equals(accessor, tokenData.accessor) &&
Objects.equals(creationTime, tokenData.creationTime) &&
Objects.equals(creationTtl, tokenData.creationTtl) &&
Objects.equals(name, tokenData.name) &&
Objects.equals(entityId, tokenData.entityId) &&
Objects.equals(expireTime, tokenData.expireTime) &&
Objects.equals(explicitMaxTtl, tokenData.explicitMaxTtl) &&
Objects.equals(id, tokenData.id) &&
Objects.equals(issueTime, tokenData.issueTime) &&
Objects.equals(meta, tokenData.meta) &&
Objects.equals(numUses, tokenData.numUses) &&
Objects.equals(path, tokenData.path) &&
Objects.equals(policies, tokenData.policies) &&
Objects.equals(ttl, tokenData.ttl) &&
Objects.equals(type, tokenData.type);
}
@Override
public int hashCode() {
return Objects.hash(accessor, creationTime, creationTtl, name, entityId, expireTime, explicitMaxTtl, id,
issueTime, meta, numUses, orphan, path, policies, renewable, ttl, type);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,19 +19,25 @@ package de.stklcode.jvault.connector.model.response.embedded;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Objects;
/**
* Embedded metadata for a single Key-Value v2 version.
*
* @author Stefan Kalscheuer
* @since 0.8
* @since 1.1 implements {@link Serializable}
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public final class VersionMetadata {
private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSX");
public final class VersionMetadata implements Serializable {
private static final long serialVersionUID = -5286693953873839611L;
private static final DateTimeFormatter TIME_FORMAT =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX");
@JsonProperty("created_time")
private String createdTimeString;
@ -103,4 +109,22 @@ public final class VersionMetadata {
return version;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o == null || getClass() != o.getClass()) {
return false;
}
VersionMetadata that = (VersionMetadata) o;
return destroyed == that.destroyed &&
Objects.equals(createdTimeString, that.createdTimeString) &&
Objects.equals(deletionTimeString, that.deletionTimeString) &&
Objects.equals(version, that.version);
}
@Override
public int hashCode() {
return Objects.hash(createdTimeString, deletionTimeString, destroyed, version);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -25,6 +25,7 @@ import de.stklcode.jvault.connector.model.response.*;
import de.stklcode.jvault.connector.test.Credentials;
import de.stklcode.jvault.connector.test.VaultConfiguration;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.condition.EnabledIf;
import org.junit.jupiter.api.io.TempDir;
import java.io.*;
@ -37,6 +38,7 @@ import java.util.regex.Pattern;
import static java.util.Collections.singletonMap;
import static org.apache.commons.io.FileUtils.copyDirectory;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.assumeFalse;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
@ -49,7 +51,7 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
* @since 0.1
*/
class HTTPVaultConnectorIT {
private static String VAULT_VERSION = "1.9.0"; // The vault version this test is supposed to run against.
private static String VAULT_VERSION = "1.14.0"; // The vault version this test is supposed to run against.
private static final String KEY1 = "E38bkCm0VhUvpdCKGQpcohhD9XmcHJ/2hreOSY019Lho";
private static final String KEY2 = "O5OHwDleY3IiPdgw61cgHlhsrEm6tVJkrxhF6QAnILd1";
private static final String KEY3 = "mw7Bm3nbt/UWa/juDjjL2EPQ04kiJ0saC5JEXwJvXYsB";
@ -57,6 +59,7 @@ class HTTPVaultConnectorIT {
private static final String USER_VALID = "validUser";
private static final String PASS_VALID = "validPass";
private static boolean legacy;
private Process vaultProcess;
private VaultConnector connector;
@ -67,6 +70,9 @@ class HTTPVaultConnectorIT {
VAULT_VERSION = System.getenv("VAULT_VERSION");
System.out.println("Vault version set to " + VAULT_VERSION);
}
if (compareVersions(VAULT_VERSION, "1.12.0") < 0) {
legacy = true;
}
}
/**
@ -80,11 +86,6 @@ class HTTPVaultConnectorIT {
// Initialize Vault.
VaultConfiguration config = initializeVault(tempDir, isTls);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Initialize connector.
HTTPVaultConnectorBuilder builder = HTTPVaultConnector.builder()
@ -551,6 +552,9 @@ class HTTPVaultConnectorIT {
@Nested
@DisplayName("App-ID Tests")
@EnabledIf(value = "de.stklcode.jvault.connector.HTTPVaultConnectorIT#isLegacy",
disabledReason = "AppID tests no longer available for Vault 1.12 and above")
@SuppressWarnings("deprecation")
class AppIdTests {
private static final String APP_ID = "152AEA38-85FB-47A8-9CBD-612D645BFACA";
private static final String USER_ID = "5ADF8218-D7FB-4089-9E38-287465DBF37E";
@ -561,7 +565,6 @@ class HTTPVaultConnectorIT {
@Test
@Order(10)
@DisplayName("Authenticate with App-ID")
@SuppressWarnings("deprecation")
void authAppIdTest() {
// Try unauthorized access first.
assumeFalse(connector.isAuthorized());
@ -584,7 +587,6 @@ class HTTPVaultConnectorIT {
@Test
@Order(20)
@DisplayName("Register App-ID")
@SuppressWarnings("deprecation")
void registerAppIdTest() {
// Authorize.
authRoot();
@ -908,7 +910,8 @@ class HTTPVaultConnectorIT {
assertFalse(res.getAuth().isOrphan(), "Root token should not be orphan");
// Starting with Vault 1.0 a warning "custom ID uses weaker SHA1.." is given.
assertEquals(1, res.getWarnings().size(), "Token creation did not return expected warning");
// Starting with Vault 1.11 a second warning "Endpoint ignored unrecognized parameters" is given.
assertFalse(res.getWarnings().isEmpty(), "Token creation did not return expected warning");
// Create token with attributes.
Token token2 = Token.builder()
@ -952,7 +955,11 @@ class HTTPVaultConnectorIT {
.withType(Token.Type.BATCH)
.build();
res = assertDoesNotThrow(() -> connector.createToken(token4), "Token creation failed");
assertTrue(res.getAuth().getClientToken().startsWith("b"), "Unexpected token prefix");
assertTrue(
// Expecting batch token. "hvb." Prefix as of Vault 1.10, "b." before.
res.getAuth().getClientToken().startsWith("b.") || res.getAuth().getClientToken().startsWith("hvb."),
"Unexpected token prefix"
);
assertEquals(1, res.getAuth().getPolicies().size(), "Invalid number of policies returned");
assertTrue(res.getAuth().getPolicies().contains("batchpolicy"), "Custom policy policy not set");
assertFalse(res.getAuth().isRenewable(), "Token should not be renewable");
@ -1073,8 +1080,13 @@ class HTTPVaultConnectorIT {
() -> connector.getAuthBackends(),
"Could not list supported auth backends"
);
assertEquals(4, supportedBackends.size());
assertTrue(supportedBackends.containsAll(List.of(AuthBackend.TOKEN, AuthBackend.USERPASS, AuthBackend.APPID, AuthBackend.APPROLE)));
if (legacy) {
assertEquals(4, supportedBackends.size());
assertTrue(supportedBackends.containsAll(List.of(AuthBackend.TOKEN, AuthBackend.USERPASS, AuthBackend.APPID, AuthBackend.APPROLE)));
} else {
assertEquals(3, supportedBackends.size());
assertTrue(supportedBackends.containsAll(List.of(AuthBackend.TOKEN, AuthBackend.USERPASS, AuthBackend.APPROLE)));
}
}
/**
@ -1200,7 +1212,11 @@ class HTTPVaultConnectorIT {
*/
private VaultConfiguration initializeVault(File dir, boolean tls) throws IllegalStateException, IOException {
File dataDir = new File(dir, "data");
copyDirectory(new File(getClass().getResource("/data_dir").getPath()), dataDir);
if (legacy) {
copyDirectory(new File(getClass().getResource("/data_dir_legacy").getPath()), dataDir);
} else {
copyDirectory(new File(getClass().getResource("/data_dir").getPath()), dataDir);
}
// Generate vault local unencrypted configuration.
VaultConfiguration config = new VaultConfiguration()
@ -1217,30 +1233,37 @@ class HTTPVaultConnectorIT {
}
// Write configuration file.
BufferedWriter bw = null;
File configFile;
try {
configFile = new File(dir, "vault.conf");
bw = new BufferedWriter(new FileWriter(configFile));
File configFile = new File(dir, "vault.conf");
try (BufferedWriter bw = new BufferedWriter(new FileWriter(configFile))) {
bw.write(config.toString());
} catch (IOException e) {
throw new IllegalStateException("Unable to generate config file", e);
} finally {
try {
if (bw != null)
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// Start vault process.
try {
vaultProcess = Runtime.getRuntime().exec("vault server -config " + configFile.toString());
vaultProcess = Runtime.getRuntime().exec("vault server -config " + configFile);
} catch (IOException e) {
throw new IllegalStateException("Unable to start vault. Make sure vault binary is in your executable path", e);
}
await().atMost(5, TimeUnit.SECONDS).until(() -> {
try (InputStream stdout = vaultProcess.getInputStream();
InputStreamReader reader = new InputStreamReader(stdout);
BufferedReader br = new BufferedReader(reader)) {
String line = br.readLine();
while (line != null) {
if (line.contains("Vault server started")) {
return true;
} else {
line = br.readLine();
}
}
return false;
}
});
return config;
}
@ -1265,28 +1288,14 @@ class HTTPVaultConnectorIT {
* @return port number
*/
private static Integer getFreePort() {
ServerSocket socket = null;
try {
socket = new ServerSocket(0);
try (ServerSocket socket = new ServerSocket(0)) {
socket.setReuseAddress(true);
int port = socket.getLocalPort();
try {
socket.close();
} catch (IOException e) {
// Ignore IOException on close()
}
return port;
return socket.getLocalPort();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
throw new IllegalStateException("Unable to find a free TCP port");
}
@ -1301,4 +1310,35 @@ class HTTPVaultConnectorIT {
th.printStackTrace(new PrintWriter(sw, true));
return sw.getBuffer().toString();
}
/**
* Compare two version strings.
*
* @param version1 Version 1
* @param version2 Version 2
* @return negative value if version 1 is smaller than version2, positive value of version 1 is greater, 0 if equal
*/
private static int compareVersions(String version1, String version2) {
int comparisonResult = 0;
String[] version1Splits = version1.split("\\.");
String[] version2Splits = version2.split("\\.");
int maxLengthOfVersionSplits = Math.max(version1Splits.length, version2Splits.length);
for (int i = 0; i < maxLengthOfVersionSplits; i++) {
Integer v1 = i < version1Splits.length ? Integer.parseInt(version1Splits[i]) : 0;
Integer v2 = i < version2Splits.length ? Integer.parseInt(version2Splits[i]) : 0;
int compare = v1.compareTo(v2);
if (compare != 0) {
comparisonResult = compare;
break;
}
}
return comparisonResult;
}
private static boolean isLegacy() {
return legacy;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,16 +16,14 @@
package de.stklcode.jvault.connector;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
import de.stklcode.jvault.connector.exception.ConnectionException;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.exception.PermissionDeniedException;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.function.Executable;
import java.io.IOException;
@ -40,6 +38,7 @@ import java.util.Collections;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static org.junit.jupiter.api.Assertions.*;
/**
@ -50,21 +49,10 @@ import static org.junit.jupiter.api.Assertions.*;
* @since 0.7.0
*/
class HTTPVaultConnectorTest {
private static WireMockServer wireMock;
@BeforeAll
static void prepare() {
// Initialize HTTP mock.
wireMock = new WireMockServer(WireMockConfiguration.options().dynamicPort());
wireMock.start();
WireMock.configureFor("localhost", wireMock.port());
}
@AfterAll
static void tearDown() {
wireMock.stop();
wireMock = null;
}
@RegisterExtension
static WireMockExtension wireMock = WireMockExtension.newInstance()
.options(wireMockConfig().dynamicPort())
.build();
/**
* Test exceptions thrown during request.
@ -108,7 +96,7 @@ class HTTPVaultConnectorTest {
// Now simulate a failing request that succeeds on second try.
connector = HTTPVaultConnector.builder(wireMock.url("/")).withNumberOfRetries(1).withTimeout(250).build();
WireMock.stubFor(
wireMock.stubFor(
WireMock.any(anyUrl())
.willReturn(aResponse().withStatus(500))
.willReturn(aResponse().withStatus(500))
@ -334,7 +322,7 @@ class HTTPVaultConnectorTest {
}
private void mockHttpResponse(int status, String body, String contentType) {
WireMock.stubFor(
wireMock.stubFor(
WireMock.any(anyUrl()).willReturn(
aResponse().withStatus(status).withBody(body).withHeader("Content-Type", contentType)
)

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,12 +16,9 @@
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -35,14 +32,21 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
* @author Stefan Kalscheuer
* @since 0.5.0
*/
class AppRoleSecretTest {
class AppRoleSecretTest extends AbstractModelTest<AppRoleSecret> {
private static final String TEST_ID = "abc123";
private static final Map<String, Object> TEST_META = new HashMap<>();
private static final List<String> TEST_CIDR = Arrays.asList("203.0.113.0/24", "198.51.100.0/24");
private static final Map<String, Object> TEST_META = Map.of(
"foo", "bar",
"number", 1337
);
private static final List<String> TEST_CIDR = List.of("203.0.113.0/24", "198.51.100.0/24");
static {
TEST_META.put("foo", "bar");
TEST_META.put("number", 1337);
AppRoleSecretTest() {
super(AppRoleSecret.class);
}
@Override
protected AppRoleSecret createFull() {
return new AppRoleSecret(TEST_ID, TEST_META, TEST_CIDR);
}
/**
@ -111,16 +115,14 @@ class AppRoleSecretTest {
*/
@Test
void jsonTest() throws NoSuchFieldException, IllegalAccessException {
ObjectMapper mapper = new ObjectMapper();
// A simple roundtrip first. All set fields should be present afterwards..
AppRoleSecret secret = new AppRoleSecret(TEST_ID, TEST_META, TEST_CIDR);
String secretJson = assertDoesNotThrow(() -> mapper.writeValueAsString(secret), "Serialization failed");
String secretJson = assertDoesNotThrow(() -> objectMapper.writeValueAsString(secret), "Serialization failed");
// CIDR list is comma-separated when used as input, but List otherwise, hence convert string to list.
String secretJson2 = commaSeparatedToList(secretJson);
AppRoleSecret secret2 = assertDoesNotThrow(
() -> mapper.readValue(secretJson2, AppRoleSecret.class),
() -> objectMapper.readValue(secretJson2, AppRoleSecret.class),
"Deserialization failed"
);
assertEquals(secret2.getId(), secret.getId());
@ -140,9 +142,9 @@ class AppRoleSecretTest {
assumeTrue(secret.getNumUses() == 678);
setPrivateField(secret, "ttl", 12345);
assumeTrue(secret.getTtl() == 12345);
String secretJson3 = assertDoesNotThrow(() -> mapper.writeValueAsString(secret), "Serialization failed");
String secretJson3 = assertDoesNotThrow(() -> objectMapper.writeValueAsString(secret), "Serialization failed");
secret2 = assertDoesNotThrow(
() -> mapper.readValue(commaSeparatedToList(secretJson3), AppRoleSecret.class),
() -> objectMapper.readValue(commaSeparatedToList(secretJson3), AppRoleSecret.class),
"Deserialization failed"
);
assertEquals(secret2.getId(), secret.getId());
@ -160,14 +162,13 @@ class AppRoleSecretTest {
"\"cidr_list\":[\"203.0.113.0/24\",\"198.51.100.0/24\"],\"secret_id_accessor\":\"TEST_ACCESSOR\"," +
"\"creation_time\":\"TEST_CREATION\",\"expiration_time\":\"TEST_EXPIRATION\"," +
"\"last_updated_time\":\"TEST_LASTUPDATE\",\"secret_id_num_uses\":678,\"secret_id_ttl\":12345}";
secret2 = assertDoesNotThrow(() -> mapper.readValue(secretJson4, AppRoleSecret.class), "Deserialization failed");
secret2 = assertDoesNotThrow(() -> objectMapper.readValue(secretJson4, AppRoleSecret.class), "Deserialization failed");
assertEquals("TEST_ACCESSOR", secret2.getAccessor());
assertEquals("TEST_CREATION", secret2.getCreationTime());
assertEquals("TEST_EXPIRATION", secret2.getExpirationTime());
assertEquals("TEST_LASTUPDATE", secret2.getLastUpdatedTime());
assertEquals(678, secret2.getNumUses());
assertEquals(12345, secret2.getTtl());
}
private static void setPrivateField(Object object, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
@ -182,5 +183,4 @@ class AppRoleSecretTest {
return json.replaceAll("\"cidr_list\":\"([^\"]*)\"", "\"cidr_list\":\\[$1\\]")
.replaceAll("(\\d+\\.\\d+\\.\\d+\\.\\d+/\\d+)", "\"$1\"");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,7 +17,6 @@
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@ -32,7 +31,7 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.4.0
*/
class AppRoleTest {
class AppRoleTest extends AbstractModelTest<AppRole> {
private static final String NAME = "TestRole";
private static final String ID = "test-id";
private static final Boolean BIND_SECRET_ID = true;
@ -56,6 +55,31 @@ class AppRoleTest {
private static final String JSON_FULL = String.format("{\"role_name\":\"%s\",\"role_id\":\"%s\",\"bind_secret_id\":%s,\"secret_id_bound_cidrs\":\"%s\",\"secret_id_num_uses\":%d,\"secret_id_ttl\":%d,\"enable_local_secret_ids\":%s,\"token_ttl\":%d,\"token_max_ttl\":%d,\"token_policies\":\"%s\",\"token_bound_cidrs\":\"%s\",\"token_explicit_max_ttl\":%d,\"token_no_default_policy\":%s,\"token_num_uses\":%d,\"token_period\":%d,\"token_type\":\"%s\"}",
NAME, ID, BIND_SECRET_ID, CIDR_1, SECRET_ID_NUM_USES, SECRET_ID_TTL, ENABLE_LOCAL_SECRET_IDS, TOKEN_TTL, TOKEN_MAX_TTL, POLICY, CIDR_1, TOKEN_EXPLICIT_MAX_TTL, TOKEN_NO_DEFAULT_POLICY, TOKEN_NUM_USES, TOKEN_PERIOD, TOKEN_TYPE.value());
AppRoleTest() {
super(AppRole.class);
}
@Override
protected AppRole createFull() {
return AppRole.builder(NAME)
.withId(ID)
.withBindSecretID(BIND_SECRET_ID)
.withSecretIdBoundCidrs(BOUND_CIDR_LIST)
.withTokenPolicies(POLICIES)
.withSecretIdNumUses(SECRET_ID_NUM_USES)
.withSecretIdTtl(SECRET_ID_TTL)
.withEnableLocalSecretIds(ENABLE_LOCAL_SECRET_IDS)
.withTokenTtl(TOKEN_TTL)
.withTokenMaxTtl(TOKEN_MAX_TTL)
.withTokenBoundCidrs(BOUND_CIDR_LIST)
.withTokenExplicitMaxTtl(TOKEN_EXPLICIT_MAX_TTL)
.withTokenNoDefaultPolicy(TOKEN_NO_DEFAULT_POLICY)
.withTokenNumUses(TOKEN_NUM_USES)
.withTokenPeriod(TOKEN_PERIOD)
.withTokenType(TOKEN_TYPE)
.build();
}
@BeforeAll
static void init() {
BOUND_CIDR_LIST.add(CIDR_1);
@ -85,7 +109,7 @@ class AppRoleTest {
assertNull(role.getTokenType());
// Optional fields should be ignored, so JSON string should only contain role_name.
assertEquals(JSON_MIN, new ObjectMapper().writeValueAsString(role));
assertEquals(JSON_MIN, objectMapper.writeValueAsString(role));
}
/**
@ -93,23 +117,7 @@ class AppRoleTest {
*/
@Test
void buildFullTest() throws JsonProcessingException {
AppRole role = AppRole.builder(NAME)
.withId(ID)
.withBindSecretID(BIND_SECRET_ID)
.withSecretIdBoundCidrs(BOUND_CIDR_LIST)
.withTokenPolicies(POLICIES)
.withSecretIdNumUses(SECRET_ID_NUM_USES)
.withSecretIdTtl(SECRET_ID_TTL)
.withEnableLocalSecretIds(ENABLE_LOCAL_SECRET_IDS)
.withTokenTtl(TOKEN_TTL)
.withTokenMaxTtl(TOKEN_MAX_TTL)
.withTokenBoundCidrs(BOUND_CIDR_LIST)
.withTokenExplicitMaxTtl(TOKEN_EXPLICIT_MAX_TTL)
.withTokenNoDefaultPolicy(TOKEN_NO_DEFAULT_POLICY)
.withTokenNumUses(TOKEN_NUM_USES)
.withTokenPeriod(TOKEN_PERIOD)
.withTokenType(TOKEN_TYPE)
.build();
AppRole role = createFull();
assertEquals(NAME, role.getName());
assertEquals(ID, role.getId());
assertEquals(BIND_SECRET_ID, role.getBindSecretId());
@ -128,7 +136,7 @@ class AppRoleTest {
assertEquals(TOKEN_TYPE.value(), role.getTokenType());
// Verify that all parameters are included in JSON string.
assertEquals(JSON_FULL, new ObjectMapper().writeValueAsString(role));
assertEquals(JSON_FULL, objectMapper.writeValueAsString(role));
}
/**

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,7 +17,6 @@
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
@ -26,21 +25,29 @@ import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit Test for {@link Token.Builder}
* Unit Test for {@link TokenRole} and {@link TokenRole.Builder}.
*
* @author Stefan Kalscheuer
* @since 0.9
*/
class TokenRoleBuilderTest {
class TokenRoleTest extends AbstractModelTest<TokenRole> {
private static final String NAME = "test-role";
private static final String ALLOWED_POLICY_1 = "apol-1";
private static final String ALLOWED_POLICY_2 = "apol-2";
private static final String ALLOWED_POLICY_3 = "apol-3";
private static final List<String> ALLOWED_POLICIES = Arrays.asList(ALLOWED_POLICY_1, ALLOWED_POLICY_2);
private static final String ALLOWED_POLICY_GLOB_1 = "apol-g1*";
private static final String ALLOWED_POLICY_GLOB_2 = "apol-g2*";
private static final String ALLOWED_POLICY_GLOB_3 = "apol-g3*";
private static final List<String> ALLOWED_POLICIES_GLOB = Arrays.asList(ALLOWED_POLICY_GLOB_2, ALLOWED_POLICY_GLOB_3);
private static final String DISALLOWED_POLICY_1 = "dpol-1";
private static final String DISALLOWED_POLICY_2 = "dpol-2";
private static final String DISALLOWED_POLICY_3 = "dpol-3";
private static final List<String> DISALLOWED_POLICIES = Arrays.asList(DISALLOWED_POLICY_2, DISALLOWED_POLICY_3);
private static final String DISALLOWED_POLICY_GLOB_1 = "dpol-g1*";
private static final String DISALLOWED_POLICY_GLOB_2 = "dpol-g2*";
private static final String DISALLOWED_POLICY_GLOB_3 = "dpol-g3*";
private static final List<String> DISALLOWED_POLICIES_GLOB = Arrays.asList(DISALLOWED_POLICY_GLOB_1, DISALLOWED_POLICY_GLOB_2);
private static final Boolean ORPHAN = false;
private static final Boolean RENEWABLE = true;
private static final String PATH_SUFFIX = "ps";
@ -61,7 +68,9 @@ class TokenRoleBuilderTest {
private static final String JSON_FULL = "{" +
"\"name\":\"" + NAME + "\"," +
"\"allowed_policies\":[\"" + ALLOWED_POLICY_1 + "\",\"" + ALLOWED_POLICY_2 + "\",\"" + ALLOWED_POLICY_3 + "\"]," +
"\"allowed_policies_glob\":[\"" + ALLOWED_POLICY_GLOB_1 + "\",\"" + ALLOWED_POLICY_GLOB_2 + "\",\"" + ALLOWED_POLICY_GLOB_3 + "\"]," +
"\"disallowed_policies\":[\"" + DISALLOWED_POLICY_1 + "\",\"" + DISALLOWED_POLICY_2 + "\",\"" + DISALLOWED_POLICY_3 + "\"]," +
"\"disallowed_policies_glob\":[\"" + DISALLOWED_POLICY_GLOB_1 + "\",\"" + DISALLOWED_POLICY_GLOB_2 + "\",\"" + DISALLOWED_POLICY_GLOB_3 + "\"]," +
"\"orphan\":" + ORPHAN + "," +
"\"renewable\":" + RENEWABLE + "," +
"\"path_suffix\":\"" + PATH_SUFFIX + "\"," +
@ -73,6 +82,37 @@ class TokenRoleBuilderTest {
"\"token_period\":" + TOKEN_PERIOD + "," +
"\"token_type\":\"" + TOKEN_TYPE.value() + "\"}";
TokenRoleTest() {
super(TokenRole.class);
}
@Override
protected TokenRole createFull() {
return TokenRole.builder()
.forName(NAME)
.withAllowedPolicies(ALLOWED_POLICIES)
.withAllowedPolicy(ALLOWED_POLICY_3)
.withAllowedPolicyGlob(ALLOWED_POLICY_GLOB_1)
.withAllowedPoliciesGlob(ALLOWED_POLICIES_GLOB)
.withDisallowedPolicy(DISALLOWED_POLICY_1)
.withDisallowedPolicies(DISALLOWED_POLICIES)
.withDisallowedPoliciesGlob(DISALLOWED_POLICIES_GLOB)
.withDisallowedPolicyGlob(DISALLOWED_POLICY_GLOB_3)
.orphan(ORPHAN)
.renewable(RENEWABLE)
.withPathSuffix(PATH_SUFFIX)
.withAllowedEntityAliases(ALLOWED_ENTITY_ALIASES)
.withAllowedEntityAlias(ALLOWED_ENTITY_ALIAS_2)
.withTokenBoundCidr(TOKEN_BOUND_CIDR_3)
.withTokenBoundCidrs(TOKEN_BOUND_CIDRS)
.withTokenExplicitMaxTtl(TOKEN_EXPLICIT_MAX_TTL)
.withTokenNoDefaultPolicy(TOKEN_NO_DEFAULT_POLICY)
.withTokenNumUses(TOKEN_NUM_USES)
.withTokenPeriod(TOKEN_PERIOD)
.withTokenType(TOKEN_TYPE)
.build();
}
/**
* Build token without any parameters.
*/
@ -92,7 +132,7 @@ class TokenRoleBuilderTest {
assertNull(role.getTokenType());
// Optional fields should be ignored, so JSON string should be empty.
assertEquals("{}", new ObjectMapper().writeValueAsString(role));
assertEquals("{}", objectMapper.writeValueAsString(role));
}
/**
@ -132,8 +172,11 @@ class TokenRoleBuilderTest {
assertNull(role.getTokenPeriod());
assertNull(role.getTokenType());
// Empty builder should be equal to no-arg construction.
assertEquals(role, new TokenRole());
// Optional fields should be ignored, so JSON string should be empty.
assertEquals("{}", new ObjectMapper().writeValueAsString(role));
assertEquals("{}", objectMapper.writeValueAsString(role));
}
/**
@ -141,30 +184,16 @@ class TokenRoleBuilderTest {
*/
@Test
void buildFullTest() throws JsonProcessingException {
TokenRole role = TokenRole.builder()
.forName(NAME)
.withAllowedPolicies(ALLOWED_POLICIES)
.withAllowedPolicy(ALLOWED_POLICY_3)
.withDisallowedPolicy(DISALLOWED_POLICY_1)
.withDisallowedPolicies(DISALLOWED_POLICIES)
.orphan(ORPHAN)
.renewable(RENEWABLE)
.withPathSuffix(PATH_SUFFIX)
.withAllowedEntityAliases(ALLOWED_ENTITY_ALIASES)
.withAllowedEntityAlias(ALLOWED_ENTITY_ALIAS_2)
.withTokenBoundCidr(TOKEN_BOUND_CIDR_3)
.withTokenBoundCidrs(TOKEN_BOUND_CIDRS)
.withTokenExplicitMaxTtl(TOKEN_EXPLICIT_MAX_TTL)
.withTokenNoDefaultPolicy(TOKEN_NO_DEFAULT_POLICY)
.withTokenNumUses(TOKEN_NUM_USES)
.withTokenPeriod(TOKEN_PERIOD)
.withTokenType(TOKEN_TYPE)
.build();
TokenRole role = createFull();
assertEquals(NAME, role.getName());
assertEquals(ALLOWED_POLICIES.size() + 1, role.getAllowedPolicies().size());
assertTrue(role.getAllowedPolicies().containsAll(List.of(ALLOWED_POLICY_1, ALLOWED_POLICY_2, ALLOWED_POLICY_3)));
assertEquals(ALLOWED_POLICIES_GLOB.size() + 1, role.getAllowedPoliciesGlob().size());
assertTrue(role.getAllowedPoliciesGlob().containsAll(List.of(ALLOWED_POLICY_GLOB_1, ALLOWED_POLICY_GLOB_2, ALLOWED_POLICY_GLOB_3)));
assertEquals(DISALLOWED_POLICIES.size() + 1, role.getDisallowedPolicies().size());
assertTrue(role.getDisallowedPolicies().containsAll(List.of(DISALLOWED_POLICY_1, DISALLOWED_POLICY_2, DISALLOWED_POLICY_3)));
assertEquals(DISALLOWED_POLICIES_GLOB.size() + 1, role.getDisallowedPoliciesGlob().size());
assertTrue(role.getDisallowedPoliciesGlob().containsAll(List.of(DISALLOWED_POLICY_GLOB_1, DISALLOWED_POLICY_GLOB_2, DISALLOWED_POLICY_GLOB_3)));
assertEquals(ORPHAN, role.getOrphan());
assertEquals(RENEWABLE, role.getRenewable());
assertEquals(PATH_SUFFIX, role.getPathSuffix());
@ -178,6 +207,6 @@ class TokenRoleBuilderTest {
assertEquals(TOKEN_TYPE.value(), role.getTokenType());
// Verify that all parameters are included in JSON string.
assertEquals(JSON_FULL, new ObjectMapper().writeValueAsString(role));
assertEquals(JSON_FULL, objectMapper.writeValueAsString(role));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,7 +17,6 @@
package de.stklcode.jvault.connector.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@ -31,7 +30,7 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.4.0
*/
class TokenTest {
class TokenTest extends AbstractModelTest<Token> {
private static final String ID = "test-id";
private static final String DISPLAY_NAME = "display-name";
private static final Boolean NO_PARENT = false;
@ -53,6 +52,29 @@ class TokenTest {
private static final String ENTITY_ALIAS = "alias-value";
private static final String JSON_FULL = "{\"id\":\"test-id\",\"type\":\"service\",\"display_name\":\"display-name\",\"no_parent\":false,\"no_default_policy\":false,\"ttl\":123,\"explicit_max_ttl\":456,\"num_uses\":4,\"policies\":[\"policy\"],\"meta\":{\"key\":\"value\"},\"renewable\":true,\"period\":3600,\"entity_alias\":\"alias-value\"}";
TokenTest() {
super(Token.class);
}
@Override
protected Token createFull() {
return Token.builder()
.withId(ID)
.withType(Token.Type.SERVICE)
.withDisplayName(DISPLAY_NAME)
.withNoParent(NO_PARENT)
.withNoDefaultPolicy(NO_DEFAULT_POLICY)
.withTtl(TTL)
.withExplicitMaxTtl(EXPLICIT_MAX_TTL)
.withNumUses(NUM_USES)
.withPolicies(POLICIES)
.withMeta(META)
.withRenewable(RENEWABLE)
.withPeriod(PERIOD)
.withEntityAlias(ENTITY_ALIAS)
.build();
}
@BeforeAll
static void init() {
POLICIES.add(POLICY);
@ -80,7 +102,10 @@ class TokenTest {
assertNull(token.getEntityAlias());
// Optional fields should be ignored, so JSON string should be empty.
assertEquals("{}", new ObjectMapper().writeValueAsString(token));
assertEquals("{}", objectMapper.writeValueAsString(token));
// Empty builder should be equal to no-arg construction.
assertEquals(token, new Token());
}
/**
@ -88,21 +113,7 @@ class TokenTest {
*/
@Test
void buildFullTest() throws JsonProcessingException {
Token token = Token.builder()
.withId(ID)
.withType(Token.Type.SERVICE)
.withDisplayName(DISPLAY_NAME)
.withNoParent(NO_PARENT)
.withNoDefaultPolicy(NO_DEFAULT_POLICY)
.withTtl(TTL)
.withExplicitMaxTtl(EXPLICIT_MAX_TTL)
.withNumUses(NUM_USES)
.withPolicies(POLICIES)
.withMeta(META)
.withRenewable(RENEWABLE)
.withPeriod(PERIOD)
.withEntityAlias(ENTITY_ALIAS)
.build();
Token token = createFull();
assertEquals(ID, token.getId());
assertEquals(Token.Type.SERVICE.value(), token.getType());
assertEquals(DISPLAY_NAME, token.getDisplayName());
@ -117,7 +128,7 @@ class TokenTest {
assertEquals(PERIOD, token.getPeriod());
// Verify that all parameters are included in JSON string.
assertEquals(JSON_FULL, new ObjectMapper().writeValueAsString(token));
assertEquals(JSON_FULL, objectMapper.writeValueAsString(token));
}
/**

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,14 +16,13 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import de.stklcode.jvault.connector.model.AuthBackend;
import de.stklcode.jvault.connector.model.response.embedded.AuthMethod;
import org.junit.jupiter.api.Test;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@ -35,12 +34,16 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class AuthMethodsResponseTest {
class AuthMethodsResponseTest extends AbstractModelTest<AuthMethodsResponse> {
private static final String GH_PATH = "github/";
private static final String GH_TYPE = "github";
private static final String GH_UUID = "4b42d1a4-0a0d-3c88-ae90-997e0c8b41be";
private static final String GH_ACCESSOR = "auth_github_badd7fd0";
private static final String GH_DESCR = "GitHub auth";
private static final String TK_PATH = "token/";
private static final String TK_TYPE = "token";
private static final String TK_UUID = "32ea9681-6bd6-6cec-eec3-d11260ba9741";
private static final String TK_ACCESSOR = "auth_token_ac0dd95a";
private static final String TK_DESCR = "token based credentials";
private static final Integer TK_LEASE_TTL = 0;
private static final Integer TK_MAX_LEASE_TTL = 0;
@ -48,8 +51,13 @@ class AuthMethodsResponseTest {
private static final String RES_JSON = "{\n" +
" \"data\": {" +
" \"" + GH_PATH + "\": {\n" +
" \"uuid\": \"" + GH_UUID + "\",\n" +
" \"type\": \"" + GH_TYPE + "\",\n" +
" \"description\": \"" + GH_DESCR + "\"\n" +
" \"accessor\": \"" + GH_ACCESSOR + "\",\n" +
" \"description\": \"" + GH_DESCR + "\",\n" +
" \"external_entropy_access\": false,\n" +
" \"local\": false,\n" +
" \"seal_wrap\": false\n" +
" },\n" +
" \"" + TK_PATH + "\": {\n" +
" \"config\": {\n" +
@ -57,15 +65,28 @@ class AuthMethodsResponseTest {
" \"max_lease_ttl\": " + TK_MAX_LEASE_TTL + "\n" +
" },\n" +
" \"description\": \"" + TK_DESCR + "\",\n" +
" \"type\": \"" + TK_TYPE + "\"\n" +
" \"type\": \"" + TK_TYPE + "\",\n" +
" \"uuid\": \"" + TK_UUID + "\",\n" +
" \"accessor\": \"" + TK_ACCESSOR + "\",\n" +
" \"external_entropy_access\": false,\n" +
" \"local\": true,\n" +
" \"seal_wrap\": false\n" +
" }\n" +
" }\n" +
"}";
private static final Map<String, Object> INVALID_DATA = new HashMap<>();
AuthMethodsResponseTest() {
super(AuthMethodsResponse.class);
}
static {
INVALID_DATA.put("dummy/", new Dummy());
@Override
protected AuthMethodsResponse createFull() {
try {
return objectMapper.readValue(RES_JSON, AuthMethodsResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
@ -76,13 +97,6 @@ class AuthMethodsResponseTest {
// Create empty Object.
AuthMethodsResponse res = new AuthMethodsResponse();
assertEquals(Collections.emptyMap(), res.getSupportedMethods(), "Initial method map should be empty");
// Parsing invalid data map should fail.
assertThrows(
InvalidResponseException.class,
() -> res.setData(INVALID_DATA),
"Parsing invalid data succeeded"
);
}
/**
@ -91,7 +105,7 @@ class AuthMethodsResponseTest {
@Test
void jsonRoundtrip() {
AuthMethodsResponse res = assertDoesNotThrow(
() -> new ObjectMapper().readValue(RES_JSON, AuthMethodsResponse.class),
() -> objectMapper.readValue(RES_JSON, AuthMethodsResponse.class),
"AuthResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
@ -107,19 +121,31 @@ class AuthMethodsResponseTest {
assertEquals(AuthBackend.GITHUB, method.getType(), "Incorrect parsed type for GitHub");
assertEquals(GH_DESCR, method.getDescription(), "Incorrect description for GitHub");
assertNull(method.getConfig(), "Unexpected config for GitHub");
assertEquals(GH_UUID, method.getUuid(), "Unexpected UUID for GitHub");
assertEquals(GH_ACCESSOR, method.getAccessor(), "Unexpected accessor for GitHub");
assertFalse(method.isLocal(), "Unexpected local flag for GitHub");
assertFalse(method.isExternalEntropyAccess(), "Unexpected external entropy flag for GitHub");
assertFalse(method.isSealWrap(), "Unexpected seal wrap flag for GitHub");
// Verify first method.
// Verify second method.
method = supported.get(TK_PATH);
assertEquals(TK_TYPE, method.getRawType(), "Incorrect raw type for Token");
assertEquals(AuthBackend.TOKEN, method.getType(), "Incorrect parsed type for Token");
assertEquals(TK_DESCR, method.getDescription(), "Incorrect description for Token");
assertEquals(TK_UUID, method.getUuid(), "Unexpected UUID for Token");
assertEquals(TK_ACCESSOR, method.getAccessor(), "Unexpected accessor for Token");
assertTrue(method.isLocal(), "Unexpected local flag for Token");
assertFalse(method.isExternalEntropyAccess(), "Unexpected external entropy flag for Token");
assertFalse(method.isSealWrap(), "Unexpected seal wrap flag for GitHub");
assertNotNull(method.getConfig(), "Missing config for Token");
assertEquals(2, method.getConfig().size(), "Unexpected config size for Token");
assertEquals(TK_LEASE_TTL.toString(), method.getConfig().get("default_lease_ttl"), "Incorrect lease TTL config");
assertEquals(TK_MAX_LEASE_TTL.toString(), method.getConfig().get("max_lease_ttl"), "Incorrect max lease TTL config");
}
private static class Dummy {
assertEquals(
Map.of(
"default_lease_ttl", TK_LEASE_TTL.toString(),
"max_lease_ttl", TK_MAX_LEASE_TTL.toString()
),
method.getConfig(),
"Unexpected config for Token"
);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,12 +16,11 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import de.stklcode.jvault.connector.model.response.embedded.AuthData;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@ -33,7 +32,7 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class AuthResponseTest {
class AuthResponseTest extends AbstractModelTest<AuthResponse> {
private static final String AUTH_ACCESSOR = "2c84f488-2133-4ced-87b0-570f93a76830";
private static final String AUTH_CLIENT_TOKEN = "ABCD";
private static final String AUTH_POLICY_1 = "web";
@ -69,31 +68,18 @@ class AuthResponseTest {
" }\n" +
"}";
private static final Map<String, Object> INVALID_AUTH_DATA = new HashMap<>();
static {
INVALID_AUTH_DATA.put("policies", "fancy-policy");
AuthResponseTest() {
super(AuthResponse.class);
}
/**
* Test getter, setter and get-methods for response data.
*/
@Test
void getDataRoundtrip() {
// Create empty Object.
AuthResponse res = new AuthResponse();
assertNull(res.getData(), "Initial data should be empty");
// Parsing invalid auth data map should fail.
assertThrows(
InvalidResponseException.class,
() -> res.setAuth(INVALID_AUTH_DATA),
"Parsing invalid auth data succeeded"
);
// Data method should be agnostic.
res.setData(INVALID_AUTH_DATA);
assertEquals(INVALID_AUTH_DATA, res.getData(), "Data not passed through");
@Override
protected AuthResponse createFull() {
try {
return objectMapper.readValue(RES_JSON, AuthResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
@ -102,7 +88,7 @@ class AuthResponseTest {
@Test
void jsonRoundtrip() {
AuthResponse res = assertDoesNotThrow(
() -> new ObjectMapper().readValue(RES_JSON, AuthResponse.class),
() -> objectMapper.readValue(RES_JSON, AuthResponse.class),
"AuthResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,14 +16,12 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link CredentialsResponse} model.
@ -31,14 +29,33 @@ import static org.junit.jupiter.api.Assertions.assertNull;
* @author Stefan Kalscheuer
* @since 0.8
*/
class CredentialsResponseTest {
private static final Map<String, Object> DATA = new HashMap<>();
class CredentialsResponseTest extends AbstractModelTest<CredentialsResponse> {
private static final String VAL_USER = "testUserName";
private static final String VAL_PASS = "5up3r5ecr3tP455";
private static final String JSON = "{\n" +
" \"request_id\": \"68315073-6658-e3ff-2da7-67939fb91bbd\",\n" +
" \"lease_id\": \"\",\n" +
" \"lease_duration\": 2764800,\n" +
" \"renewable\": false,\n" +
" \"data\": {\n" +
" \"username\": \"" + VAL_USER + "\",\n" +
" \"password\": \"" + VAL_PASS + "\"\n" +
" },\n" +
" \"warnings\": null\n" +
"}";
static {
DATA.put("username", VAL_USER);
DATA.put("password", VAL_PASS);
CredentialsResponseTest() {
super(CredentialsResponse.class);
}
@Override
protected CredentialsResponse createFull() {
try {
return objectMapper.readValue(JSON, CredentialsResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
@ -47,15 +64,16 @@ class CredentialsResponseTest {
* @throws InvalidResponseException Should not occur
*/
@Test
@SuppressWarnings("unchecked")
void getCredentialsTest() throws InvalidResponseException {
// Create empty Object.
CredentialsResponse res = new CredentialsResponse();
assertNull(res.getUsername(), "Username not present in data map should not return anything");
assertNull(res.getPassword(), "Password not present in data map should not return anything");
// Fill data map.
res.setData(DATA);
res = assertDoesNotThrow(
() -> objectMapper.readValue(JSON, CredentialsResponse.class),
"Deserialization of CredentialsResponse failed"
);
assertEquals(VAL_USER, res.getUsername(), "Incorrect username");
assertEquals(VAL_PASS, res.getPassword(), "Incorrect password");
}

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,7 +16,8 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
@ -27,7 +28,7 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.7.0
*/
class HealthResponseTest {
class HealthResponseTest extends AbstractModelTest<HealthResponse> {
private static final String CLUSTER_ID = "c9abceea-4f46-4dab-a688-5ce55f89e228";
private static final String CLUSTER_NAME = "vault-cluster-5515c810";
private static final String VERSION = "0.9.2";
@ -47,18 +48,32 @@ class HealthResponseTest {
" \"standby\": " + STANDBY + ",\n" +
" \"sealed\": " + SEALED + ",\n" +
" \"initialized\": " + INITIALIZED + ",\n" +
" \"replication_perf_mode\": \"" + REPL_PERF_MODE + "\",\n" +
" \"replication_performance_mode\": \"" + REPL_PERF_MODE + "\",\n" +
" \"replication_dr_mode\": \"" + REPL_DR_MODE + "\",\n" +
" \"performance_standby\": " + PERF_STANDBY + "\n" +
"}";
HealthResponseTest() {
super(HealthResponse.class);
}
@Override
protected HealthResponse createFull() {
try {
return objectMapper.readValue(RES_JSON, HealthResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
*/
@Test
void jsonRoundtrip() {
HealthResponse res = assertDoesNotThrow(
() -> new ObjectMapper().readValue(RES_JSON, HealthResponse.class),
() -> objectMapper.readValue(RES_JSON, HealthResponse.class),
"Health deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,33 +16,21 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
/**
* JUnit Test for {@link SecretResponse} model.
* JUnit Test for {@link MetaSecretResponse} model.
*
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class SecretResponseTest {
private static final Map<String, Object> DATA = new HashMap<>();
private static final String KEY_UNKNOWN = "unknown";
private static final String KEY_STRING = "test1";
private static final String VAL_STRING = "testvalue";
private static final String KEY_INTEGER = "test2";
private static final Integer VAL_INTEGER = 42;
private static final String KEY_LIST = "list";
private static final String VAL_LIST = "[\"first\",\"second\"]";
class MetaSecretResponseTest extends AbstractModelTest<MetaSecretResponse> {
private static final String SECRET_REQUEST_ID = "68315073-6658-e3ff-2da7-67939fb91bbd";
private static final String SECRET_LEASE_ID = "";
private static final Integer SECRET_LEASE_DURATION = 2764800;
@ -54,17 +42,6 @@ class SecretResponseTest {
private static final String SECRET_META_CREATED = "2018-03-22T02:24:06.945319214Z";
private static final String SECRET_META_DELETED = "2018-03-23T03:25:07.056420325Z";
private static final List<String> SECRET_WARNINGS = null;
private static final String SECRET_JSON = "{\n" +
" \"request_id\": \"" + SECRET_REQUEST_ID + "\",\n" +
" \"lease_id\": \"" + SECRET_LEASE_ID + "\",\n" +
" \"lease_duration\": " + SECRET_LEASE_DURATION + ",\n" +
" \"renewable\": " + SECRET_RENEWABLE + ",\n" +
" \"data\": {\n" +
" \"" + SECRET_DATA_K1 + "\": \"" + SECRET_DATA_V1 + "\",\n" +
" \"" + SECRET_DATA_K2 + "\": \"" + SECRET_DATA_V2 + "\"\n" +
" },\n" +
" \"warnings\": " + SECRET_WARNINGS + "\n" +
"}";
private static final String SECRET_JSON_V2 = "{\n" +
" \"request_id\": \"" + SECRET_REQUEST_ID + "\",\n" +
" \"lease_id\": \"" + SECRET_LEASE_ID + "\",\n" +
@ -104,49 +81,18 @@ class SecretResponseTest {
" \"warnings\": " + SECRET_WARNINGS + "\n" +
"}";
static {
DATA.put(KEY_STRING, VAL_STRING);
DATA.put(KEY_INTEGER, VAL_INTEGER);
DATA.put(KEY_LIST, VAL_LIST);
MetaSecretResponseTest() {
super(MetaSecretResponse.class);
}
/**
* Test getter, setter and get-methods for response data.
*
* @throws InvalidResponseException Should not occur
*/
@Test
@SuppressWarnings("unchecked")
void getDataRoundtrip() throws InvalidResponseException {
// Create empty Object.
SecretResponse res = new SecretResponse();
assertNotNull(res.getData(), "Initial data should be Map");
assertTrue(res.getData().isEmpty(), "Initial data should be empty");
assertNull(res.get(KEY_STRING), "Getter should return NULL on empty data map");
// Fill data map.
res.setData(DATA);
assertEquals(DATA, res.getData(), "Data setter/getter not transparent");
assertEquals(DATA.size(), res.getData().keySet().size(), "Data size modified");
assertTrue(res.getData().keySet().containsAll(Set.of(KEY_STRING, KEY_INTEGER, KEY_LIST)), "Data keys not passed correctly");
assertEquals(VAL_STRING, res.get(KEY_STRING), "Data values not passed correctly");
assertEquals(VAL_INTEGER, res.get(KEY_INTEGER), "Data values not passed correctly");
assertNull(res.get(KEY_UNKNOWN), "Non-Null returned on unknown key");
// Try explicit JSON conversion.
final List<?> list = res.get(KEY_LIST, List.class);
assertNotNull(list, "JSON parsing of list failed");
assertEquals(2, list.size(), "JSON parsing of list returned incorrect size");
assertTrue(list.containsAll(List.of("first", "second")), "JSON parsing of list returned incorrect elements");
assertNull(res.get(KEY_UNKNOWN, Object.class), "Non-Null returned on unknown key");
// Requesting invalid class should result in Exception.
assertThrows(
InvalidResponseException.class,
() -> res.get(KEY_LIST, Double.class),
"JSON parsing to incorrect type succeeded"
);
@Override
protected MetaSecretResponse createFull() {
try {
return objectMapper.readValue(SECRET_JSON_V2, MetaSecretResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
@ -154,15 +100,9 @@ class SecretResponseTest {
*/
@Test
void jsonRoundtrip() {
SecretResponse res = assertDoesNotThrow(
() -> new ObjectMapper().readValue(SECRET_JSON, SecretResponse.class),
"SecretResponse deserialization failed"
);
assertSecretData(res);
// KV v2 secret.
res = assertDoesNotThrow(
() -> new ObjectMapper().readValue(SECRET_JSON_V2, SecretResponse.class),
MetaSecretResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(SECRET_JSON_V2, MetaSecretResponse.class),
"SecretResponse deserialization failed"
);
assertSecretData(res);
@ -171,12 +111,12 @@ class SecretResponseTest {
assertNotNull(res.getMetadata().getCreatedTime(), "Creation date parsing failed");
assertEquals("", res.getMetadata().getDeletionTimeString(), "Incorrect deletion date string");
assertNull(res.getMetadata().getDeletionTime(), "Incorrect deletion date");
assertEquals(false, res.getMetadata().isDestroyed(), "Secret destroyed when not expected");
assertFalse(res.getMetadata().isDestroyed(), "Secret destroyed when not expected");
assertEquals(1, res.getMetadata().getVersion(), "Incorrect secret version");
// Deleted KV v2 secret.
res = assertDoesNotThrow(
() -> new ObjectMapper().readValue(SECRET_JSON_V2_2, SecretResponse.class),
() -> objectMapper.readValue(SECRET_JSON_V2_2, MetaSecretResponse.class),
"SecretResponse deserialization failed"
);
assertSecretData(res);
@ -185,12 +125,13 @@ class SecretResponseTest {
assertNotNull(res.getMetadata().getCreatedTime(), "Creation date parsing failed");
assertEquals(SECRET_META_DELETED, res.getMetadata().getDeletionTimeString(), "Incorrect deletion date string");
assertNotNull(res.getMetadata().getDeletionTime(), "Incorrect deletion date");
assertEquals(true, res.getMetadata().isDestroyed(), "Secret destroyed when not expected");
assertTrue(res.getMetadata().isDestroyed(), "Secret destroyed when not expected");
assertEquals(2, res.getMetadata().getVersion(), "Incorrect secret version");
}
private void assertSecretData(SecretResponse res) {
assertNotNull(res, "Parsed response is NULL");
assertEquals(SECRET_REQUEST_ID, res.getRequestId(), "Incorrect request ID");
assertEquals(SECRET_LEASE_ID, res.getLeaseId(), "Incorrect lease ID");
assertEquals(SECRET_LEASE_DURATION, res.getLeaseDuration(), "Incorrect lease duration");
assertEquals(SECRET_RENEWABLE, res.isRenewable(), "Incorrect renewable status");

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,7 +16,8 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
@ -27,7 +28,7 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.8
*/
class MetadataResponseTest {
class MetadataResponseTest extends AbstractModelTest<MetadataResponse> {
private static final String V1_TIME = "2018-03-22T02:24:06.945319214Z";
private static final String V3_TIME = "2018-03-22T02:36:43.986212308Z";
private static final String V2_TIME = "2018-03-22T02:36:33.954880664Z";
@ -62,13 +63,27 @@ class MetadataResponseTest {
" }\n" +
"}";
MetadataResponseTest() {
super(MetadataResponse.class);
}
@Override
protected MetadataResponse createFull() {
try {
return objectMapper.readValue(META_JSON, MetadataResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
*/
@Test
void jsonRoundtrip() {
MetadataResponse res = assertDoesNotThrow(
() -> new ObjectMapper().readValue(META_JSON, MetadataResponse.class),
() -> objectMapper.readValue(META_JSON, MetadataResponse.class),
"MetadataResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,7 +16,8 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
@ -27,16 +28,19 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.8
*/
class SealResponseTest {
class SealResponseTest extends AbstractModelTest<SealResponse> {
private static final String TYPE = "shamir";
private static final Integer THRESHOLD = 3;
private static final Integer SHARES = 5;
private static final Integer PROGRESS_SEALED = 2;
private static final Integer PROGRESS_UNSEALED = 0;
private static final String VERSION = "0.11.2";
private static final String VERSION = "1.8.2";
private static final String CLUSTER_NAME = "vault-cluster-d6ec3c7f";
private static final String CLUSTER_ID = "3e8b3fec-3749-e056-ba41-b62a63b997e8";
private static final String NONCE = "ef05d55d-4d2c-c594-a5e8-55bc88604c24";
private static final Boolean MIGRATION = false;
private static final Boolean RECOVERY_SEAL = false;
private static final String STORAGE_TYPE = "file";
private static final String RES_SEALED = "{\n" +
" \"type\": \"" + TYPE + "\",\n" +
@ -46,7 +50,10 @@ class SealResponseTest {
" \"n\": " + SHARES + ",\n" +
" \"progress\": " + PROGRESS_SEALED + ",\n" +
" \"nonce\": \"\",\n" +
" \"version\": \"" + VERSION + "\"\n" +
" \"version\": \"" + VERSION + "\",\n" +
" \"migration\": \"" + MIGRATION + "\",\n" +
" \"recovery_seal\": \"" + RECOVERY_SEAL + "\",\n" +
" \"storage_type\": \"" + STORAGE_TYPE + "\"\n" +
"}";
private static final String RES_UNSEALED = "{\n" +
@ -59,9 +66,26 @@ class SealResponseTest {
" \"version\": \"" + VERSION + "\",\n" +
" \"cluster_name\": \"" + CLUSTER_NAME + "\",\n" +
" \"cluster_id\": \"" + CLUSTER_ID + "\",\n" +
" \"nonce\": \"" + NONCE + "\"\n" +
" \"nonce\": \"" + NONCE + "\",\n" +
" \"migration\": \"" + MIGRATION + "\",\n" +
" \"recovery_seal\": \"" + RECOVERY_SEAL + "\",\n" +
" \"storage_type\": \"" + STORAGE_TYPE + "\"\n" +
"}";
SealResponseTest() {
super(SealResponse.class);
}
@Override
protected SealResponse createFull() {
try {
return objectMapper.readValue(RES_UNSEALED, SealResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test creation from JSON value as returned by Vault when sealed (JSON example close to Vault documentation).
*/
@ -69,8 +93,8 @@ class SealResponseTest {
void jsonRoundtripSealed() {
// First test sealed Vault's response.
SealResponse res = assertDoesNotThrow(
() -> new ObjectMapper().readValue(RES_SEALED, SealResponse.class),
"TokenResponse deserialization failed"
() -> objectMapper.readValue(RES_SEALED, SealResponse.class),
"SealResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
assertEquals(TYPE, res.getType(), "Incorrect seal type");
@ -81,6 +105,9 @@ class SealResponseTest {
assertEquals(PROGRESS_SEALED, res.getProgress(), "Incorrect progress");
assertEquals("", res.getNonce(), "Nonce not empty");
assertEquals(VERSION, res.getVersion(), "Incorrect version");
assertEquals(MIGRATION, res.getMigration(), "Incorrect migration");
assertEquals(RECOVERY_SEAL, res.getRecoverySeal(), "Incorrect recovery seal");
assertEquals(STORAGE_TYPE, res.getStorageType(), "Incorrect storage type");
// And the fields, that should not be filled.
assertNull(res.getClusterName(), "Cluster name should not be populated");
assertNull(res.getClusterId(), "Cluster ID should not be populated");
@ -88,8 +115,8 @@ class SealResponseTest {
// Not test unsealed Vault's response.
res = assertDoesNotThrow(
() -> new ObjectMapper().readValue(RES_UNSEALED, SealResponse.class),
"TokenResponse deserialization failed"
() -> objectMapper.readValue(RES_UNSEALED, SealResponse.class),
"SealResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
assertEquals(TYPE, res.getType(), "Incorrect seal type");
@ -102,5 +129,8 @@ class SealResponseTest {
assertEquals(VERSION, res.getVersion(), "Incorrect version");
assertEquals(CLUSTER_NAME, res.getClusterName(), "Incorrect cluster name");
assertEquals(CLUSTER_ID, res.getClusterId(), "Incorrect cluster ID");
assertEquals(MIGRATION, res.getMigration(), "Incorrect migration");
assertEquals(RECOVERY_SEAL, res.getRecoverySeal(), "Incorrect recovery seal");
assertEquals(STORAGE_TYPE, res.getStorageType(), "Incorrect storage type");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,10 +16,11 @@
package de.stklcode.jvault.connector.model.response;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import java.util.*;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@ -29,40 +30,46 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.8
*/
class SecretListResponseTest {
private static final Map<String, Object> DATA = new HashMap<>();
class SecretListResponseTest extends AbstractModelTest<SecretListResponse> {
private static final String KEY1 = "key1";
private static final String KEY2 = "key-2";
private static final List<String> KEYS = Arrays.asList(KEY1, KEY2);
private static final String JSON = "{\n" +
" \"auth\": null,\n" +
" \"data\": {\n" +
" \"keys\": [" +
" \"" + KEY1 + "\",\n" +
" \"" + KEY2 + "\"\n" +
" ]\n" +
" },\n" +
" \"lease_duration\": 2764800,\n" +
" \"lease_id\": \"\",\n" +
" \"renewable\": false\n" +
"}";
static {
DATA.put("keys", KEYS);
SecretListResponseTest() {
super(SecretListResponse.class);
}
@Override
protected SecretListResponse createFull() {
try {
return objectMapper.readValue(JSON, SecretListResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test getter, setter and get-methods for response data.
*
* @throws InvalidResponseException Should not occur
* Test JSON deserialization and key getter.
*/
@Test
void getKeysTest() throws InvalidResponseException {
// Create empty Object.
SecretListResponse res = new SecretListResponse();
assertNull(res.getKeys(), "Keys should be null without initialization");
// Provoke internal ClassCastException.
Map<String, Object> invalidData = new HashMap<>();
invalidData.put("keys", "some string");
assertThrows(
InvalidResponseException.class,
() -> res.setData(invalidData),
"Setting incorrect class succeeded"
void getKeysTest() {
SecretListResponse res = assertDoesNotThrow(
() -> objectMapper.readValue(JSON, SecretListResponse.class),
"SecretListResponse deserialization failed"
);
// Fill correct data.
res.setData(DATA);
assertNotNull(res.getKeys(), "Keys should be filled here");
assertEquals(2, res.getKeys().size(), "Unexpected number of keys");
assertTrue(res.getKeys().containsAll(Set.of(KEY1, KEY2)), "Unexpected keys");
assertEquals(List.of(KEY1, KEY2), res.getKeys(), "Unexpected secret keys");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,7 +16,8 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
@ -27,7 +28,7 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.8
*/
class SecretVersionResponseTest {
class SecretVersionResponseTest extends AbstractModelTest<SecretVersionResponse> {
private static final String CREATION_TIME = "2018-03-22T02:24:06.945319214Z";
private static final String DELETION_TIME = "2018-03-22T02:36:43.986212308Z";
private static final Integer VERSION = 42;
@ -41,20 +42,34 @@ class SecretVersionResponseTest {
" }\n" +
"}";
SecretVersionResponseTest() {
super(SecretVersionResponse.class);
}
@Override
protected SecretVersionResponse createFull() {
try {
return objectMapper.readValue(META_JSON, SecretVersionResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
* Test creation from JSON value as returned by Vault (JSON example copied from Vault documentation).
*/
@Test
void jsonRoundtrip() {
SecretVersionResponse res = assertDoesNotThrow(
() -> new ObjectMapper().readValue(META_JSON, SecretVersionResponse.class),
() -> objectMapper.readValue(META_JSON, SecretVersionResponse.class),
"SecretVersionResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");
assertNotNull(res.getMetadata(), "Parsed metadata is NULL");
assertEquals(CREATION_TIME, res.getMetadata().getCreatedTimeString(), "Incorrect created time");
assertEquals(DELETION_TIME, res.getMetadata().getDeletionTimeString(), "Incorrect deletion time");
assertEquals(false, res.getMetadata().isDestroyed(), "Incorrect destroyed state");
assertFalse(res.getMetadata().isDestroyed(), "Incorrect destroyed state");
assertEquals(VERSION, res.getMetadata().getVersion(), "Incorrect version");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 Stefan Kalscheuer
* Copyright 2016-2023 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,13 +16,12 @@
package de.stklcode.jvault.connector.model.response;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.jvault.connector.exception.InvalidResponseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import de.stklcode.jvault.connector.model.AbstractModelTest;
import de.stklcode.jvault.connector.model.response.embedded.TokenData;
import org.junit.jupiter.api.Test;
import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -34,7 +33,7 @@ import static org.junit.jupiter.api.Assertions.*;
* @author Stefan Kalscheuer
* @since 0.6.2
*/
class TokenResponseTest {
class TokenResponseTest extends AbstractModelTest<TokenResponse> {
private static final Integer TOKEN_CREATION_TIME = 1457533232;
private static final Integer TOKEN_TTL = 2764800;
private static final Integer TOKEN_EXPLICIT_MAX_TTL = 0;
@ -89,10 +88,18 @@ class TokenResponseTest {
" \"auth\": null\n" +
"}";
private static final Map<String, Object> INVALID_TOKEN_DATA = new HashMap<>();
TokenResponseTest() {
super(TokenResponse.class);
}
static {
INVALID_TOKEN_DATA.put("num_uses", "fourtytwo");
@Override
protected TokenResponse createFull() {
try {
return objectMapper.readValue(RES_JSON, TokenResponse.class);
} catch (JsonProcessingException e) {
fail("Creation of full model instance failed", e);
return null;
}
}
/**
@ -103,13 +110,6 @@ class TokenResponseTest {
// Create empty Object.
TokenResponse res = new TokenResponse();
assertNull(res.getData(), "Initial data should be empty");
// Parsing invalid data map should fail.
assertThrows(
InvalidResponseException.class,
() -> res.setData(INVALID_TOKEN_DATA),
"Parsing invalid token data succeeded"
);
}
/**
@ -118,7 +118,7 @@ class TokenResponseTest {
@Test
void jsonRoundtrip() {
TokenResponse res = assertDoesNotThrow(
() -> new ObjectMapper().readValue(RES_JSON, TokenResponse.class),
() -> objectMapper.readValue(RES_JSON, TokenResponse.class),
"TokenResponse deserialization failed"
);
assertNotNull(res, "Parsed response is NULL");

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1 @@
{"Value":"AAAAAQIq05o3NmsucipTxPrcRbT1sXpAJ8w2PpiShnof74Kuzf/4kkHj3AZL5AObGFLAkYUvUrv3RRmYBIhw6Jk4FCbgdQyJAjPNVUTwBun/kQVyzP5sQ9hUFgHJwINomtVDiDgPkOc92zk8ydr1hfnMmTAtS71G3xloHDn6CF/1Y9WI1PkHdSkZ8d+yBNxr+qjGyewrV3QVmQvAfpY56uQ6AOztItD9NgiPrtNP+clbCczsieY6Y9Ce2FZawmuKFi9svMcBtnEcMILV/SGt4iCiMgFwkCJ9gQsGEdWPifu6ITPB92LgT4Ccw4gVRO31QVcPl6S+FG6iCeN6lk2yRXYjyhBuU+GklouEZIsA6SoxlIXPZuvauyS1MWwMxtSOQUFVYr3kvtXzCpcpEHDyBOEUdxPaYUZXHNdhGtMr/JuJCN50t0ng5mEAqfhjoJfJ/tBTqAjySj4zmEHuY0RnqYLPmsp203Q="}

View File

@ -0,0 +1 @@
{"Value":"AAAAAQI695zhv1Tv/6m1Fx/L62lITd+ZWCi+xCDHkev2YtCSIDPrZgNzYnrCHG3cUjBePZt6NYUSgzvZTXbxZPN4rK2rPj/BN9xj9v1vH1woOMY6lNPmBR7r"}

View File

@ -0,0 +1 @@
{"Value":"AAAAAQKHd7fFuNKfj/RnIQoxQEOTorNNl1NfcVtynLwYvtvZGDvhAO34YmOFKJSQVSiT4Js08ik48DWWnZHCZzAyMlK0HqNGYQRzCkuHkzYpH0uLrTcddXLuKyc7j6IiRTl3qYb1pzdlTzDtlwsi4J7s+7orETS146yY/GnGPWM/Tmet7p5qOECRq7m04gBX0pnwZl12iRqWG4aHHY5D4aFp9KjKUBKCIhz2Tb9wcSKV/Aa/ct1d0K0k8pyu1r1OkaJqCQXQeIaJR/WBMECR4omezvg7IGCoBIkMjwFR1urSaB0xNdgk+ByZE0C5zeDfmVRylYlypPAlIBrGL/Q/d6+NWiiOzXdoQoqAa/Pyg7e2gClsKDBFDvSL1QVBdsnBIskDeig2t46Ew5qM00wY58BWlUxqjlCgsNm3nPHtWpc6+XiR4ZkEZ9VeEIQhwC/R+NxS+QCDKeuSfyZM3OqQBwOx22mTL0i86YzlUph0alBmDF1b1FkDbg46MSWTANrkov1LPDnOvvNet7pb0L6exN5Q+HKitmxn36E0KAiqj1hEaHMZF6Pe+IIScLPClgPNeMkZWLeD5kvLv9kfObTYneHVHqj8O9jGtk03T4vOoaUNJY9U0irBGzlV+GkneJUgBL1QBspfK4GvFvUrd0Ds/teayJba8HDxlpCEWr6h062BXsNPg5gUn4H/uvginsFng02M8IyrDA1QOb4XS1zdfrvq"}

View File

@ -0,0 +1 @@
{"Value":"AAAAAQKyaZ3WVPXS+CbQr/JTfSM4yHT5DN21JfJlKh7ALVkue05z4cy703LvXnlfx5ZRqszSbFAe98ZzwELK89SEq26v2GYe2/7tFYeIAp0YvWNe5uahL0N6KUhFArPtC9gMV+9f7ZdjRDS6AKIHmzWRiXVtTsb+j4MnE+RM9NmwmvpDDTRAFgzjxEQ9IT/nGXieacg49U8NhjmZMh9Dt/7db3e5bGRJFDc3IDuF5xgHr5q+NJBbGrU3X1siH0oiCUbHUKsssmbVI0rwf6lkhvFQIIckYRgwL8/70WjrfELZeN+CgBliwQ=="}

View File

@ -0,0 +1 @@
{"Value":"AAAAAQII71tl2nQI+IFOoGw3z5x+xUwHdaZUXNW2GLNCJaq7tc2Lv3cLz9loi+q9yDVm/tVDhqK8k0D8lA2adOOGXOiaituANawDLAZu8VrwzpX73+mwtoEk"}

View File

@ -0,0 +1 @@
{"Value":"AAAAAQKKxZ6U5JakeVWOBYonzhPVLF2WNyxMYFqpYnb000GLiTWD0kLJQG5rBFyPadehhAmlQQvy7zDpCf5RCcsZbeCTSIA9yUiGp+G2uBsXAgLYKRocHTw="}

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