Skip to content
This repository has been archived by the owner on Mar 6, 2020. It is now read-only.

Commit

Permalink
Merge pull request #29 from agorapulse/upgrade/1.1.0
Browse files Browse the repository at this point in the history
Upgrade to Micronaut 1.1.0
  • Loading branch information
musketyr committed May 7, 2019
2 parents 000829a + f3d3c51 commit 95a3bc7
Show file tree
Hide file tree
Showing 17 changed files with 431 additions and 11 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ subprojects { Project subproject ->
entry 'aws-java-sdk-ses'
entry 'aws-java-sdk-sns'
entry 'aws-java-sdk-sqs'
entry 'aws-java-sdk-sts'
entry 'jmespath'
}
dependency group: 'com.amazonaws', name: 'amazon-dax-client', version: '1.0.202017.0'
Expand Down
13 changes: 13 additions & 0 deletions docs/aws.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Provided integrations:
* <<Simple Email Service (SES)>>
* <<Simple Notification Service (SNS)>>
* <<Simple Queue Service (SQS)>>
* <<Security Token Service (STS)>>
* <<WebSockets for API Gateway>>
NOTE: <<Micronaut for API Gateway Proxy>> is handled separately in its own library.
Expand Down Expand Up @@ -60,6 +61,9 @@ compile group: 'com.amazonaws', name: 'aws-java-sdk-sns', version: '1.11.500'
// only required for SQS integration
compile group: 'com.amazonaws', name: 'aws-java-sdk-sqs', version: '1.11.500'
// only required for STS integration
compile group: 'com.amazonaws', name: 'aws-java-sdk-sts', version: '1.11.500'
----

[source,xml,indent=0,role="secondary",subs='verbatim,attributes']
Expand Down Expand Up @@ -125,6 +129,13 @@ compile group: 'com.amazonaws', name: 'aws-java-sdk-sqs', version: '1.11.500'
<artifactId>aws-java-sdk-sqs</artifactId>
<version>1.11.500</version>
</dependency>
<!-- only required for STS integration -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-sts</artifactId>
<version>1.11.500</version>
</dependency>
----

include::dynamodb.adoc[]
Expand All @@ -139,4 +150,6 @@ include::sns.adoc[]

include::sqs.adoc[]

include::sts.adoc[]

include::websockets.adoc[]
25 changes: 25 additions & 0 deletions docs/sts.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
=== Security Token Service (STS)

> The AWS Security Token Service (STS) is a web service that enables you to request temporary, limited-privilege credentials for AWS Identity and Access Management (IAM) users or for users that you authenticate (federated users).

This library provides basic support for Amazon STS using <<Security Token Service>>

==== Security Token Service

`SecurityTokenService` provides only one method (with multiple variations) to create credentials
which assumes usage of a certain IAM role.

Following example shows how to create credentials for assumed role.

[source,groovy,indent=0,options="nowrap",role="primary"]
.Assume Role
----
include::../micronaut-aws-sdk/src/test/groovy/com/agorapulse/micronaut/aws/sts/SecurityTokenServiceSpec.groovy[tag=usage]
----

Please, see https://agorapulse.github.io/micronaut-libraries/docs/javadoc/micronaut-aws-sdk/com/agorapulse/micronaut/aws/sts/SecurityTokenService.html[SecurityTokenService] for the full reference.

==== Testing
It is recommended just to mock the `SecurityTokenService` in your tests as it only contains single abstract method.


14 changes: 7 additions & 7 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
version = 1.0.4.4
micronautVersion = 1.0.4
gruVersion = 0.7.1
druVersion = 0.5.0
version = 1.1.0
micronautVersion = 1.1.0
gruVersion = 0.8.0
druVersion = 0.6.0
groovyVersion = 2.5.6
spockVersion = 1.2-groovy-2.5
awsSdkVersion = 1.11.500
testcontainersVersion = 1.10.6
spockVersion = 1.3-groovy-2.5
awsSdkVersion = 1.11.542
testcontainersVersion = 1.11.2

