From 5f1f94f59c1ef1fce142f1c3d204200746e89d2d Mon Sep 17 00:00:00 2001 From: Stefan Kalscheuer Date: Sat, 22 Jun 2024 14:32:07 +0200 Subject: [PATCH] feat: add custom_metadata, cas_required and delete_version_after fields --- CHANGELOG.md | 1 + .../response/embedded/SecretMetadata.java | 44 +++++++++++++++++-- .../response/embedded/VersionMetadata.java | 20 +++++++-- .../response/MetaSecretResponseTest.java | 10 +++++ .../model/response/MetadataResponseTest.java | 14 ++++++ 5 files changed, 83 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c203d6..797fdb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * Add missing `num_uses` field to `AuthData` * Add `mount_type` attribute to common response model * Add `auth` attribute to common response model +* Add `custom_metadata`, `cas_required` and `delete_version_after` fields for KVv2 metadata ### Fix * Rename `enable_local_secret_id` to `local_secret_ids` in `AppRole` model diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/SecretMetadata.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/SecretMetadata.java index 99a1ee2..5451f0b 100644 --- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/SecretMetadata.java +++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/SecretMetadata.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.io.Serializable; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; +import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -34,7 +35,7 @@ import java.util.Objects; */ @JsonIgnoreProperties(ignoreUnknown = true) public final class SecretMetadata implements Serializable { - private static final long serialVersionUID = -4967896264361344676L; + private static final long serialVersionUID = -905059942871916214L; private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX"); @@ -57,6 +58,15 @@ public final class SecretMetadata implements Serializable { @JsonProperty("versions") private Map versions; + @JsonProperty("cas_required") + private Boolean casRequired; + + @JsonProperty("custom_metadata") + private HashMap customMetadata; + + @JsonProperty("delete_version_after") + private String deleteVersionAfter; + /** * @return Time of secret creation as raw string representation. * @deprecated Method left for backwards compatibility only. Use {@link #getCreatedTime()} instead. @@ -125,6 +135,30 @@ public final class SecretMetadata implements Serializable { return versions; } + /** + * @return CAS required? + * @since 1.3 + */ + public Boolean isCasRequired() { + return casRequired; + } + + /** + * @return Custom metadata. + * @since 1.3 + */ + public Map getCustomMetadata() { + return customMetadata; + } + + /** + * @return time duration to delete version + * @since 1.3 + */ + public String getDeleteVersionAfter() { + return deleteVersionAfter; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -138,11 +172,15 @@ public final class SecretMetadata implements Serializable { Objects.equals(maxVersions, that.maxVersions) && Objects.equals(oldestVersion, that.oldestVersion) && Objects.equals(updatedTime, that.updatedTime) && - Objects.equals(versions, that.versions); + Objects.equals(versions, that.versions) && + Objects.equals(casRequired, that.casRequired) && + Objects.equals(customMetadata, that.customMetadata) && + Objects.equals(deleteVersionAfter, that.deleteVersionAfter); } @Override public int hashCode() { - return Objects.hash(createdTime, currentVersion, maxVersions, oldestVersion, updatedTime, versions); + return Objects.hash(createdTime, currentVersion, maxVersions, oldestVersion, updatedTime, versions, casRequired, + customMetadata, deleteVersionAfter); } } diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/VersionMetadata.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/VersionMetadata.java index 49aa0c2..012e736 100644 --- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/VersionMetadata.java +++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/VersionMetadata.java @@ -22,6 +22,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import java.io.Serializable; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; /** @@ -33,7 +35,7 @@ import java.util.Objects; */ @JsonIgnoreProperties(ignoreUnknown = true) public final class VersionMetadata implements Serializable { - private static final long serialVersionUID = -6815731513868586713L; + private static final long serialVersionUID = 8495687554714216478L; private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXX"); @@ -50,6 +52,9 @@ public final class VersionMetadata implements Serializable { @JsonProperty("version") private Integer version; + @JsonProperty("custom_metadata") + private HashMap customMetadata; + /** * @return Time of secret creation as raw string representation. * @deprecated Method left for backwards compatibility only. Use {@link #getCreatedTime()} instead. @@ -104,6 +109,14 @@ public final class VersionMetadata implements Serializable { return version; } + /** + * @return Custom metadata. + * @since 1.3 + */ + public Map getCustomMetadata() { + return customMetadata; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -115,11 +128,12 @@ public final class VersionMetadata implements Serializable { return destroyed == that.destroyed && Objects.equals(createdTime, that.createdTime) && Objects.equals(deletionTime, that.deletionTime) && - Objects.equals(version, that.version); + Objects.equals(version, that.version) && + Objects.equals(customMetadata, that.customMetadata); } @Override public int hashCode() { - return Objects.hash(createdTime, deletionTime, destroyed, version); + return Objects.hash(createdTime, deletionTime, destroyed, version, customMetadata); } } diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/MetaSecretResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/MetaSecretResponseTest.java index b3e8194..6706d49 100644 --- a/src/test/java/de/stklcode/jvault/connector/model/response/MetaSecretResponseTest.java +++ b/src/test/java/de/stklcode/jvault/connector/model/response/MetaSecretResponseTest.java @@ -21,6 +21,7 @@ import de.stklcode.jvault.connector.model.AbstractModelTest; import org.junit.jupiter.api.Test; import java.util.List; +import java.util.Map; import static org.junit.jupiter.api.Assertions.*; @@ -42,6 +43,9 @@ class MetaSecretResponseTest extends AbstractModelTest { 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 SECRET_WARNINGS = null; + private static final String CUSTOM_META_KEY = "foo"; + private static final String CUSTOM_META_VAL = "bar"; + private static final String SECRET_JSON_V2 = "{\n" + " \"request_id\": \"" + SECRET_REQUEST_ID + "\",\n" + " \"lease_id\": \"" + SECRET_LEASE_ID + "\",\n" + @@ -54,6 +58,7 @@ class MetaSecretResponseTest extends AbstractModelTest { " },\n" + " \"metadata\": {\n" + " \"created_time\": \"" + SECRET_META_CREATED + "\",\n" + + " \"custom_metadata\": null,\n" + " \"deletion_time\": \"\",\n" + " \"destroyed\": false,\n" + " \"version\": 1\n" + @@ -73,6 +78,9 @@ class MetaSecretResponseTest extends AbstractModelTest { " },\n" + " \"metadata\": {\n" + " \"created_time\": \"" + SECRET_META_CREATED + "\",\n" + + " \"custom_metadata\": {" + + " \"" + CUSTOM_META_KEY + "\": \"" + CUSTOM_META_VAL + "\"" + + " },\n" + " \"deletion_time\": \"" + SECRET_META_DELETED + "\",\n" + " \"destroyed\": true,\n" + " \"version\": 2\n" + @@ -113,6 +121,7 @@ class MetaSecretResponseTest extends AbstractModelTest { assertNull(res.getMetadata().getDeletionTime(), "Incorrect deletion date"); assertFalse(res.getMetadata().isDestroyed(), "Secret destroyed when not expected"); assertEquals(1, res.getMetadata().getVersion(), "Incorrect secret version"); + assertNull(res.getMetadata().getCustomMetadata(), "Incorrect custom metadata"); // Deleted KV v2 secret. res = assertDoesNotThrow( @@ -127,6 +136,7 @@ class MetaSecretResponseTest extends AbstractModelTest { assertNotNull(res.getMetadata().getDeletionTime(), "Incorrect deletion date"); assertTrue(res.getMetadata().isDestroyed(), "Secret destroyed when not expected"); assertEquals(2, res.getMetadata().getVersion(), "Incorrect secret version"); + assertEquals(Map.of(CUSTOM_META_KEY, CUSTOM_META_VAL), res.getMetadata().getCustomMetadata(), "Incorrect custom metadata"); } private void assertSecretData(SecretResponse res) { diff --git a/src/test/java/de/stklcode/jvault/connector/model/response/MetadataResponseTest.java b/src/test/java/de/stklcode/jvault/connector/model/response/MetadataResponseTest.java index 932ac0d..2215e18 100644 --- a/src/test/java/de/stklcode/jvault/connector/model/response/MetadataResponseTest.java +++ b/src/test/java/de/stklcode/jvault/connector/model/response/MetadataResponseTest.java @@ -20,6 +20,8 @@ import com.fasterxml.jackson.core.JsonProcessingException; import de.stklcode.jvault.connector.model.AbstractModelTest; import org.junit.jupiter.api.Test; +import java.util.Map; + import static org.junit.jupiter.api.Assertions.*; /** @@ -35,11 +37,20 @@ class MetadataResponseTest extends AbstractModelTest { private static final Integer CURRENT_VERSION = 3; private static final Integer MAX_VERSIONS = 0; private static final Integer OLDEST_VERSION = 1; + private static final Boolean CAS_REQUIRED = false; + private static final String CUSTOM_META_KEY = "test"; + private static final String CUSTOM_META_VAL = "123"; + private static final String DELETE_VERSION_AFTER = "0s"; private static final String META_JSON = "{\n" + " \"data\": {\n" + + " \"cas_required\": " + CAS_REQUIRED + ",\n" + " \"created_time\": \"" + V1_TIME + "\",\n" + " \"current_version\": " + CURRENT_VERSION + ",\n" + + " \"custom_metadata\": {" + + " \"" + CUSTOM_META_KEY + "\": \"" + CUSTOM_META_VAL + "\"" + + " },\n" + + " \"delete_version_after\": \"" + DELETE_VERSION_AFTER + "\"," + " \"max_versions\": " + MAX_VERSIONS + ",\n" + " \"oldest_version\": " + OLDEST_VERSION + ",\n" + " \"updated_time\": \"" + V3_TIME + "\",\n" + @@ -88,11 +99,14 @@ class MetadataResponseTest extends AbstractModelTest { ); assertNotNull(res, "Parsed response is NULL"); assertNotNull(res.getMetadata(), "Parsed metadata is NULL"); + assertEquals(CAS_REQUIRED, res.getMetadata().isCasRequired(), "Incorrect CAS required flag"); assertEquals(V1_TIME, res.getMetadata().getCreatedTimeString(), "Incorrect created time"); assertNotNull(res.getMetadata().getCreatedTime(), "Parting created time failed"); assertEquals(CURRENT_VERSION, res.getMetadata().getCurrentVersion(), "Incorrect current version"); assertEquals(MAX_VERSIONS, res.getMetadata().getMaxVersions(), "Incorrect max versions"); assertEquals(OLDEST_VERSION, res.getMetadata().getOldestVersion(), "Incorrect oldest version"); + assertEquals(Map.of(CUSTOM_META_KEY, CUSTOM_META_VAL), res.getMetadata().getCustomMetadata(), "Incorrect custom metadata"); + assertEquals(DELETE_VERSION_AFTER, res.getMetadata().getDeleteVersionAfter(), "Incorrect delete version after"); assertEquals(V3_TIME, res.getMetadata().getUpdatedTimeString(), "Incorrect updated time"); assertNotNull(res.getMetadata().getUpdatedTime(), "Parting updated time failed"); assertEquals(3, res.getMetadata().getVersions().size(), "Incorrect number of versions");