You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2017/08/29 11:35:50 UTC

camel git commit: CAMEL-11713: Camel-AWS S3: Support Client side Symmetric/Asymmetric Encryption

Repository: camel
Updated Branches:
  refs/heads/master cad37dc67 -> a2d2a1f35


CAMEL-11713: Camel-AWS S3: Support Client side Symmetric/Asymmetric Encryption


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/a2d2a1f3
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/a2d2a1f3
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/a2d2a1f3

Branch: refs/heads/master
Commit: a2d2a1f35278f80e581d94cb215abf6c2b3f05ab
Parents: cad37dc
Author: Andrea Cosentino <an...@gmail.com>
Authored: Tue Aug 29 13:32:34 2017 +0200
Committer: Andrea Cosentino <an...@gmail.com>
Committed: Tue Aug 29 13:32:34 2017 +0200

----------------------------------------------------------------------
 .../src/main/docs/aws-s3-component.adoc         |   4 +-
 .../camel/component/aws/s3/S3Configuration.java |  98 +++-
 .../camel/component/aws/s3/S3Endpoint.java      |  15 +-
 .../aws/s3/AmazonS3EncryptionClientMock.java    | 473 +++++++++++++++++++
 .../s3/S3ComponentCopyObjectEncryptionTest.java |  92 ++++
 5 files changed, 652 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/a2d2a1f3/components/camel-aws/src/main/docs/aws-s3-component.adoc
----------------------------------------------------------------------
diff --git a/components/camel-aws/src/main/docs/aws-s3-component.adoc b/components/camel-aws/src/main/docs/aws-s3-component.adoc
index 8ec277b..2612603 100644
--- a/components/camel-aws/src/main/docs/aws-s3-component.adoc
+++ b/components/camel-aws/src/main/docs/aws-s3-component.adoc
@@ -63,7 +63,7 @@ with the following path and query parameters:
 | **bucketNameOrArn** | *Required* Bucket name or ARN |  | String
 |=======================================================================
 
-#### Query Parameters (41 parameters):
+#### Query Parameters (43 parameters):
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |=======================================================================
@@ -71,11 +71,13 @@ with the following path and query parameters:
 | **accessKey** (common) | Amazon AWS Access Key |  | String
 | **amazonS3Client** (common) | Reference to a com.amazonaws.services.sqs.AmazonS3 in the link:registry.htmlRegistry. |  | AmazonS3
 | **amazonS3Endpoint** (common) | The region with which the AWS-S3 client wants to work with. |  | String
+| **encryptionMaterials** (common) | The encryption materials to use in case of Symmetric/Asymmetric client usage |  | EncryptionMaterials
 | **pathStyleAccess** (common) | Whether or not the S3 client should use path style access | false | boolean
 | **policy** (common) | Camel 2.8.4: The policy for this queue to set in the com.amazonaws.services.s3.AmazonS3setBucketPolicy() method. |  | String
 | **proxyHost** (common) | Camel 2.16: To define a proxy host when instantiating the SQS client |  | String
 | **proxyPort** (common) | Camel 2.16: Specify a proxy port to be used inside the client definition. |  | Integer
 | **secretKey** (common) | Amazon AWS Secret Key |  | String
+| **useEncryption** (common) | Define if encryption must be used or not | false | boolean
 | **autocloseBody** (consumer) | If this option is true and includeBody is true then the S3Object.close() method will be called on exchange completion This option is strongly related to includeBody option. In case of setting includeBody to true and autocloseBody to false it will be up to the caller to close the S3Object stream. Setting autocloseBody to true will close the S3Object stream automatically. | true | boolean
 | **bridgeErrorHandler** (consumer) | Allows for bridging the consumer to the Camel routing Error Handler which mean any exceptions occurred while the consumer is trying to pickup incoming messages or the likes will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions that will be logged at WARN or ERROR level and ignored. | false | boolean
 | **deleteAfterRead** (consumer) | Delete objects from S3 after they have been retrieved. The delete is only performed if the Exchange is committed. If a rollback occurs the object is not deleted. If this option is false then the same objects will be retrieve over and over again on the polls. Therefore you need to use the Idempotent Consumer EIP in the route to filter out duplicates. You can filter using the link S3ConstantsBUCKET_NAME and link S3ConstantsKEY headers or only the link S3ConstantsKEY header. | true | boolean

