Polishing.

Add author and since tags. Refine nullability and toString rendering.

Original pull request: gh-808
See gh-789
This commit is contained in:
Mark Paluch
2023-09-22 13:55:07 +02:00
parent c5a087acef
commit c7f47b2d5b
7 changed files with 112 additions and 95 deletions

View File

@@ -36,6 +36,7 @@ import org.springframework.vault.support.Versioned;
*
* @author Zakaria Amine
* @author Mark Paluch
* @author Jeroen Willemsen
* @since 2.3
*/
class VaultKeyValueMetadataTemplate implements VaultKeyValueMetadataOperations {
@@ -120,12 +121,8 @@ class VaultKeyValueMetadataTemplate implements VaultKeyValueMetadataOperations {
.createdAt(createdTime)
.deletedAt(deletionTime)
.destroyed(destroyed)
.version(kvVersion);
if (versionData.get("custom_metadata") != null) {
Map<String, String> customMetadata = (Map<String, String>) versionData.get("custom_metadata");
builder.customMetadata(customMetadata);
}
.version(kvVersion)
.customMetadata((Map<String, String>) versionData.get("custom_metadata"));
return builder.build();
}

View File

@@ -43,6 +43,7 @@ public interface VaultVersionedKeyValueOperations extends VaultKeyValueOperation
* @param path must not be {@literal null}.
* @return the data. May be {@literal null} if the path does not exist.
*/
@Override
@Nullable
default Versioned<Map<String, Object>> get(String path) {
return get(path, Version.unversioned());

View File

@@ -46,6 +46,7 @@ import org.springframework.web.client.HttpStatusCodeException;
*
* @author Mark Paluch
* @author Maciej Drozdzowski
* @author Jeroen Willemsen
* @since 2.1
*/
public class VaultVersionedKeyValueTemplate extends VaultKeyValue2Accessor implements VaultVersionedKeyValueOperations {
@@ -159,6 +160,7 @@ public class VaultVersionedKeyValueTemplate extends VaultKeyValue2Accessor imple
return getMetadata(response.getRequiredData());
}
@SuppressWarnings("unchecked")
private static Metadata getMetadata(Map<String, Object> responseMetadata) {
MetadataBuilder builder = Metadata.builder();
@@ -176,12 +178,8 @@ public class VaultVersionedKeyValueTemplate extends VaultKeyValue2Accessor imple
}
Integer version = (Integer) responseMetadata.get("version");
builder.version(Version.from(version));
if (responseMetadata.get("custom_metadata") != null) {
Map<String, String> customMetadata = (Map<String, String>) responseMetadata.get("custom_metadata");
builder.customMetadata(customMetadata);
}
builder.version(Version.from(version))
.customMetadata((Map<String, String>) responseMetadata.get("custom_metadata"));
return builder.build();
}

View File

@@ -26,6 +26,7 @@ import org.springframework.lang.Nullable;
* Value object to bind Vault HTTP kv metadata update API requests.
*
* @author Zakaria Amine
* @author Jeroen Willemsen
* @see <a href=
* "https://www.vaultproject.io/api-docs/secret/kv/kv-v2#update-metadata">Update
* Metadata</a>
@@ -43,28 +44,21 @@ public class VaultMetadataRequest {
private final String deleteVersionAfter;
@JsonProperty("custom_metadata")
private final Map<String, String> customMetadata;
private final @Nullable Map<String, String> customMetadata;
private VaultMetadataRequest(int maxVersions, boolean casRequired, @Nullable Duration deleteVersionAfter,
@Nullable Map<String, String> customMetadata) {
this.maxVersions = maxVersions;
private VaultMetadataRequest(boolean casRequired, @Nullable Map<String, String> customMetadata,
@Nullable Duration deleteVersionAfter, int maxVersions) {
this.casRequired = casRequired;
this.customMetadata = customMetadata;
this.deleteVersionAfter = DurationParser
.formatDuration(deleteVersionAfter != null ? deleteVersionAfter : Duration.ZERO);
this.customMetadata = customMetadata;
this.maxVersions = maxVersions;
}
public static VaultMetadataRequestBuilder builder() {
return new VaultMetadataRequestBuilder();
}
/**
* @return The number of versions to keep per key.
*/
public int getMaxVersions() {
return this.maxVersions;
}
/**
* @return If true all keys will require the cas parameter to be set on all write
* requests.
@@ -73,6 +67,11 @@ public class VaultMetadataRequest {
return this.casRequired;
}
@Nullable
public Map<String, String> getCustomMetadata() {
return this.customMetadata;
}
/**
* @return the deletion_time for all new versions written to this key. Accepts
* <a href="https://golang.org/pkg/time/#ParseDuration">Go duration format string</a>.
@@ -81,31 +80,33 @@ public class VaultMetadataRequest {
return this.deleteVersionAfter;
}
@Nullable
public Map<String, String> getCustomMetadata() {
return this.customMetadata;
/**
* @return The number of versions to keep per key.
*/
public int getMaxVersions() {
return this.maxVersions;
}
public static class VaultMetadataRequestBuilder {
private int maxVersions;
private boolean casRequired;
@Nullable
private Duration deleteVersionAfter;
@Nullable
private Map<String, String> customMetadata;
@Nullable
private Duration deleteVersionAfter;
private int maxVersions;
/**
* Set the number of versions to keep per key.
* @param maxVersions
* Set the cas_required parameter to {@code true} to require the cas parameter to
* be set on all write requests.
* @return {@link VaultMetadataRequest}
* @since 3.1
*/
public VaultMetadataRequestBuilder maxVersions(int maxVersions) {
this.maxVersions = maxVersions;
return this;
public VaultMetadataRequestBuilder casRequired() {
return casRequired(true);
}
/**
@@ -119,6 +120,17 @@ public class VaultMetadataRequest {
return this;
}
/**
* Sets the custom Metadata for the metadata request.
* @param customMetadata
* @return {@link VaultMetadataRequest}
* @since 3.1
*/
public VaultMetadataRequestBuilder customMetadata(Map<String, String> customMetadata) {
this.customMetadata = customMetadata;
return this;
}
/**
* Sets the deletion time for all new versions written to this key.
* @param deleteVersionAfter
@@ -130,12 +142,12 @@ public class VaultMetadataRequest {
}
/**
* Sets the custom Metadata for the metadatarequest
* @param customMetadata
* Set the number of versions to keep per key.
* @param maxVersions
* @return {@link VaultMetadataRequest}
*/
public VaultMetadataRequestBuilder customMetadata(Map<String, String> customMetadata) {
this.customMetadata = customMetadata;
public VaultMetadataRequestBuilder maxVersions(int maxVersions) {
this.maxVersions = maxVersions;
return this;
}
@@ -143,8 +155,8 @@ public class VaultMetadataRequest {
* @return a new {@link VaultMetadataRequest}
*/
public VaultMetadataRequest build() {
return new VaultMetadataRequest(this.maxVersions, this.casRequired, this.deleteVersionAfter,
this.customMetadata);
return new VaultMetadataRequest(this.casRequired, this.customMetadata, this.deleteVersionAfter,
this.maxVersions);
}
}

View File

@@ -18,15 +18,18 @@ package org.springframework.vault.support;
import java.time.Duration;
import java.time.Instant;
import java.time.Period;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.vault.support.Versioned.Metadata;
/**
* Value object to bind Vault HTTP kv read metadata API responses.
*
* @author Zakaria Amine
* @author Jeroen Willemsen
* @since 2.3
*/
public class VaultMetadataResponse {
@@ -37,6 +40,8 @@ public class VaultMetadataResponse {
private final int currentVersion;
private final Map<String, String> customMetadata;
private final Duration deleteVersionAfter;
private final int maxVersions;
@@ -47,20 +52,19 @@ public class VaultMetadataResponse {
private final List<Versioned.Metadata> versions;
private final Map<String, String> customMetadata;
private VaultMetadataResponse(boolean casRequired, Instant createdTime, int currentVersion,
Duration deleteVersionAfter, int maxVersions, int oldestVersion, Instant updatedTime,
List<Versioned.Metadata> versions, Map<String, String> customMetadata) {
Map<String, String> customMetadata, Duration deleteVersionAfter, int maxVersions, int oldestVersion,
Instant updatedTime, List<Metadata> versions) {
this.casRequired = casRequired;
this.createdTime = createdTime;
this.customMetadata = customMetadata;
this.currentVersion = currentVersion;
this.deleteVersionAfter = deleteVersionAfter;
this.maxVersions = maxVersions;
this.oldestVersion = oldestVersion;
this.updatedTime = updatedTime;
this.versions = versions;
this.customMetadata = customMetadata;
}
public static VaultMetadataResponseBuilder builder() {
@@ -98,9 +102,9 @@ public class VaultMetadataResponse {
}
/**
* @return KV of customMetadata. Entries can be any arbitrary key-value pairs
* @return the custom metadata. Entries can be any arbitrary key-value pairs
* @since 3.1
*/
@Nullable
public Map<String, String> getCustomMetadata() {
return this.customMetadata;
}
@@ -127,12 +131,10 @@ public class VaultMetadataResponse {
}
/**
* Follows the following format.
*
* "versions": { "1": { "created_time": "2020-05-18T12:23:09.895587932Z",
* "deletion_time": "2020-05-18T12:31:00.66257744Z", "destroyed": false }, "2": {
* "created_time": "2020-05-18T12:23:10.122081788Z", "deletion_time": "", "destroyed":
* false } }
* Follows the following format. "versions": { "1": { "created_time":
* "2020-05-18T12:23:09.895587932Z", "deletion_time": "2020-05-18T12:31:00.66257744Z",
* "destroyed": false }, "2": { "created_time": "2020-05-18T12:23:10.122081788Z",
* "deletion_time": "", "destroyed": false } }
* @return the key versions and their details
*/
public List<Versioned.Metadata> getVersions() {
@@ -143,6 +145,8 @@ public class VaultMetadataResponse {
private boolean casRequired;
private Map<String, String> customMetadata;
private Instant createdTime;
private int currentVersion;
@@ -157,8 +161,6 @@ public class VaultMetadataResponse {
private List<Versioned.Metadata> versions;
private Map<String, String> customMetadata;
public VaultMetadataResponseBuilder casRequired(boolean casRequired) {
this.casRequired = casRequired;
return this;
@@ -174,6 +176,11 @@ public class VaultMetadataResponse {
return this;
}
public VaultMetadataResponseBuilder customMetadata(@Nullable Map<String, String> customMetadata) {
this.customMetadata = customMetadata != null ? customMetadata : Collections.emptyMap();
return this;
}
public VaultMetadataResponseBuilder deleteVersionAfter(Duration deleteVersionAfter) {
this.deleteVersionAfter = deleteVersionAfter;
return this;
@@ -199,15 +206,10 @@ public class VaultMetadataResponse {
return this;
}
public VaultMetadataResponseBuilder customMetadata(Map<String, String> customMetadata) {
this.customMetadata = customMetadata;
return this;
}
public VaultMetadataResponse build() {
return new VaultMetadataResponse(this.casRequired, this.createdTime, this.currentVersion,
this.deleteVersionAfter, this.maxVersions, this.oldestVersion, this.updatedTime, this.versions,
this.customMetadata);
this.customMetadata, this.deleteVersionAfter, this.maxVersions, this.oldestVersion,
this.updatedTime, this.versions);
}
}

View File

@@ -16,17 +16,19 @@
package org.springframework.vault.support;
import java.time.Instant;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* Value object representing versioned secrets along {@link Version} metadata. A versioned
* object can hold various states to represent:
*
* <ul>
* <li>Initial (not yet versioned) secrets via {@link Versioned#create(Object)}</li>
* <li>Versioned secrets via {@link Versioned#create(Object, Version)}</li>
@@ -35,7 +37,6 @@ import org.springframework.util.Assert;
* </ul>
* <p>
* Versioned secrets follow a lifecycle that spans from creation to destruction:
*
* <ol>
* <li>Creation of an unversioned secret: Secret is not yet persisted.</li>
* <li>Versioned secret: Secret is persisted.</li>
@@ -45,6 +46,7 @@ import org.springframework.util.Assert;
* </ol>
*
* @author Mark Paluch
* @author Jeroen Willemsen
* @see Version
* @see Metadata
* @since 2.1
@@ -218,21 +220,22 @@ public class Versioned<T> {
private final Instant createdAt;
private final @Nullable Map<String, String> customMetadata;
private final @Nullable Instant deletedAt;
private final boolean destroyed;
private final Version version;
private final @Nullable Map<String, String> customMetadata;
private Metadata(Instant createdAt, @Nullable Map<String, String> customMetadata, @Nullable Instant deletedAt,
boolean destroyed, Version version) {
private Metadata(Instant createdAt, @Nullable Instant deletedAt, boolean destroyed, Version version,
@Nullable Map<String, String> customMetadata) {
this.createdAt = createdAt;
this.customMetadata = customMetadata;
this.deletedAt = deletedAt;
this.destroyed = destroyed;
this.version = version;
this.customMetadata = customMetadata;
}
/**
@@ -243,6 +246,13 @@ public class Versioned<T> {
return new MetadataBuilder();
}
/**
* @return custom metadata, if provided.
*/
public Map<String, String> getCustomMetadata() {
return customMetadata == null ? Collections.emptyMap() : customMetadata;
}
/**
* @return {@link Instant} at which the version was created.
*/
@@ -280,27 +290,19 @@ public class Versioned<T> {
return this.destroyed;
}
/**
* @return Metadata .
*/
@Nullable
public Map<String, String> getCustomMetadata() {
return customMetadata;
}
@Override
public String toString() {
String customMetadataString = "";
StringBuilder customMetadataString = new StringBuilder(", customMetadata=[");
if (customMetadata != null && customMetadata.keySet().size() > 0) {
StringBuilder metadataPrintBuilder = new StringBuilder(", customMetadata=Map[");
for (String key : customMetadata.keySet()) {
metadataPrintBuilder.append(key).append(":").append(customMetadata.get(key)).append(" ");
customMetadataString.append(key).append(":").append(customMetadata.get(key)).append(" ");
}
metadataPrintBuilder.append("]");
customMetadataString = metadataPrintBuilder.toString();
}
customMetadataString.append("]");
return getClass().getSimpleName() + " [createdAt=" + this.createdAt + ", deletedAt=" + this.deletedAt
+ ", destroyed=" + this.destroyed + ", version=" + this.version + customMetadataString + ']';
}
@@ -379,12 +381,17 @@ public class Versioned<T> {
return this;
}
/**
* Configure the custom metadata map.
* @param customMetadata must not be {@literal null} and not empty.
* @return {@code this} {@link MetadataBuilder}.
* @since 3.1
*/
public MetadataBuilder customMetadata(Map<String, String> customMetadata) {
Assert.notNull(customMetadata, "customMetadata should not be null");
Assert.notEmpty(customMetadata.keySet(), "customMetadata should have at least one key");
Assert.notEmpty(customMetadata.values(), "customMetadata should have at least one value");
this.customMetadata = customMetadata;
this.customMetadata = customMetadata != null && !CollectionUtils.isEmpty(customMetadata)
? new LinkedHashMap<>(customMetadata) : null;
return this;
}
@@ -399,7 +406,7 @@ public class Versioned<T> {
Assert.notNull(this.createdAt, "CreatedAt must not be null");
Assert.notNull(this.version, "Version must not be null");
return new Metadata(this.createdAt, this.deletedAt, this.destroyed, this.version, this.customMetadata);
return new Metadata(this.createdAt, this.customMetadata, this.deletedAt, this.destroyed, this.version);
}
}
@@ -469,10 +476,9 @@ public class Versioned<T> {
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Version))
if (!(o instanceof Version other))
return false;
Version version1 = (Version) o;
return this.version == version1.version;
return this.version == other.version;
}
@Override

View File

@@ -45,6 +45,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
* Integration tests for {@link VaultVersionedKeyValueTemplate}.
*
* @author Mark Paluch
* @author Jeroen Willemsen
*/
@ExtendWith(SpringExtension.class)
@RequiresVaultVersion(VaultInitializer.VERSIONING_INTRODUCED_WITH_VALUE)
@@ -88,6 +89,7 @@ class VaultVersionedKeyValueTemplateIntegrationTests extends IntegrationTestSupp
Versioned<Person> versioned = this.versionedOperations.get(key, Person.class);
assertThat(versioned.getRequiredData()).isEqualTo(person);
assertThat(versioned.getRequiredMetadata().getCustomMetadata()).isEmpty();
}
@Test
@@ -107,6 +109,7 @@ class VaultVersionedKeyValueTemplateIntegrationTests extends IntegrationTestSupp
@Test
void shouldWriteSecretWithCustomMetadata() {
Person person = new Person();
person.setFirstname("Walter");
person.setLastname("White");
@@ -124,9 +127,7 @@ class VaultVersionedKeyValueTemplateIntegrationTests extends IntegrationTestSupp
this.versionedOperations.opsForKeyValueMetadata().put(key, request);
Versioned<Person> versioned = this.versionedOperations.get(key, Person.class);
assertThat(versioned.getMetadata().getCustomMetadata().get("foo")).isEqualTo("bar");
assertThat(versioned.getRequiredMetadata().getCustomMetadata()).containsEntry("foo", "bar");
}
@Test