Add response models for KV v2 API
Secret response is now split in data and metadata. Pure metadata queries return the new SecretMetadata class.
This commit is contained in:
parent
12083df14b
commit
04e92626bd
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016-2018 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 com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||||
|
import de.stklcode.jvault.connector.model.response.embedded.SecretMetadata;
|
||||||
|
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vault response for secret metadata (KV v2).
|
||||||
|
*
|
||||||
|
* @author Stefan Kalscheuer
|
||||||
|
* @since 0.8
|
||||||
|
*/
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class MetadataResponse extends VaultDataResponse {
|
||||||
|
|
||||||
|
private SecretMetadata metadata;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void setData(final Map<String, Object> data) throws InvalidResponseException {
|
||||||
|
ObjectMapper 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.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public SecretMetadata getMetadata() {
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,7 @@ package de.stklcode.jvault.connector.model.response;
|
|||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
import de.stklcode.jvault.connector.exception.InvalidResponseException;
|
||||||
|
import de.stklcode.jvault.connector.model.response.embedded.VersionMetadata;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -33,10 +34,25 @@ import java.util.Map;
|
|||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
public class SecretResponse extends VaultDataResponse {
|
public class SecretResponse extends VaultDataResponse {
|
||||||
private Map<String, Object> data;
|
private Map<String, Object> data;
|
||||||
|
private VersionMetadata metadata;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void setData(final Map<String, Object> data) throws InvalidResponseException {
|
public final void setData(final Map<String, Object> data) throws InvalidResponseException {
|
||||||
this.data = data;
|
if (data.size() == 2
|
||||||
|
&& data.containsKey("data") && data.get("data") instanceof Map
|
||||||
|
&& data.containsKey("metadata") && data.get("metadata") instanceof Map) {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
try {
|
||||||
|
// This is apparently a KV v2 value.
|
||||||
|
this.data = (Map<String, Object>) data.get("data");
|
||||||
|
this.metadata = mapper.readValue(mapper.writeValueAsString(data.get("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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,11 +62,22 @@ public class SecretResponse extends VaultDataResponse {
|
|||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
public final Map<String, Object> getData() {
|
public final Map<String, Object> getData() {
|
||||||
if (data == null)
|
if (data == null) {
|
||||||
return new HashMap<>();
|
return new HashMap<>();
|
||||||
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get secret metadata. This is only available for KV v2 secrets.
|
||||||
|
*
|
||||||
|
* @return Metadata of the secret.
|
||||||
|
* @since 0.8
|
||||||
|
*/
|
||||||
|
public final VersionMetadata getMetadata() {
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a single value for given key.
|
* Get a single value for given key.
|
||||||
*
|
*
|
||||||
@ -59,8 +86,9 @@ public class SecretResponse extends VaultDataResponse {
|
|||||||
* @since 0.4.0
|
* @since 0.4.0
|
||||||
*/
|
*/
|
||||||
public final Object get(final String key) {
|
public final Object get(final String key) {
|
||||||
if (data == null)
|
if (data == null) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
return getData().get(key);
|
return getData().get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,8 +102,9 @@ public class SecretResponse extends VaultDataResponse {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public final String getValue() {
|
public final String getValue() {
|
||||||
Object value = get("value");
|
Object value = get("value");
|
||||||
if (value == null)
|
if (value == null) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
return value.toString();
|
return value.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +126,7 @@ public class SecretResponse extends VaultDataResponse {
|
|||||||
/**
|
/**
|
||||||
* Get response parsed as JSON.
|
* Get response parsed as JSON.
|
||||||
*
|
*
|
||||||
* @param key the key
|
* @param key the key
|
||||||
* @param type Class to parse response
|
* @param type Class to parse response
|
||||||
* @param <T> Class to parse response
|
* @param <T> Class to parse response
|
||||||
* @return Parsed object or {@code null} if absent
|
* @return Parsed object or {@code null} if absent
|
||||||
@ -107,8 +136,9 @@ public class SecretResponse extends VaultDataResponse {
|
|||||||
public final <T> T get(final String key, final Class<T> type) throws InvalidResponseException {
|
public final <T> T get(final String key, final Class<T> type) throws InvalidResponseException {
|
||||||
try {
|
try {
|
||||||
Object rawValue = get(key);
|
Object rawValue = get(key);
|
||||||
if (rawValue == null)
|
if (rawValue == null) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
return new ObjectMapper().readValue(rawValue.toString(), type);
|
return new ObjectMapper().readValue(rawValue.toString(), type);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new InvalidResponseException("Unable to parse response payload: " + e.getMessage());
|
throw new InvalidResponseException("Unable to parse response payload: " + e.getMessage());
|
||||||
|
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016-2018 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.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Embedded metadata for Key-Value v2 secrets.
|
||||||
|
*
|
||||||
|
* @author Stefan Kalscheuer
|
||||||
|
* @since 0.8
|
||||||
|
*/
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public final class SecretMetadata {
|
||||||
|
private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSX");
|
||||||
|
|
||||||
|
@JsonProperty("created_time")
|
||||||
|
private String createdTimeString;
|
||||||
|
|
||||||
|
@JsonProperty("current_version")
|
||||||
|
private Integer currentVersion;
|
||||||
|
|
||||||
|
@JsonProperty("max_version")
|
||||||
|
private Integer maxVersions;
|
||||||
|
|
||||||
|
@JsonProperty("oldest_version")
|
||||||
|
private Integer oldestVersion;
|
||||||
|
|
||||||
|
@JsonProperty("updated_time")
|
||||||
|
private String updatedTime;
|
||||||
|
|
||||||
|
@JsonProperty("versions")
|
||||||
|
private Map<Integer, VersionMetadata> versions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Time of secret creation as raw string representation.
|
||||||
|
*/
|
||||||
|
public String getCreatedTimeString() {
|
||||||
|
return createdTimeString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Time of secret creation.
|
||||||
|
*/
|
||||||
|
public ZonedDateTime getCreatedTime() {
|
||||||
|
if (createdTimeString != null && !createdTimeString.isEmpty()) {
|
||||||
|
try {
|
||||||
|
return ZonedDateTime.parse(createdTimeString, TIME_FORMAT);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
// Ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Current version number.
|
||||||
|
*/
|
||||||
|
public Integer getCurrentVersion() {
|
||||||
|
return currentVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Maximum number of versions.
|
||||||
|
*/
|
||||||
|
public Integer getMaxVersions() {
|
||||||
|
return maxVersions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Oldest available version number.
|
||||||
|
*/
|
||||||
|
public Integer getOldestVersion() {
|
||||||
|
return oldestVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Time of secret update as raw string representation.
|
||||||
|
*/
|
||||||
|
public String getUpdatedTimeString() {
|
||||||
|
return updatedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Time of secret update..
|
||||||
|
*/
|
||||||
|
public ZonedDateTime getUpdatedTime() {
|
||||||
|
if (updatedTime != null && !updatedTime.isEmpty()) {
|
||||||
|
try {
|
||||||
|
return ZonedDateTime.parse(updatedTime, TIME_FORMAT);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
// Ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Version of the entry.
|
||||||
|
*/
|
||||||
|
public Map<Integer, VersionMetadata> getVersions() {
|
||||||
|
return versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016-2018 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.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Embedded metadata for a single Key-Value v2 version.
|
||||||
|
*
|
||||||
|
* @author Stefan Kalscheuer
|
||||||
|
* @since 0.8
|
||||||
|
*/
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public final class VersionMetadata {
|
||||||
|
private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSX");
|
||||||
|
|
||||||
|
@JsonProperty("created_time")
|
||||||
|
private String createdTimeString;
|
||||||
|
|
||||||
|
@JsonProperty("deletion_time")
|
||||||
|
private String deletionTimeString;
|
||||||
|
|
||||||
|
@JsonProperty("destroyed")
|
||||||
|
private boolean destroyed;
|
||||||
|
|
||||||
|
@JsonProperty("version")
|
||||||
|
private Integer version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Time of secret creation as raw string representation.
|
||||||
|
*/
|
||||||
|
public String getCreatedTimeString() {
|
||||||
|
return createdTimeString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Time of secret creation.
|
||||||
|
*/
|
||||||
|
public ZonedDateTime getCreatedTime() {
|
||||||
|
if (createdTimeString != null && !createdTimeString.isEmpty()) {
|
||||||
|
try {
|
||||||
|
return ZonedDateTime.parse(createdTimeString, TIME_FORMAT);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
// Ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Time for secret deletion as raw string representation.
|
||||||
|
*/
|
||||||
|
public String getDeletionTimeString() {
|
||||||
|
return deletionTimeString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Time for secret deletion.
|
||||||
|
*/
|
||||||
|
public ZonedDateTime getDeletionTime() {
|
||||||
|
if (deletionTimeString != null && !deletionTimeString.isEmpty()) {
|
||||||
|
try {
|
||||||
|
return ZonedDateTime.parse(deletionTimeString, TIME_FORMAT);
|
||||||
|
} catch (DateTimeParseException e) {
|
||||||
|
// Ignore.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Whether the secret is destroyed.
|
||||||
|
*/
|
||||||
|
public boolean isDestroyed() {
|
||||||
|
return destroyed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Version of the entry.
|
||||||
|
*/
|
||||||
|
public Integer getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user