7 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
17 changed files with 327 additions and 145 deletions

View File

@ -25,7 +25,7 @@ steps:
- name: setup-vault
image: alpine:latest
environment:
VAULT_VERSION: 1.13.3
VAULT_VERSION: 1.14.0
commands:
- wget -q -O vault_$${VAULT_VERSION}_linux_amd64.zip https://releases.hashicorp.com/vault/$${VAULT_VERSION}/vault_$${VAULT_VERSION}_linux_amd64.zip
- wget -q -O - https://releases.hashicorp.com/vault/$${VAULT_VERSION}/vault_$${VAULT_VERSION}_SHA256SUMS | grep linux_amd64 | sha256sum -c
@ -40,7 +40,7 @@ steps:
- name: unit-integration-tests
image: maven:3-eclipse-temurin-17
environment:
VAULT_VERSION: 1.13.3
VAULT_VERSION: 1.14.0
commands:
- export PATH=.bin:$${PATH}
- mvn -B -P integration-test verify

View File

@ -6,10 +6,10 @@ jobs:
strategy:
matrix:
jdk: [ 11, 17, 20 ]
vault: [ '1.2.0', '1.11.11', '1.13.3' ]
vault: [ '1.2.0', '1.11.12', '1.14.0' ]
include:
- jdk: 17
vault: '1.11.11'
vault: '1.11.12'
analysis: true
steps:
- name: Checkout

View File

