Skip to content

Commit 0fe33b7

Browse files
james-luke-airwallexmp911de
authored andcommitted
Add reactive support for transit operations.
Closes gh-620 Original pull request: gh-778
1 parent 4f7f7e9 commit 0fe33b7

File tree

10 files changed

+1471
-33
lines changed

10 files changed

+1471
-33
lines changed

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

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2022 the original author or authors.
2+
* Copyright 2017-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,18 +15,17 @@
1515
*/
1616
package org.springframework.vault.core;
1717

18-
import java.util.function.Function;
19-
2018
import org.reactivestreams.Publisher;
21-
import reactor.core.publisher.Flux;
22-
import reactor.core.publisher.Mono;
23-
2419
import org.springframework.lang.Nullable;
2520
import org.springframework.vault.VaultException;
2621
import org.springframework.vault.support.VaultResponse;
2722
import org.springframework.vault.support.VaultResponseSupport;
2823
import org.springframework.web.reactive.function.client.WebClient;
2924
import org.springframework.web.reactive.function.client.WebClientException;
25+
import reactor.core.publisher.Flux;
26+
import reactor.core.publisher.Mono;
27+
28+
import java.util.function.Function;
3029

3130
/**
3231
* Interface that specifies a basic set of Vault operations executed on a reactive
@@ -123,4 +122,17 @@ <V, T extends Publisher<V>> T doWithVault(Function<WebClient, ? extends T> clien
123122
<V, T extends Publisher<V>> T doWithSession(Function<WebClient, ? extends T> sessionCallback)
124123
throws VaultException, WebClientException;
125124

125+
/**
126+
* @return the operations interface to interact with the Vault transit backend.
127+
*/
128+
ReactiveVaultTransitOperations opsForTransit();
129+
130+
/**
131+
* Return {@link ReactiveVaultTransitOperations} if the transit backend is mounted on
132+
* a different path than {@code transit}.
133+
* @param path the mount path
134+
* @return the operations interface to interact with the Vault transit backend.
135+
*/
136+
ReactiveVaultTransitOperations opsForTransit(String path);
137+
126138
}

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

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2022 the original author or authors.
2+
* Copyright 2017-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,17 +15,9 @@
1515
*/
1616
package org.springframework.vault.core;
1717

18-
import java.util.List;
19-
import java.util.Map;
20-
import java.util.function.Function;
21-
2218
import org.reactivestreams.Publisher;
23-
import reactor.core.publisher.Flux;
24-
import reactor.core.publisher.Mono;
25-
2619
import org.springframework.core.ParameterizedTypeReference;
2720
import org.springframework.http.HttpMethod;
28-
import org.springframework.http.HttpStatus;
2921
import org.springframework.http.client.reactive.ClientHttpConnector;
3022
import org.springframework.lang.Nullable;
3123
import org.springframework.util.Assert;
@@ -49,6 +41,12 @@
4941
import org.springframework.web.reactive.function.client.WebClient;
5042
import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec;
5143
import org.springframework.web.reactive.function.client.WebClientException;
44+
import reactor.core.publisher.Flux;
45+
import reactor.core.publisher.Mono;
46+
47+
import java.util.List;
48+
import java.util.Map;
49+
import java.util.function.Function;
5250

5351
import static org.springframework.web.reactive.function.client.ExchangeFilterFunction.ofRequestProcessor;
5452

@@ -367,4 +365,14 @@ public Mono<VaultToken> getVaultToken() {
367365

368366
}
369367

