This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch camel-4.22.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-4.22.x by this push:
new 072844868ecf [backport camel-4.22.x] CAMEL-26336: camel-minio:
MinioProducer should apply configured server-side encryption options (#28615)
072844868ecf is described below
commit 072844868ecf0a5f309ec270fa57a3ce4f979f87
Author: Andrea Cosentino <[email protected]>
AuthorDate: Wed Oct 28 21:50:25 2026 +0100
[backport camel-4.22.x] CAMEL-26336: camel-minio: MinioProducer should
apply configured server-side encryption options (#28615)
* [backport camel-4.22.x] CAMEL-26336: camel-minio: MinioProducer should
apply configured server-side encryption options
(cherry picked from commit b9b931f9f5522dd8d61ad9ded50510c065fe6965)
Signed-off-by: Andrea Cosentino <[email protected]>
* CAMEL-26336: camel-minio - adapt the encryption test to the operations of
camel-4.22.x
The test sent MinioOperations.getObjectRange, which exists only on main
(CAMEL-25933 renamed getPartialObject to getObjectRange). On this branch
the operation is getPartialObject, which reaches the same producer method.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Andrea Cosentino <[email protected]>
---------
Signed-off-by: Andrea Cosentino <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
---
.../camel/component/minio/MinioProducer.java | 48 ++++-
.../minio/MinioProducerEncryptionTest.java | 240 +++++++++++++++++++++
2 files changed, 282 insertions(+), 6 deletions(-)
diff --git
a/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioProducer.java
b/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioProducer.java
index 9b9d926883a9..d95a2636226f 100644
---
a/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioProducer.java
+++
b/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioProducer.java
@@ -67,6 +67,16 @@ public class MinioProducer extends DefaultProducer {
super(endpoint);
}
+ @Override
+ protected void doStart() throws Exception {
+ super.doStart();
+ if (getConfiguration().getServerSideEncryption() != null
+ && getConfiguration().getServerSideEncryptionCustomerKey() !=
null) {
+ throw new IllegalArgumentException(
+ "Only one of serverSideEncryption or
serverSideEncryptionCustomerKey can be configured");
+ }
+ }
+
public static Message getMessageForResponse(final Exchange exchange) {
return exchange.getMessage();
}
@@ -195,6 +205,12 @@ public class MinioProducer extends DefaultProducer {
.object(objectName)
.userMetadata(objectMetadata);
+ if (getConfiguration().getServerSideEncryptionCustomerKey() != null) {
+
putObjectRequest.sse(getConfiguration().getServerSideEncryptionCustomerKey());
+ } else if (getConfiguration().getServerSideEncryption() != null) {
+ putObjectRequest.sse(getConfiguration().getServerSideEncryption());
+ }
+
if (!extraHeaders.isEmpty()) {
putObjectRequest.extraHeaders(extraHeaders);
}
@@ -255,11 +271,21 @@ public class MinioProducer extends DefaultProducer {
.bucket(bucketName)
.object(sourceKey);
+ if (getConfiguration().getServerSideEncryptionCustomerKey() !=
null) {
+
copySourceBuilder.ssec(getConfiguration().getServerSideEncryptionCustomerKey());
+ }
+
CopyObjectArgs.Builder copyObjectRequest = CopyObjectArgs.builder()
.bucket(destinationBucketName)
.object(destinationKey)
.source(copySourceBuilder.build());
+ if (getConfiguration().getServerSideEncryptionCustomerKey() !=
null) {
+
copyObjectRequest.sse(getConfiguration().getServerSideEncryptionCustomerKey());
+ } else if (getConfiguration().getServerSideEncryption() != null) {
+
copyObjectRequest.sse(getConfiguration().getServerSideEncryption());
+ }
+
ObjectWriteResponse copyObjectResult =
minioClient.copyObject(copyObjectRequest.build());
Message message = getMessageForResponse(exchange);
@@ -340,10 +366,15 @@ public class MinioProducer extends DefaultProducer {
final String bucketName = determineBucketName(exchange);
final String sourceKey = determineObjectName(exchange);
- InputStream respond = minioClient.getObject(GetObjectArgs.builder()
+ GetObjectArgs.Builder getObjectRequest = GetObjectArgs.builder()
.bucket(bucketName)
- .object(sourceKey)
- .build());
+ .object(sourceKey);
+
+ if (getConfiguration().getServerSideEncryptionCustomerKey() !=
null) {
+
getObjectRequest.ssec(getConfiguration().getServerSideEncryptionCustomerKey());
+ }
+
+ InputStream respond =
minioClient.getObject(getObjectRequest.build());
Message message = getMessageForResponse(exchange);
message.setBody(respond);
@@ -370,12 +401,17 @@ public class MinioProducer extends DefaultProducer {
"A Offset and length header must be configured to
perform a partial get operation.");
}
- InputStream respond = minioClient.getObject(GetObjectArgs.builder()
+ GetObjectArgs.Builder getObjectRequest = GetObjectArgs.builder()
.bucket(bucketName)
.object(sourceKey)
.offset(Long.parseLong(offset))
- .length(Long.parseLong(length))
- .build());
+ .length(Long.parseLong(length));
+
+ if (getConfiguration().getServerSideEncryptionCustomerKey() !=
null) {
+
getObjectRequest.ssec(getConfiguration().getServerSideEncryptionCustomerKey());
+ }
+
+ InputStream respond =
minioClient.getObject(getObjectRequest.build());
Message message = getMessageForResponse(exchange);
message.setBody(respond);
diff --git
a/components/camel-minio/src/test/java/org/apache/camel/component/minio/MinioProducerEncryptionTest.java
b/components/camel-minio/src/test/java/org/apache/camel/component/minio/MinioProducerEncryptionTest.java
new file mode 100644
index 000000000000..98ad4c0ac899
--- /dev/null
+++
b/components/camel-minio/src/test/java/org/apache/camel/component/minio/MinioProducerEncryptionTest.java
@@ -0,0 +1,240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.minio;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import io.minio.BucketExistsArgs;
+import io.minio.CopyObjectArgs;
+import io.minio.GetObjectArgs;
+import io.minio.GetObjectResponse;
+import io.minio.MinioClient;
+import io.minio.ObjectWriteResponse;
+import io.minio.PutObjectArgs;
+import io.minio.ServerSideEncryption;
+import org.apache.camel.Exchange;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class MinioProducerEncryptionTest extends CamelTestSupport {
+
+ private MinioClient minioClient;
+ private SecretKey secretKey;
+
+ @BeforeEach
+ void init() throws Exception {
+ minioClient = mock(MinioClient.class);
+
when(minioClient.bucketExists(any(BucketExistsArgs.class))).thenReturn(true);
+ KeyGenerator generator = KeyGenerator.getInstance("AES");
+ generator.init(256);
+ secretKey = generator.generateKey();
+ }
+
+ private MinioProducer createProducer(MinioEndpoint endpoint) throws
Exception {
+ endpoint.start();
+ MinioProducer producer = new MinioProducer(endpoint);
+ producer.start();
+ return producer;
+ }
+
+ @Test
+ void putObjectWithServerSideEncryption() throws Exception {
+ ServerSideEncryption.S3 sse = new ServerSideEncryption.S3();
+ MinioComponent component = context.getComponent("minio",
MinioComponent.class);
+ MinioEndpoint endpoint = (MinioEndpoint)
component.createEndpoint("minio://mybucket?autoCreateBucket=false");
+ endpoint.getConfiguration().setMinioClient(minioClient);
+ endpoint.getConfiguration().setServerSideEncryption(sse);
+
+
when(minioClient.putObject(any(PutObjectArgs.class))).thenReturn(mock(ObjectWriteResponse.class));
+
+ MinioProducer producer = createProducer(endpoint);
+ Exchange exchange = endpoint.createExchange();
+ exchange.getIn().setHeader(MinioConstants.OBJECT_NAME, "test.txt");
+ exchange.getIn().setBody("content");
+
+ producer.process(exchange);
+
+ ArgumentCaptor<PutObjectArgs> captor =
ArgumentCaptor.forClass(PutObjectArgs.class);
+ verify(minioClient).putObject(captor.capture());
+ assertSame(sse, captor.getValue().sse());
+ producer.stop();
+ endpoint.stop();
+ }
+
+ @Test
+ void putObjectWithCustomerKey() throws Exception {
+ ServerSideEncryption.CustomerKey ssec = new
ServerSideEncryption.CustomerKey(secretKey);
+ MinioComponent component = context.getComponent("minio",
MinioComponent.class);
+ MinioEndpoint endpoint = (MinioEndpoint)
component.createEndpoint("minio://mybucket?autoCreateBucket=false");
+ endpoint.getConfiguration().setMinioClient(minioClient);
+ endpoint.getConfiguration().setServerSideEncryptionCustomerKey(ssec);
+
+
when(minioClient.putObject(any(PutObjectArgs.class))).thenReturn(mock(ObjectWriteResponse.class));
+
+ MinioProducer producer = createProducer(endpoint);
+ Exchange exchange = endpoint.createExchange();
+ exchange.getIn().setHeader(MinioConstants.OBJECT_NAME, "test.txt");
+ exchange.getIn().setBody("content");
+
+ producer.process(exchange);
+
+ ArgumentCaptor<PutObjectArgs> captor =
ArgumentCaptor.forClass(PutObjectArgs.class);
+ verify(minioClient).putObject(captor.capture());
+ assertSame(ssec, captor.getValue().sse());
+ producer.stop();
+ endpoint.stop();
+ }
+
+ @Test
+ void producerStartWithBothEncryptionOptionsThrows() throws Exception {
+ ServerSideEncryption.S3 sse = new ServerSideEncryption.S3();
+ ServerSideEncryption.CustomerKey ssec = new
ServerSideEncryption.CustomerKey(secretKey);
+
+ MinioComponent component = context.getComponent("minio",
MinioComponent.class);
+ MinioEndpoint endpoint = (MinioEndpoint)
component.createEndpoint("minio://mybucket?autoCreateBucket=false");
+ endpoint.getConfiguration().setMinioClient(minioClient);
+ endpoint.getConfiguration().setServerSideEncryption(sse);
+ endpoint.getConfiguration().setServerSideEncryptionCustomerKey(ssec);
+
+ endpoint.start();
+ MinioProducer producer = new MinioProducer(endpoint);
+ assertThrows(IllegalArgumentException.class, producer::start);
+ endpoint.stop();
+ }
+
+ @Test
+ void copyObjectWithServerSideEncryption() throws Exception {
+ ServerSideEncryption.S3 sse = new ServerSideEncryption.S3();
+
+ MinioComponent component = context.getComponent("minio",
MinioComponent.class);
+ MinioEndpoint endpoint = (MinioEndpoint)
component.createEndpoint("minio://mybucket?autoCreateBucket=false");
+ endpoint.getConfiguration().setMinioClient(minioClient);
+ endpoint.getConfiguration().setServerSideEncryption(sse);
+
+
when(minioClient.copyObject(any(CopyObjectArgs.class))).thenReturn(mock(ObjectWriteResponse.class));
+
+ MinioProducer producer = createProducer(endpoint);
+ Exchange exchange = endpoint.createExchange();
+ exchange.getIn().setHeader(MinioConstants.MINIO_OPERATION,
MinioOperations.copyObject);
+ exchange.getIn().setHeader(MinioConstants.OBJECT_NAME, "source.txt");
+ exchange.getIn().setHeader(MinioConstants.DESTINATION_OBJECT_NAME,
"dest.txt");
+ exchange.getIn().setHeader(MinioConstants.DESTINATION_BUCKET_NAME,
"dest-bucket");
+
+ producer.process(exchange);
+
+ ArgumentCaptor<CopyObjectArgs> captor =
ArgumentCaptor.forClass(CopyObjectArgs.class);
+ verify(minioClient).copyObject(captor.capture());
+ assertSame(sse, captor.getValue().sse());
+ producer.stop();
+ endpoint.stop();
+ }
+
+ @Test
+ void copyObjectWithCustomerKey() throws Exception {
+ ServerSideEncryption.CustomerKey ssec = new
ServerSideEncryption.CustomerKey(secretKey);
+
+ MinioComponent component = context.getComponent("minio",
MinioComponent.class);
+ MinioEndpoint endpoint = (MinioEndpoint)
component.createEndpoint("minio://mybucket?autoCreateBucket=false");
+ endpoint.getConfiguration().setMinioClient(minioClient);
+ endpoint.getConfiguration().setServerSideEncryptionCustomerKey(ssec);
+
+
when(minioClient.copyObject(any(CopyObjectArgs.class))).thenReturn(mock(ObjectWriteResponse.class));
+
+ MinioProducer producer = createProducer(endpoint);
+ Exchange exchange = endpoint.createExchange();
+ exchange.getIn().setHeader(MinioConstants.MINIO_OPERATION,
MinioOperations.copyObject);
+ exchange.getIn().setHeader(MinioConstants.OBJECT_NAME, "source.txt");
+ exchange.getIn().setHeader(MinioConstants.DESTINATION_OBJECT_NAME,
"dest.txt");
+ exchange.getIn().setHeader(MinioConstants.DESTINATION_BUCKET_NAME,
"dest-bucket");
+
+ producer.process(exchange);
+
+ ArgumentCaptor<CopyObjectArgs> captor =
ArgumentCaptor.forClass(CopyObjectArgs.class);
+ verify(minioClient).copyObject(captor.capture());
+ assertSame(ssec, captor.getValue().sse());
+ assertNotNull(captor.getValue().source());
+ assertSame(ssec, captor.getValue().source().ssec());
+ producer.stop();
+ endpoint.stop();
+ }
+
+ @Test
+ void getObjectWithCustomerKey() throws Exception {
+ ServerSideEncryption.CustomerKey ssec = new
ServerSideEncryption.CustomerKey(secretKey);
+
+ MinioComponent component = context.getComponent("minio",
MinioComponent.class);
+ MinioEndpoint endpoint = (MinioEndpoint)
component.createEndpoint("minio://mybucket?autoCreateBucket=false");
+ endpoint.getConfiguration().setMinioClient(minioClient);
+ endpoint.getConfiguration().setServerSideEncryptionCustomerKey(ssec);
+
+
when(minioClient.getObject(any(GetObjectArgs.class))).thenReturn(mock(GetObjectResponse.class));
+
+ MinioProducer producer = createProducer(endpoint);
+ Exchange exchange = endpoint.createExchange();
+ exchange.getIn().setHeader(MinioConstants.MINIO_OPERATION,
MinioOperations.getObject);
+ exchange.getIn().setHeader(MinioConstants.OBJECT_NAME, "test.txt");
+
+ producer.process(exchange);
+
+ ArgumentCaptor<GetObjectArgs> captor =
ArgumentCaptor.forClass(GetObjectArgs.class);
+ verify(minioClient).getObject(captor.capture());
+ assertSame(ssec, captor.getValue().ssec());
+ producer.stop();
+ endpoint.stop();
+ }
+
+ @Test
+ void getPartialObjectWithCustomerKey() throws Exception {
+ ServerSideEncryption.CustomerKey ssec = new
ServerSideEncryption.CustomerKey(secretKey);
+
+ MinioComponent component = context.getComponent("minio",
MinioComponent.class);
+ MinioEndpoint endpoint = (MinioEndpoint)
component.createEndpoint("minio://mybucket?autoCreateBucket=false");
+ endpoint.getConfiguration().setMinioClient(minioClient);
+ endpoint.getConfiguration().setServerSideEncryptionCustomerKey(ssec);
+
+
when(minioClient.getObject(any(GetObjectArgs.class))).thenReturn(mock(GetObjectResponse.class));
+
+ MinioProducer producer = createProducer(endpoint);
+ Exchange exchange = endpoint.createExchange();
+ exchange.getIn().setHeader(MinioConstants.MINIO_OPERATION,
MinioOperations.getPartialObject);
+ exchange.getIn().setHeader(MinioConstants.OBJECT_NAME, "test.txt");
+ exchange.getIn().setHeader(MinioConstants.OFFSET, "10");
+ exchange.getIn().setHeader(MinioConstants.LENGTH, "20");
+
+ producer.process(exchange);
+
+ ArgumentCaptor<GetObjectArgs> captor =
ArgumentCaptor.forClass(GetObjectArgs.class);
+ verify(minioClient).getObject(captor.capture());
+ assertSame(ssec, captor.getValue().ssec());
+ assertEquals(10L, captor.getValue().offset());
+ assertEquals(20L, captor.getValue().length());
+ producer.stop();
+ endpoint.stop();
+ }
+}