# this should be aligned to Micronaut version
# required for AWS CBOR marshalling
Expand Down
1 change: 1 addition & 0 deletions micronaut-aws-sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies {
optional group: 'com.amazonaws', name: 'aws-java-sdk-ses'
optional group: 'com.amazonaws', name: 'aws-java-sdk-sns'
optional group: 'com.amazonaws', name: 'aws-java-sdk-sqs'
optional group: 'com.amazonaws', name: 'aws-java-sdk-sts'


optional 'javax.mail:mail:1.4.4'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,45 @@ class DefaultSimpleStorageService implements SimpleStorageService {
metadata
}

@SuppressWarnings([
'DuplicateStringLiteral',
'UnnecessarySubstring',
])
static String getBucketFromUri(String aURI) {
URI uri = new URI(aURI)
String path = uri.path.startsWith('/') ? uri.path.substring(1, uri.path.length()) : uri.path
if (uri.host) {
// direct bucket URI not using any CNAME
if (uri.host.endsWith('amazonaws.com')) {
if (uri.host.startsWith('s3')) {
return path.substring(0, path.indexOf('/'))
}
return uri.host.substring(0, uri.host.indexOf('.s3.'))
}
return uri.host
}
// consider the bucket name is using CNAME of the same name as the bucket
return path.substring(0, path.indexOf('/'))
}

@SuppressWarnings([
'DuplicateStringLiteral',
'UnnecessarySubstring',
])
static String getKeyFromUri(String aURI) {
URI uri = new URI(aURI)
String path = uri.path.startsWith('/') ? uri.path.substring(1, uri.path.length()) : uri.path
if (uri.host) {
// direct bucket URI not using any CNAME
if (uri.host.endsWith('amazonaws.com') && uri.host.startsWith('s3')) {
return path.substring(path.indexOf('/') + 1, path.length())
}
return path
}
// consider the bucket name is using CNAME of the same name as the bucket
return path.substring(path.indexOf('/') + 1, path.length())
}

/**
*
* @param bucketName
Expand Down Expand Up @@ -153,6 +192,7 @@ class DefaultSimpleStorageService implements SimpleStorageService {
* @param prefix
* @return
*/
@SuppressWarnings('DuplicateStringLiteral')
boolean deleteFiles(String bucketName, String prefix) {
assert prefix.tokenize('/').size() >= 2, 'Multiple delete are only allowed in sub/sub directories'

Expand Down Expand Up @@ -313,6 +353,53 @@ class DefaultSimpleStorageService implements SimpleStorageService {
return defaultBucketName
}

/**
* Move S3 object to different location (key).
*
* Moving objects is useful in combination with
* <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/how-to-set-lifecycle-configuration-intro.html">
* S3 Lifecycle Configurations
* </a> for prefixes.
*
* @param sourceBucketName the name of the source bucket
* @param sourceKey the key of the source object
* @param destinationBucketName the name of the destination bucket
* @param destinationKey the key of the destination object
* @return the destination URL or <code>null</code> if the file wasn't moved
*/
String moveObject(
String sourceBucketName,
String sourceKey,
String destinationBucketName,
String destinationKey
) {
try {
CopyObjectRequest request = new CopyObjectRequest(sourceBucketName, sourceKey, destinationBucketName, destinationKey)

S3Object object = client.getObject(sourceBucketName, sourceKey)

if (object.taggingCount) {
GetObjectTaggingRequest taggingRequest = new GetObjectTaggingRequest(sourceBucketName, sourceKey)
GetObjectTaggingResult taggingResult = client.getObjectTagging(taggingRequest)
request.withNewObjectTagging(new ObjectTagging(taggingResult.tagSet))
}

request.withNewObjectMetadata(object.objectMetadata)

AccessControlList acl = client.getObjectAcl(sourceBucketName, sourceKey)
AccessControlList newAcls = new AccessControlList()
newAcls.grantAllPermissions(acl.grantsAsList as Grant[])
request.withAccessControlList(newAcls)

client.copyObject(request)
client.deleteObject(sourceBucketName, sourceKey)
return client.getUrl(destinationBucketName, destinationKey)
} catch (AmazonClientException e) {
log.error("Exception moving object $sourceBucketName/$sourceKey to $destinationBucketName/$destinationKey", e)
}
return null
}

// PRIVATE
private void assertDefaultBucketName() {
assert defaultBucketName, 'Default bucket must be defined'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@
*/
public interface SimpleStorageService {

static String getBucketFromUri(String aURI) {
return DefaultSimpleStorageService.getBucketFromUri(aURI);
}

static String getKeyFromUri(String aURI) {
return DefaultSimpleStorageService.getKeyFromUri(aURI);
}

/**
* @return default name of the bucket
Expand Down Expand Up @@ -407,4 +414,22 @@ default String storeMultipartFile(String path, PartData multipartFile, CannedAcc
return storeMultipartFile(getDefaultBucketName(), path, multipartFile, cannedAcl, metadata);
}

/**
* Move S3 object to different location (key).
*
* Moving objects is useful in combination with <a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/how-to-set-lifecycle-configuration-intro.html">S3 Lifecycle Configurations</a> for prefixes.
*
* @param sourceBucketName the name of the source bucket
* @param sourceKey the key of the source object
* @param destinationBucketName the name of the destination bucket
* @param destinationKey the key of the destination object
* @return the destination URL or <code>null</code> if the file wasn't moved
*/
String moveObject(
String sourceBucketName,
String sourceKey,
String destinationBucketName,
String destinationKey
);

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import groovy.transform.CompileStatic
import groovy.transform.Synchronized
import groovy.util.logging.Slf4j

import java.util.function.Consumer

/**
* Default simple queue service implementation.
*/
Expand Down Expand Up @@ -232,6 +234,25 @@ class DefaultSimpleQueueService implements SimpleQueueService {
messageId
}

/**
*
* @param queueName
* @param messageBody
* @param delaySeconds
* @return
*/
String sendMessage(String queueName, String messageBody, Consumer<SendMessageRequest> messageConfiguration) {
String queueUrl = getQueueUrl(queueName)

SendMessageRequest request = new SendMessageRequest(queueUrl, messageBody)

messageConfiguration.accept(request)

String messageId = client.sendMessage(request).messageId
log.debug "Message sent (messageId=$messageId)"
messageId
}

void assertDefaultQueueName() {
assert configuration.queue, 'Default queue must be defined'
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package com.agorapulse.micronaut.aws.sqs;

import com.amazonaws.services.sqs.model.Message;
import com.amazonaws.services.sqs.model.SendMessageRequest;
import groovy.lang.Closure;
import groovy.lang.DelegatesTo;
import groovy.transform.stc.ClosureParams;
import groovy.transform.stc.FromString;
import space.jasan.support.groovy.closure.ConsumerWithDelegate;

import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

/**
* Amazon SQS services
Expand Down Expand Up @@ -250,4 +257,53 @@ default String sendMessage(String messageBody, int delaySeconds, String groupId)
return sendMessage(getDefaultQueueName(), messageBody, delaySeconds, null);
}

/**
* Sends message with additional configuration into the default queue.
* @param messageBody message body
* @param messageConfiguration additional configuration
* @return message id
*/
default String sendMessage(String messageBody, Consumer<SendMessageRequest> messageConfiguration) {
return sendMessage(getDefaultQueueName(), messageBody, messageConfiguration);
}

/**
* Sends message with additional configuration into the default queue.
* @param messageBody message body
* @param messageConfiguration additional configuration
* @return message id
*/
default String sendMessage(String messageBody,
@DelegatesTo(value = SendMessageRequest.class, strategy = Closure.DELEGATE_FIRST)
@ClosureParams(value = FromString.class, options = "com.amazonaws.services.sqs.model.SendMessageRequest")
Closure messageConfiguration
) {
return sendMessage(getDefaultQueueName(), messageBody, ConsumerWithDelegate.create(messageConfiguration));
}

/**
* Sends message with additional configuration into the given queue.
* @param queueName name of the queue
* @param messageBody message body
* @param messageConfiguration additional configuration
* @return message id
*/
default String sendMessage(
String queueName,
String messageBody,
@DelegatesTo(value = SendMessageRequest.class, strategy = Closure.DELEGATE_FIRST)
@ClosureParams(value = FromString.class, options = "com.amazonaws.services.sqs.model.SendMessageRequest")
Closure messageConfiguration
) {
return sendMessage(queueName, messageBody, ConsumerWithDelegate.create(messageConfiguration));
}

/**
* Sends message with additional configuration into the given queue.
* @param queueName name of the queue
* @param messageBody message body
* @param messageConfiguration additional configuration
* @return message id
*/
String sendMessage(String queueName, String messageBody, Consumer<SendMessageRequest> messageConfiguration);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.agorapulse.micronaut.aws.sts;

import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
import com.amazonaws.services.securitytoken.model.AssumeRoleRequest;
import com.amazonaws.services.securitytoken.model.AssumeRoleResult;
import io.micronaut.context.annotation.Requires;

import javax.inject.Singleton;
import java.util.function.Consumer;

@Singleton
@Requires(classes = AWSSecurityTokenService.class)
public class DefaultSecurityTokenService implements SecurityTokenService {

private final AWSSecurityTokenService client;

public DefaultSecurityTokenService(AWSSecurityTokenService client) {
this.client = client;
}

@Override
public AssumeRoleResult assumeRole(String sessionName, String roleArn, int durationInSeconds, Consumer<AssumeRoleRequest> additionParameters) {
AssumeRoleRequest request = new AssumeRoleRequest()
.withRoleSessionName(sessionName)
.withRoleArn(roleArn)
.withDurationSeconds(durationInSeconds);

additionParameters.accept(request);

return client.assumeRole(request);
}
}
Loading

0 comments on commit 95a3bc7

Please sign in to comment.