368+
@Override
369+
public ReactiveVaultTransitOperations opsForTransit() {
370+
return opsForTransit("transit");
371+
}
372+
373+
@Override
374+
public ReactiveVaultTransitOperations opsForTransit(String path) {
375+
return new ReactiveVaultTransitTemplate(this, path);
376+
}
377+
370378
}
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
/*
2+
* Copyright 2023-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.vault.core;
17+
18+
import org.springframework.vault.support.Ciphertext;
19+
import org.springframework.vault.support.Hmac;
20+
import org.springframework.vault.support.Plaintext;
21+
import org.springframework.vault.support.RawTransitKey;
22+
import org.springframework.vault.support.Signature;
23+
import org.springframework.vault.support.SignatureValidation;
24+
import org.springframework.vault.support.TransitKeyType;
25+
import org.springframework.vault.support.VaultDecryptionResult;
26+
import org.springframework.vault.support.VaultEncryptionResult;
27+
import org.springframework.vault.support.VaultHmacRequest;
28+
import org.springframework.vault.support.VaultSignRequest;
29+
import org.springframework.vault.support.VaultSignatureVerificationRequest;
30+
import org.springframework.vault.support.VaultTransitContext;
31+
import org.springframework.vault.support.VaultTransitKey;
32+
import org.springframework.vault.support.VaultTransitKeyConfiguration;
33+
import org.springframework.vault.support.VaultTransitKeyCreationRequest;
34+
import reactor.core.publisher.Flux;
35+
import reactor.core.publisher.Mono;
36+
37+
import java.util.List;
38+
39+
/**
40+
* Interface that specifies a set of {@code transit} operations executed on a reactive
41+
* infrastructure, implemented by
42+
* {@link org.springframework.vault.core.ReactiveVaultTransitTemplate}.
43+
*
44+
* @author James Luke
45+
*/
46+
public interface ReactiveVaultTransitOperations {
47+
48+
/**
49+
* Create a new named encryption key given a {@code name}
50+
* @param keyName must not be empty or {@literal null}
51+
*/
52+
Mono<Void> createKey(String keyName);
53+
54+
/**
55+
* Create a new named encryption key given a {@code name} and
56+
* {@link VaultTransitKeyCreationRequest}. The key options set here cannot be changed
57+
* after key creation.
58+
* @param keyName must not be empty or {@literal null}.
59+
* @param createKeyRequest must not be {@literal null}.
60+
*/
61+
Mono<Void> createKey(String keyName, VaultTransitKeyCreationRequest createKeyRequest);
62+
63+
/**
64+
* @return stream of transit key names.
65+
*/
66+
Flux<String> getKeys();
67+
68+
/**
69+
* Create a new named encryption key given a {@code name}.
70+
* @param keyName must not be empty or {@literal null}.
71+
* @param keyConfiguration must not be {@literal null}.
72+
*/
73+
Mono<Void> configureKey(String keyName, VaultTransitKeyConfiguration keyConfiguration);
74+
75+
/**
76+
* Returns the value of the named encryption key. Depending on the type of key,
77+
* different information may be returned. The key must be exportable to support this
78+
* operation.
79+
* @param keyName must not be empty or {@literal null}.
80+
* @param type must not be {@literal null}.
81+
* @return the {@link RawTransitKey}. May be empty if key does not exist
82+
*/
83+
Mono<RawTransitKey> exportKey(String keyName, TransitKeyType type);
84+
85+
/**
86+
* Return information about a named encryption key.
87+
* @param keyName must not be empty or {@literal null}.
88+
* @return the {@link VaultTransitKey}. May be empty if key does not exist
89+
*/
90+
Mono<VaultTransitKey> getKey(String keyName);
91+
92+
/**
93+
* Deletes a named encryption key. It will no longer be possible to decrypt any data
94+
* encrypted with the named key.
95+
* @param keyName must not be empty or {@literal null}.
96+
*/
97+
Mono<Void> deleteKey(String keyName);
98+
99+
/**
100+
* Rotates the version of the named key. After rotation, new plain text requests will
101+
* be encrypted with the new version of the key. To upgrade ciphertext to be encrypted
102+
* with the latest version of the key, use {@link #rewrap(String, String)}.
103+
* @param keyName must not be empty or {@literal null}.
104+
* @see #rewrap(String, String)
105+
*/
106+
Mono<Void> rotate(String keyName);
107+
108+
/**
109+
* Encrypts the provided plain text using the named key. The given {@code plaintext}
110+
* is encoded into bytes using the {@link java.nio.charset.Charset#defaultCharset()
111+
* default charset}. Use
112+
* {@link #encrypt(String, org.springframework.vault.support.Plaintext)} to construct
113+
* a {@link org.springframework.vault.support.Plaintext#of(byte[]) Plaintext} object
114+
* from bytes to avoid {@link java.nio.charset.Charset} mismatches.
115+
* @param keyName must not be empty or {@literal null}.
116+
* @param plaintext must not be empty or {@literal null}.
117+
* @return cipher text.
118+
*/
119+
Mono<String> encrypt(String keyName, String plaintext);
120+
121+
/**
122+
* Encrypts the provided {@code plaintext} using the named key.
123+
* @param keyName must not be empty or {@literal null}.
124+
* @param plaintext must not be {@literal null}.
125+
* @return cipher text.
126+
*/
127+
Mono<Ciphertext> encrypt(String keyName, Plaintext plaintext);
128+
129+
/**
130+
* Encrypts the provided {@code plaintext} using the named key.
131+
* @param keyName must not be empty or {@literal null}.
132+
* @param plaintext must not be empty or {@literal null}.
133+
* @param transitRequest must not be {@literal null}. Use
134+
* {@link VaultTransitContext#empty()} if no request options provided.
135+
* @return cipher text.
136+
*/
137+
Mono<String> encrypt(String keyName, byte[] plaintext, VaultTransitContext transitRequest);
138+
139+
/**
140+
* Encrypts the provided batch of {@code plaintext} using the named key and context.
141+
* The encryption is done using transit backend's batch operation.
142+
* @param keyName must not be empty or {@literal null}.
143+
* @param batchRequest a list of {@link Plaintext} which includes plain text and an
144+
* optional context.
145+
* @return the encrypted result in the order of {@code batchRequest} plaintexts.
146+
*/
147+
Flux<VaultEncryptionResult> encrypt(String keyName, List<Plaintext> batchRequest);
148+
149+
/**
150+
* Decrypts the provided plain text using the named key. The decoded {@code plaintext}
151+
* is decoded into {@link String} the {@link java.nio.charset.Charset#defaultCharset()
152+
* default charset}. Use
153+
* {@link #decrypt(String, org.springframework.vault.support.Ciphertext)} to obtain a
154+
* {@link org.springframework.vault.support.Ciphertext} object that allows to control
155+
* the {@link java.nio.charset.Charset} for later consumption.
156+
* @param keyName must not be empty or {@literal null}.
157+
* @param ciphertext must not be empty or {@literal null}.
158+
* @return plain text.
159+
*/
160+
Mono<String> decrypt(String keyName, String ciphertext);
161+
162+
/**
163+
* Decrypts the provided cipher text using the named key.
164+
* @param keyName must not be empty or {@literal null}.
165+
* @param ciphertext must not be {@literal null}.
166+
* @return plain text.
167+
*/
168+
Mono<Plaintext> decrypt(String keyName, Ciphertext ciphertext);
169+
170+
/**
171+
* Decrypts the provided {@code ciphertext} using the named key.
172+
* @param keyName must not be empty or {@literal null}.
173+
* @param ciphertext must not be empty or {@literal null}.
174+
* @param transitContext must not be {@literal null}. Use
175+
* {@link VaultTransitContext#empty()} if no request options provided.
176+
* @return cipher text.
177+
* @return plain text.
178+
*/
179+
Mono<byte[]> decrypt(String keyName, String ciphertext, VaultTransitContext transitContext);
180+
181+
/**
182+
* Decrypts the provided batch of cipher text using the named key and context. The*
183+
* decryption is done using transit backend's batch operation.
184+
* @param keyName must not be empty or {@literal null}.
185+
* @param batchRequest a list of {@link Ciphertext} which includes plain text and an
186+
* optional context.
187+
* @return the decrypted result in the order of {@code batchRequest} ciphertexts.
188+
*/
189+
Flux<VaultDecryptionResult> decrypt(String keyName, List<Ciphertext> batchRequest);
190+
191+
/**
192+
* Rewrap the provided cipher text using the latest version of the named key. Because
193+
* this never returns plain text, it is possible to delegate this functionality to
194+
* untrusted users or scripts.
195+
* @param keyName must not be empty or {@literal null}.
196+
* @param ciphertext must not be empty or {@literal null}.
197+
* @return cipher text.
198+
* @see #rotate(String)
199+
*/
200+
Mono<String> rewrap(String keyName, String ciphertext);
201+
202+
/**
203+
* Rewrap the provided cipher text using the latest version of the named key. Because
204+
* this never returns plain text, it is possible to delegate this functionality to
205+
* untrusted users or scripts.
206+
* @param keyName must not be empty or {@literal null}.
207+
* @param ciphertext must not be empty or {@literal null}.
208+
* @param transitContext must not be {@literal null}. Use
209+
* {@link VaultTransitContext#empty()} if no request options provided.
210+
* @return cipher text.
211+
* @see #rotate(String)
212+
*/
213+
Mono<String> rewrap(String keyName, String ciphertext, VaultTransitContext transitContext);
214+
215+
/**
216+
* Create a HMAC using {@code keyName} of given {@link Plaintext} using the default
217+
* hash algorithm. The key can be of any type supported by transit; the raw key will
218+
* be marshaled into bytes to be used for the HMAC function. If the key is of a type
219+
* that supports rotation, the latest (current) version will be used.
220+
* @param keyName must not be empty or {@literal null}.
221+
* @param plaintext must not be {@literal null}.
222+
* @return the digest of given data the default hash algorithm and the named key.
223+
*/
224+
Mono<Hmac> getHmac(String keyName, Plaintext plaintext);
225+
226+
/**
227+
* Create a HMAC using {@code keyName} of given {@link VaultHmacRequest} using the
228+
* default hash algorithm. The key can be of any type supported by transit; the raw
229+
* key will be marshaled into bytes to be used for the HMAC function. If the key is of
230+
* a type that supports rotation, configured {@link VaultHmacRequest#getKeyVersion()}
231+
* will be used.
232+
* @param keyName must not be empty or {@literal null}.
233+
* @param hmacRequest the {@link VaultHmacRequest}, must not be {@literal null}.
234+
* @return the digest of given data the default hash algorithm and the named key.
235+
*/
236+
Mono<Hmac> getHmac(String keyName, VaultHmacRequest hmacRequest);
237+
238+
/**
239+
* Create a cryptographic signature using {@code keyName} of the given
240+
* {@link Plaintext} and the default hash algorithm. The key must be of a type that
241+
* supports signing.
242+
* @param keyName must not be empty or {@literal null}.
243+
* @param plaintext must not be empty or {@literal null}.
244+
* @return Signature for {@link Plaintext}.
245+
*/
246+
Mono<Signature> sign(String keyName, Plaintext plaintext);
247+
248+
/**
249+
* Create a cryptographic signature using {@code keyName} of the given
250+
* {@link VaultSignRequest} and the specified hash algorithm. The key must be of a
251+
* type that supports signing.
252+
* @param keyName must not be empty or {@literal null}.
253+
* @param signRequest {@link VaultSignRequest} must not be empty or {@literal null}.
254+
* @return Signature for {@link VaultSignRequest}.
255+
*/
256+
Mono<Signature> sign(String keyName, VaultSignRequest signRequest);
257+
258+
/**
259+
* Verify the cryptographic signature using {@code keyName} of the given
260+
* {@link Plaintext} and {@link Signature}.
261+
* @param keyName must not be empty or {@literal null}.
262+
* @param plaintext must not be {@literal null}.
263+
* @param signature Signature to be verified, must not be {@literal null}.
264+
* @return {@literal true} if the signature is valid, {@literal false} otherwise.
265+
*/
266+
Mono<Boolean> verify(String keyName, Plaintext plaintext, Signature signature);
267+
268+
/**
269+
* Verify the cryptographic signature using {@code keyName} of the given
270+
* {@link VaultSignRequest}.
271+
* @param keyName must not be empty or {@literal null}.
272+
* @param verificationRequest {@link VaultSignatureVerificationRequest} must not be
273+
* {@literal null}.
274+
* @return the resulting {@link SignatureValidation}.
275+
*/
276+
Mono<SignatureValidation> verify(String keyName, VaultSignatureVerificationRequest verificationRequest);
277+
278+
}

0 commit comments

Comments
 (0)