/// <summary>
        /// Check to see if the policy for the queue has already given permission to the topic.
        /// </summary>
        /// <param name="policy"></param>
        /// <param name="topicArn"></param>
        /// <param name="sqsQueueArn"></param>
        /// <returns></returns>
        private static bool HasSQSPermission(Policy policy, string topicArn, string sqsQueueArn)
        {
            foreach (Statement statement in policy.Statements)
            {
                // See if the statement contains the topic as a resource
                bool containsResource = false;
                foreach (var resource in statement.Resources)
                {
                    if (resource.Id.Equals(sqsQueueArn))
                    {
                        containsResource = true;
                        break;
                    }
                }

                // If queue found as the resource see if the condition is for this topic
                if (containsResource)
                {
                    foreach (var condition in statement.Conditions)
                    {
                        if ((string.Equals(condition.Type, ConditionFactory.StringComparisonType.StringLike.ToString(), StringComparison.OrdinalIgnoreCase) ||
                                string.Equals(condition.Type, ConditionFactory.StringComparisonType.StringEquals.ToString(), StringComparison.OrdinalIgnoreCase) ||
                                string.Equals(condition.Type, ConditionFactory.ArnComparisonType.ArnEquals.ToString(), StringComparison.OrdinalIgnoreCase) ||
                                string.Equals(condition.Type, ConditionFactory.ArnComparisonType.ArnLike.ToString(), StringComparison.OrdinalIgnoreCase)) &&
                            string.Equals(condition.ConditionKey, ConditionFactory.SOURCE_ARN_CONDITION_KEY, StringComparison.OrdinalIgnoreCase) &&
                            condition.Values.Contains<string>(topicArn))
                            return true;
                    }
                }
            }

            return false;
        }
 /// <summary>
 /// Add statement to the policy that gives the sns topic access to send a message to the queue.
 /// </summary>
 /// <param name="policy"></param>
 /// <param name="topicArn"></param>
 /// <param name="sqsQueueArn"></param>
 private static void AddSQSPermission(Policy policy, string topicArn, string sqsQueueArn)
 {
     Statement statement = new Statement(Statement.StatementEffect.Allow);
     statement.Actions.Add(SQSActionIdentifiers.SendMessage);
     statement.Resources.Add(new Resource(sqsQueueArn));
     statement.Conditions.Add(ConditionFactory.NewSourceArnCondition(topicArn));
     statement.Principals.Add(new Principal("*"));
     policy.Statements.Add(statement);
 }
Exemple #3
0
        public static void CreateLambdaFunction(string functionName, string iamRoleName, out string iamRoleArn, out string functionArn)
        {
            var iamCreateResponse = iamClient.CreateRole(new CreateRoleRequest
            {
                RoleName = iamRoleName,
                AssumeRolePolicyDocument = LAMBDA_ASSUME_ROLE_POLICY
            });

            iamRoleArn = iamCreateResponse.Role.Arn;

            var statement = new Statement(Statement.StatementEffect.Allow);

            statement.Actions.Add(S3ActionIdentifiers.PutObject);
            statement.Actions.Add(S3ActionIdentifiers.GetObject);
            statement.Resources.Add(new Resource("*"));


            var policy = new Amazon.Auth.AccessControlPolicy.Policy();

            policy.Statements.Add(statement);

            iamClient.PutRolePolicy(new PutRolePolicyRequest
            {
                RoleName       = iamRoleName,
                PolicyName     = "admin",
                PolicyDocument = policy.ToJson()
            });

            // Wait for the role and policy to propagate
            Thread.Sleep(5000);

            MemoryStream stream        = CreateScriptStream();
            var          uploadRequest = new CreateFunctionRequest
            {
                FunctionName = functionName,
                Code         = new FunctionCode
                {
                    ZipFile = stream
                },
                Handler = "helloworld.handler",
                //Mode = Mode.Event,
                Runtime = Runtime.Nodejs,
                Role    = iamCreateResponse.Role.Arn
            };

            var uploadResponse = Client.CreateFunction(uploadRequest);

            createdFunctionNames.Add(functionName);

            Assert.IsTrue(uploadResponse.CodeSize > 0);
            Assert.IsNotNull(uploadResponse.FunctionArn);

            functionArn = uploadResponse.FunctionArn;
        }