http://git-wip-us.apache.org/repos/asf/camel/blob/a2d2a1f3/components/camel-aws/src/main/java/org/apache/camel/component/aws/s3/S3Configuration.java
----------------------------------------------------------------------
diff --git a/components/camel-aws/src/main/java/org/apache/camel/component/aws/s3/S3Configuration.java b/components/camel-aws/src/main/java/org/apache/camel/component/aws/s3/S3Configuration.java
index bd26cea..ff4184a 100644
--- a/components/camel-aws/src/main/java/org/apache/camel/component/aws/s3/S3Configuration.java
+++ b/components/camel-aws/src/main/java/org/apache/camel/component/aws/s3/S3Configuration.java
@@ -17,6 +17,7 @@
 package org.apache.camel.component.aws.s3;
 
 import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.model.EncryptionMaterials;
 
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriParams;
@@ -66,13 +67,18 @@ public class S3Configuration implements Cloneable {
     private S3Operations operation;
     @UriParam(label = "consumer", defaultValue = "true")
     private boolean autocloseBody = true;
+    @UriParam(label = "common")
+    private EncryptionMaterials encryptionMaterials;
+    @UriParam(label = "common", defaultValue = "false")
+    private boolean useEncryption;
 
     public long getPartSize() {
         return partSize;
     }
 
     /**
-     * *Camel 2.15.0*: Setup the partSize which is used in multi part upload, the default size is 25M.
+     * *Camel 2.15.0*: Setup the partSize which is used in multi part upload,
+     * the default size is 25M.
      */
     public void setPartSize(long partSize) {
         this.partSize = partSize;
@@ -83,7 +89,8 @@ public class S3Configuration implements Cloneable {
     }
 
     /**
-     * *Camel 2.15.0*: If it is true, camel will upload the file with multi part format, the part size is decided by the option of `partSize`
+     * *Camel 2.15.0*: If it is true, camel will upload the file with multi part
+     * format, the part size is decided by the option of `partSize`
      */
     public void setMultiPartUpload(boolean multiPartUpload) {
         this.multiPartUpload = multiPartUpload;
@@ -127,7 +134,8 @@ public class S3Configuration implements Cloneable {
     }
 
     /**
-     * Reference to a `com.amazonaws.services.sqs.AmazonS3` in the link:registry.html[Registry].
+     * Reference to a `com.amazonaws.services.sqs.AmazonS3` in the
+     * link:registry.html[Registry].
      */
     public void setAmazonS3Client(AmazonS3 amazonS3Client) {
         this.amazonS3Client = amazonS3Client;
@@ -138,8 +146,9 @@ public class S3Configuration implements Cloneable {
     }
 
     /**
-     * *Camel 2.10.1*: The prefix which is used in the com.amazonaws.services.s3.model.ListObjectsRequest
-     * to only consume objects we are interested in.
+     * *Camel 2.10.1*: The prefix which is used in the
+     * com.amazonaws.services.s3.model.ListObjectsRequest to only consume
+     * objects we are interested in.
      */
     public void setPrefix(String prefix) {
         this.prefix = prefix;
@@ -150,7 +159,8 @@ public class S3Configuration implements Cloneable {
     }
 
     /**
-     * Name of the bucket. The bucket will be created if it don't already exists.
+     * Name of the bucket. The bucket will be created if it don't already
+     * exists.
      */
     public void setBucketName(String bucketName) {
         this.bucketName = bucketName;
@@ -180,10 +190,13 @@ public class S3Configuration implements Cloneable {
     }
 
     /**
-     * If it is true, the exchange body will be set to a stream to the contents of the file.
-     * If false, the headers will be set with the S3 object metadata, but the body will be null. 
-     * This option is strongly related to autocloseBody option. In case of setting includeBody to true and autocloseBody to false, it 
-     * will be up to the caller to close the S3Object stream. Setting autocloseBody to true, will close the S3Object stream automatically.
+     * If it is true, the exchange body will be set to a stream to the contents
+     * of the file. If false, the headers will be set with the S3 object
+     * metadata, but the body will be null. This option is strongly related to
+     * autocloseBody option. In case of setting includeBody to true and
+     * autocloseBody to false, it will be up to the caller to close the S3Object
+     * stream. Setting autocloseBody to true, will close the S3Object stream
+     * automatically.
      */
     public void setIncludeBody(boolean includeBody) {
         this.includeBody = includeBody;
@@ -198,12 +211,15 @@ public class S3Configuration implements Cloneable {
     }
 
     /**
-     * Delete objects from S3 after they have been retrieved.  The delete is only performed if the Exchange is committed.
-     * If a rollback occurs, the object is not deleted.
+     * Delete objects from S3 after they have been retrieved. The delete is only
+     * performed if the Exchange is committed. If a rollback occurs, the object
+     * is not deleted.
      * <p/>
-     * If this option is false, then the same objects will be retrieve over and over again on the polls. Therefore you
-     * need to use the Idempotent Consumer EIP in the route to filter out duplicates. You can filter using the
-     * {@link S3Constants#BUCKET_NAME} and {@link S3Constants#KEY} headers, or only the {@link S3Constants#KEY} header.
+     * If this option is false, then the same objects will be retrieve over and
+     * over again on the polls. Therefore you need to use the Idempotent
+     * Consumer EIP in the route to filter out duplicates. You can filter using
+     * the {@link S3Constants#BUCKET_NAME} and {@link S3Constants#KEY} headers,
+     * or only the {@link S3Constants#KEY} header.
      */
     public void setDeleteAfterRead(boolean deleteAfterRead) {
         this.deleteAfterRead = deleteAfterRead;
@@ -225,7 +241,8 @@ public class S3Configuration implements Cloneable {
     }
 
     /**
-     * *Camel 2.8.4*: The policy for this queue to set in the `com.amazonaws.services.s3.AmazonS3#setBucketPolicy()` method.
+     * *Camel 2.8.4*: The policy for this queue to set in the
+     * `com.amazonaws.services.s3.AmazonS3#setBucketPolicy()` method.
      */
     public void setPolicy(String policy) {
         this.policy = policy;
@@ -236,7 +253,8 @@ public class S3Configuration implements Cloneable {
     }
 
     /**
-     * *Camel 2.8.4*: The storage class to set in the `com.amazonaws.services.s3.model.PutObjectRequest` request.
+     * *Camel 2.8.4*: The storage class to set in the
+     * `com.amazonaws.services.s3.model.PutObjectRequest` request.
      */
     public void setStorageClass(String storageClass) {
         this.storageClass = storageClass;
@@ -247,13 +265,13 @@ public class S3Configuration implements Cloneable {
     }
 
     /**
-     * *Camel 2.16*: Sets the server-side encryption algorithm when encrypting the object using AWS-managed keys.
-     * For example use <tt>AES256</tt>.
+     * *Camel 2.16*: Sets the server-side encryption algorithm when encrypting
+     * the object using AWS-managed keys. For example use <tt>AES256</tt>.
      */
     public void setServerSideEncryption(String serverSideEncryption) {
         this.serverSideEncryption = serverSideEncryption;
     }
-    
+
     public String getProxyHost() {
         return proxyHost;
     }
@@ -270,7 +288,8 @@ public class S3Configuration implements Cloneable {
     }
 
     /**
-     * *Camel 2.16*: Specify a proxy port to be used inside the client definition.
+     * *Camel 2.16*: Specify a proxy port to be used inside the client
+     * definition.
      */
     public void setProxyPort(Integer proxyPort) {
         this.proxyPort = proxyPort;
@@ -292,7 +311,8 @@ public class S3Configuration implements Cloneable {
     }
 
     /**
-     * *Camel 2.18*: The operation to do in case the user don't want to do only an upload
+     * *Camel 2.18*: The operation to do in case the user don't want to do only
+     * an upload
      */
     public void setOperation(S3Operations operation) {
         this.operation = operation;
@@ -303,15 +323,41 @@ public class S3Configuration implements Cloneable {
     }
 
     /**
-     * If this option is true and includeBody is true, then the S3Object.close() method will be called on exchange completion
-     * This option is strongly related to includeBody option. In case of setting includeBody to true and autocloseBody to false, it 
-     * will be up to the caller to close the S3Object stream. Setting autocloseBody to true, will close the S3Object stream automatically.
+     * If this option is true and includeBody is true, then the S3Object.close()
+     * method will be called on exchange completion This option is strongly
+     * related to includeBody option. In case of setting includeBody to true and
+     * autocloseBody to false, it will be up to the caller to close the S3Object
+     * stream. Setting autocloseBody to true, will close the S3Object stream
+     * automatically.
      */
     public void setAutocloseBody(boolean autocloseBody) {
         this.autocloseBody = autocloseBody;
     }
 
+    public EncryptionMaterials getEncryptionMaterials() {
+        return encryptionMaterials;
+    }
+
+    /**
+     * The encryption materials to use in case of Symmetric/Asymmetric client
+     * usage
+     */
+    public void setEncryptionMaterials(EncryptionMaterials encryptionMaterials) {
+        this.encryptionMaterials = encryptionMaterials;
+    }
+
+    public boolean isUseEncryption() {
+        return useEncryption;
+    }
+
+    /**
+     * Define if encryption must be used or not
+     */
+    public void setUseEncryption(boolean useEncryption) {
+        this.useEncryption = useEncryption;
+    }
+
     boolean hasProxyConfiguration() {
         return ObjectHelper.isNotEmpty(getProxyHost()) && ObjectHelper.isNotEmpty(getProxyPort());
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a2d2a1f3/components/camel-aws/src/main/java/org/apache/camel/component/aws/s3/S3Endpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-aws/src/main/java/org/apache/camel/component/aws/s3/S3Endpoint.java b/components/camel-aws/src/main/java/org/apache/camel/component/aws/s3/S3Endpoint.java
index df9538a..73caa01 100644
--- a/components/camel-aws/src/main/java/org/apache/camel/component/aws/s3/S3Endpoint.java
+++ b/components/camel-aws/src/main/java/org/apache/camel/component/aws/s3/S3Endpoint.java
@@ -26,11 +26,13 @@ import com.amazonaws.auth.AWSStaticCredentialsProvider;
 import com.amazonaws.auth.BasicAWSCredentials;
 import com.amazonaws.services.s3.AmazonS3;
 import com.amazonaws.services.s3.AmazonS3ClientBuilder;
+import com.amazonaws.services.s3.AmazonS3EncryptionClientBuilder;
 import com.amazonaws.services.s3.S3ClientOptions;
 import com.amazonaws.services.s3.model.CreateBucketRequest;
 import com.amazonaws.services.s3.model.ListObjectsRequest;
 import com.amazonaws.services.s3.model.ObjectMetadata;
 import com.amazonaws.services.s3.model.S3Object;
+import com.amazonaws.services.s3.model.StaticEncryptionMaterialsProvider;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Component;
@@ -47,7 +49,6 @@ import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriPath;
 import org.apache.camel.support.SynchronizationAdapter;
 import org.apache.camel.util.ObjectHelper;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -254,14 +255,22 @@ public class S3Endpoint extends ScheduledPollEndpoint {
         if (configuration.getAccessKey() != null && configuration.getSecretKey() != null) {
             AWSCredentials credentials = new BasicAWSCredentials(configuration.getAccessKey(), configuration.getSecretKey());
             AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials);
-            if (isClientConfigFound) {
+            if (isClientConfigFound && !configuration.isUseEncryption()) {
                 client = AmazonS3ClientBuilder.standard().withClientConfiguration(clientConfiguration).withCredentials(credentialsProvider).build();
+            } else if (isClientConfigFound && configuration.isUseEncryption()) {
+                StaticEncryptionMaterialsProvider encryptionMaterialsProvider = new StaticEncryptionMaterialsProvider(configuration.getEncryptionMaterials());
+                client = AmazonS3EncryptionClientBuilder.standard().withClientConfiguration(clientConfiguration)
+                   .withCredentials(credentialsProvider).withEncryptionMaterials(encryptionMaterialsProvider).build();
             } else {
                 client = AmazonS3ClientBuilder.standard().withCredentials(credentialsProvider).build();
             }
         } else {
-            if (isClientConfigFound) {
+            if (isClientConfigFound && !configuration.isUseEncryption()) {
                 client = AmazonS3ClientBuilder.standard().build();
+            } else if (isClientConfigFound && configuration.isUseEncryption()) {
+                StaticEncryptionMaterialsProvider encryptionMaterialsProvider = new StaticEncryptionMaterialsProvider(configuration.getEncryptionMaterials());
+                client = AmazonS3EncryptionClientBuilder.standard().withClientConfiguration(clientConfiguration)
+                  .withEncryptionMaterials(encryptionMaterialsProvider).build();
             } else {
                 client = AmazonS3ClientBuilder.standard().withClientConfiguration(clientConfiguration).build();
             }

http://git-wip-us.apache.org/repos/asf/camel/blob/a2d2a1f3/components/camel-aws/src/test/java/org/apache/camel/component/aws/s3/AmazonS3EncryptionClientMock.java
----------------------------------------------------------------------
diff --git a/components/camel-aws/src/test/java/org/apache/camel/component/aws/s3/AmazonS3EncryptionClientMock.java b/components/camel-aws/src/test/java/org/apache/camel/component/aws/s3/AmazonS3EncryptionClientMock.java
new file mode 100644
index 0000000..afdf8ad
--- /dev/null
+++ b/components/camel-aws/src/test/java/org/apache/camel/component/aws/s3/AmazonS3EncryptionClientMock.java
@@ -0,0 +1,473 @@
+/**
+ * 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.aws.s3;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.KeyPair;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import com.amazonaws.AmazonClientException;
+import com.amazonaws.AmazonServiceException;
+import com.amazonaws.AmazonWebServiceRequest;
+import com.amazonaws.HttpMethod;
+import com.amazonaws.auth.BasicAWSCredentials;
+import com.amazonaws.services.s3.AmazonS3Client;
+import com.amazonaws.services.s3.AmazonS3EncryptionClient;
+import com.amazonaws.services.s3.S3ResponseMetadata;
+import com.amazonaws.services.s3.model.AbortMultipartUploadRequest;
+import com.amazonaws.services.s3.model.AccessControlList;
+import com.amazonaws.services.s3.model.Bucket;
+import com.amazonaws.services.s3.model.BucketLoggingConfiguration;
+import com.amazonaws.services.s3.model.BucketNotificationConfiguration;
+import com.amazonaws.services.s3.model.BucketPolicy;
+import com.amazonaws.services.s3.model.BucketVersioningConfiguration;
+import com.amazonaws.services.s3.model.CannedAccessControlList;
+import com.amazonaws.services.s3.model.CompleteMultipartUploadRequest;
+import com.amazonaws.services.s3.model.CompleteMultipartUploadResult;
+import com.amazonaws.services.s3.model.CopyObjectRequest;
+import com.amazonaws.services.s3.model.CopyObjectResult;
+import com.amazonaws.services.s3.model.CreateBucketRequest;
+import com.amazonaws.services.s3.model.DeleteBucketRequest;
+import com.amazonaws.services.s3.model.DeleteObjectRequest;
+import com.amazonaws.services.s3.model.DeleteVersionRequest;
+import com.amazonaws.services.s3.model.EncryptionMaterials;
+import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
+import com.amazonaws.services.s3.model.GetObjectMetadataRequest;
+import com.amazonaws.services.s3.model.GetObjectRequest;
+import com.amazonaws.services.s3.model.InitiateMultipartUploadRequest;
+import com.amazonaws.services.s3.model.InitiateMultipartUploadResult;
+import com.amazonaws.services.s3.model.ListBucketsRequest;
+import com.amazonaws.services.s3.model.ListMultipartUploadsRequest;
+import com.amazonaws.services.s3.model.ListObjectsRequest;
+import com.amazonaws.services.s3.model.ListPartsRequest;
+import com.amazonaws.services.s3.model.ListVersionsRequest;
+import com.amazonaws.services.s3.model.MultipartUploadListing;
+import com.amazonaws.services.s3.model.ObjectListing;
+import com.amazonaws.services.s3.model.ObjectMetadata;
+import com.amazonaws.services.s3.model.Owner;
+import com.amazonaws.services.s3.model.PartListing;
+import com.amazonaws.services.s3.model.PutObjectRequest;
+import com.amazonaws.services.s3.model.PutObjectResult;
+import com.amazonaws.services.s3.model.Region;
+import com.amazonaws.services.s3.model.S3Object;
+import com.amazonaws.services.s3.model.S3ObjectSummary;
+import com.amazonaws.services.s3.model.SetBucketLoggingConfigurationRequest;
+import com.amazonaws.services.s3.model.SetBucketVersioningConfigurationRequest;
+import com.amazonaws.services.s3.model.StaticEncryptionMaterialsProvider;
+import com.amazonaws.services.s3.model.StorageClass;
+import com.amazonaws.services.s3.model.UploadPartRequest;
+import com.amazonaws.services.s3.model.UploadPartResult;
+import com.amazonaws.services.s3.model.VersionListing;
+
+import org.apache.camel.util.ObjectHelper;
+import org.junit.Assert;
+
+public class AmazonS3EncryptionClientMock extends AmazonS3EncryptionClient {
+    
+    List<S3Object> objects = new CopyOnWriteArrayList<S3Object>();
+    List<PutObjectRequest> putObjectRequests = new CopyOnWriteArrayList<PutObjectRequest>();
+    
+    private boolean nonExistingBucketCreated;
+    
+    private int maxCapacity = 100;
+    
+    public AmazonS3EncryptionClientMock() {
+        super(new StaticEncryptionMaterialsProvider(new EncryptionMaterials(new KeyPair(null, null))));
+    }
+
+    @Override
+    public VersionListing listNextBatchOfVersions(VersionListing previousVersionListing) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public VersionListing listVersions(String bucketName, String prefix) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public VersionListing listVersions(String bucketName, String prefix, String keyMarker, String versionIdMarker, String delimiter, Integer maxKeys) 
+        throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public VersionListing listVersions(ListVersionsRequest listVersionsRequest) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ObjectListing listObjects(String bucketName) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ObjectListing listObjects(String bucketName, String prefix) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ObjectListing listObjects(ListObjectsRequest listObjectsRequest) throws AmazonClientException, AmazonServiceException {
+        if ("nonExistingBucket".equals(listObjectsRequest.getBucketName()) && !nonExistingBucketCreated) {
+            AmazonServiceException ex = new AmazonServiceException("Unknown bucket");
+            ex.setStatusCode(404);
+            throw ex; 
+        }
+        int capacity;
+        ObjectListing objectListing = new ObjectListing();
+        if (!ObjectHelper.isEmpty(listObjectsRequest.getMaxKeys()) && listObjectsRequest.getMaxKeys() != null) {
+            capacity = listObjectsRequest.getMaxKeys();
+        } else {
+            capacity = maxCapacity;
+        }
+        
+        for (int index = 0; index < objects.size() && index < capacity; index++) {
+            S3ObjectSummary s3ObjectSummary = new S3ObjectSummary();
+            s3ObjectSummary.setBucketName(objects.get(index).getBucketName());
+            s3ObjectSummary.setKey(objects.get(index).getKey());
+            
+            objectListing.getObjectSummaries().add(s3ObjectSummary);
+        }
+
+        return objectListing;
+    }
+
+    @Override
+    public ObjectListing listNextBatchOfObjects(ObjectListing previousObjectListing) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Owner getS3AccountOwner() throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<Bucket> listBuckets(ListBucketsRequest listBucketsRequest) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<Bucket> listBuckets() throws AmazonClientException, AmazonServiceException {
+        ArrayList<Bucket> list = new ArrayList<Bucket>();
+        Bucket bucket = new Bucket("camel-bucket");
+        bucket.setOwner(new Owner("Camel", "camel"));
+        bucket.setCreationDate(new Date());
+        list.add(bucket);
+        return list;
+    }
+
+    @Override
+    public String getBucketLocation(String bucketName) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Bucket createBucket(String bucketName) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Bucket createBucket(String bucketName, Region region) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Bucket createBucket(String bucketName, String region) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Bucket createBucket(CreateBucketRequest createBucketRequest) throws AmazonClientException, AmazonServiceException {
+        if ("nonExistingBucket".equals(createBucketRequest.getBucketName())) {
+            nonExistingBucketCreated = true; 
+        }
+        
+        Bucket bucket = new Bucket();
+        bucket.setName(createBucketRequest.getBucketName());
+        bucket.setCreationDate(new Date());
+        bucket.setOwner(new Owner("c2efc7302b9011ba9a78a92ac5fd1cd47b61790499ab5ddf5a37c31f0638a8fc ", "Christian Mueller"));
+        return bucket;
+    }
+
+    @Override
+    public AccessControlList getObjectAcl(String bucketName, String key) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public AccessControlList getObjectAcl(String bucketName, String key, String versionId) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setObjectAcl(String bucketName, String key, AccessControlList acl) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setObjectAcl(String bucketName, String key, CannedAccessControlList acl) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setObjectAcl(String bucketName, String key, String versionId, AccessControlList acl) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setObjectAcl(String bucketName, String key, String versionId, CannedAccessControlList acl) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public AccessControlList getBucketAcl(String bucketName) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setBucketAcl(String bucketName, AccessControlList acl) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setBucketAcl(String bucketName, CannedAccessControlList acl) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ObjectMetadata getObjectMetadata(String bucketName, String key) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ObjectMetadata getObjectMetadata(GetObjectMetadataRequest getObjectMetadataRequest) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+    
+    
+    @Override
+    public S3Object getObject(String bucketName, String key) throws AmazonClientException, AmazonServiceException {
+        for (S3Object s3Object : objects) {
+            if (bucketName.equals(s3Object.getBucketName()) && key.equals(s3Object.getKey())) {
+                return s3Object;
+            }
+        }
+        
+        return null;
+    }
+
+    @Override
+    public boolean doesBucketExist(String bucketName) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void changeObjectStorageClass(String bucketName, String key, StorageClass newStorageClass) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public S3Object getObject(GetObjectRequest getObjectRequest) throws AmazonClientException, AmazonServiceException {
+        return getObject(getObjectRequest.getBucketName(), getObjectRequest.getKey());
+    }
+
+    @Override
+    public ObjectMetadata getObject(GetObjectRequest getObjectRequest, File destinationFile) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void deleteBucket(String bucketName) throws AmazonClientException, AmazonServiceException {
+        // noop
+    }
+
+    @Override
+    public void deleteBucket(DeleteBucketRequest deleteBucketRequest) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public PutObjectResult putObject(String bucketName, String key, File file) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public PutObjectResult putObject(String bucketName, String key, InputStream input, ObjectMetadata metadata) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @SuppressWarnings("resource")
+    @Override
+    public PutObjectResult putObject(PutObjectRequest putObjectRequest) throws AmazonClientException, AmazonServiceException {
+        putObjectRequests.add(putObjectRequest);
+        
+        S3Object s3Object = new S3Object();
+        s3Object.setBucketName(putObjectRequest.getBucketName());
+        s3Object.setKey(putObjectRequest.getKey());
+        if (putObjectRequest.getFile() != null) {
+            try {
+                s3Object.setObjectContent(new FileInputStream(putObjectRequest.getFile()));
+            } catch (FileNotFoundException e) {
+                throw new AmazonServiceException("Cannot store the file object.", e);
+            }
+        } else {
+            s3Object.setObjectContent(putObjectRequest.getInputStream());
+        }
+        objects.add(s3Object);
+        
+        PutObjectResult putObjectResult = new PutObjectResult();
+        putObjectResult.setETag("3a5c8b1ad448bca04584ecb55b836264");
+        return putObjectResult;
+    }
+
+    @Override
+    public CopyObjectResult copyObject(String sourceBucketName, String sourceKey, String destinationBucketName, String destinationKey) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CopyObjectResult copyObject(CopyObjectRequest copyObjectRequest) throws AmazonClientException, AmazonServiceException {
+        CopyObjectResult copyObjectResult = new CopyObjectResult();
+        copyObjectResult.setETag("3a5c8b1ad448bca04584ecb55b836264");
+        copyObjectResult.setVersionId("11192828ahsh2723");
+        return copyObjectResult;
+    }
+
+    @Override
+    public void deleteObject(String bucketName, String key) throws AmazonClientException, AmazonServiceException {
+        //noop
+    }
+
+    @Override
+    public void deleteObject(DeleteObjectRequest deleteObjectRequest) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void deleteVersion(String bucketName, String key, String versionId) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void deleteVersion(DeleteVersionRequest deleteVersionRequest) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setBucketVersioningConfiguration(SetBucketVersioningConfigurationRequest setBucketVersioningConfigurationRequest) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public BucketVersioningConfiguration getBucketVersioningConfiguration(String bucketName) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setBucketNotificationConfiguration(String bucketName, BucketNotificationConfiguration bucketNotificationConfiguration) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public BucketNotificationConfiguration getBucketNotificationConfiguration(String bucketName) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public BucketLoggingConfiguration getBucketLoggingConfiguration(String bucketName) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setBucketLoggingConfiguration(SetBucketLoggingConfigurationRequest setBucketLoggingConfigurationRequest) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public BucketPolicy getBucketPolicy(String bucketName) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setBucketPolicy(String bucketName, String policyText) throws AmazonClientException, AmazonServiceException {
+        Assert.assertEquals("nonExistingBucket", bucketName);
+        Assert.assertEquals("xxx", policyText);
+    }
+
+    @Override
+    public void deleteBucketPolicy(String bucketName) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public URL generatePresignedUrl(String bucketName, String key, Date expiration) throws AmazonClientException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public URL generatePresignedUrl(String bucketName, String key, Date expiration, HttpMethod method) throws AmazonClientException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public URL generatePresignedUrl(GeneratePresignedUrlRequest generatePresignedUrlRequest) throws AmazonClientException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void abortMultipartUpload(AbortMultipartUploadRequest abortMultipartUploadRequest) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public CompleteMultipartUploadResult completeMultipartUpload(CompleteMultipartUploadRequest completeMultipartUploadRequest) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public InitiateMultipartUploadResult initiateMultipartUpload(InitiateMultipartUploadRequest initiateMultipartUploadRequest) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public MultipartUploadListing listMultipartUploads(ListMultipartUploadsRequest listMultipartUploadsRequest) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public PartListing listParts(ListPartsRequest listPartsRequest) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public UploadPartResult uploadPart(UploadPartRequest uploadPartRequest) throws AmazonClientException, AmazonServiceException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public S3ResponseMetadata getCachedResponseMetadata(AmazonWebServiceRequest request) {
+        throw new UnsupportedOperationException();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/a2d2a1f3/components/camel-aws/src/test/java/org/apache/camel/component/aws/s3/S3ComponentCopyObjectEncryptionTest.java
----------------------------------------------------------------------
diff --git a/components/camel-aws/src/test/java/org/apache/camel/component/aws/s3/S3ComponentCopyObjectEncryptionTest.java b/components/camel-aws/src/test/java/org/apache/camel/component/aws/s3/S3ComponentCopyObjectEncryptionTest.java
new file mode 100644
index 0000000..acec0ab
--- /dev/null
+++ b/components/camel-aws/src/test/java/org/apache/camel/component/aws/s3/S3ComponentCopyObjectEncryptionTest.java
@@ -0,0 +1,92 @@
+/**
+ * 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.aws.s3;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.Processor;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+public class S3ComponentCopyObjectEncryptionTest extends CamelTestSupport {
+
+    @EndpointInject(uri = "direct:start")
+    private ProducerTemplate template;
+
+    @EndpointInject(uri = "mock:result")
+    private MockEndpoint result;
+
+    private AmazonS3EncryptionClientMock client;
+
+    @Test
+    public void sendIn() throws Exception {
+        result.expectedMessageCount(1);
+
+        template.send("direct:start", ExchangePattern.InOnly, new Processor() {
+            public void process(Exchange exchange) throws Exception {
+                exchange.getIn().setHeader(S3Constants.BUCKET_DESTINATION_NAME, "camelDestinationBucket");
+                exchange.getIn().setHeader(S3Constants.KEY, "camelKey");
+                exchange.getIn().setHeader(S3Constants.DESTINATION_KEY, "camelDestinationKey");
+            }
+        });
+
+        assertMockEndpointsSatisfied();
+
+        assertResultExchange(result.getExchanges().get(0));
+
+    }
+
+    private void assertResultExchange(Exchange resultExchange) {
+        assertEquals(resultExchange.getIn().getHeader(S3Constants.VERSION_ID), "11192828ahsh2723");
+        assertNull(resultExchange.getIn().getHeader(S3Constants.LAST_MODIFIED));
+        assertEquals(resultExchange.getIn().getHeader(S3Constants.E_TAG), "3a5c8b1ad448bca04584ecb55b836264");
+        assertNull(resultExchange.getIn().getHeader(S3Constants.CONTENT_TYPE));
+        assertNull(resultExchange.getIn().getHeader(S3Constants.CONTENT_ENCODING));
+        assertNull(resultExchange.getIn().getHeader(S3Constants.CONTENT_DISPOSITION));
+        assertNull(resultExchange.getIn().getHeader(S3Constants.CONTENT_MD5));
+        assertNull(resultExchange.getIn().getHeader(S3Constants.CACHE_CONTROL));
+        assertNull(resultExchange.getIn().getHeader(S3Constants.USER_METADATA));
+    }
+
+    @Override
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry registry = super.createRegistry();
+
+        client = new AmazonS3EncryptionClientMock();
+        registry.bind("amazonS3Client", client);
+
+        return registry;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                String awsEndpoint = "aws-s3://mycamelbucket?amazonS3Client=#amazonS3Client&region=us-west-1&operation=copyObject";
+
+                from("direct:start").to(awsEndpoint).to("mock:result");
+
+            }
+        };
+    }
+}