Skip to content
Permalink
Browse files
Fix #3169 to add S3 KMS encryption test (#3176)
  • Loading branch information
zhfeng committed Oct 12, 2021
1 parent ee27b64 commit abd2673ecf4dc9ac0c62249c34af392867fb4018
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 67 deletions.
@@ -35,6 +35,10 @@
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-aws2-s3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-aws2-kms</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-amazon-s3</artifactId>
@@ -71,6 +75,19 @@
</dependency>

<!-- The following dependencies guarantee that this module is built after them. You can update them by running `mvn process-resources -Pformat -N` from the source tree root directory -->
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-aws2-kms-deployment</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-aws2-s3-deployment</artifactId>
@@ -28,12 +28,14 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
@@ -72,11 +74,16 @@ public class Aws2S3Resource {
@ConfigProperty(name = "aws-s3.bucket-name")
String bucketName;

@ConfigProperty(name = "aws-s3.kms-key-id")
Optional<String> kmsKeyId;

@Path("s3/object/{key}")
@POST
@Consumes(MediaType.TEXT_PLAIN)
public Response post(String message, @PathParam("key") String key) throws Exception {
producerTemplate.sendBodyAndHeader(componentUri(),
public Response post(String message, @PathParam("key") String key,
@QueryParam("useKms") @DefaultValue("false") boolean useKms) throws Exception {
producerTemplate.sendBodyAndHeader(
componentUri() + (useKms && kmsKeyId.isPresent() ? "?useAwsKMS=true&awsKMSKeyId=" + kmsKeyId : ""),
message,
AWS2S3Constants.KEY,
key);
@@ -86,13 +93,15 @@ public Response post(String message, @PathParam("key") String key) throws Except
@Path("s3/object/{key}")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String get(@PathParam("key") String key, @QueryParam("bucket") String bucket) throws Exception {
public String get(@PathParam("key") String key, @QueryParam("bucket") String bucket,
@QueryParam("useKms") @DefaultValue("false") boolean useKms) throws Exception {
if (bucket == null) {
bucket = bucketName;
}

return producerTemplate.requestBodyAndHeader(
componentUri(bucket, AWS2S3Operations.getObject),
componentUri(bucket, AWS2S3Operations.getObject)
+ (useKms && kmsKeyId.isPresent() ? "&useAwsKMS=true&awsKMSKeyId=" + kmsKeyId : ""),
null,
AWS2S3Constants.KEY,
key,
@@ -118,21 +127,45 @@ public Response read(@PathParam("key") String key) throws Exception {
return Response.noContent().build();
}

@Path("s3/bucket/{bucketName}/object/{key}")
@DELETE
@Produces(MediaType.TEXT_PLAIN)
public Response read(@PathParam("bucketName") String bucketName, @PathParam("key") String key) throws Exception {
producerTemplate.sendBodyAndHeader(
componentUri(bucketName, AWS2S3Operations.deleteObject),
null,
AWS2S3Constants.KEY,
key);
return Response.noContent().build();
}

@Path("s3/object-keys")
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<String> objectKey(@QueryParam("bucket") String bucket) throws Exception {
if (bucket == null) {
bucket = bucketName;
}

public List<String> objectKey() throws Exception {
final List<S3Object> objects = (List<S3Object>) producerTemplate.requestBody(
componentUri(bucket, AWS2S3Operations.listObjects) + "&autoCreateBucket=true",
componentUri(AWS2S3Operations.listObjects),
null,
List.class);
return objects.stream().map(S3Object::key).collect(Collectors.toList());
}

/**
* Do not forget to delete every bucket created through this endpoint after the test.
*
* @param newBucketName
* @return
*/
@Path("s3/autoCreateBucket/{newBucketName}")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response autoCreateBucket(@PathParam("newBucketName") String newBucketName) {
producerTemplate.sendBody(
componentUri(newBucketName, AWS2S3Operations.listObjects) + "&autoCreateBucket=true",
null);
return Response.noContent().build();
}

@Path("s3/upload/{key}")
@POST
@Consumes(MediaType.TEXT_PLAIN)
@@ -16,6 +16,7 @@
*/
package org.apache.camel.quarkus.component.aws2.s3.it;

import java.util.Locale;
import java.util.UUID;
import java.util.stream.Stream;

@@ -127,6 +128,31 @@ public void consumer() {
}
}

@Test
public void testKms() throws Exception {
final String oid = UUID.randomUUID().toString();
final String blobContent = "Hello KMS " + oid;

// Create
RestAssured.given()
.contentType(ContentType.TEXT)
.body(blobContent)
.post("/aws2/s3/object/" + oid + "?useKms=true")
.then()
.statusCode(201);

// Read
RestAssured.get("/aws2/s3/object/" + oid + "?useKms=true")
.then()
.statusCode(200)
.body(is(blobContent));

// Delete
RestAssured.delete("/aws2/s3/object/" + oid)
.then()
.statusCode(204);
}

@Test
public void upload() throws Exception {
final String oid = UUID.randomUUID().toString();
@@ -150,40 +176,64 @@ public void upload() throws Exception {
}

@Test
public void copyObject() throws Exception {
public void copyObjectDeleteBucket() throws Exception {
final String oid1 = UUID.randomUUID().toString();
final String oid2 = UUID.randomUUID().toString();
final String blobContent = "Hello " + oid1;
final String bucket = "mycamel";
final String destinationBucket = "camel-quarkus-copy-object-"
+ RandomStringUtils.randomAlphanumeric(32).toLowerCase(Locale.ROOT);

// Create
// Create an object to copy
RestAssured.given()
.contentType(ContentType.TEXT)
.body(blobContent)
.post("/aws2/s3/object/" + oid1)
.then()
.statusCode(201);

// Check the dest bucket does not contain oid2
final String[] objects = getAllObjects(bucket);
Assertions.assertTrue(Stream.of(objects).noneMatch(key -> key.equals(oid2)));
try {
autoCreateBucket(destinationBucket);

// Copy
RestAssured.given()
.contentType(ContentType.URLENC)
.formParam("dest_key", oid2)
.formParam("dest_bucket", bucket)
.post("/aws2/s3/copy/" + oid1)
.then()
.statusCode(204);
// Make sure the bucket was created
String[] buckets = getAllBuckets();
Assertions.assertTrue(Stream.of(buckets).anyMatch(key -> key.equals(destinationBucket)));

// Verify the object
RestAssured.given()
.contentType(ContentType.TEXT)
.get("/aws2/s3/object/" + oid2 + "?bucket=" + bucket)
.then()
.statusCode(200)
.body(is(blobContent));
// Copy
RestAssured.given()
.contentType(ContentType.URLENC)
.formParam("dest_key", oid2)
.formParam("dest_bucket", destinationBucket)
.post("/aws2/s3/copy/" + oid1)
.then()
.statusCode(204);

// Verify the object
RestAssured.given()
.contentType(ContentType.TEXT)
.get("/aws2/s3/object/" + oid2 + "?bucket=" + destinationBucket)
.then()
.statusCode(200)
.body(is(blobContent));

} finally {
// Delete the object before deleting the bucket
try {
RestAssured.delete("/aws2/s3/bucket/" + destinationBucket + "/object/" + oid2)
.then()
.statusCode(204);
} catch (Exception ignored) {
}

// Delete the bucket
RestAssured.delete("/aws2/s3/bucket/" + destinationBucket)
.then()
.statusCode(204);

// Make sure destinationBucket was really deleted
final String[] buckets = getAllBuckets();
Assertions.assertTrue(Stream.of(buckets).noneMatch(key -> key.equals(destinationBucket)));

}

}

@@ -194,24 +244,6 @@ void listBuckets() throws Exception {
Assertions.assertTrue(Stream.of(buckets).anyMatch(key -> key.startsWith("camel-quarkus")));
}

@Test
void deleteBucket() throws Exception {
final String bucket = "mycamel-delete";

String[] objects = getAllObjects(bucket);
Assertions.assertTrue(objects.length == 0);

String[] buckets = getAllBuckets();
Assertions.assertTrue(Stream.of(buckets).anyMatch(key -> key.equals("mycamel-delete")));

RestAssured.delete("/aws2/s3/bucket/" + bucket)
.then()
.statusCode(204);

buckets = getAllBuckets();
Assertions.assertTrue(Stream.of(buckets).noneMatch(key -> key.equals("mycamel-delete")));
}

@Test
public void downloadLink() throws Exception {
final String oid = UUID.randomUUID().toString();
@@ -256,16 +288,16 @@ private void createObject(String oid, String blobContent) {
.statusCode(201);
}

private String[] getAllObjects(String bucket) {
final String[] objects = RestAssured.given()
.param("bucket", bucket)
.get("/aws2/s3/object-keys")
/**
* Do not forget to delete every bucket you create!
*
* @param newBucketName
*/
private void autoCreateBucket(String newBucketName) {
RestAssured.given()
.get("/aws2/s3/autoCreateBucket/" + newBucketName)
.then()
.statusCode(200)
.extract()
.body().as(String[].class);

return objects;
.statusCode(204);
}

private String[] getAllBuckets() {
@@ -22,8 +22,11 @@

import org.apache.camel.quarkus.test.support.aws2.Aws2TestEnvContext;
import org.apache.camel.quarkus.test.support.aws2.Aws2TestEnvCustomizer;
import org.apache.camel.quarkus.test.support.aws2.Aws2TestResource;
import org.apache.commons.lang3.RandomStringUtils;
import org.testcontainers.containers.localstack.LocalStackContainer.Service;
import software.amazon.awssdk.services.kms.KmsClient;
import software.amazon.awssdk.services.kms.model.CreateKeyRequest;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
import software.amazon.awssdk.services.s3.model.DeleteBucketRequest;
@@ -32,22 +35,33 @@ public class Aws2S3TestEnvCustomizer implements Aws2TestEnvCustomizer {

@Override
public Service[] localstackServices() {
return new Service[] { Service.S3 };
return new Service[] { Service.S3, Service.KMS };
}

@Override
public void customize(Aws2TestEnvContext envContext) {
final S3Client s3Client = envContext.client(Service.S3, S3Client::builder);
final KmsClient kmsClient = envContext.client(Service.KMS, KmsClient::builder);

final String bucketName = "camel-quarkus-" + RandomStringUtils.randomAlphanumeric(49).toLowerCase(Locale.ROOT);
s3Client.createBucket(CreateBucketRequest.builder().bucket(bucketName).build());
envContext.property("aws-s3.bucket-name", bucketName);
envContext.closeable(() -> s3Client.deleteBucket(DeleteBucketRequest.builder().bucket(bucketName).build()));

if (envContext.isLocalStack()) {
final String kmsKeyId = kmsClient.createKey(CreateKeyRequest.builder().description("Test_key").build())
.keyMetadata().keyId();
envContext.property("aws-s3.kms-key-id", kmsKeyId);
}

Map<String, String> envContextProperties = envContext.getProperies();
String accessKey = envContextProperties.get("camel.component.aws2-s3.access-key");
String secretKey = envContextProperties.get("camel.component.aws2-s3.secret-key");
String region = envContextProperties.get("camel.component.aws2-s3.region");

String accessKey = envContextProperties.getOrDefault("camel.component.aws2-s3.access-key",
System.getenv(Aws2TestResource.AWS_ACCESS_KEY));
String secretKey = envContextProperties.getOrDefault("camel.component.aws2-s3.secret-key",
System.getenv(Aws2TestResource.AWS_SECRET_KEY));
String region = envContextProperties.getOrDefault("camel.component.aws2-s3.region",
System.getenv(Aws2TestResource.AWS_REGION));

envContext.property("quarkus.s3.aws.credentials.static-provider.access-key-id", accessKey);
envContext.property("quarkus.s3.aws.credentials.static-provider.secret-access-key", secretKey);
@@ -35,6 +35,10 @@
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-aws2-s3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-aws2-kms</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
@@ -66,6 +70,19 @@
</dependency>

<!-- The following dependencies guarantee that this module is built after them. You can update them by running `mvn process-resources -Pformat -N` from the source tree root directory -->
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-aws2-kms-deployment</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-aws2-s3-deployment</artifactId>

0 comments on commit abd2673

Please sign in to comment.