quantranhong1999 commented on code in PR #2488: URL: https://github.com/apache/james-project/pull/2488#discussion_r1847566373
########## server/blob/blob-s3/src/main/java/org/apache/james/blob/objectstorage/aws/S3BlobStoreDAO.java: ########## @@ -166,64 +177,79 @@ private static class FluxResponse { } private Mono<FluxResponse> getObject(BucketName bucketName, BlobId blobId) { - return Mono.fromFuture(() -> - client.getObject( - builder -> builder.bucket(bucketName.asString()).key(blobId.asString()), - new AsyncResponseTransformer<GetObjectResponse, FluxResponse>() { - - FluxResponse response; - - @Override - public CompletableFuture<FluxResponse> prepare() { - response = new FluxResponse(); - return response.supportingCompletableFuture; - } - - @Override - public void onResponse(GetObjectResponse response) { - this.response.sdkResponse = response; - } - - @Override - public void exceptionOccurred(Throwable error) { - this.response.supportingCompletableFuture.completeExceptionally(error); - } - - @Override - public void onStream(SdkPublisher<ByteBuffer> publisher) { - response.flux = Flux.from(publisher); - response.supportingCompletableFuture.complete(response); - } - })) - .switchIfEmpty(Mono.error(() -> new ObjectStoreIOException("Request was unexpectedly canceled, no GetObjectResponse"))); + return buildGetObjectRequestBuilder(bucketName, blobId) + .flatMap(getObjectRequestBuilder -> Mono.fromFuture(() -> + client.getObject(getObjectRequestBuilder.build(), + new AsyncResponseTransformer<GetObjectResponse, FluxResponse>() { + + FluxResponse response; + + @Override + public CompletableFuture<FluxResponse> prepare() { + response = new FluxResponse(); + return response.supportingCompletableFuture; + } + + @Override + public void onResponse(GetObjectResponse response) { + this.response.sdkResponse = response; + } + + @Override + public void exceptionOccurred(Throwable error) { + this.response.supportingCompletableFuture.completeExceptionally(error); + } + + @Override + public void onStream(SdkPublisher<ByteBuffer> publisher) { + response.flux = Flux.from(publisher); + response.supportingCompletableFuture.complete(response); + } + })) + .switchIfEmpty(Mono.error(() -> new ObjectStoreIOException("Request was unexpectedly canceled, no GetObjectResponse")))); } @Override public Mono<byte[]> readBytes(BucketName bucketName, BlobId blobId) { BucketName resolvedBucketName = bucketNameResolver.resolve(bucketName); - return Mono.fromFuture(() -> - client.getObject( - builder -> builder.bucket(resolvedBucketName.asString()).key(blobId.asString()), - new MinimalCopyBytesResponseTransformer(configuration, blobId))) - .onErrorMap(NoSuchBucketException.class, e -> new ObjectNotFoundException("Bucket not found " + resolvedBucketName.asString(), e)) - .onErrorMap(NoSuchKeyException.class, e -> new ObjectNotFoundException("Blob not found " + blobId.asString() + " in bucket " + resolvedBucketName.asString(), e)) - .publishOn(Schedulers.parallel()) - .map(BytesWrapper::asByteArrayUnsafe) - .onErrorMap(e -> e.getCause() instanceof OutOfMemoryError, Throwable::getCause); + return buildGetObjectRequestBuilder(resolvedBucketName, blobId) + .flatMap(putObjectRequest -> Mono.fromFuture(() -> + client.getObject(putObjectRequest.build(), new MinimalCopyBytesResponseTransformer(configuration, blobId))) + .onErrorMap(NoSuchBucketException.class, e -> new ObjectNotFoundException("Bucket not found " + resolvedBucketName.asString(), e)) + .onErrorMap(NoSuchKeyException.class, e -> new ObjectNotFoundException("Blob not found " + blobId.asString() + " in bucket " + resolvedBucketName.asString(), e)) + .publishOn(Schedulers.parallel()) + .map(BytesWrapper::asByteArrayUnsafe) + .onErrorMap(e -> e.getCause() instanceof OutOfMemoryError, Throwable::getCause)); + } + + private Mono<GetObjectRequest.Builder> buildGetObjectRequestBuilder(BucketName bucketName, BlobId blobId) { + GetObjectRequest.Builder baseBuilder = GetObjectRequest.builder() + .bucket(bucketName.asString()) + .key(blobId.asString()); + + if (s3RequestOption.ssec().enable()) { + return Mono.from(s3RequestOption.ssec().sseCustomerKeyFactory().get() + .generate(bucketName, blobId)) + .map(sseCustomerKey -> baseBuilder + .sseCustomerAlgorithm(sseCustomerKey.ssecAlgorithm()) Review Comment: > Consider this scenario: SSE-C is configured to encrypt objects with AES256, an object A is uploaded using that configuration, then the configured decryption algorihtm is changed to DES: What happends when we I try download object A? IMO it is a failure. The admin needs to make sure to keep the same encryption/decryption configuration IMO. For example AES blob store https://github.com/apache/james-project/blob/master/docs/modules/servers/partials/configure/blobstore.adoc#encryption-choice. > Maybe we can use [get-bucket-encryption](https://docs.aws.amazon.com/cli/latest/reference/s3api/get-bucket-encryption.html)? BTW how would you resolve the issue with that? It seems to me that `get-bucket-encryption` is more at the bucket level while SSE-C is more at the object level. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org