From 2ad0f2fc1c95626372631c98b575a74722e5f02a Mon Sep 17 00:00:00 2001 From: Adam Gilman Date: Mon, 13 Nov 2017 18:27:11 +0000 Subject: [PATCH] SNS create_topic should only accept valid characters (#1329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * SNS create_topic should only accept valid characters Closes #1328 * Fix flake8 errors * Updated regex to match full TopicName constraints Fixed test_server as it contained invalid TopicNames’ per constraints * fix error message for invalid topic name --- moto/sns/exceptions.py | 8 ++++++++ moto/sns/models.py | 7 ++++++- tests/test_sns/test_server.py | 6 +++--- tests/test_sns/test_topics_boto3.py | 24 +++++++++++++++++++++--- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/moto/sns/exceptions.py b/moto/sns/exceptions.py index 95b91acca..0e7a0bdcf 100644 --- a/moto/sns/exceptions.py +++ b/moto/sns/exceptions.py @@ -32,3 +32,11 @@ class SNSInvalidParameter(RESTError): def __init__(self, message): super(SNSInvalidParameter, self).__init__( "InvalidParameter", message) + + +class InvalidParameterValue(RESTError): + code = 400 + + def __init__(self, message): + super(InvalidParameterValue, self).__init__( + "InvalidParameterValue", message) diff --git a/moto/sns/models.py b/moto/sns/models.py index bf7c605e4..80da5f92f 100644 --- a/moto/sns/models.py +++ b/moto/sns/models.py @@ -7,6 +7,7 @@ import json import boto.sns import requests import six +import re from moto.compat import OrderedDict from moto.core import BaseBackend, BaseModel @@ -15,7 +16,8 @@ from moto.sqs import sqs_backends from moto.awslambda import lambda_backends from .exceptions import ( - SNSNotFoundError, DuplicateSnsEndpointError, SnsEndpointDisabled, SNSInvalidParameter + SNSNotFoundError, DuplicateSnsEndpointError, SnsEndpointDisabled, SNSInvalidParameter, + InvalidParameterValue ) from .utils import make_arn_for_topic, make_arn_for_subscription @@ -193,6 +195,9 @@ class SNSBackend(BaseBackend): self.sms_attributes.update(attrs) def create_topic(self, name): + fails_constraints = not re.match(r'^[a-zA-Z0-9](?:[A-Za-z0-9_-]{0,253}[a-zA-Z0-9])?$', name) + if fails_constraints: + raise InvalidParameterValue("Topic names must be made up of only uppercase and lowercase ASCII letters, numbers, underscores, and hyphens, and must be between 1 and 256 characters long.") candidate_topic = Topic(name, self) if candidate_topic.arn in self.topics: return self.topics[candidate_topic.arn] diff --git a/tests/test_sns/test_server.py b/tests/test_sns/test_server.py index ce505278f..465dfa2c2 100644 --- a/tests/test_sns/test_server.py +++ b/tests/test_sns/test_server.py @@ -13,12 +13,12 @@ def test_sns_server_get(): backend = server.create_backend_app("sns") test_client = backend.test_client() - topic_data = test_client.action_data("CreateTopic", Name="test topic") + topic_data = test_client.action_data("CreateTopic", Name="testtopic") topic_data.should.contain("CreateTopicResult") topic_data.should.contain( - "arn:aws:sns:us-east-1:123456789012:test topic") + "arn:aws:sns:us-east-1:123456789012:testtopic") topics_data = test_client.action_data("ListTopics") topics_data.should.contain("ListTopicsResult") topic_data.should.contain( - "arn:aws:sns:us-east-1:123456789012:test topic") + "arn:aws:sns:us-east-1:123456789012:testtopic") diff --git a/tests/test_sns/test_topics_boto3.py b/tests/test_sns/test_topics_boto3.py index 495e63e72..95dd41f89 100644 --- a/tests/test_sns/test_topics_boto3.py +++ b/tests/test_sns/test_topics_boto3.py @@ -50,17 +50,35 @@ def test_create_topic_should_be_indempodent(): topic_display_name = conn.get_topic_attributes( TopicArn=topic_arn )['Attributes']['DisplayName'] - topic_display_name.should.be.equal("should_be_set") - - @mock_sns def test_get_missing_topic(): conn = boto3.client("sns", region_name="us-east-1") conn.get_topic_attributes.when.called_with( TopicArn="a-fake-arn").should.throw(ClientError) +@mock_sns +def test_create_topic_must_meet_constraints(): + conn = boto3.client("sns", region_name="us-east-1") + common_random_chars = [':', ";", "!", "@", "|", "^", "%"] + for char in common_random_chars: + conn.create_topic.when.called_with( + Name="no%s_invalidchar" % char).should.throw(ClientError) + conn.create_topic.when.called_with( + Name="no spaces allowed").should.throw(ClientError) + + +@mock_sns +def test_create_topic_should_be_of_certain_length(): + conn = boto3.client("sns", region_name="us-east-1") + too_short = "" + conn.create_topic.when.called_with( + Name=too_short).should.throw(ClientError) + too_long = "x" * 257 + conn.create_topic.when.called_with( + Name=too_long).should.throw(ClientError) + @mock_sns def test_create_topic_in_multiple_regions():