18
18
import software .amazon .awssdk .services .s3 .model .ObjectIdentifier ;
19
19
import software .amazon .awssdk .services .s3 .model .PutObjectRequest ;
20
20
import software .amazon .awssdk .services .s3 .model .PutObjectResponse ;
21
+ import software .amazon .awssdk .services .s3 .model .S3Request ;
21
22
import software .amazon .encryption .s3 .internal .GetEncryptedObjectPipeline ;
22
23
import software .amazon .encryption .s3 .internal .NoRetriesAsyncRequestBody ;
23
24
import software .amazon .encryption .s3 .internal .PutEncryptedObjectPipeline ;
41
42
42
43
import static software .amazon .encryption .s3 .internal .ApiNameVersion .API_NAME_INTERCEPTOR ;
43
44
45
+ /**
46
+ * This client is a drop-in replacement for the S3 Async client. It will automatically encrypt objects
47
+ * on putObject and decrypt objects on getObject using the provided encryption key(s).
48
+ */
44
49
public class S3AsyncEncryptionClient extends DelegatingS3AsyncClient {
45
50
46
51
private final S3AsyncClient _wrappedClient ;
@@ -60,16 +65,51 @@ private S3AsyncEncryptionClient(Builder builder) {
60
65
_enableMultipartPutObject = builder ._enableMultipartPutObject ;
61
66
}
62
67
68
+ /**
69
+ * Creates a builder that can be used to configure and create a {@link S3AsyncEncryptionClient}.
70
+ */
63
71
public static Builder builder () {
64
72
return new Builder ();
65
73
}
66
74
67
- // Helper function to attach encryption contexts to a request
75
+
76
+ /**
77
+ * Attaches encryption context to a request. Must be used as a parameter to
78
+ * {@link S3Request#overrideConfiguration()} in the request.
79
+ * Encryption context can be used to enforce authentication of ciphertext.
80
+ * The same encryption context used to encrypt MUST be provided on decrypt.
81
+ * Encryption context is only supported with KMS keys.
82
+ * @param encryptionContext the encryption context to use for the request.
83
+ * @return Consumer for use in overrideConfiguration()
84
+ */
68
85
public static Consumer <AwsRequestOverrideConfiguration .Builder > withAdditionalEncryptionContext (Map <String , String > encryptionContext ) {
69
86
return builder ->
70
87
builder .putExecutionAttribute (S3EncryptionClient .ENCRYPTION_CONTEXT , encryptionContext );
71
88
}
72
89
90
+ /**
91
+ * See {@link S3AsyncClient#putObject(PutObjectRequest, AsyncRequestBody)}.
92
+ * <p>
93
+ * In the S3AsyncEncryptionClient, putObject encrypts the data in the requestBody as it is
94
+ * written to S3.
95
+ * </p>
96
+ * @param putObjectRequest the request instance
97
+ * @param requestBody
98
+ * Functional interface that can be implemented to produce the request content in a non-blocking manner. The
99
+ * size of the content is expected to be known up front. See {@link AsyncRequestBody} for specific details on
100
+ * implementing this interface as well as links to precanned implementations for common scenarios like
101
+ * uploading from a file.
102
+ * @return A Java Future containing the result of the PutObject operation returned by the service.<br/>
103
+ * The CompletableFuture returned by this method can be completed exceptionally with the following
104
+ * exceptions.
105
+ * <ul>
106
+ * <li>SdkException Base class for all exceptions that can be thrown by the SDK (both service and client).
107
+ * Can be used for catch all scenarios.</li>
108
+ * <li>SdkClientException If any client side error occurs such as an IO related failure, failure to get
109
+ * credentials, etc.</li>
110
+ * <li>S3EncryptionClientException Base class for all encryption client specific exceptions.</li>
111
+ * </ul>
112
+ */
73
113
@ Override
74
114
public CompletableFuture <PutObjectResponse > putObject (PutObjectRequest putObjectRequest , AsyncRequestBody requestBody )
75
115
throws AwsServiceException , SdkClientException {
@@ -106,6 +146,29 @@ private CompletableFuture<PutObjectResponse> multipartPutObject(PutObjectRequest
106
146
return pipeline .putObject (putObjectRequest , noRetryBody );
107
147
}
108
148
149
+ /**
150
+ * See {@link S3AsyncClient#getObject(GetObjectRequest, AsyncResponseTransformer)}
151
+ * <p>
152
+ * In the S3AsyncEncryptionClient, getObject decrypts the data as it is read from S3.
153
+ * </p>
154
+ * @param getObjectRequest the request instance.
155
+ * @param asyncResponseTransformer
156
+ * The response transformer for processing the streaming response in a non-blocking manner. See
157
+ * {@link AsyncResponseTransformer} for details on how this callback should be implemented and for links to
158
+ * precanned implementations for common scenarios like downloading to a file.
159
+ * @return A future to the transformed result of the AsyncResponseTransformer.<br/>
160
+ * The CompletableFuture returned by this method can be completed exceptionally with the following
161
+ * exceptions.
162
+ * <ul>
163
+ * <li>NoSuchKeyException The specified key does not exist.</li>
164
+ * <li>InvalidObjectStateException Object is archived and inaccessible until restored.</li>
165
+ * <li>SdkException Base class for all exceptions that can be thrown by the SDK (both service and client).
166
+ * Can be used for catch all scenarios.</li>
167
+ * <li>SdkClientException If any client side error occurs such as an IO related failure, failure to get
168
+ * credentials, etc.</li>
169
+ * <li>S3EncryptionClientException Base class for all encryption client exceptions.</li>
170
+ * </ul>
171
+ */
109
172
@ Override
110
173
public <T > CompletableFuture <T > getObject (GetObjectRequest getObjectRequest ,
111
174
AsyncResponseTransformer <GetObjectResponse , T > asyncResponseTransformer ) {
@@ -119,6 +182,15 @@ public <T> CompletableFuture<T> getObject(GetObjectRequest getObjectRequest,
119
182
return pipeline .getObject (getObjectRequest , asyncResponseTransformer );
120
183
}
121
184
185
+ /**
186
+ * See {@link S3AsyncClient#deleteObject(DeleteObjectRequest)}.
187
+ * <p>
188
+ * In the S3 Encryption Client, deleteObject also deletes the instruction file,
189
+ * if present.
190
+ * </p>
191
+ * @param deleteObjectRequest the request instance
192
+ * @return A Java Future containing the result of the DeleteObject operation returned by the service.
193
+ */
122
194
@ Override
123
195
public CompletableFuture <DeleteObjectResponse > deleteObject (DeleteObjectRequest deleteObjectRequest ) {
124
196
final DeleteObjectRequest actualRequest = deleteObjectRequest .toBuilder ()
@@ -136,6 +208,15 @@ public CompletableFuture<DeleteObjectResponse> deleteObject(DeleteObjectRequest
136
208
return instructionResponse .thenApplyAsync (deletion );
137
209
}
138
210
211
+ /**
212
+ * See {@link S3AsyncClient#deleteObjects(DeleteObjectsRequest)}.
213
+ * <p>
214
+ * In the S3 Encryption Client, deleteObjects also deletes the instruction file(s),
215
+ * if present.
216
+ * </p>
217
+ * @param deleteObjectsRequest the request instance
218
+ * @return A Java Future containing the result of the DeleteObjects operation returned by the service.
219
+ */
139
220
@ Override
140
221
public CompletableFuture <DeleteObjectsResponse > deleteObjects (DeleteObjectsRequest deleteObjectsRequest ) throws AwsServiceException ,
141
222
SdkClientException {
@@ -149,6 +230,9 @@ public CompletableFuture<DeleteObjectsResponse> deleteObjects(DeleteObjectsReque
149
230
.build ());
150
231
}
151
232
233
+ /**
234
+ * Closes the wrapped {@link S3AsyncClient} instance.
235
+ */
152
236
@ Override
153
237
public void close () {
154
238
_wrappedClient .close ();
@@ -174,6 +258,14 @@ private Builder() {
174
258
}
175
259
176
260
/**
261
+ * Specifies the wrapped client to use for the actual S3 request.
262
+ * This client will be used for all async operations.
263
+ * You can pass any S3AsyncClient implementation (e.g. the CRT
264
+ * client), but you cannot pass an S3AsyncEncryptionClient.
265
+ * @param wrappedClient the client to use for S3 operations.
266
+ * @return Returns a reference to this object so that method calls can be chained together.
267
+ */
268
+ /*
177
269
* Note that this does NOT create a defensive clone of S3Client. Any modifications made to the wrapped
178
270
* S3Client will be reflected in this Builder.
179
271
*/
@@ -187,41 +279,77 @@ public Builder wrappedClient(S3AsyncClient wrappedClient) {
187
279
return this ;
188
280
}
189
281
282
+ /**
283
+ * Specifies the {@link CryptographicMaterialsManager} to use for managing key wrapping keys.
284
+ * @param cryptoMaterialsManager the CMM to use
285
+ * @return Returns a reference to this object so that method calls can be chained together.
286
+ */
190
287
public Builder cryptoMaterialsManager (CryptographicMaterialsManager cryptoMaterialsManager ) {
191
288
this ._cryptoMaterialsManager = cryptoMaterialsManager ;
192
289
checkKeyOptions ();
193
290
194
291
return this ;
195
292
}
196
293
294
+ /**
295
+ * Specifies the {@link Keyring} to use for key wrapping and unwrapping.
296
+ * @param keyring the Keyring instance to use
297
+ * @return Returns a reference to this object so that method calls can be chained together.
298
+ */
197
299
public Builder keyring (Keyring keyring ) {
198
300
this ._keyring = keyring ;
199
301
checkKeyOptions ();
200
302
201
303
return this ;
202
304
}
203
305
306
+ /**
307
+ * Specifies a "raw" AES key to use for key wrapping/unwrapping.
308
+ * @param aesKey the AES key as a {@link SecretKey} instance
309
+ * @return Returns a reference to this object so that method calls can be chained together.
310
+ */
204
311
public Builder aesKey (SecretKey aesKey ) {
205
312
this ._aesKey = aesKey ;
206
313
checkKeyOptions ();
207
314
208
315
return this ;
209
316
}
210
317
318
+ /**
319
+ * Specifies a "raw" RSA key pair to use for key wrapping/unwrapping.
320
+ * @param rsaKeyPair the RSA key pair as a {@link KeyPair} instance
321
+ * @return Returns a reference to this object so that method calls can be chained together.
322
+ */
211
323
public Builder rsaKeyPair (KeyPair rsaKeyPair ) {
212
324
this ._rsaKeyPair = new PartialRsaKeyPair (rsaKeyPair );
213
325
checkKeyOptions ();
214
326
215
327
return this ;
216
328
}
217
329
330
+ /**
331
+ * Specifies a "raw" RSA key pair to use for key wrapping/unwrapping.
332
+ * This option takes a {@link PartialRsaKeyPair} instance, which allows
333
+ * either a public key (decryption only) or private key (encryption only)
334
+ * rather than requiring both parts.
335
+ * @param partialRsaKeyPair the RSA key pair as a {@link PartialRsaKeyPair} instance
336
+ * @return Returns a reference to this object so that method calls can be chained together.
337
+ */
218
338
public Builder rsaKeyPair (PartialRsaKeyPair partialRsaKeyPair ) {
219
339
this ._rsaKeyPair = partialRsaKeyPair ;
220
340
checkKeyOptions ();
221
341
222
342
return this ;
223
343
}
224
344
345
+ /**
346
+ * Specifies a KMS key to use for key wrapping/unwrapping. Any valid KMS key
347
+ * identifier (including the full ARN or an alias ARN) is permitted. When
348
+ * decrypting objects, the key referred to by this KMS key identifier is
349
+ * always used.
350
+ * @param kmsKeyId the KMS key identifier as a {@link String} instance
351
+ * @return Returns a reference to this object so that method calls can be chained together.
352
+ */
225
353
public Builder kmsKeyId (String kmsKeyId ) {
226
354
this ._kmsKeyId = kmsKeyId ;
227
355
checkKeyOptions ();
@@ -253,31 +381,79 @@ private boolean onlyOneNonNull(Object... values) {
253
381
return haveOneNonNull ;
254
382
}
255
383
384
+ /**
385
+ * When set to true, decryption of objects using legacy key wrapping
386
+ * modes is enabled.
387
+ * @param shouldEnableLegacyWrappingAlgorithms true to enable legacy wrapping algorithms
388
+ * @return Returns a reference to this object so that method calls can be chained together.
389
+ */
256
390
public Builder enableLegacyWrappingAlgorithms (boolean shouldEnableLegacyWrappingAlgorithms ) {
257
391
this ._enableLegacyWrappingAlgorithms = shouldEnableLegacyWrappingAlgorithms ;
258
392
return this ;
259
393
}
260
394
395
+ /**
396
+ * When set to true, decryption of content using legacy encryption algorithms
397
+ * is enabled. This includes use of GetObject requests with a range, as this
398
+ * mode is not authenticated.
399
+ * @param shouldEnableLegacyUnauthenticatedModes true to enable legacy content algorithms
400
+ * @return Returns a reference to this object so that method calls can be chained together.
401
+ */
261
402
public Builder enableLegacyUnauthenticatedModes (boolean shouldEnableLegacyUnauthenticatedModes ) {
262
403
this ._enableLegacyUnauthenticatedModes = shouldEnableLegacyUnauthenticatedModes ;
263
404
return this ;
264
405
}
265
406
407
+ /**
408
+ * When set to true, authentication of streamed objects is delayed until the
409
+ * entire object is read from the stream. When this mode is enabled, the consuming
410
+ * application must support a way to invalidate any data read from the stream as
411
+ * the tag will not be validated until the stream is read to completion, as the
412
+ * integrity of the data cannot be ensured. See the AWS Documentation for more
413
+ * information.
414
+ * @param shouldEnableDelayedAuthenticationMode true to enable delayed authentication
415
+ * @return Returns a reference to this object so that method calls can be chained together.
416
+ */
266
417
public Builder enableDelayedAuthenticationMode (boolean shouldEnableDelayedAuthenticationMode ) {
267
418
this ._enableDelayedAuthenticationMode = shouldEnableDelayedAuthenticationMode ;
268
419
return this ;
269
420
}
270
421
422
+ /**
423
+ * When set to true, the putObject method will use multipart upload to perform
424
+ * the upload. Disabled by default.
425
+ * @param _enableMultipartPutObject true enables the multipart upload implementation of putObject
426
+ * @return Returns a reference to this object so that method calls can be chained together.
427
+ */
271
428
public Builder enableMultipartPutObject (boolean _enableMultipartPutObject ) {
272
429
this ._enableMultipartPutObject = _enableMultipartPutObject ;
273
430
return this ;
274
431
}
275
432
433
+ /**
434
+ * Allows the user to pass an instance of {@link Provider} to be used
435
+ * for cryptographic operations. By default, the S3 Encryption Client
436
+ * will use the first compatible {@link Provider} in the chain. When this option
437
+ * is used, the given provider will be used for all cryptographic operations.
438
+ * If the provider is missing a required algorithm suite, e.g. AES-GCM, then
439
+ * operations may fail.
440
+ * Advanced option. Users who configure a {@link Provider} are responsible
441
+ * for the security and correctness of the provider.
442
+ * @param cryptoProvider the {@link Provider to always use}
443
+ * @return Returns a reference to this object so that method calls can be chained together.
444
+ */
276
445
public Builder cryptoProvider (Provider cryptoProvider ) {
277
446
this ._cryptoProvider = cryptoProvider ;
278
447
return this ;
279
448
}
280
449
450
+ /**
451
+ * Allows the user to pass an instance of {@link SecureRandom} to be used
452
+ * for generating keys and IVs. Advanced option. Users who provide a {@link SecureRandom}
453
+ * are responsible for the security and correctness of the {@link SecureRandom} implementation.
454
+ * @param secureRandom the {@link SecureRandom} instance to use
455
+ * @return Returns a reference to this object so that method calls can be chained together.
456
+ */
281
457
public Builder secureRandom (SecureRandom secureRandom ) {
282
458
if (secureRandom == null ) {
283
459
throw new S3EncryptionClientException ("SecureRandom provided to S3EncryptionClient cannot be null" );
@@ -286,6 +462,11 @@ public Builder secureRandom(SecureRandom secureRandom) {
286
462
return this ;
287
463
}
288
464
465
+ /**
466
+ * Validates and builds the S3AsyncEncryptionClient according
467
+ * to the configuration options passed to the Builder object.
468
+ * @return an instance of the S3AsyncEncryptionClient
469
+ */
289
470
public S3AsyncEncryptionClient build () {
290
471
if (!onlyOneNonNull (_cryptoMaterialsManager , _keyring , _aesKey , _rsaKeyPair , _kmsKeyId )) {
291
472
throw new S3EncryptionClientException ("Exactly one must be set of: crypto materials manager, keyring, AES key, RSA key pair, KMS key id" );
0 commit comments