Skip to content

Commit 596e3b4

Browse files
rchandran80mp911de
authored andcommitted
Add reference support in Transform FPE.
Original pull request: gh-897 Closes gh-894 Signed-off-by: Roopesh Chandran <[email protected]>
1 parent 51d8875 commit 596e3b4

File tree

4 files changed

+127
-10
lines changed

4 files changed

+127
-10
lines changed

spring-vault-core/src/main/java/org/springframework/vault/core/VaultTransformTemplate.java

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,10 @@ private static void applyTransformOptions(VaultTransformContext context, Map<Str
181181
if (!ObjectUtils.isEmpty(context.getTweak())) {
182182
request.put("tweak", Base64.getEncoder().encodeToString(context.getTweak()));
183183
}
184+
// NEW: pass "reference" in each item, if present
185+
if (StringUtils.hasText(context.getReference())) {
186+
request.put("reference", context.getReference());
187+
}
184188
}
185189

186190
private static List<VaultTransformEncodeResult> toEncodedResults(VaultResponse vaultResponse,
@@ -221,17 +225,17 @@ private static List<VaultTransformDecodeResult> toDecryptionResults(VaultRespons
221225

222226
for (int i = 0; i < batchRequest.size(); i++) {
223227

224-
VaultTransformDecodeResult encrypted;
228+
VaultTransformDecodeResult decodeResult; // Renamed from "encrypted"
225229
TransformCiphertext ciphertext = batchRequest.get(i);
226230

227231
if (batchData.size() > i) {
228-
encrypted = getDecryptionResult(batchData.get(i), ciphertext);
232+
decodeResult = getDecryptionResult(batchData.get(i), ciphertext);
229233
}
230234
else {
231-
encrypted = new VaultTransformDecodeResult(new VaultException("No result for ciphertext #" + i));
235+
decodeResult = new VaultTransformDecodeResult(new VaultException("No result for ciphertext #" + i));
232236
}
233237

234-
result.add(encrypted);
238+
result.add(decodeResult);
235239
}
236240

237241
return result;
@@ -246,8 +250,29 @@ private static VaultTransformDecodeResult getDecryptionResult(Map<String, String
246250

247251
if (StringUtils.hasText(data.get("decoded_value"))) {
248252

249-
return new VaultTransformDecodeResult(
250-
TransformPlaintext.of(data.get("decoded_value")).with(ciphertext.getContext()));
253+
// 1. Read reference from Vault's response (if present).
254+
String returnedRef = data.get("reference");
255+
256+
// 2. Build an updated context that merges the existing transformation/tweak
257+
// with the newly-returned reference. If no reference is returned, keep the
258+
// old one. Note:- Relying on reference from originalContext is aimed at
259+
// providing a
260+
// fallback strategy, if vault does not return the reference, in any
261+
// circumstance.
262+
VaultTransformContext originalContext = ciphertext.getContext();
263+
VaultTransformContext updatedContext = VaultTransformContext.builder()
264+
.transformation(originalContext.getTransformation())
265+
.tweak(originalContext.getTweak())
266+
.reference(returnedRef != null ? returnedRef : originalContext.getReference())
267+
.build();
268+
269+
// 3. Attach that updated context to the newly decoded plaintext.
270+
TransformPlaintext decodedPlaintext = TransformPlaintext.of(data.get("decoded_value")).with(updatedContext);
271+
272+
return new VaultTransformDecodeResult(decodedPlaintext);
273+
274+
// return new VaultTransformDecodeResult(
275+
// TransformPlaintext.of(data.get("decoded_value")).with(ciphertext.getContext()));
251276
}
252277

253278
return new VaultTransformDecodeResult(TransformPlaintext.empty().with(ciphertext.getContext()));
@@ -257,12 +282,16 @@ private static TransformCiphertext toCiphertext(Map<String, ?> data, VaultTransf
257282

258283
String ciphertext = (String) data.get("encoded_value");
259284

285+
// if Vault returns "reference" in batch_results,capturing it for co-relation.
286+
String returnedRef = (String) data.get("reference");
287+
260288
VaultTransformContext contextToUse = context;
261289
if (data.containsKey("tweak")) {
262290
byte[] tweak = Base64.getDecoder().decode((String) data.get("tweak"));
263291
contextToUse = VaultTransformContext.builder()
264292
.transformation(context.getTransformation())
265293
.tweak(tweak)
294+
.reference(returnedRef != null ? returnedRef : context.getReference())
266295
.build();
267296
}
268297

spring-vault-core/src/main/java/org/springframework/vault/support/VaultTransformContext.java

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,18 @@ public class VaultTransformContext {
3232
* Empty (default) {@link VaultTransformContext} without a {@literal context} and
3333
* {@literal nonce}.
3434
*/
35-
private static final VaultTransformContext EMPTY = new VaultTransformContext("", new byte[0]);
35+
private static final VaultTransformContext EMPTY = new VaultTransformContext("", new byte[0], "");
3636

3737
private final String transformation;
3838

3939
private final byte[] tweak;
4040

41-
private VaultTransformContext(String transformation, byte[] tweak) {
41+
private final String reference;
42+
43+
private VaultTransformContext(String transformation, byte[] tweak, String reference) {
4244
this.transformation = transformation;
4345
this.tweak = tweak;
46+
this.reference = reference;
4447
}
4548

4649
/**
@@ -98,6 +101,13 @@ public byte[] getTweak() {
98101
return this.tweak;
99102
}
100103

104+
/**
105+
* @return The reference identifier for batch operations
106+
*/
107+
public String getReference() {
108+
return this.reference;
109+
}
110+
101111
@Override
102112
public boolean equals(Object o) {
103113
if (this == o)
@@ -123,6 +133,20 @@ public static class VaultTransformRequestBuilder {
123133

124134
private byte[] tweak = new byte[0];
125135

136+
/**
137+
* A user-defined identifier that can be used to correlate items in a batch
138+
* request with their corresponding results in Vault's {@code batch_results}.
139+
* <br/>
140+
* <br/>
141+
*
142+
* <p>
143+
* If set, Vault echoes this value in the response so clients can match inputs to
144+
* outputs reliably. If Vault does not return the {@code reference}, the original
145+
* client-supplied reference remains available for correlation.
146+
* </p>
147+
*/
148+
private String reference = "";
149+
126150
private VaultTransformRequestBuilder() {
127151
}
128152

@@ -157,12 +181,24 @@ public VaultTransformRequestBuilder tweak(byte[] tweak) {
157181
return this;
158182
}
159183

184+
/**
185+
* Set a user-defined reference identifier. This reference is placed into each
186+
* item of a batch request and, if supported by Vault, echoed in the batch
187+
* results.
188+
* @param reference the correlation identifier; can be {@code null} or empty.
189+
* @return {@code this} builder instance .
190+
*/
191+
public VaultTransformRequestBuilder reference(String reference) {
192+
this.reference = reference;
193+
return this;
194+
}
195+
160196
/**
161197
* Build a new {@link VaultTransformContext} instance.
162198
* @return a new {@link VaultTransformContext}.
163199
*/
164200
public VaultTransformContext build() {
165-
return new VaultTransformContext(this.transformation, this.tweak);
201+
return new VaultTransformContext(this.transformation, this.tweak, this.reference);
166202
}
167203

168204
}

spring-vault-core/src/test/java/org/springframework/vault/core/VaultTransformTemplateIntegrationTests.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.vault.core;
1717

18+
import java.util.ArrayList;
1819
import java.util.Arrays;
1920
import java.util.List;
2021
import java.util.stream.Collectors;
@@ -248,4 +249,37 @@ void batchEncodeAndDecodeYieldsStartingResultsForInternalWithNoContext() {
248249
}
249250
}
250251

251-
}
252+
@Test
253+
void batchEncodeAndDecodeWithReference() {
254+
// Prepare test data
255+
List<TransformPlaintext> batch = new ArrayList<>();
256+
batch.add(TransformPlaintext.of("123-45-6789")
257+
.with(VaultTransformContext.builder().transformation("myssn").reference("ref-1").build()));
258+
batch.add(TransformPlaintext.of("234-56-7890")
259+
.with(VaultTransformContext.builder().transformation("myssn").reference("ref-2").build()));
260+
261+
// Encode
262+
List<VaultTransformEncodeResult> encodeResults = transformOperations.encode("myrole", batch);
263+
264+
// Verify encode results
265+
assertThat(encodeResults).hasSize(2);
266+
assertThat(encodeResults.get(0).isSuccessful()).isTrue();
267+
assertThat(encodeResults.get(1).isSuccessful()).isTrue();
268+
269+
// Prepare decode batch
270+
List<TransformCiphertext> ciphertexts = new ArrayList<>();
271+
ciphertexts.add(encodeResults.get(0).get());
272+
ciphertexts.add(encodeResults.get(1).get());
273+
274+
// Decode
275+
List<VaultTransformDecodeResult> decodeResults = transformOperations.decode("myrole", ciphertexts);
276+
277+
// Verify decode results
278+
assertThat(decodeResults).hasSize(2);
279+
assertThat(decodeResults.get(0).get().asString()).isEqualTo("123-45-6789");
280+
assertThat(decodeResults.get(1).get().asString()).isEqualTo("234-56-7890");
281+
assertThat(decodeResults.get(0).get().getContext().getReference()).isEqualTo("ref-1");
282+
assertThat(decodeResults.get(1).get().getContext().getReference()).isEqualTo("ref-2");
283+
}
284+
285+
}

spring-vault-core/src/test/java/org/springframework/vault/support/VaultTransformContextUnitTests.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,22 @@ void createsFromTweak() {
5858
assertThat(context.getTransformation()).isEmpty();
5959
}
6060

61+
@Test
62+
void createsContextWithReference() {
63+
64+
String transformName = "some_transformation";
65+
byte[] tweak = { 1, 2, 3, 4, 5, 6, 7 };
66+
String referenceValue = "my-reference";
67+
68+
VaultTransformContext context = VaultTransformContext.builder()
69+
.transformation(transformName)
70+
.tweak(tweak)
71+
.reference(referenceValue)
72+
.build();
73+
74+
assertThat(context.getTransformation()).isEqualTo(transformName);
75+
assertThat(context.getTweak()).isEqualTo(tweak);
76+
assertThat(context.getReference()).isEqualTo(referenceValue);
77+
}
78+
6179
}

0 commit comments

Comments
 (0)