From 5ce4141003ba7e64a62c011a61d87f1646a778f1 Mon Sep 17 00:00:00 2001 From: Simon-Pierre Gingras Date: Thu, 4 Jul 2019 01:54:11 -0700 Subject: [PATCH] fix(sns): allow tokens to be used in UrlSubscription (#2938) --- .../@aws-cdk/aws-sns-subscriptions/lib/url.ts | 28 +++++++++++-- .../aws-sns-subscriptions/test/subs.test.ts | 40 ++++++++++++++++++- 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/aws-sns-subscriptions/lib/url.ts b/packages/@aws-cdk/aws-sns-subscriptions/lib/url.ts index 5eb0029a93e48..12f13512aa132 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/lib/url.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/lib/url.ts @@ -1,4 +1,5 @@ import sns = require('@aws-cdk/aws-sns'); +import { Token } from '@aws-cdk/core'; import { SubscriptionProps } from './subscription'; /** @@ -13,6 +14,13 @@ export interface UrlSubscriptionProps extends SubscriptionProps { * @default false */ readonly rawMessageDelivery?: boolean; + + /** + * The subscription's protocol. + * + * @default - Protocol is derived from url + */ + readonly protocol?: sns.SubscriptionProtocol; } /** @@ -23,17 +31,31 @@ export interface UrlSubscriptionProps extends SubscriptionProps { * @see https://docs.aws.amazon.com/sns/latest/dg/sns-http-https-endpoint-as-subscriber.html */ export class UrlSubscription implements sns.ITopicSubscription { + private readonly protocol: sns.SubscriptionProtocol; + private readonly unresolvedUrl: boolean; + constructor(private readonly url: string, private readonly props: UrlSubscriptionProps = {}) { - if (!url.startsWith('http://') && !url.startsWith('https://')) { + this.unresolvedUrl = Token.isUnresolved(url); + if (!this.unresolvedUrl && !url.startsWith('http://') && !url.startsWith('https://')) { throw new Error('URL must start with either http:// or https://'); } + + if (this.unresolvedUrl && props.protocol === undefined) { + throw new Error('Must provide protocol if url is unresolved'); + } + + if (this.unresolvedUrl) { + this.protocol = props.protocol!; + } else { + this.protocol = this.url.startsWith('https:') ? sns.SubscriptionProtocol.HTTPS : sns.SubscriptionProtocol.HTTP; + } } public bind(_topic: sns.ITopic): sns.TopicSubscriptionConfig { return { - subscriberId: this.url, + subscriberId: this.unresolvedUrl ? 'UnresolvedUrl' : this.url, endpoint: this.url, - protocol: this.url.startsWith('https:') ? sns.SubscriptionProtocol.HTTPS : sns.SubscriptionProtocol.HTTP, + protocol: this.protocol, rawMessageDelivery: this.props.rawMessageDelivery, filterPolicy: this.props.filterPolicy, }; diff --git a/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts b/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts index 41c1c180d5824..012c2cd0e85ff 100644 --- a/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts +++ b/packages/@aws-cdk/aws-sns-subscriptions/test/subs.test.ts @@ -2,7 +2,7 @@ import '@aws-cdk/assert/jest'; import lambda = require('@aws-cdk/aws-lambda'); import sns = require('@aws-cdk/aws-sns'); import sqs = require('@aws-cdk/aws-sqs'); -import { Stack } from '@aws-cdk/core'; +import { SecretValue, Stack } from '@aws-cdk/core'; import subs = require('../lib'); // tslint:disable:object-literal-key-quotes @@ -71,6 +71,44 @@ test('url subscription (with raw delivery)', () => { }); }); +test('url subscription (unresolved url with protocol)', () => { + const secret = SecretValue.secretsManager('my-secret'); + const url = secret.toString(); + topic.addSubscription(new subs.UrlSubscription(url, {protocol: sns.SubscriptionProtocol.HTTPS})); + + expect(stack).toMatchTemplate({ + "Resources": { + "MyTopic86869434": { + "Type": "AWS::SNS::Topic", + "Properties": { + "DisplayName": "displayName", + "TopicName": "topicName" + } + }, + "MyTopicUnresolvedUrlBA127FB3": { + "Type": "AWS::SNS::Subscription", + "Properties": { + "Endpoint": "{{resolve:secretsmanager:my-secret:SecretString:::}}", + "Protocol": "https", + "TopicArn": { "Ref": "MyTopic86869434" }, + } + } + } + }); +}); + +test('url subscription (unknown protocol)', () => { + expect(() => topic.addSubscription(new subs.UrlSubscription('some-protocol://foobar.com/'))) + .toThrowError(/URL must start with either http:\/\/ or https:\/\//); +}); + +test('url subscription (unresolved url without protocol)', () => { + const secret = SecretValue.secretsManager('my-secret'); + const url = secret.toString(); + expect(() => topic.addSubscription(new subs.UrlSubscription(url))) + .toThrowError(/Must provide protocol if url is unresolved/); +}); + test('queue subscription', () => { const queue = new sqs.Queue(stack, 'MyQueue');