Polishing.
Add author and since tags. Refine nullability and toString rendering. Original pull request: gh-808 See gh-789
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user