baouss
baouss

Reputation: 1870

Use AWS SDK without credentials to confirm a SNS subscription --> No RegionEndpoint or ServiceURL configured

I don't have an AWS account. I do have an HTTP POST webhook that should receive to the HTTPS endpoint of a SNS topic. When trying to confirm the subscription there is the following error message in the logs:

No RegionEndpoint or ServiceURL configured

I used the official AWS SDK for .NET calling the ConfirmSubscriptionAsync method. The purpose of me using the SDK was that it itself should handle the signature validation, as is proposed in the AWS docs. However, this cannot be done if I don't provide myself have an AWS account. Is this expected?

Here's the code that should handle the incoming requests

    public class Func
    {
        [FunctionName(nameof(Func))]
        public async Task Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "/receive/sns")] HttpRequest req, ILogger log)
        {
            if (req.Headers.TryGetValue("x-amz-sns-message-type" , out var msgType))
            {
                if (msgType == "SubscriptionConfirmation")
                {
                    var snsClient = new AmazonSimpleNotificationServiceClient();
                    var subscriptionRequest = await JsonSerializer.DeserializeAsync<ConfirmSubscriptionRequest>(req.Body);
                    var subscriptionResponse = await snsClient.ConfirmSubscriptionAsync(subscriptionRequest);
                    log.LogTrace(Newtonsoft.Json.JsonConvert.SerializeObject(subscriptionResponse));
                }
                else if (msgType == "Notification")
                {
                    var notification = await JsonSerializer.DeserializeAsync<AwsSnsNotification>(req.Body);
                    log.LogTrace(JsonSerializer.Serialize(notification));
                }
                else
                {
                    throw new ArgumentOutOfRangeException("`x-amz-sns-message-type header`", msgType, "Allowed as per AWS doc: `SubscriptionConfirmation`, `Notification`");
                }
            }
            else
            {
                throw new ArgumentNullException("x-amz-sns-message-type header not set");
            }
        }
    }

Upvotes: 1

Views: 559

Answers (1)

baouss
baouss

Reputation: 1870

Solved it without needing to create an instance of the client. The message model exposes a the static ParseMessage method. Then on the instance of Message I can invoke the IsMessageSignatureValid method. Subsequently I just HTTP GET the subscription confirmation url and done. Posting here so hopefully this is helpful for others as well.

    public class Func
    {
        [FunctionName(nameof(Func))]
        public async Task Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "receive/sns")] HttpRequest req, ILogger log)
        {
            if (req.Headers.TryGetValue("x-amz-sns-message-type" , out var msgType))
            {
                var reqBody = await new StreamReader(req.Body, Encoding.UTF8).ReadToEndAsync();
                var msg = Message.ParseMessage(reqBody);
                if (!msg.IsMessageSignatureValid())
                {
                    throw new UnauthorizedAccessException("Message signature invalid");
                }
                else
                {
                    if (msgType == "SubscriptionConfirmation")
                    {
                        await Http.GetAsync(msg.SubscribeURL);
                    }
                    else if (msgType == "Notification")
                    {
                        log.LogTrace(msg.MessageText);
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException("`x-amz-sns-message-type header`", msgType, "Allowed as per AWS doc: `SubscriptionConfirmation`, `Notification`");
                    }
                }
            }
            else
            {
                throw new ArgumentNullException("x-amz-sns-message-type header not set");
            }
        }
    }

Upvotes: 1

Related Questions