Exemple #4
0
        public void Save(string sourceArn, IAmazonSimpleNotificationService client)
        {
            ActionIdentifier[] actions = { SNSActionIdentifiers.Subscribe};

            var snsPolicy = new Policy()
                .WithStatements(GetDefaultStatement(sourceArn))
                .WithStatements(new Statement(Statement.StatementEffect.Allow)
                    .WithPrincipals(_accountIds.Select(a => new Principal(a)).ToArray())
                    .WithResources(new Resource(sourceArn))
                    .WithActionIdentifiers(actions));
            var attributeValue = snsPolicy.ToJson();
            var setQueueAttributesRequest = new SetTopicAttributesRequest(sourceArn, "Policy", attributeValue);

            client.SetTopicAttributes(setQueueAttributesRequest);
        }
Exemple #5
0
        public static void Save(string sourceArn, string queueArn, string queueUrl, IAmazonSQS client)
        {
            var topicArnWildcard = CreateTopicArnWildcard(sourceArn);
            ActionIdentifier[] actions = { SQSActionIdentifiers.SendMessage };

            Policy sqsPolicy = new Policy()
                .WithStatements(new Statement(Statement.StatementEffect.Allow)
                    .WithPrincipals(Principal.AllUsers)
                    .WithResources(new Resource(queueArn))
                    .WithConditions(ConditionFactory.NewSourceArnCondition(topicArnWildcard))
                    .WithActionIdentifiers(actions));
            SetQueueAttributesRequest setQueueAttributesRequest = new SetQueueAttributesRequest();
            setQueueAttributesRequest.QueueUrl = queueUrl;
            setQueueAttributesRequest.Attributes["Policy"] = sqsPolicy.ToJson();
            client.SetQueueAttributes(setQueueAttributesRequest);
        }
        /// <summary>
        /// Helper method for AuthorizeS3ToSendMessage()
        /// </summary>
        /// <param name="response"></param>
        /// <param name="bucket"></param>
        /// <param name="policy"></param>
        /// <param name="statement"></param>
        private static void GetNewPolicyAndStatement(GetQueueAttributesResponse response, string bucket, out Policy policy, out Statement statement)
        {
            if (!string.IsNullOrEmpty(response.Policy))
            {
                policy = Policy.FromJson(response.Policy);
            }
            else
            {
                policy = new Policy();
            }

            var sourceArn = string.Format(CultureInfo.InvariantCulture, "arn:aws:s3:*:*:{0}", bucket);

            statement = new Statement(Statement.StatementEffect.Allow);
            statement.Actions.Add(SQSActionIdentifiers.SendMessage);
            statement.Resources.Add(new Resource(response.QueueARN));
            statement.Conditions.Add(ConditionFactory.NewSourceArnCondition(sourceArn));
            statement.Principals.Add(new Principal("*"));
        }
        /// <summary>
        /// This is a utility method which updates the policy of a queue to allow the
        /// S3 bucket to publish events to it.
        /// </summary>
        /// <param name="queueUrl">The queue that will have its policy updated.</param>
        /// <param name="bucket">The bucket that will be given access to send messages from.</param>
        /// <returns>The ARN for the SQS queue. This can be used when setting up the S3 bucket notification.</returns>
        public string AuthorizeS3ToSendMessage(string queueUrl, string bucket)
        {
            var getAttributeResponse = this.GetQueueAttributes(new GetQueueAttributesRequest
            {
                QueueUrl = queueUrl,
                AttributeNames = new List<string> { "All"}
            });

            Policy policy;
            if (!string.IsNullOrEmpty(getAttributeResponse.Policy))
            {
                policy = Policy.FromJson(getAttributeResponse.Policy);
            }
            else
            {
                policy = new Policy();
            }

            var sourceArn = string.Format(CultureInfo.InvariantCulture, "arn:aws:s3:*:*:{0}", bucket);

            Statement statement = new Statement(Statement.StatementEffect.Allow);
            statement.Actions.Add(SQSActionIdentifiers.SendMessage);
            statement.Resources.Add(new Resource(getAttributeResponse.QueueARN));
            statement.Conditions.Add(ConditionFactory.NewSourceArnCondition(sourceArn));
            statement.Principals.Add(new Principal("*"));

            if (!policy.CheckIfStatementExists(statement))
            {
                policy.Statements.Add(statement);

                var policyString = policy.ToJson();
                this.SetQueueAttributes(new SetQueueAttributesRequest
                {
                    QueueUrl = queueUrl,
                    Attributes = new Dictionary<string, string>
                    {
                        {"Policy", policyString}
                    }
                });
            }

            return getAttributeResponse.QueueARN;
        }
        public void TestIfStatementAlreadyExists()
        {
            var policy = new Policy();

            Statement statement = new Statement(Statement.StatementEffect.Allow);
            statement.Actions.Add(SQSActionIdentifiers.SendMessage);
            statement.Resources.Add(new Resource("the:queue:arn"));
            statement.Conditions.Add(ConditionFactory.NewSourceArnCondition("source:arn"));
            statement.Principals.Add(new Principal("*"));

            policy.Statements.Add(statement);

            Statement newStatement = new Statement(Statement.StatementEffect.Allow);
            newStatement.Actions.Add(SQSActionIdentifiers.SendMessage);
            newStatement.Resources.Add(new Resource("the:queue:arn"));
            newStatement.Conditions.Add(ConditionFactory.NewSourceArnCondition("source:arn"));
            newStatement.Principals.Add(new Principal("*"));

            Assert.IsTrue(policy.CheckIfStatementExists(newStatement));

            newStatement.Effect = Statement.StatementEffect.Deny;
            Assert.IsFalse(policy.CheckIfStatementExists(newStatement));

            newStatement.Effect = Statement.StatementEffect.Allow;
            Assert.IsTrue(policy.CheckIfStatementExists(newStatement));

            newStatement.Actions.Add(SQSActionIdentifiers.AddPermission);
            Assert.IsFalse(policy.CheckIfStatementExists(newStatement));

            newStatement.Actions.Remove(SQSActionIdentifiers.AddPermission);
            Assert.IsTrue(policy.CheckIfStatementExists(newStatement));

            newStatement.Principals.Add(new Principal("data"));
            Assert.IsFalse(policy.CheckIfStatementExists(newStatement));

            newStatement.Principals.RemoveAt(1);
            Assert.IsTrue(policy.CheckIfStatementExists(newStatement));

            newStatement.Conditions[0].ConditionKey = "new:arn";
            Assert.IsFalse(policy.CheckIfStatementExists(newStatement));
        }
