Polishing

Add author tags. Return generated tweak from encode and batch encode methods. Switch simple encode/decode methods to default interface methods.

Introduce VaultTransformContext.isEmpty() method to check if the context is empty.

Align equals/hashCode methods with Spring style. Reformat code.

Resolves gh-570.
This commit is contained in:
Mark Paluch
2020-09-07 15:28:43 +02:00
parent a1278c809f
commit 81094fca7f
11 changed files with 195 additions and 198 deletions

View File

@@ -34,6 +34,7 @@ import org.springframework.web.client.RestClientException;
* the {@link #doWithVault(RestOperationsCallback) without a session}.
*
* @author Mark Paluch
* @author Lauren Voswinkel
* @see #doWithSession(RestOperationsCallback)
* @see #doWithVault(RestOperationsCallback)
* @see org.springframework.web.client.RestOperations

View File

@@ -15,21 +15,29 @@
*/
package org.springframework.vault.core;
import org.springframework.vault.support.*;
import java.util.List;
import org.springframework.vault.support.Ciphertext;
import org.springframework.vault.support.Plaintext;
import org.springframework.vault.support.TransformCiphertext;
import org.springframework.vault.support.TransformPlaintext;
import org.springframework.vault.support.VaultTransformContext;
import org.springframework.vault.support.VaultTransformDecodeResult;
import org.springframework.vault.support.VaultTransformEncodeResult;
/**
* Interface that specifies operations using the {@code transform} backend.
*
* @author Lauren Voswinkel
* @author Mark Paluch
* @since 2.3
* @see <a href="https://www.vaultproject.io/docs/secrets/transform/index.html">Transform
* Secrets Engine</a>
* @since 2.3
*/
public interface VaultTransformOperations {
/**
* Encodes the provided plaintext using the named role.
* Encode the provided plaintext using the named role.
* @param roleName must not be empty or {@literal null}.
* @param plaintext must not be empty or {@literal null}.
* @return cipher text.
@@ -37,7 +45,7 @@ public interface VaultTransformOperations {
String encode(String roleName, String plaintext);
/**
* Encodes the provided plaintext using the named role.
* Encode the provided plaintext using the named role.
* @param roleName must not be empty or {@literal null}.
* @param plaintext must not be {@literal null}.
* @return cipher text.
@@ -45,14 +53,16 @@ public interface VaultTransformOperations {
TransformCiphertext encode(String roleName, TransformPlaintext plaintext);
/**
* Encodes the provided plaintext using the named role.
* Encode the provided plaintext using the named role.
* @param roleName must not be empty or {@literal null}.
* @param plaintext must not be empty or {@literal null}.
* @param transformRequest must not be {@literal null}. Use
* {@link VaultTransformContext#empty()} if no request options provided.
* @return cipher text.
*/
String encode(String roleName, byte[] plaintext, VaultTransformContext transformRequest);
default TransformCiphertext encode(String roleName, byte[] plaintext, VaultTransformContext transformRequest) {
return encode(roleName, TransformPlaintext.of(plaintext).with(transformRequest));
}
/**
* Encode the provided batch of plaintext using the role given and transformation in
@@ -71,7 +81,9 @@ public interface VaultTransformOperations {
* @param ciphertext must not be empty or {@literal null}.
* @return plain text.
*/
String decode(String roleName, String ciphertext);
default String decode(String roleName, String ciphertext) {
return decode(roleName, TransformCiphertext.of(ciphertext)).asString();
}
/**
* Decode the provided ciphertext using the named role.
@@ -101,4 +113,5 @@ public interface VaultTransformOperations {
* @return the decrypted result in the order of {@code batchRequest} ciphertexts.
*/
List<VaultTransformDecodeResult> decode(String roleName, List<TransformCiphertext> batchRequest);
}

View File

@@ -15,20 +15,29 @@
*/
package org.springframework.vault.core;
import org.springframework.lang.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.util.Assert;
import org.springframework.util.Base64Utils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.vault.VaultException;
import org.springframework.vault.support.*;
import java.util.*;
import org.springframework.vault.support.TransformCiphertext;
import org.springframework.vault.support.TransformPlaintext;
import org.springframework.vault.support.VaultResponse;
import org.springframework.vault.support.VaultTransformContext;
import org.springframework.vault.support.VaultTransformDecodeResult;
import org.springframework.vault.support.VaultTransformEncodeResult;
/**
* Default implementation of {@link VaultTransformOperations}.
*
* @author Lauren Voswinkel
* @author Mark Paluch
* @since 2.3
*/
public class VaultTransformTemplate implements VaultTransformOperations {
@@ -72,27 +81,16 @@ public class VaultTransformTemplate implements VaultTransformOperations {
Assert.hasText(roleName, "Role name must not be empty");
Assert.notNull(plaintext, "Plaintext must not be null");
String ciphertext = encode(roleName, plaintext.getPlaintext(), plaintext.getContext());
return toCiphertext(ciphertext, plaintext.getContext());
}
@Override
public String encode(String roleName, byte[] plaintext, VaultTransformContext transformContext) {
Assert.hasText(roleName, "Role name must not be empty");
Assert.notNull(plaintext, "Plaintext must not be null");
Assert.notNull(transformContext, "VaultTransformContext must not be null");
Map<String, String> request = new LinkedHashMap<>();
String value = new String(plaintext);
request.put("value", value);
request.put("value", plaintext.asString());
applyTransformOptions(transformContext, request);
applyTransformOptions(plaintext.getContext(), request);
return (String) this.vaultOperations.write(String.format("%s/encode/%s", this.path, roleName), request)
.getRequiredData().get("encoded_value");
Map<String, Object> data = this.vaultOperations
.write(String.format("%s/encode/%s", this.path, roleName), request).getRequiredData();
return toCiphertext(data, plaintext.getContext());
}
@Override
@@ -109,9 +107,7 @@ public class VaultTransformTemplate implements VaultTransformOperations {
vaultRequest.put("value", request.asString());
if (request.getContext() != null) {
applyTransformOptions(request.getContext(), vaultRequest);
}
applyTransformOptions(request.getContext(), vaultRequest);
batch.add(vaultRequest);
}
@@ -122,22 +118,6 @@ public class VaultTransformTemplate implements VaultTransformOperations {
return toEncodedResults(vaultResponse, batchRequest);
}
@Override
public String decode(String roleName, String ciphertext) {
Assert.hasText(roleName, "Key name must not be empty");
Assert.hasText(ciphertext, "Ciphertext must not be empty");
Map<String, String> request = new LinkedHashMap<>();
request.put("value", ciphertext);
String plaintext = (String) this.vaultOperations
.write(String.format("%s/decode/%s", this.path, roleName), request).getRequiredData().get("decoded_value");
return new String(plaintext);
}
@Override
public TransformPlaintext decode(String roleName, TransformCiphertext ciphertext) {
@@ -162,10 +142,8 @@ public class VaultTransformTemplate implements VaultTransformOperations {
applyTransformOptions(transformContext, request);
String plaintext = (String) this.vaultOperations
.write(String.format("%s/decode/%s", this.path, roleName), request).getRequiredData().get("decoded_value");
return plaintext;
return (String) this.vaultOperations.write(String.format("%s/decode/%s", this.path, roleName), request)
.getRequiredData().get("decoded_value");
}
@Override
@@ -181,10 +159,7 @@ public class VaultTransformTemplate implements VaultTransformOperations {
Map<String, String> vaultRequest = new LinkedHashMap<>(2);
vaultRequest.put("value", request.getCiphertext());
if (request.getContext() != null) {
applyTransformOptions(request.getContext(), vaultRequest);
}
applyTransformOptions(request.getContext(), vaultRequest);
batch.add(vaultRequest);
}
@@ -207,7 +182,7 @@ public class VaultTransformTemplate implements VaultTransformOperations {
}
private static List<VaultTransformEncodeResult> toEncodedResults(VaultResponse vaultResponse,
List<TransformPlaintext> batchRequest) {
List<TransformPlaintext> batchRequest) {
List<VaultTransformEncodeResult> result = new ArrayList<>(batchRequest.size());
List<Map<String, String>> batchData = getBatchData(vaultResponse);
@@ -223,7 +198,7 @@ public class VaultTransformTemplate implements VaultTransformOperations {
encoded = new VaultTransformEncodeResult(new VaultException(data.get("error")));
}
else {
encoded = new VaultTransformEncodeResult(toCiphertext(data.get("encoded_value"), plaintext.getContext()));
encoded = new VaultTransformEncodeResult(toCiphertext(data, plaintext.getContext()));
}
}
else {
@@ -260,7 +235,8 @@ public class VaultTransformTemplate implements VaultTransformOperations {
return result;
}
private static VaultTransformDecodeResult getDecryptionResult(Map<String, String> data, TransformCiphertext ciphertext) {
private static VaultTransformDecodeResult getDecryptionResult(Map<String, String> data,
TransformCiphertext ciphertext) {
if (StringUtils.hasText(data.get("error"))) {
return new VaultTransformDecodeResult(new VaultException(data.get("error")));
@@ -268,15 +244,26 @@ public class VaultTransformTemplate implements VaultTransformOperations {
if (StringUtils.hasText(data.get("decoded_value"))) {
byte[] plaintext = data.get("decoded_value").getBytes();
return new VaultTransformDecodeResult(TransformPlaintext.of(plaintext).with(ciphertext.getContext()));
return new VaultTransformDecodeResult(
TransformPlaintext.of(data.get("decoded_value")).with(ciphertext.getContext()));
}
return new VaultTransformDecodeResult(TransformPlaintext.empty().with(ciphertext.getContext()));
}
private static TransformCiphertext toCiphertext(String ciphertext, @Nullable VaultTransformContext context) {
return context != null ? TransformCiphertext.of(ciphertext).with(context) : TransformCiphertext.of(ciphertext);
private static TransformCiphertext toCiphertext(Map<String, ?> data, VaultTransformContext context) {
String ciphertext = (String) data.get("encoded_value");
VaultTransformContext contextToUse = context;
if (data.containsKey("tweak")) {
byte[] tweak = Base64Utils.decodeFromString((String) data.get("tweak"));
contextToUse = VaultTransformContext.builder().transformation(context.getTransformation()).tweak(tweak)
.build();
}
return contextToUse.isEmpty() ? TransformCiphertext.of(ciphertext)
: TransformCiphertext.of(ciphertext).with(contextToUse);
}
@SuppressWarnings("unchecked")
@@ -284,14 +271,4 @@ public class VaultTransformTemplate implements VaultTransformOperations {
return (List<Map<String, String>>) vaultResponse.getRequiredData().get("batch_results");
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(getClass().getSimpleName());
sb.append(" [vaultOperations=").append(this.vaultOperations);
sb.append(", path='").append(this.path).append('\'');
sb.append(']');
return sb.toString();
}
}

View File

@@ -38,7 +38,8 @@ public class TransformCiphertext {
}
/**
* Factory method to create {@link TransformCiphertext} from the given {@code ciphertext}.
* Factory method to create {@link TransformCiphertext} from the given
* {@code ciphertext}.
* @param ciphertext the ciphertext to decrypt, must not be {@literal null} or empty.
* @return the {@link TransformCiphertext} for {@code ciphertext}.
*/
@@ -58,8 +59,8 @@ public class TransformCiphertext {
}
/**
* Create a new {@link TransformCiphertext} object from this ciphertext associated with the
* given {@link VaultTransformContext}.
* Create a new {@link TransformCiphertext} object from this ciphertext associated
* with the given {@link VaultTransformContext}.
* @param context transit context, must not be {@literal null}.
* @return the new {@link TransformCiphertext} object.
*/

View File

@@ -16,9 +16,7 @@
package org.springframework.vault.support;
import org.springframework.util.Assert;
import java.util.Arrays;
import java.util.Objects;
import org.springframework.util.ObjectUtils;
/**
* Value object representing plaintext with an optional {@link VaultTransformContext}.
@@ -44,7 +42,6 @@ public class TransformPlaintext {
/**
* Factory method to create an empty {@link TransformPlaintext}.
* @return the empty {@link TransformPlaintext} object.
* @since 1.1.2
*/
public static TransformPlaintext empty() {
return EMPTY;
@@ -93,12 +90,15 @@ public class TransformPlaintext {
}
/**
* Create a new {@link TransformPlaintext} object from this plaintext associated with the given
* {@link VaultTransformContext}.
* Create a new {@link TransformPlaintext} object from this plaintext associated with
* the given {@link VaultTransformContext}.
* @param context transform context.
* @return the new {@link TransformPlaintext} object.
*/
public TransformPlaintext with(VaultTransformContext context) {
Assert.notNull(context, "VaultTransformContext must not be null");
return new TransformPlaintext(getPlaintext(), context);
}
@@ -116,14 +116,17 @@ public class TransformPlaintext {
return true;
if (!(o instanceof TransformPlaintext))
return false;
TransformPlaintext plaintext1 = (TransformPlaintext) o;
return Arrays.equals(this.plaintext, plaintext1.plaintext) && this.context.equals(plaintext1.context);
TransformPlaintext that = (TransformPlaintext) o;
if (!ObjectUtils.nullSafeEquals(this.plaintext, that.plaintext)) {
return false;
}
return ObjectUtils.nullSafeEquals(this.context, that.context);
}
@Override
public int hashCode() {
int result = Objects.hash(this.context);
result = 31 * result + Arrays.hashCode(this.plaintext);
int result = ObjectUtils.nullSafeHashCode(this.plaintext);
result = 31 * result + ObjectUtils.nullSafeHashCode(this.context);
return result;
}

View File

@@ -15,10 +15,12 @@
*/
package org.springframework.vault.support;
import org.springframework.util.Assert;
import java.util.Arrays;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* Transform backend encode/decode context object.
*
@@ -37,7 +39,7 @@ public class VaultTransformContext {
private final byte[] tweak;
VaultTransformContext(String transformation, byte[] tweak) {
private VaultTransformContext(String transformation, byte[] tweak) {
this.transformation = transformation;
this.tweak = tweak;
}
@@ -74,6 +76,15 @@ public class VaultTransformContext {
return builder().tweak(tweak).build();
}
/**
* Return whether this object is an empty one. That is, transformation and tweak are
* both empty.
* @return {@code true} if this object is empty.
*/
public boolean isEmpty() {
return StringUtils.isEmpty(this.transformation) && ObjectUtils.isEmpty(this.tweak);
}
/**
* @return the transformation name.
*/
@@ -114,7 +125,7 @@ public class VaultTransformContext {
private byte[] tweak = new byte[0];
VaultTransformRequestBuilder() {
private VaultTransformRequestBuilder() {
}
/**

View File

@@ -30,8 +30,8 @@ public class VaultTransformDecodeResult extends AbstractResult<TransformPlaintex
private final @Nullable TransformPlaintext plaintext;
/**
* Create {@link VaultTransformDecodeResult} for a successfully decrypted {@link TransformPlaintext}
* .
* Create {@link VaultTransformDecodeResult} for a successfully decrypted
* {@link TransformPlaintext} .
* @param plaintext must not be {@literal null}.
*/
public VaultTransformDecodeResult(TransformPlaintext plaintext) {

View File

@@ -66,4 +66,5 @@ public class VaultTransformEncodeResult extends AbstractResult<TransformCipherte
TransformCiphertext ciphertext = get();
return ciphertext == null ? null : ciphertext.getCiphertext();
}
}

View File

@@ -20,6 +20,7 @@ import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@@ -49,7 +50,9 @@ class VaultTemplateTransformIntegrationTests extends IntegrationTestSupport {
@BeforeEach
void before() {
Assumptions.assumeTrue(prepare().getVersion().isEnterprise(), "Transform Secrets Engine requires enterprise version");
Assumptions.assumeTrue(prepare().getVersion().isEnterprise(),
"Transform Secrets Engine requires enterprise version");
VaultSysOperations adminOperations = this.vaultOperations.opsForSys();
@@ -60,7 +63,8 @@ class VaultTemplateTransformIntegrationTests extends IntegrationTestSupport {
}
// Write a transformation/role
this.vaultOperations.write("transform/transformation/myssn", "{\"type\": \"fpe\", \"template\": \"builtin/socialsecuritynumber\", \"allowed_roles\": [\"myrole\"]}");
this.vaultOperations.write("transform/transformation/myssn",
"{\"type\": \"fpe\", \"template\": \"builtin/socialsecuritynumber\", \"allowed_roles\": [\"myrole\"]}");
this.vaultOperations.write("transform/role/myrole", "{\"transformations\": [\"myssn\"]}");
}
@@ -73,9 +77,8 @@ class VaultTemplateTransformIntegrationTests extends IntegrationTestSupport {
@Test
void shouldEncode() {
VaultResponse response = this.vaultOperations.write("transform/encode/myrole",
String.format("{\"value\": \"123-45-6789\", \"tweak\": \"%s\"}",
Base64Utils.encodeToString("somenum".getBytes())));
VaultResponse response = this.vaultOperations.write("transform/encode/myrole", String.format(
"{\"value\": \"123-45-6789\", \"tweak\": \"%s\"}", Base64Utils.encodeToString("somenum".getBytes())));
assertThat((String) response.getRequiredData().get("encoded_value")).isNotEmpty();
}
@@ -84,19 +87,14 @@ class VaultTemplateTransformIntegrationTests extends IntegrationTestSupport {
void shouldEncodeAndDecode() {
String value = "123-45-6789";
VaultResponse response = this.vaultOperations.write("transform/encode/myrole",
String.format("{\"value\": \"%s\", \"tweak\": \"%s\"}",
value,
Base64Utils.encodeToString("somenum".getBytes())));
VaultResponse response = this.vaultOperations.write("transform/encode/myrole", String.format(
"{\"value\": \"%s\", \"tweak\": \"%s\"}", value, Base64Utils.encodeToString("somenum".getBytes())));
String encoded = (String) response.getRequiredData().get("encoded_value");
VaultResponse decoded = this.vaultOperations.write("transform/decode/myrole",
String.format("{\"value\": \"%s\", \"tweak\": \"%s\"}",
encoded,
Base64Utils.encodeToString("somenum".getBytes())));
VaultResponse decoded = this.vaultOperations.write("transform/decode/myrole", String.format(
"{\"value\": \"%s\", \"tweak\": \"%s\"}", encoded, Base64Utils.encodeToString("somenum".getBytes())));
assertThat((String) decoded.getRequiredData().get("decoded_value"))
.isEqualTo(value);
assertThat((String) decoded.getRequiredData().get("decoded_value")).isEqualTo(value);
}
}

View File

@@ -15,17 +15,22 @@
*/
package org.springframework.vault.core;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.vault.VaultException;
import org.springframework.vault.support.TransformPlaintext;
import org.springframework.vault.support.TransformCiphertext;
import org.springframework.vault.support.TransformPlaintext;
import org.springframework.vault.support.VaultMount;
import org.springframework.vault.support.VaultTransformContext;
import org.springframework.vault.support.VaultTransformDecodeResult;
@@ -34,16 +39,14 @@ import org.springframework.vault.util.IntegrationTestSupport;
import org.springframework.vault.util.RequiresVaultVersion;
import org.springframework.vault.util.Version;
import java.util.Arrays;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Integration tests for {@link VaultTemplate} using the {@code transform} backend.
*
* @author Lauren Voswinkel
* @author Mark Paluch
*/
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = VaultIntegrationTestConfiguration.class)
@@ -59,7 +62,9 @@ class VaultTransformTemplateIntegrationTests extends IntegrationTestSupport {
@BeforeEach
void before() {
Assumptions.assumeTrue(prepare().getVersion().isEnterprise(), "Transform Secrets Engine requires enterprise version");
Assumptions.assumeTrue(prepare().getVersion().isEnterprise(),
"Transform Secrets Engine requires enterprise version");
VaultSysOperations adminOperations = this.vaultOperations.opsForSys();
this.transformOperations = this.vaultOperations.opsForTransform();
@@ -71,38 +76,44 @@ class VaultTransformTemplateIntegrationTests extends IntegrationTestSupport {
}
// Write a transformation/role
this.vaultOperations.write("transform/transformation/myssn", "{" +
"\"type\": \"fpe\", " +
"\"template\": \"builtin/socialsecuritynumber\", " +
"\"allowed_roles\": [\"myrole\"]}"
);
this.vaultOperations.write("transform/transformation/myssn", "{" + "\"type\": \"fpe\", "
+ "\"template\": \"builtin/socialsecuritynumber\", " + "\"allowed_roles\": [\"myrole\"]}");
this.vaultOperations.write("transform/role/myrole", "{\"transformations\": [\"myssn\", \"internalssn\"]}");
this.vaultOperations.write("transform/transformation/internalssn", "{" +
"\"type\": \"fpe\", " +
"\"tweak_source\": \"internal\", " +
"\"template\": \"builtin/socialsecuritynumber\", " +
"\"allowed_roles\": [\"myrole\", \"internalrole\"]}"
);
this.vaultOperations.write("transform/transformation/internalssn",
"{" + "\"type\": \"fpe\", " + "\"tweak_source\": \"internal\", "
+ "\"template\": \"builtin/socialsecuritynumber\", "
+ "\"allowed_roles\": [\"myrole\", \"internalrole\"]}");
this.vaultOperations.write("transform/transformation/generatedssn",
"{" + "\"type\": \"fpe\", " + "\"tweak_source\": \"generated\", "
+ "\"template\": \"builtin/socialsecuritynumber\", "
+ "\"allowed_roles\": [\"generatedrole\"]}");
this.vaultOperations.write("transform/role/internalrole", "{\"transformations\": [\"internalssn\"]}");
this.vaultOperations.write("transform/role/generatedrole", "{\"transformations\": [\"generatedssn\"]}");
}
@AfterEach
void tearDown() {
this.vaultOperations.delete("transform/role/myrole");
this.vaultOperations.delete("transform/role/internalrole");
this.vaultOperations.delete("transform/role/generatedrole");
this.vaultOperations.delete("transform/transformation/myssn");
this.vaultOperations.delete("transform/transformation/internalssn");
this.vaultOperations.delete("transform/transformation/generatedssn");
}
@Test
void encodeCreatesCiphertextWithTransformationAndTweak() {
void encodeCreatesCiphertextWithTransformationAndProvidedTweak() {
VaultTransformContext transformRequest = VaultTransformContext.builder().transformation("myssn")
.tweak("somenum".getBytes())
.build();
.tweak("somenum".getBytes()).build();
String response = this.transformOperations.encode("myrole", "123-45-6789".getBytes(), transformRequest);
assertThat(response).matches("[0-9]{3}-[0-9]{2}-[0-9]{4}");
TransformCiphertext ciphertext = this.transformOperations.encode("myrole", "123-45-6789".getBytes(),
transformRequest);
assertThat(ciphertext.getCiphertext()).matches("[0-9]{3}-[0-9]{2}-[0-9]{4}");
assertThat(new String(ciphertext.getContext().getTweak())).isEqualTo("somenum");
}
@Test
@@ -110,14 +121,9 @@ class VaultTransformTemplateIntegrationTests extends IntegrationTestSupport {
VaultTransformContext transformRequest = VaultTransformContext.builder().transformation("myssn").build();
Exception exception = assertThrows(VaultException.class, () -> {
assertThatExceptionOfType(VaultException.class).isThrownBy(() -> {
this.transformOperations.encode("myrole", "123-45-6789".getBytes(), transformRequest);
});
String expectedMessage = "incorrect tweak size provided";
String actualMessage = exception.getMessage();
assertThat(actualMessage).contains(expectedMessage);
}).withMessageContaining("incorrect tweak size provided");
}
@Test
@@ -125,45 +131,64 @@ class VaultTransformTemplateIntegrationTests extends IntegrationTestSupport {
VaultTransformContext transformRequest = VaultTransformContext.builder().transformation("internalssn").build();
String response = this.transformOperations.encode("myrole", "123-45-6789".getBytes(), transformRequest);
assertThat(response).matches("[0-9]{3}-[0-9]{2}-[0-9]{4}");
TransformCiphertext ciphertext = this.transformOperations.encode("myrole", "123-45-6789".getBytes(),
transformRequest);
assertThat(ciphertext.getCiphertext()).matches("[0-9]{3}-[0-9]{2}-[0-9]{4}");
}
@Test
void encodeAndDecodeYieldsStartingResultWithSameTweakValueProvided() {
VaultTransformContext transformRequest = VaultTransformContext.builder().transformation("myssn").tweak("somenum".getBytes()).build();
VaultTransformContext transformRequest = VaultTransformContext.builder().transformation("myssn")
.tweak("somenum".getBytes()).build();
String targetValue = "123-45-6789";
String response = this.transformOperations.encode("myrole", targetValue.getBytes(), transformRequest);
assertThat(response).matches("[0-9]{3}-[0-9]{2}-[0-9]{4}");
assertThat(response).isNotEqualTo(targetValue);
TransformCiphertext ciphertext = this.transformOperations.encode("myrole", targetValue.getBytes(),
transformRequest);
assertThat(ciphertext.getCiphertext()).matches("[0-9]{3}-[0-9]{2}-[0-9]{4}").isNotEqualTo(targetValue);
String decodeResponse = this.transformOperations.decode("myrole", response, transformRequest);
String decodeResponse = this.transformOperations.decode("myrole", ciphertext.getCiphertext(), transformRequest);
assertThat(decodeResponse).isEqualTo(targetValue);
}
@Test
void encodeAndDecodeDoesNotYieldStartingResultWithDifferentTweakValueProvided() {
VaultTransformContext transformRequest = VaultTransformContext.builder().transformation("myssn").tweak("somenum".getBytes()).build();
VaultTransformContext transformRequest = VaultTransformContext.builder().transformation("myssn")
.tweak("somenum".getBytes()).build();
String targetValue = "123-45-6789";
String response = this.transformOperations.encode("myrole", targetValue.getBytes(), transformRequest);
assertThat(response).matches("[0-9]{3}-[0-9]{2}-[0-9]{4}");
assertThat(response).isNotEqualTo(targetValue);
TransformCiphertext ciphertext = this.transformOperations.encode("myrole", targetValue.getBytes(),
transformRequest);
assertThat(ciphertext.getCiphertext()).matches("[0-9]{3}-[0-9]{2}-[0-9]{4}").isNotEqualTo(targetValue);
VaultTransformContext decodeRequest = VaultTransformContext.builder().transformation("myssn").tweak("numsome".getBytes()).build();
VaultTransformContext otherDecodeRequest = VaultTransformContext.builder().transformation("myssn")
.tweak("numsome".getBytes()).build();
String decodeResponse = this.transformOperations.decode("myrole", response, decodeRequest);
String decodeResponse = this.transformOperations.decode("myrole", ciphertext.getCiphertext(),
otherDecodeRequest);
assertThat(decodeResponse).isNotEqualTo(targetValue);
}
@Test
void encodeAndDecodeWithoutContextWorksForGeneratedTweakSource() {
VaultTransformContext transformRequest = VaultTransformContext.builder().transformation("generatedssn").build();
TransformCiphertext ciphertext = this.transformOperations.encode("generatedrole", "123-45-6789".getBytes(),
transformRequest);
TransformPlaintext plaintext = this.transformOperations.decode("generatedrole", ciphertext);
assertThat(plaintext.asString()).isEqualTo("123-45-6789");
}
@Test
void encodeAndDecodeWithoutContextWorksForInternalTweakSource() {
String targetValue = "123-45-6789";
String response = this.transformOperations.encode("internalrole", targetValue);
assertThat(response).matches("[0-9]{3}-[0-9]{2}-[0-9]{4}");
assertThat(response).isNotEqualTo(targetValue);
assertThat(response).matches("[0-9]{3}-[0-9]{2}-[0-9]{4}").isNotEqualTo(targetValue);
String decodeResponse = this.transformOperations.decode("internalrole", response);
assertThat(decodeResponse).isEqualTo(targetValue);
@@ -171,35 +196,19 @@ class VaultTransformTemplateIntegrationTests extends IntegrationTestSupport {
@Test
void batchEncodeAndDecodeYieldsStartingResults() {
VaultTransformContext transformRequest = VaultTransformContext.builder().transformation("myssn").tweak("somenum".getBytes()).build();
List<String> ssns = Arrays.asList(
"123-01-4567",
"123-02-4567",
"123-03-4567",
"123-04-4567",
"123-05-4567"
);
VaultTransformContext transformRequest = VaultTransformContext.builder().transformation("myssn")
.tweak("somenum".getBytes()).build();
List<String> ssns = Arrays.asList("123-01-4567", "123-02-4567", "123-03-4567", "123-04-4567", "123-05-4567");
List<VaultTransformEncodeResult> encoded = this.transformOperations.encode("myrole",
Arrays.asList(
TransformPlaintext.of(ssns.get(0)).with(transformRequest),
TransformPlaintext.of(ssns.get(1)).with(transformRequest),
TransformPlaintext.of(ssns.get(2)).with(transformRequest),
TransformPlaintext.of(ssns.get(3)).with(transformRequest),
TransformPlaintext.of(ssns.get(4)).with(transformRequest)
)
);
ssns.stream().map(TransformPlaintext::of).map(plaintext -> plaintext.with(transformRequest))
.collect(Collectors.toList()));
List<VaultTransformDecodeResult> decoded = this.transformOperations.decode("myrole",
Arrays.asList(
TransformCiphertext.of(encoded.get(0).getAsString()).with(transformRequest),
TransformCiphertext.of(encoded.get(1).getAsString()).with(transformRequest),
TransformCiphertext.of(encoded.get(2).getAsString()).with(transformRequest),
TransformCiphertext.of(encoded.get(3).getAsString()).with(transformRequest),
TransformCiphertext.of(encoded.get(4).getAsString()).with(transformRequest)
)
);
encoded.stream().map(VaultTransformEncodeResult::getAsString).map(TransformCiphertext::of)
.map(ciphertext -> ciphertext.with(transformRequest)).collect(Collectors.toList()));
for (int i = 0; i < decoded.size(); i++) {
assertThat(decoded.get(i).getAsString()).isEqualTo(ssns.get(i));
@@ -209,36 +218,18 @@ class VaultTransformTemplateIntegrationTests extends IntegrationTestSupport {
@Test
void batchEncodeAndDecodeYieldsStartingResultsForInternalWithNoContext() {
List<String> ssns = Arrays.asList(
"123-01-4567",
"123-02-4567",
"123-03-4567",
"123-04-4567",
"123-05-4567"
);
List<String> ssns = Arrays.asList("123-01-4567", "123-02-4567", "123-03-4567", "123-04-4567", "123-05-4567");
List<VaultTransformEncodeResult> encoded = this.transformOperations.encode("internalrole",
Arrays.asList(
TransformPlaintext.of(ssns.get(0)),
TransformPlaintext.of(ssns.get(1)),
TransformPlaintext.of(ssns.get(2)),
TransformPlaintext.of(ssns.get(3)),
TransformPlaintext.of(ssns.get(4))
)
);
ssns.stream().map(TransformPlaintext::of).collect(Collectors.toList()));
List<VaultTransformDecodeResult> decoded = this.transformOperations.decode("internalrole",
Arrays.asList(
TransformCiphertext.of(encoded.get(0).getAsString()),
TransformCiphertext.of(encoded.get(1).getAsString()),
TransformCiphertext.of(encoded.get(2).getAsString()),
TransformCiphertext.of(encoded.get(3).getAsString()),
TransformCiphertext.of(encoded.get(4).getAsString())
)
);
encoded.stream().map(VaultTransformEncodeResult::getAsString).map(TransformCiphertext::of)
.collect(Collectors.toList()));
for (int i = 0; i < decoded.size(); i++) {
assertThat(decoded.get(i).getAsString()).isEqualTo(ssns.get(i));
}
}
}

View File

@@ -7,6 +7,7 @@
* Support for PEM-encoded certificates for keystore and truststore usage.
* `ReactiveVaultEndpointProvider` for non-blocking lookup of `VaultEndpoint`.
* `VaultKeyValueMetadataOperations` for Key-Value metadata interaction.
* Support for `transform` backend (Enterprise Feature).
[[new-features.2-2-0]]
=== What's new in Spring Vault 2.2