Skip to content

Commit b2f78be

Browse files
committed
make SNS CertUrl configurable even if not resolvable
1 parent 35cb30e commit b2f78be

File tree

3 files changed

+57
-2
lines changed

3 files changed

+57
-2
lines changed

localstack-core/localstack/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,6 +1125,8 @@ def populate_edge_configuration(
11251125

11261126
SNS_SES_SENDER_ADDRESS = os.environ.get("SNS_SES_SENDER_ADDRESS", "").strip()
11271127

1128+
SNS_CERT_URL_HOST = os.environ.get("SNS_CERT_URL_HOST", "").strip()
1129+
11281130
# Whether the Next Gen APIGW invocation logic is enabled (on by default)
11291131
APIGW_NEXT_GEN_PROVIDER = os.environ.get("PROVIDER_OVERRIDE_APIGATEWAY", "") in ("next_gen", "")
11301132

localstack-core/localstack/services/sns/publisher.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ def prepare_message(
237237
:param subscriber: the SNS subscription
238238
:return: an SNS message body formatted as a lambda Event in a JSON string
239239
"""
240-
external_url = external_service_url().rstrip("/")
240+
external_url = get_cert_base_url()
241241
unsubscribe_url = create_unsubscribe_url(external_url, subscriber["SubscriptionArn"])
242242
message_attributes = prepare_message_attributes(message_context.message_attributes)
243243

@@ -958,7 +958,7 @@ def create_sns_message_body(
958958
if message_type == "Notification" and is_raw_message_delivery(subscriber):
959959
return message_content
960960

961-
external_url = external_service_url().rstrip("/")
961+
external_url = get_cert_base_url()
962962

963963
data = {
964964
"Type": message_type,
@@ -1129,6 +1129,13 @@ def store_delivery_log(
11291129
)
11301130

11311131

1132+
def get_cert_base_url() -> str:
1133+
if config.SNS_CERT_URL_HOST:
1134+
return f"https://{config.SNS_CERT_URL_HOST}"
1135+
1136+
return external_service_url().rstrip("/")
1137+
1138+
11321139
def create_subscribe_url(external_url, topic_arn, subscription_token):
11331140
return f"{external_url}/?Action=ConfirmSubscription&TopicArn={topic_arn}&Token={subscription_token}"
11341141

tests/aws/services/sns/test_sns.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
from localstack import config
2424
from localstack.aws.api.lambda_ import Runtime
25+
from localstack.config import external_service_url
2526
from localstack.constants import (
2627
AWS_REGION_US_EAST_1,
2728
)
@@ -4352,6 +4353,51 @@ def get_log_events():
43524353
snapshot.match("delivery-events", events)
43534354

43544355

4356+
class TestSNSCertEndpoint:
4357+
@markers.aws.only_localstack
4358+
@pytest.mark.parametrize("cert_host", ["", "sns.us-east-1.amazonaws.com"])
4359+
def test_cert_endpoint_host(
4360+
self,
4361+
aws_client,
4362+
sns_create_topic,
4363+
sqs_create_queue,
4364+
sns_create_sqs_subscription,
4365+
monkeypatch,
4366+
cert_host,
4367+
):
4368+
"""
4369+
Some SDK will validate the Cert URL matches a certain regex pattern. We validate the user can set the value
4370+
to arbitrary host, but those will obviously not resolve / return a valid certificate.
4371+
"""
4372+
monkeypatch.setattr(config, "SNS_CERT_URL_HOST", cert_host)
4373+
topic_arn = sns_create_topic(
4374+
Attributes={
4375+
"DisplayName": "TestTopicSignature",
4376+
"SignatureVersion": "1",
4377+
},
4378+
)["TopicArn"]
4379+
4380+
queue_url = sqs_create_queue()
4381+
sns_create_sqs_subscription(topic_arn=topic_arn, queue_url=queue_url)
4382+
4383+
aws_client.sns.publish(
4384+
TopicArn=topic_arn,
4385+
Message="test cert host",
4386+
)
4387+
response = aws_client.sqs.receive_message(
4388+
QueueUrl=queue_url,
4389+
WaitTimeSeconds=10,
4390+
)
4391+
message = json.loads(response["Messages"][0]["Body"])
4392+
4393+
cert_url = message["SigningCertURL"]
4394+
if not cert_host:
4395+
assert external_service_url() in cert_url
4396+
else:
4397+
assert cert_host in cert_url
4398+
assert external_service_url() not in cert_url
4399+
4400+
43554401
@pytest.mark.usefixtures("openapi_validate")
43564402
class TestSNSRetrospectionEndpoints:
43574403
@markers.aws.only_localstack

0 commit comments

Comments
 (0)