Exemple #9
0
        public void TestAnonymousPrincipal()
        {
            var policy = new Policy 
            {
                Statements =
                {
                    new Statement(Statement.StatementEffect.Deny)
                    {
                         Principals = { Principal.Anonymous }
                    }
                }
            };

            var json = policy.ToJson();
            Console.WriteLine(json);
            Assert.IsTrue(json.Contains("\"Principal\" : \"*\""));

            var roundTripPolicy = Policy.FromJson(json);

            Assert.AreEqual(Principal.Anonymous, roundTripPolicy.Statements[0].Principals[0]);
        }
        public ISubscribeReponseMessage Subscribe(string queueUrl)
        {
            var sqsConfig = new AmazonSQSConfig {ServiceURL = SqsServiceUrl};
            var snsConfig = new AmazonSimpleNotificationServiceConfig {ServiceURL = SnsServiceUrl};

            using (var sqsClient = _awsConfig.CreateAwsClient<AmazonSQSClient>(sqsConfig))
            {
                var attributesRequest = new GetQueueAttributesRequest(queueUrl, new List<string> {"QueueArn"});

                var attributesResponse = sqsClient.GetQueueAttributes(attributesRequest);

                using (var snsClient = _awsConfig.CreateAwsClient<AmazonSimpleNotificationServiceClient>(snsConfig))
                {
                    var subribeResonse =
                        snsClient.Subscribe(new SubscribeRequest(TopicArn, "sqs", attributesResponse.QueueARN));
                }

                var actions = new ActionIdentifier[2];
                actions[0] = SQSActionIdentifiers.SendMessage;
                actions[1] = SQSActionIdentifiers.ReceiveMessage;
                var sqsPolicy =
                    new Policy().WithStatements(
                        new Statement(Statement.StatementEffect.Allow).WithPrincipals(Principal.AllUsers)
                            .WithResources(
                                new Resource(attributesResponse.QueueARN))
                            .WithConditions(
                                ConditionFactory.NewSourceArnCondition(
                                    TopicArn))
                            .WithActionIdentifiers(actions));
                var setQueueAttributesRequest = new SetQueueAttributesRequest();

                var attributes = new Dictionary<string, string> {{"Policy", sqsPolicy.ToJson()}};
                var attRequest = new SetQueueAttributesRequest(attributesRequest.QueueUrl, attributes);

                sqsClient.SetQueueAttributes(attRequest);

                return new SubcriptionMessage("Ok");
            }
        }
