Require API version for Key/Value backend usage.
We now require specification of the desired Key/Value API version to interact with Vault's Key/Value backends. Vault 0.10.1 removed request downgrading so the client is in charge of using the proper API version. KeyValue API implementation classes are package-protected now as API stability in Vault isn't given so we want to be able to adapt to API changes without breaking public API. See gh-245.
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.vault.core;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.support.VaultResponseSupport;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link VaultKeyValueOperations} for the Key/Value backend
|
||||
* version 1.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.1
|
||||
* @see KeyValueBackend#KV_1
|
||||
*/
|
||||
class VaultKeyValue1Template extends VaultKeyValueAccessor implements
|
||||
VaultKeyValueOperations {
|
||||
|
||||
private final VaultOperations vaultOperations;
|
||||
private final String path;
|
||||
|
||||
/**
|
||||
* Create a new {@link VaultKeyValue1Template} given {@link VaultOperations} and the
|
||||
* mount {@code path}.
|
||||
*
|
||||
* @param vaultOperations must not be {@literal null}.
|
||||
* @param path must not be empty or {@literal null}.
|
||||
*/
|
||||
public VaultKeyValue1Template(VaultOperations vaultOperations, String path) {
|
||||
|
||||
super(vaultOperations, path);
|
||||
|
||||
this.vaultOperations = vaultOperations;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> list(String path) {
|
||||
return vaultOperations.list(createDataPath(path));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public VaultResponse get(String path) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
return doRead(path, Map.class, (response, data) -> {
|
||||
|
||||
VaultResponse vaultResponse = new VaultResponse();
|
||||
vaultResponse.setRenewable(response.isRenewable());
|
||||
vaultResponse.setAuth(response.getAuth());
|
||||
vaultResponse.setLeaseDuration(response.getLeaseDuration());
|
||||
vaultResponse.setLeaseId(response.getLeaseId());
|
||||
vaultResponse.setMetadata(response.getMetadata());
|
||||
vaultResponse.setRequestId(response.getRequestId());
|
||||
vaultResponse.setWarnings(response.getWarnings());
|
||||
vaultResponse.setWrapInfo(response.getWrapInfo());
|
||||
vaultResponse.setData(data);
|
||||
|
||||
return vaultResponse;
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> VaultResponseSupport<T> get(String path, Class<T> responseType) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
Assert.notNull(responseType, "Response type must not be null");
|
||||
|
||||
return doRead(path, responseType, (response, data) -> {
|
||||
|
||||
VaultResponseSupport result = response;
|
||||
result.setData(data);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String path, Object body) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
doWrite(createDataPath(path), body);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyValueBackend getApiVersion() {
|
||||
return KeyValueBackend.KV_1;
|
||||
}
|
||||
|
||||
@Override
|
||||
JsonNode getJsonNode(VaultResponseSupport<JsonNode> response) {
|
||||
return response.getRequiredData();
|
||||
}
|
||||
|
||||
@Override
|
||||
String createDataPath(String path) {
|
||||
return String.format("%s/%s", this.path, path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.vault.core;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.vault.support.VaultResponseSupport;
|
||||
|
||||
/**
|
||||
* Support class to build accessor methods for the Vault key-value backend version 2.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.1
|
||||
* @see KeyValueBackend#KV_2
|
||||
*/
|
||||
abstract class VaultKeyValue2Accessor extends VaultKeyValueAccessor {
|
||||
|
||||
private final String path;
|
||||
|
||||
/**
|
||||
* Create a new {@link VaultKeyValue2Accessor} given {@link VaultOperations} and the
|
||||
* mount {@code path}.
|
||||
*
|
||||
* @param vaultOperations must not be {@literal null}.
|
||||
* @param path must not be empty or {@literal null}.
|
||||
*/
|
||||
VaultKeyValue2Accessor(VaultOperations vaultOperations, String path) {
|
||||
|
||||
super(vaultOperations, path);
|
||||
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<String> list(String path) {
|
||||
|
||||
String pathToUse = path.equals("/") ? "" : path.endsWith("/") ? path
|
||||
: (path + "/");
|
||||
|
||||
VaultListResponse read = doRead(restOperations -> {
|
||||
return restOperations.exchange(String.format("%s?list=true",
|
||||
createBackendPath("metadata", pathToUse)), HttpMethod.GET, null,
|
||||
VaultListResponse.class);
|
||||
});
|
||||
|
||||
if (read == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return (List<String>) read.getRequiredData().get("keys");
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyValueBackend getApiVersion() {
|
||||
return KeyValueBackend.KV_2;
|
||||
}
|
||||
|
||||
JsonNode getJsonNode(VaultResponseSupport<JsonNode> response) {
|
||||
return response.getRequiredData().at("/data");
|
||||
}
|
||||
|
||||
String createDataPath(String path) {
|
||||
return createBackendPath("data", path);
|
||||
}
|
||||
|
||||
String createBackendPath(String segment, String path) {
|
||||
return String.format("%s/%s/%s", this.path, segment, path);
|
||||
}
|
||||
}
|
||||
@@ -24,23 +24,23 @@ import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.support.VaultResponseSupport;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link VaultKeyValueOperations}.
|
||||
* Default implementation of {@link VaultKeyValueOperations} for the key-value backend
|
||||
* version 2.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.1
|
||||
*/
|
||||
public class VaultKeyValueTemplate extends VaultKeyValueAccessor implements
|
||||
class VaultKeyValue2Template extends VaultKeyValue2Accessor implements
|
||||
VaultKeyValueOperations {
|
||||
|
||||
/**
|
||||
* Create a new {@link VaultKeyValueTemplate} given {@link VaultOperations} and the
|
||||
* Create a new {@link VaultKeyValue2Template} given {@link VaultOperations} and the
|
||||
* mount {@code path}.
|
||||
*
|
||||
* @param vaultOperations must not be {@literal null}.
|
||||
* @param path must not be empty or {@literal null}.
|
||||
*/
|
||||
public VaultKeyValueTemplate(VaultOperations vaultOperations, String path) {
|
||||
|
||||
public VaultKeyValue2Template(VaultOperations vaultOperations, String path) {
|
||||
super(vaultOperations, path);
|
||||
}
|
||||
|
||||
@@ -16,17 +16,15 @@
|
||||
package org.springframework.vault.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -42,16 +40,16 @@ import org.springframework.web.client.RestOperations;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* Base class for {@link VaultVersionedKeyValueTemplate} and {@link VaultKeyValueTemplate}
|
||||
* and other Vault KV-accessing helpers, defining common
|
||||
* Base class for {@link VaultVersionedKeyValueTemplate} and
|
||||
* {@link VaultKeyValue2Template} and other Vault KV-accessing helpers, defining common
|
||||
* <p/>
|
||||
* Not intended to be used directly. See {@link VaultVersionedKeyValueTemplate} and
|
||||
* {@link VaultKeyValueTemplate}.
|
||||
* {@link VaultKeyValue2Template}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.1
|
||||
*/
|
||||
public abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSupport {
|
||||
abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSupport {
|
||||
|
||||
private final VaultOperations vaultOperations;
|
||||
|
||||
@@ -66,7 +64,7 @@ public abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSu
|
||||
* @param vaultOperations must not be {@literal null}.
|
||||
* @param path must not be empty or {@literal null}.
|
||||
*/
|
||||
public VaultKeyValueAccessor(VaultOperations vaultOperations, String path) {
|
||||
VaultKeyValueAccessor(VaultOperations vaultOperations, String path) {
|
||||
|
||||
Assert.notNull(vaultOperations, "VaultOperations must not be null");
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
@@ -76,43 +74,23 @@ public abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSu
|
||||
this.mapper = extractObjectMapper(vaultOperations);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<String> list(String path) {
|
||||
|
||||
String pathToUse = path.equals("/") ? "" : path.endsWith("/") ? path
|
||||
: (path + "/");
|
||||
|
||||
VaultListResponse read = doRead((restOperations, httpEntity) -> {
|
||||
return restOperations.exchange(String.format("%s?list=true",
|
||||
createBackendPath("metadata", pathToUse)), HttpMethod.GET,
|
||||
httpEntity, VaultListResponse.class);
|
||||
});
|
||||
|
||||
if (read == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return (List<String>) read.getRequiredData().get("keys");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String path) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
doWithSession(((restOperations, httpHeaders) -> {
|
||||
vaultOperations.doWithSession((restOperations -> {
|
||||
restOperations.exchange(createDataPath(path), HttpMethod.DELETE,
|
||||
new HttpEntity<>(httpHeaders), Void.class);
|
||||
null,
|
||||
Void.class);
|
||||
|
||||
return null;
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a secret at {@code path} and deserialize the nested {@literal data} element to
|
||||
* the given {@link Class type}.
|
||||
* Read a secret at {@code path} and deserialize the {@literal data} element to the
|
||||
* given {@link Class type}.
|
||||
*
|
||||
* @param path must not be {@literal null}.
|
||||
* @param deserializeAs must not be {@literal null}.
|
||||
@@ -133,7 +111,7 @@ public abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSu
|
||||
|
||||
if (response != null) {
|
||||
|
||||
JsonNode jsonNode = response.getRequiredData().at("/data");
|
||||
JsonNode jsonNode = getJsonNode(response);
|
||||
|
||||
return mappingFunction.apply(response, deserialize(jsonNode, deserializeAs));
|
||||
}
|
||||
@@ -141,6 +119,29 @@ public abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSu
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a secret at {@code path} and deserialize the {@literal data} element to the
|
||||
* given {@link ParameterizedTypeReference type}.
|
||||
*
|
||||
* @param path must not be {@literal null} or empty.
|
||||
* @param typeReference must not be {@literal null}
|
||||
* @return mapped value.
|
||||
*/
|
||||
@Nullable
|
||||
<T> T doRead(String path, ParameterizedTypeReference<T> typeReference) {
|
||||
|
||||
return doRead((restOperations) -> {
|
||||
return restOperations.exchange(path, HttpMethod.GET, null, typeReference);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize a {@link JsonNode} to the requested {@link Class type}.
|
||||
*
|
||||
* @param jsonNode must not be {@literal null}.
|
||||
* @param type must not be {@literal null}.
|
||||
* @return the deserialized object.
|
||||
*/
|
||||
<T> T deserialize(JsonNode jsonNode, Class<T> type) {
|
||||
|
||||
try {
|
||||
@@ -151,23 +152,21 @@ public abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSu
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a read action within a callback that gets access to a session-bound
|
||||
* {@link RestOperations} object. {@link HttpStatusCodeException} with
|
||||
* {@link HttpStatus#NOT_FOUND} are translated to a {@literal null} response.
|
||||
*
|
||||
* @param callback must not be {@literal null}.
|
||||
* @return can be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
private <T> T doRead(String path, ParameterizedTypeReference<T> typeReference) {
|
||||
<T> T doRead(Function<RestOperations, ResponseEntity<T>> callback) {
|
||||
|
||||
return doRead((restOperations, httpEntity) -> {
|
||||
return restOperations.exchange(path, HttpMethod.GET, httpEntity,
|
||||
typeReference);
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <T> T doRead(
|
||||
BiFunction<RestOperations, HttpEntity<?>, ResponseEntity<T>> callback) {
|
||||
|
||||
return doWithSession((restOperations, headers) -> {
|
||||
return vaultOperations.doWithSession((restOperations) -> {
|
||||
|
||||
try {
|
||||
return callback.apply(restOperations, new HttpEntity<>(headers))
|
||||
return callback.apply(restOperations)
|
||||
.getBody();
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
@@ -181,6 +180,13 @@ public abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSu
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the {@code body} to the given Vault {@code path}.
|
||||
*
|
||||
* @param path must not be {@literal null} or empty.
|
||||
* @param body
|
||||
* @return the response of this write action.
|
||||
*/
|
||||
@Nullable
|
||||
VaultResponse doWrite(String path, Object body) {
|
||||
|
||||
@@ -188,9 +194,9 @@ public abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSu
|
||||
|
||||
try {
|
||||
|
||||
return doWithSession((restOperations, httpHeaders) -> {
|
||||
return vaultOperations.doWithSession((restOperations) -> {
|
||||
return restOperations.exchange(path, HttpMethod.POST,
|
||||
new HttpEntity<>(body, httpHeaders), VaultResponse.class)
|
||||
new HttpEntity<>(body), VaultResponse.class)
|
||||
.getBody();
|
||||
});
|
||||
}
|
||||
@@ -199,25 +205,19 @@ public abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSu
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
<T> T doWithSession(BiFunction<RestOperations, HttpHeaders, T> callback) {
|
||||
/**
|
||||
* Return the {@link JsonNode} that contains the actual response body.
|
||||
*
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
abstract JsonNode getJsonNode(VaultResponseSupport<JsonNode> response);
|
||||
|
||||
return vaultOperations.doWithSession(restOperations -> {
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set("X-Vault-Kv-Client", "v2");
|
||||
|
||||
return callback.apply(restOperations, headers);
|
||||
});
|
||||
}
|
||||
|
||||
String createDataPath(String path) {
|
||||
return createBackendPath("data", path);
|
||||
}
|
||||
|
||||
String createBackendPath(String segment, String path) {
|
||||
return String.format("%s/%s/%s", this.path, segment, path);
|
||||
}
|
||||
/**
|
||||
* @param path must not be {@literal null} or empty.
|
||||
* @return backend path representing the data path.
|
||||
*/
|
||||
abstract String createDataPath(String path);
|
||||
|
||||
private static ObjectMapper extractObjectMapper(VaultOperations vaultOperations) {
|
||||
|
||||
@@ -231,7 +231,6 @@ public abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSu
|
||||
Optional<AbstractJackson2HttpMessageConverter> jackson2Converter = template
|
||||
.getMessageConverters()
|
||||
.stream()
|
||||
//
|
||||
.filter(AbstractJackson2HttpMessageConverter.class::isInstance) //
|
||||
.map(AbstractJackson2HttpMessageConverter.class::cast) //
|
||||
.findFirst();
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.springframework.vault.support.VaultResponseSupport;
|
||||
* @author Mark Paluch
|
||||
* @since 2.1
|
||||
* @see VaultVersionedKeyValueOperations
|
||||
* @see KeyValueBackend
|
||||
*/
|
||||
public interface VaultKeyValueOperations extends VaultKeyValueOperationsSupport {
|
||||
|
||||
|
||||
@@ -54,4 +54,39 @@ public interface VaultKeyValueOperationsSupport {
|
||||
* @param path must not be {@literal null}.
|
||||
*/
|
||||
void delete(String path);
|
||||
|
||||
/**
|
||||
* @return the used API version.
|
||||
*/
|
||||
KeyValueBackend getApiVersion();
|
||||
|
||||
/**
|
||||
* Enumeration of supported Key/Value backend API versions.
|
||||
*/
|
||||
enum KeyValueBackend {
|
||||
|
||||
/**
|
||||
* Key/Value backend version 1 (unversioned).
|
||||
*/
|
||||
KV_1,
|
||||
|
||||
/**
|
||||
* K/V backend version 2 (versioned).
|
||||
*/
|
||||
KV_2;
|
||||
|
||||
/**
|
||||
* @return the K/V version 1 (unversioned).
|
||||
*/
|
||||
public static KeyValueBackend unversioned() {
|
||||
return KV_1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the K/V version 2 (versioned).
|
||||
*/
|
||||
public static KeyValueBackend versioned() {
|
||||
return KV_2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.util.List;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.core.VaultKeyValueOperationsSupport.KeyValueBackend;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.support.VaultResponseSupport;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
@@ -46,12 +47,12 @@ public interface VaultOperations {
|
||||
/**
|
||||
* Return {@link VaultKeyValueOperations}.
|
||||
*
|
||||
* @param path the mount path
|
||||
* @return the operations interface to interact with the Vault Key/Value (version 2)
|
||||
* backend.
|
||||
* @param path the mount path, must not be empty or {@literal null}.
|
||||
* @param apiVersion API version to use, must not be {@literal null}.
|
||||
* @return the operations interface to interact with the Vault Key/Value backend.
|
||||
* @since 2.1
|
||||
*/
|
||||
VaultKeyValueOperations opsForKeyValue(String path);
|
||||
VaultKeyValueOperations opsForKeyValue(String path, KeyValueBackend apiVersion);
|
||||
|
||||
/**
|
||||
* Return {@link VaultVersionedKeyValueOperations}.
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.client.VaultEndpointProvider;
|
||||
import org.springframework.vault.client.VaultHttpHeaders;
|
||||
import org.springframework.vault.client.VaultResponses;
|
||||
import org.springframework.vault.core.VaultKeyValueOperationsSupport.KeyValueBackend;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.support.VaultResponseSupport;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
@@ -206,8 +207,18 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultKeyValueOperations opsForKeyValue(String path) {
|
||||
return new VaultKeyValueTemplate(this, path);
|
||||
public VaultKeyValueOperations opsForKeyValue(String path, KeyValueBackend apiVersion) {
|
||||
|
||||
switch (apiVersion) {
|
||||
case KV_1:
|
||||
return new VaultKeyValue1Template(this, path);
|
||||
case KV_2:
|
||||
return new VaultKeyValue2Template(this, path);
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException(String.format(
|
||||
"Key/Value backend version %s not supported", apiVersion));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,7 +27,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -48,9 +47,11 @@ import org.springframework.web.client.HttpStatusCodeException;
|
||||
* @author Mark Paluch
|
||||
* @since 2.1
|
||||
*/
|
||||
public class VaultVersionedKeyValueTemplate extends VaultKeyValueAccessor implements
|
||||
public class VaultVersionedKeyValueTemplate extends VaultKeyValue2Accessor implements
|
||||
VaultVersionedKeyValueOperations {
|
||||
|
||||
private final VaultOperations vaultOperations;
|
||||
|
||||
/**
|
||||
* Create a new {@link VaultVersionedKeyValueTemplate} given {@link VaultOperations}
|
||||
* and the mount {@code path}.
|
||||
@@ -59,7 +60,10 @@ public class VaultVersionedKeyValueTemplate extends VaultKeyValueAccessor implem
|
||||
* @param path must not be empty or {@literal null}.
|
||||
*/
|
||||
public VaultVersionedKeyValueTemplate(VaultOperations vaultOperations, String path) {
|
||||
|
||||
super(vaultOperations, path);
|
||||
|
||||
this.vaultOperations = vaultOperations;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -90,11 +94,12 @@ public class VaultVersionedKeyValueTemplate extends VaultKeyValueAccessor implem
|
||||
String secretPath = version.isVersioned() ? String.format("%s?version=%d",
|
||||
createDataPath(path), version.getVersion()) : createDataPath(path);
|
||||
|
||||
VersionedResponse response = doWithSession((restOperations, httpHeaders) -> {
|
||||
VersionedResponse response = vaultOperations.doWithSession(restOperations -> {
|
||||
|
||||
try {
|
||||
return restOperations.exchange(secretPath, HttpMethod.GET,
|
||||
new HttpEntity<>(httpHeaders), VersionedResponse.class).getBody();
|
||||
null,
|
||||
VersionedResponse.class).getBody();
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.vault.core.VaultKeyValueOperationsSupport.KeyValueBackend;
|
||||
import org.springframework.vault.util.IntegrationTestSupport;
|
||||
import org.springframework.vault.util.VaultRule;
|
||||
|
||||
@@ -31,7 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link VaultKeyValueTemplate}.
|
||||
* Integration tests for {@link VaultKeyValue2Template}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@@ -39,13 +40,15 @@ public abstract class AbstractVaultKeyValueTemplateIntegrationTests extends
|
||||
IntegrationTestSupport {
|
||||
|
||||
private final String path;
|
||||
private final KeyValueBackend apiVersion;
|
||||
|
||||
@Autowired
|
||||
VaultOperations vaultOperations;
|
||||
VaultKeyValueOperations kvOperations;
|
||||
|
||||
AbstractVaultKeyValueTemplateIntegrationTests(String path) {
|
||||
AbstractVaultKeyValueTemplateIntegrationTests(String path, KeyValueBackend apiVersion) {
|
||||
this.path = path;
|
||||
this.apiVersion = apiVersion;
|
||||
}
|
||||
|
||||
@Before
|
||||
@@ -54,7 +57,12 @@ public abstract class AbstractVaultKeyValueTemplateIntegrationTests extends
|
||||
assumeTrue(prepare().getVersion().isGreaterThanOrEqualTo(
|
||||
VaultRule.VERSIONING_INTRODUCED_WITH));
|
||||
|
||||
kvOperations = vaultOperations.opsForKeyValue(path);
|
||||
kvOperations = vaultOperations.opsForKeyValue(path, apiVersion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReportExpectedApiVersion() {
|
||||
assertThat(kvOperations.getApiVersion()).isEqualTo(apiVersion);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -23,13 +23,14 @@ import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.vault.core.VaultKeyValueOperationsSupport.KeyValueBackend;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link VaultKeyValueTemplate} using the non-versioned key-value
|
||||
* backend.
|
||||
* Integration tests for {@link VaultKeyValue2Template} using the non-versioned Key/Value
|
||||
* (k/v version 1) backend.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@@ -39,7 +40,7 @@ public class VaultKeyValueTemplateIntegrationTests extends
|
||||
AbstractVaultKeyValueTemplateIntegrationTests {
|
||||
|
||||
public VaultKeyValueTemplateIntegrationTests() {
|
||||
super("secret");
|
||||
super("secret", KeyValueBackend.unversioned());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -19,10 +19,11 @@ import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.vault.core.VaultKeyValueOperationsSupport.KeyValueBackend;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link VaultKeyValueTemplate} using the versioned key-value
|
||||
* backend.
|
||||
* Integration tests for {@link VaultKeyValue2Template} using the versioned Key/Value (k/v
|
||||
* version 2) backend.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@@ -32,6 +33,6 @@ public class VaultKeyValueTemplateVersionedIntegrationTests extends
|
||||
AbstractVaultKeyValueTemplateIntegrationTests {
|
||||
|
||||
public VaultKeyValueTemplateVersionedIntegrationTests() {
|
||||
super("versioned");
|
||||
super("versioned", KeyValueBackend.versioned());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user