--- /dev/null
+import json
+import pytest
+from botocore.exceptions import ClientError
+from . import (
+ configfile,
+ get_iam_root_client,
+ get_iam_alt_root_client,
+ get_new_bucket_name,
+ get_prefix,
+ nuke_prefixed_buckets,
+)
+from .iam import iam_root, iam_alt_root
+from .utils import assert_raises, _get_status_and_error_code
+
+def get_new_topic_name():
+ return get_new_bucket_name()
+
+def nuke_topics(client, prefix):
+ p = client.get_paginator('list_topics')
+ for response in p.paginate():
+ for topic in response['Topics']:
+ arn = topic['TopicArn']
+ if prefix not in arn:
+ pass
+ try:
+ client.delete_topic(TopicArn=arn)
+ except:
+ pass
+
+@pytest.fixture
+def sns(iam_root):
+ client = get_iam_root_client(service_name='sns')
+ yield client
+ nuke_topics(client, get_prefix())
+
+@pytest.fixture
+def sns_alt(iam_alt_root):
+ client = get_iam_alt_root_client(service_name='sns')
+ yield client
+ nuke_topics(client, get_prefix())
+
+@pytest.fixture
+def s3(iam_root):
+ client = get_iam_root_client(service_name='s3')
+ yield client
+ nuke_prefixed_buckets(get_prefix(), client)
+
+@pytest.fixture
+def s3_alt(iam_alt_root):
+ client = get_iam_alt_root_client(service_name='s3')
+ yield client
+ nuke_prefixed_buckets(get_prefix(), client)
+
+
+@pytest.mark.iam_account
+@pytest.mark.sns
+def test_account_topic(sns):
+ name = get_new_topic_name()
+
+ response = sns.create_topic(Name=name)
+ arn = response['TopicArn']
+ assert arn.startswith('arn:aws:sns:')
+ assert arn.endswith(f':{name}')
+
+ response = sns.list_topics()
+ assert arn in [p['TopicArn'] for p in response['Topics']]
+
+ sns.set_topic_attributes(TopicArn=arn, AttributeName='Policy', AttributeValue='')
+
+ response = sns.get_topic_attributes(TopicArn=arn)
+ assert 'Attributes' in response
+
+ sns.delete_topic(TopicArn=arn)
+
+ response = sns.list_topics()
+ assert arn not in [p['TopicArn'] for p in response['Topics']]
+
+ with pytest.raises(sns.exceptions.NotFoundException):
+ sns.get_topic_attributes(TopicArn=arn)
+ sns.delete_topic(TopicArn=arn)
+
+@pytest.mark.iam_account
+@pytest.mark.sns
+def test_cross_account_topic(sns, sns_alt):
+ name = get_new_topic_name()
+ arn = sns.create_topic(Name=name)['TopicArn']
+
+ # not visible to any alt user apis
+ with pytest.raises(sns.exceptions.NotFoundException):
+ sns_alt.get_topic_attributes(TopicArn=arn)
+ with pytest.raises(sns.exceptions.NotFoundException):
+ sns_alt.set_topic_attributes(TopicArn=arn, AttributeName='Policy', AttributeValue='')
+
+ # delete returns success
+ sns_alt.delete_topic(TopicArn=arn)
+
+ response = sns_alt.list_topics()
+ assert arn not in [p['TopicArn'] for p in response['Topics']]
+
+@pytest.mark.iam_account
+@pytest.mark.sns
+def test_account_topic_publish(sns, s3):
+ name = get_new_topic_name()
+
+ response = sns.create_topic(Name=name)
+ topic_arn = response['TopicArn']
+
+ bucket = get_new_bucket_name()
+ s3.create_bucket(Bucket=bucket)
+
+ config = {'TopicConfigurations': [{
+ 'Id': 'id',
+ 'TopicArn': topic_arn,
+ 'Events': [ 's3:ObjectCreated:*' ],
+ }]}
+ s3.put_bucket_notification_configuration(
+ Bucket=bucket, NotificationConfiguration=config)
+
+@pytest.mark.iam_account
+@pytest.mark.iam_cross_account
+@pytest.mark.sns
+def test_cross_account_topic_publish(sns, s3_alt, iam_alt_root):
+ name = get_new_topic_name()
+
+ response = sns.create_topic(Name=name)
+ topic_arn = response['TopicArn']
+
+ bucket = get_new_bucket_name()
+ s3_alt.create_bucket(Bucket=bucket)
+
+ config = {'TopicConfigurations': [{
+ 'Id': 'id',
+ 'TopicArn': topic_arn,
+ 'Events': [ 's3:ObjectCreated:*' ],
+ }]}
+
+ # expect AccessDenies because no resource policy allows cross-account access
+ e = assert_raises(ClientError, s3_alt.put_bucket_notification_configuration,
+ Bucket=bucket, NotificationConfiguration=config)
+ status, error_code = _get_status_and_error_code(e.response)
+ assert status == 403
+ assert error_code == 'AccessDenied'
+
+ # add topic policy to allow the alt user
+ alt_principal = iam_alt_root.get_user()['User']['Arn']
+ policy = json.dumps({
+ 'Version': '2012-10-17',
+ 'Statement': [{
+ 'Effect': 'Allow',
+ 'Principal': {'AWS': alt_principal},
+ 'Action': 'sns:Publish',
+ 'Resource': topic_arn
+ }]
+ })
+ sns.set_topic_attributes(TopicArn=topic_arn, AttributeName='Policy',
+ AttributeValue=policy)
+
+ s3_alt.put_bucket_notification_configuration(
+ Bucket=bucket, NotificationConfiguration=config)