Exemple #11
0
        public void create_sqs_queue()
        {
            GetUserNameAndPassword();
            var sqsClient = Amazon.AWSClientFactory.CreateAmazonSQSClient(_key, _secret);
            var snsTopic = Amazon.AWSClientFactory.CreateAmazonSNSClient(_key, _secret);
            var topicArn = "arn:aws:sns:us-east-1:451419498740:Elliott-has-an-awesome-blog";
            //Create a new SQS queue
            var createQueueRequest = new CreateQueueRequest().WithQueueName("elliotts-blog");
            var createQueueResponse = sqsClient.CreateQueue(createQueueRequest);
            // keep the queueUrl handy
            var queueUrl = createQueueResponse.CreateQueueResult.QueueUrl;
            // get the Access Resource Name so we can allow the SNS to put messages on it
            var getQueueArnRequest = new GetQueueAttributesRequest()
                .WithQueueUrl(queueUrl)
                .WithAttributeName("QueueArn");
            var getQueueArnResponse = sqsClient.GetQueueAttributes(getQueueArnRequest);
            var queueArn = getQueueArnResponse.GetQueueAttributesResult.Attribute[0].Value;

            //create a Policy for the SQS queue that allows SNS to publish to it
            var allowSnsStatement = new Statement(Statement.StatementEffect.Allow)
                .WithPrincipals(Principal.AllUsers)
                .WithResources(new Resource(queueArn))
                .WithConditions(ConditionFactory.NewSourceArnCondition(topicArn))
                .WithActionIdentifiers(SQSActionIdentifiers.SendMessage);
            var policy = new Policy("allow sns").WithStatements(new[] {allowSnsStatement});
            var attribute = new Attribute().WithName("Policy").WithValue(policy.ToJson());
            var setQueueAttributesRequest =
                new SetQueueAttributesRequest().WithQueueUrl(queueUrl).WithAttribute(attribute);
            sqsClient.SetQueueAttributes(setQueueAttributesRequest);

            // ok, now lets create the subscription for sqs with the queueArn we created
            var subscribeRequest = new SubscribeRequest()
                .WithEndpoint(queueArn)
                .WithTopicArn(topicArn)
                .WithProtocol("sqs");

            snsTopic.Subscribe(subscribeRequest);
        }
        public virtual void GrantNotificationPermission(AmazonSQSClient sqsClient, string queueArn, string queueUrl,
            string topicArn)
        {
            // Create a policy to allow the queue to receive notifications from the SNS topic
            var policy = new Policy("SubscriptionPermission")
            {
                Statements =
                {
                    new Statement(Statement.StatementEffect.Allow)
                    {
                        Actions = {SQSActionIdentifiers.SendMessage},
                        Principals = {new Principal("*")},
                        Conditions = {ConditionFactory.NewSourceArnCondition(topicArn)},
                        Resources = {new Resource(queueArn)}
                    }
                }
            };

            var attributes = new Dictionary<string, string>();
            attributes.Add("Policy", policy.ToJson());

            // Create the request to set the queue attributes for policy
            var setQueueAttributesRequest = new SetQueueAttributesRequest
            {
                QueueUrl = queueUrl,
                Attributes = attributes
            };

            // Set the queue policy
            sqsClient.SetQueueAttributes(setQueueAttributesRequest);
        }
        public void LambdaFunctionTest()
        {
            const string HELLO_SCRIPT = 
@"console.log('Loading http')
 
exports.handler = function (request, response) {
    response.write(""Hello, world!"");
    response.end();
    console.log(""Request completed"");
}";
            MemoryStream stream = new MemoryStream();
            using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create, true))
            {
                var entry = archive.CreateEntry("helloworld.js");
                using (var entryStream = entry.Open())
                using (var writer = new StreamWriter(entryStream))
                {
                    writer.Write(HELLO_SCRIPT);
                }
            }
            stream.Position = 0;

            var functionName = "HelloWorld";
            bool uploaded = false;

            var iamRoleName = "Lambda-" + DateTime.Now.Ticks;
            bool iamRoleCreated = false;
            try
            {
                var iamCreateResponse = iamClient.CreateRole(new CreateRoleRequest
                    {
                        RoleName = iamRoleName,
                        AssumeRolePolicyDocument = LAMBDA_ASSUME_ROLE_POLICY
                    });

                var statement = new Statement(Statement.StatementEffect.Allow);
                statement.Actions.Add(S3ActionIdentifiers.PutObject);
                statement.Actions.Add(S3ActionIdentifiers.GetObject);
                statement.Resources.Add(new Resource("*"));


                var policy = new Policy();
                policy.Statements.Add(statement);

                iamClient.PutRolePolicy(new PutRolePolicyRequest
                    {
                        RoleName = iamRoleName,
                        PolicyName = "admin",
                        PolicyDocument = policy.ToJson()
                    });

                // Wait for the role and policy to propagate
                Thread.Sleep(5000);

                var uploadRequest = new UploadFunctionRequest
                {
                    FunctionName = functionName,
                    FunctionZip = stream,
                    Handler = "helloworld.handler",
                    Mode = Mode.Event,
                    Runtime = Runtime.Nodejs,
                    Role = iamCreateResponse.Role.Arn
                };

                var uploadResponse = lambdaClient.UploadFunction(uploadRequest);
                uploaded = true;
                Assert.IsTrue(uploadResponse.CodeSize > 0);
                Assert.IsNotNull(uploadResponse.ConfigurationId);

                // List all the functions and make sure the newly uploaded function is in the collection
                var listResponse = lambdaClient.ListFunctions();
                var function = listResponse.Functions.FirstOrDefault(x => x.FunctionName == functionName);
                Assert.IsNotNull(function);
                Assert.AreEqual("helloworld.handler", function.Handler);
                Assert.AreEqual(iamCreateResponse.Role.Arn, function.Role);

                // Get the function with a presigned URL to the uploaded code
                var getFunctionResponse = lambdaClient.GetFunction(functionName);
                Assert.AreEqual("helloworld.handler", getFunctionResponse.Configuration.Handler);
                Assert.IsNotNull(getFunctionResponse.Code.Location);

                // Get the function's configuration only
                var getFunctionConfiguration = lambdaClient.GetFunctionConfiguration(functionName);
                Assert.AreEqual("helloworld.handler", getFunctionConfiguration.Handler);

                // Call the function
                var invokeResponse = lambdaClient.InvokeAsync(functionName);
                Assert.AreEqual(invokeResponse.Status, 202); // Status Code Accepted

            }
            finally
            {
                if(uploaded)
                    lambdaClient.DeleteFunction(functionName);

                if (iamRoleCreated)
                    iamClient.DeleteRole(new DeleteRoleRequest { RoleName = iamRoleName });
            }
        }
        public string SetSqsPolicyForSnsPublish(Uri queueUrl, string queueArn, string mytopicArn)
        {
            queueUrl.Requires("queueUrl").IsNotNull();
            queueArn.Requires("queueArn").IsNotNullOrWhiteSpace();
            mytopicArn.Requires("mytopicArn").IsNotNullOrWhiteSpace();

            var sqsPolicy = new Policy().WithStatements(
                new Statement(Statement.StatementEffect.Allow)
                    .WithResources(new Resource(queueArn))
                    .WithPrincipals(Principal.AllUsers)
                    .WithActionIdentifiers(SQSActionIdentifiers.SendMessage)
                    .WithConditions(ConditionFactory.NewCondition(ConditionFactory.ArnComparisonType.ArnEquals,
                        ConditionSourceArn, mytopicArn)));

            var attributes = new Dictionary<string, string>
            {
                {QueueAttributeName.Policy, sqsPolicy.ToJson()}
            };

            var setQueueAttributesRequest = new SetQueueAttributesRequest(queueUrl.AbsoluteUri, attributes);
            using (var sqs = amazonSqsFactory())
            {
                var response = sqs.SetQueueAttributes(setQueueAttributesRequest);
                return response.ResponseMetadata.RequestId;
            }
        }
        /// <summary>
        /// Subscribes an existing Amazon SQS queue to existing Amazon SNS topics asynchronously.
        /// <para>
        /// The policy applied to the SQS queue is similar to this:
        /// <code>
        /// {
        /// 	"Version" : "2008-10-17",
        /// 	"Statement" : [{
        /// 	    "Sid" : "topic-subscription-arn:aws:sns:us-west-2:599109622955:myTopic",
        /// 		"Effect" : "Allow",
        /// 		"Principal" : "*",
        /// 		"Action" : ["sqs:SendMessage"],
        /// 		"Resource":["arn:aws:sqs:us-west-2:599109622955:myQueue"],
        /// 		"Condition" : {
        /// 			"ArnLike":{
        /// 				"aws:SourceArn":["arn:aws:sns:us-west-2:599109622955:myTopic"]
        /// 			}
        /// 		}
        ///     }]
        /// }
        /// </code>
        /// </para>
        /// <para>
        /// There might be a small time period immediately after
        /// subscribing the SQS queue to the SNS topic and updating the SQS queue's
        /// policy, where messages are not able to be delivered to the queue. After a
        /// moment, the new queue policy will propagate and the queue will be able to
        /// receive messages. This delay only occurs immediately after initially
        /// subscribing the queue.
        /// </para>
        /// </summary>
        /// <param name="topicArns">The topics to subscribe to</param>
        /// <param name="sqsClient">The SQS client used to get attributes and set the policy on the SQS queue.</param>
        /// <param name="sqsQueueUrl">The queue to add a subscription to.</param>
        /// <returns>The mapping of topic ARNs to subscription ARNs as returned by Amazon SNS when the queue is 
        /// successfully subscribed to each topic.</returns>
        public async Task<IDictionary<string, string>> SubscribeQueueToTopicsAsync(IList<string> topicArns, ICoreAmazonSQS sqsClient, string sqsQueueUrl)
        {
            // Get the queue's existing policy and ARN
            var queueAttributes = await sqsClient.GetAttributesAsync(sqsQueueUrl).ConfigureAwait(false);

            string sqsQueueArn = queueAttributes["QueueArn"];

            Policy policy;
            string policyStr = null;
            if(queueAttributes.ContainsKey("Policy"))
                policyStr = queueAttributes["Policy"];
            if (string.IsNullOrEmpty(policyStr))
                policy = new Policy();
            else
                policy = Policy.FromJson(policyStr);

            var subscriptionArns = new Dictionary<string,string>();

            foreach (var topicArn in topicArns)
            {
                if (!HasSQSPermission(policy, topicArn, sqsQueueArn))
                    AddSQSPermission(policy, topicArn, sqsQueueArn);

                SubscribeResponse response = await this.SubscribeAsync(new SubscribeRequest
                {
                    TopicArn = topicArn,
                    Protocol = "sqs",
                    Endpoint = sqsQueueArn,
                }).ConfigureAwait(false);
                subscriptionArns.Add(topicArn, response.SubscriptionArn);
            }

            var setAttributes = new Dictionary<string, string> { { "Policy", policy.ToJson() } };
            await sqsClient.SetAttributesAsync(sqsQueueUrl, setAttributes).ConfigureAwait(false);

            return subscriptionArns;
        }