@ -1,3 +1,9 @@
## 1.1.5 (2023-08-19)
### Fix
* Fixed JSON type conversion in `SecretResponse#get(String, Class)` (#67)
## 1.1.4 (2023-06-15)
### 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.2 to 1.13
* 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.1.4</version>
<version>1.1.5</version>
</dependency>
```

120
pom.xml
View File

@ -4,7 +4,7 @@
<groupId>de.stklcode.jvault</groupId>
<artifactId>jvault-connector</artifactId>
<version>1.1.4</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,6 +40,62 @@
<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>
<pluginManagement>
<plugins>
@ -60,7 +111,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>3.2.0</version>
<version>3.3.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -136,57 +187,6 @@
</pluginManagement>
</build>
<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.9.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.3.1</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.14.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>4.2.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>sources</id>
@ -316,7 +316,7 @@
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>8.2.1</version>
<version>8.3.1</version>
<executions>
<execution>
<goals>

View File

@ -75,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.
*
@ -108,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;
@ -419,7 +419,8 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
public final SecretResponse readSecretVersion(final String mount, final String key, final Integer version) throws VaultConnectorException {
public final SecretResponse readSecretVersion(final String mount, final String key, final Integer version)
throws VaultConnectorException {
requireAuth();
/* Request HTTP response and parse secret metadata */
Map<String, String> args = mapOfStrings("version", version);
@ -428,7 +429,8 @@ public class HTTPVaultConnector implements VaultConnector {
}
@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 */
@ -436,7 +438,10 @@ public class HTTPVaultConnector implements VaultConnector {
}
@Override
public void updateSecretMetadata(final String mount, final String key, final Integer maxVersions, final boolean casRequired) throws VaultConnectorException {
public void updateSecretMetadata(final String mount,
final String key,
final Integer maxVersions,
final boolean casRequired) throws VaultConnectorException {
requireAuth();
Map<String, Object> payload = mapOf(
@ -448,7 +453,10 @@ public class HTTPVaultConnector implements VaultConnector {
}
@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()) {
@ -480,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()) {
@ -521,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);
}
@ -545,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 */
@ -698,7 +713,7 @@ public class HTTPVaultConnector implements VaultConnector {
*/
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) {
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) {

View File

@ -422,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);
}
@ -440,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.
@ -455,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.
@ -484,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.
@ -529,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.
@ -576,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.
@ -588,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.
@ -600,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

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

View File

@ -34,17 +34,6 @@ import java.util.Objects;
public final class AppRole implements Serializable {
private static final long serialVersionUID = -6248529625864573990L;
/**
* Get {@link Builder} instance.
*
* @param name Role name.
* @return AppRole Builder.
* @since 0.8
*/
public static Builder builder(final String name) {
return new Builder(name);
}
@JsonProperty("role_name")
private String name;
@ -134,6 +123,17 @@ public final class AppRole implements Serializable {
this.tokenType = builder.tokenType != null ? builder.tokenType.value() : null;
}
/**
* Get {@link Builder} instance.
*
* @param name Role name.
* @return AppRole Builder.
* @since 0.8
*/
public static Builder builder(final String name) {
return new Builder(name);
}
/**
* @return the role name
*/

View File

@ -34,16 +34,6 @@ import java.util.*;
public final class Token implements Serializable {
private static final long serialVersionUID = 5208508683665365287L;
/**
* Get {@link Builder} instance.
*
* @return Token Builder.
* @since 0.8
*/
public static Builder builder() {
return new Builder();
}
@JsonProperty("id")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String id;
@ -123,6 +113,16 @@ public final class Token implements Serializable {
this.entityAlias = builder.entityAlias;
}
/**
* Get {@link Builder} instance.
*
* @return Token Builder.
* @since 0.8
*/
public static Builder builder() {
return new Builder();
}
/**
* @return Token ID
*/

View File

@ -36,15 +36,6 @@ import java.util.Objects;
public final class TokenRole implements Serializable {
private static final long serialVersionUID = -3505215215838576321L;
/**
* Get {@link Builder} instance.
*
* @return Token Role Builder.
*/
public static Builder builder() {
return new Builder();
}
@JsonProperty("name")
@JsonInclude(JsonInclude.Include.NON_NULL)
private String name;
@ -129,6 +120,15 @@ public final class TokenRole implements Serializable {
this.tokenType = builder.tokenType != null ? builder.tokenType.value() : null;
}
/**
* Get {@link Builder} instance.
*
* @return Token Role Builder.
*/
public static Builder builder() {
return new Builder();
}
/**
* @return Token Role name
*/
@ -264,7 +264,7 @@ public final class TokenRole implements Serializable {
@Override
public int hashCode() {
return Objects.hash(name, allowedPolicies, allowedPoliciesGlob, disallowedPolicies, disallowedPoliciesGlob,
orphan, renewable, pathSuffix, allowedEntityAliases, tokenBoundCidrs, tokenExplicitMaxTtl,
orphan, renewable, pathSuffix, allowedEntityAliases, tokenBoundCidrs, tokenExplicitMaxTtl,
tokenNoDefaultPolicy, tokenNumUses, tokenPeriod, tokenType);
}

View File

@ -41,7 +41,7 @@ public class MetaSecretResponse extends SecretResponse {
@Override
public final Map<String, Serializable> getData() {
if (secret != null) {
if (secret != null) {
return secret.getData();
} else {
return Collections.emptyMap();
@ -50,7 +50,7 @@ public class MetaSecretResponse extends SecretResponse {
@Override
public final VersionMetadata getMetadata() {
if (secret != null) {
if (secret != null) {
return secret.getMetadata();
} else {
return null;

View File

@ -79,8 +79,16 @@ public abstract class SecretResponse extends VaultDataResponse {
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

@ -37,7 +37,8 @@ import java.util.Objects;
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");
private static final DateTimeFormatter TIME_FORMAT =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX");
@JsonProperty("created_time")
private String createdTimeString;

View File

@ -36,7 +36,8 @@ import java.util.Objects;
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");
private static final DateTimeFormatter TIME_FORMAT =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX");
@JsonProperty("created_time")
private String createdTimeString;

View File

@ -51,7 +51,7 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
* @since 0.1
*/
class HTTPVaultConnectorIT {
private static String VAULT_VERSION = "1.13.3"; // 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";

View File

@ -16,11 +16,13 @@
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.List;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
@ -85,4 +87,137 @@ class PlainSecretResponseTest extends AbstractModelTest<PlainSecretResponse> {
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);
}
}
}