Exemple #16
0
        public void LambdaFunctionTest()
        {
            const string HELLO_SCRIPT =
                @"console.log('Loading http')
 
exports.handler = function (request, response) {
    response.write(""Hello, world!"");
    response.end();
    console.log(""Request completed"");
}";
            MemoryStream stream = new MemoryStream();

            using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create, true))
            {
                var entry = archive.CreateEntry("helloworld.js");
                using (var entryStream = entry.Open())
                    using (var writer = new StreamWriter(entryStream))
                    {
                        writer.Write(HELLO_SCRIPT);
                    }
            }
            stream.Position = 0;

            var  functionName = "HelloWorld";
            bool uploaded     = false;

            var  iamRoleName    = "Lambda-" + DateTime.Now.Ticks;
            bool iamRoleCreated = false;

            try
            {
                var iamCreateResponse = iamClient.CreateRole(new CreateRoleRequest
                {
                    RoleName = iamRoleName,
                    AssumeRolePolicyDocument = LAMBDA_ASSUME_ROLE_POLICY
                });

                var statement = new Statement(Statement.StatementEffect.Allow);
                statement.Actions.Add(S3ActionIdentifiers.PutObject);
                statement.Actions.Add(S3ActionIdentifiers.GetObject);
                statement.Resources.Add(new Resource("*"));


                var policy = new Amazon.Auth.AccessControlPolicy.Policy();
                policy.Statements.Add(statement);

                iamClient.PutRolePolicy(new PutRolePolicyRequest
                {
                    RoleName       = iamRoleName,
                    PolicyName     = "admin",
                    PolicyDocument = policy.ToJson()
                });

                // Wait for the role and policy to propagate
                Thread.Sleep(5000);

                var uploadRequest = new UploadFunctionRequest
                {
                    FunctionName = functionName,
                    FunctionZip  = stream,
                    Handler      = "helloworld.handler",
                    Mode         = Mode.Event,
                    Runtime      = Runtime.Nodejs,
                    Role         = iamCreateResponse.Role.Arn
                };

                var uploadResponse = lambdaClient.UploadFunction(uploadRequest);
                uploaded = true;
                Assert.IsTrue(uploadResponse.CodeSize > 0);
                Assert.IsNotNull(uploadResponse.ConfigurationId);

                // List all the functions and make sure the newly uploaded function is in the collection
                var listResponse = lambdaClient.ListFunctions();
                var function     = listResponse.Functions.FirstOrDefault(x => x.FunctionName == functionName);
                Assert.IsNotNull(function);
                Assert.AreEqual("helloworld.handler", function.Handler);
                Assert.AreEqual(iamCreateResponse.Role.Arn, function.Role);

                // Get the function with a presigned URL to the uploaded code
                var getFunctionResponse = lambdaClient.GetFunction(functionName);
                Assert.AreEqual("helloworld.handler", getFunctionResponse.Configuration.Handler);
                Assert.IsNotNull(getFunctionResponse.Code.Location);

                // Get the function's configuration only
                var getFunctionConfiguration = lambdaClient.GetFunctionConfiguration(functionName);
                Assert.AreEqual("helloworld.handler", getFunctionConfiguration.Handler);

                // Call the function
                var invokeResponse = lambdaClient.InvokeAsync(functionName);
                Assert.AreEqual(invokeResponse.Status, 202); // Status Code Accepted
            }
            finally
            {
                if (uploaded)
                {
                    lambdaClient.DeleteFunction(functionName);
                }

                if (iamRoleCreated)
                {
                    iamClient.DeleteRole(new DeleteRoleRequest {
                        RoleName = iamRoleName
                    });
                }
            }
        }
        /// <summary>
        /// Subscribes an existing Amazon SQS queue to an existing Amazon SNS topic.
        /// <para>
        /// The policy applied to the SQS queue is similar to this:
        /// <code>
        /// {
        /// 	"Version" : "2008-10-17",
        /// 	"Statement" : [{
        /// 	    "Sid" : "topic-subscription-arn:aws:sns:us-west-2:599109622955:myTopic",
        /// 		"Effect" : "Allow",
        /// 		"Principal" : {
        /// 			"AWS":["*"]
        /// 		},
        /// 		"Action" : ["sqs:SendMessage"],
        /// 		"Resource":["arn:aws:sqs:us-west-2:599109622955:myQueue"],
        /// 		"Condition" : {
        /// 			"ArnLike":{
        /// 				"aws:SourceArn":["arn:aws:sns:us-west-2:599109622955:myTopic"]
        /// 			}
        /// 		}
        ///     }]
        /// }
        /// </code>
        /// </para>
        /// <para>
        /// There might be a small time period immediately after
        /// subscribing the SQS queue to the SNS topic and updating the SQS queue's
        /// policy, where messages are not able to be delivered to the queue. After a
        /// moment, the new queue policy will propagate and the queue will be able to
        /// receive messages. This delay only occurs immediately after initially
        /// subscribing the queue.
        /// </para>
        /// </summary>
        /// <param name="topicArn">The topic to subscribe to</param>
        /// <param name="sqsClient">The SQS client used to get attributes and set the policy on the SQS queue.</param>
        /// <param name="sqsQueueUrl">The queue to add a subscription to.</param>
        /// <returns>The subscription ARN as returned by Amazon SNS when the queue is 
        /// successfully subscribed to the topic.</returns>
        public string SubscribeQueue(string topicArn, IAmazonSQS sqsClient, string sqsQueueUrl)
        {
            // Get the queue's existing policy and ARN
            var getAttributeResponse = sqsClient.GetQueueAttributes(new GetQueueAttributesRequest()
            {
                AttributeNames = new List<string>() { "All" },
                QueueUrl = sqsQueueUrl
            });

            string sqsQueueArn = getAttributeResponse.QueueARN;

            Policy policy;
            string policyStr = getAttributeResponse.Policy;
            if (string.IsNullOrEmpty(policyStr))
                policy = new Policy();
            else
                policy = Policy.FromJson(policyStr);

            if (!HasSQSPermission(policy, topicArn, sqsQueueArn))
            {
                AddSQSPermission(policy, topicArn, sqsQueueArn);
                sqsClient.SetQueueAttributes(new SetQueueAttributesRequest()
                {
                    QueueUrl = sqsQueueUrl,
                    Attributes = new Dictionary<string, string>() { { "Policy", policy.ToJson() } }
                });
            }

            var subscribeResponse = this.Subscribe(new SubscribeRequest()
            {
                TopicArn = topicArn,
                Protocol = "sqs",
                Endpoint = sqsQueueArn
            });

            return subscribeResponse.SubscriptionArn;
        }
        public string SetSqsPolicyForSnsPublish(Uri queueUrl, string queueArn, string mytopicArn)
        {
            Validate.That(queueUrl).IsNotNull();
            Validate.That(queueArn).IsNotNullOrEmpty();
            Validate.That(mytopicArn).IsNotNullOrEmpty();

            var sqsPolicy = new Policy().WithStatements(
                new Statement(Statement.StatementEffect.Allow)
                    .WithResources(new Resource(queueArn))
                    .WithPrincipals(Principal.AllUsers)
                    .WithActionIdentifiers(SQSActionIdentifiers.SendMessage)
                    .WithConditions(ConditionFactory.NewCondition(ConditionFactory.ArnComparisonType.ArnEquals,
                                                                  conditionSourceArn, mytopicArn)));

            var setQueueAttributesRequest =
                new SetQueueAttributesRequest().WithQueueUrl(queueUrl.AbsoluteUri).WithPolicy(sqsPolicy.ToJson());
            using (var sqs = amazonSqsFactory())
            {
                var response = sqs.SetQueueAttributes(setQueueAttributesRequest);
                return response.ResponseMetadata.RequestId;
            }
        }
        /// <summary>
        /// This is a utility method which updates the policy of a topic to allow the
        /// S3 bucket to publish events to it.
        /// </summary>
        /// <param name="topicArn">The topic that will have its policy updated.</param>
        /// <param name="bucket">The bucket that will be given access to publish from.</param>
        public void AuthorizeS3ToPublish(string topicArn, string bucket)
        {
            var attributes = this.GetTopicAttributes(new GetTopicAttributesRequest
                {
                    TopicArn = topicArn
                }).Attributes;

            Policy policy;
            if(attributes.ContainsKey("Policy") && !string.IsNullOrEmpty(attributes["Policy"]))
            {
                policy = Policy.FromJson(attributes["Policy"]);
            }
            else
            {
                policy = new Policy();
            }

            var sourceArn = string.Format(CultureInfo.InvariantCulture, "arn:aws:s3:*:*:{0}", bucket);


            Statement newStatement = new Statement(Statement.StatementEffect.Allow);
            newStatement.Actions.Add(SNSActionIdentifiers.Publish);
            newStatement.Resources.Add(new Resource(topicArn));
            newStatement.Conditions.Add(ConditionFactory.NewSourceArnCondition(sourceArn));
            newStatement.Principals.Add(new Principal("*"));

            if (!policy.CheckIfStatementExists(newStatement))
            {
                policy.Statements.Add(newStatement);

                var policyString = policy.ToJson();
                this.SetTopicAttributes(new SetTopicAttributesRequest
                {
                    TopicArn = topicArn,
                    AttributeName = "Policy",
                    AttributeValue = policyString
                });
            }
        }
        /// <summary>
        /// Helper method for AuthorizeS3ToPublishAsync()
        /// </summary>
        /// <param name="attributes"></param>
        /// <param name="topicArn"></param>
        /// <param name="bucket"></param>
        /// <param name="policy"></param>
        /// <param name="statement"></param>
        private static void GetNewPolicyAndStatementForTopicAttributes(Dictionary<string, string> attributes, string topicArn, string bucket, out Policy policy, out Statement statement)
        {
            if(attributes.ContainsKey("Policy") && !string.IsNullOrEmpty(attributes["Policy"]))
            {
                policy = Policy.FromJson(attributes["Policy"]);
            }
            else
            {
                policy = new Policy();
            }

            var sourceArn = string.Format(CultureInfo.InvariantCulture, "arn:aws:s3:*:*:{0}", bucket);

            statement = new Statement(Statement.StatementEffect.Allow);
            statement.Actions.Add(SNSActionIdentifiers.Publish);
            statement.Resources.Add(new Resource(topicArn));
            statement.Conditions.Add(ConditionFactory.NewSourceArnCondition(sourceArn));
            statement.Principals.Add(new Principal("*"));
        }