From f1dbdc9184498819d3fe8f47e34f19d8e03f64d0 Mon Sep 17 00:00:00 2001 From: gruebel Date: Sun, 3 Nov 2019 19:55:58 +0100 Subject: [PATCH] Refactor events.describe_event_bus, put_permission & remove_permission --- moto/events/models.py | 94 +++++++++++++++++++++--------- moto/events/responses.py | 21 ++++++- tests/test_events/test_events.py | 98 ++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+), 31 deletions(-) diff --git a/moto/events/models.py b/moto/events/models.py index b1d9bf25..005acc0c 100644 --- a/moto/events/models.py +++ b/moto/events/models.py @@ -60,12 +60,36 @@ class EventBus(BaseModel): self.region = region_name self.name = name + self._permissions = {} + @property def arn(self): return "arn:aws:events:{region}:{account_id}:event-bus/{name}".format( region=self.region, account_id=ACCOUNT_ID, name=self.name ) + @property + def policy(self): + if not len(self._permissions): + return None + + policy = {"Version": "2012-10-17", "Statement": []} + + for sid, permission in self._permissions.items(): + policy["Statement"].append( + { + "Sid": sid, + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam::{}:root".format(permission["Principal"]) + }, + "Action": permission["Action"], + "Resource": self.arn, + } + ) + + return json.dumps(policy) + class EventsBackend(BaseBackend): ACCOUNT_ID = re.compile(r"^(\d{1,12}|\*)$") @@ -78,7 +102,6 @@ class EventsBackend(BaseBackend): self.rules_order = [] self.next_tokens = {} self.region_name = region_name - self.permissions = {} self.event_buses = {} self.event_sources = {} @@ -241,9 +264,17 @@ class EventsBackend(BaseBackend): def test_event_pattern(self): raise NotImplementedError() - def put_permission(self, action, principal, statement_id): + def put_permission(self, event_bus_name, action, principal, statement_id): + if not event_bus_name: + event_bus_name = "default" + + event_bus = self.describe_event_bus(event_bus_name) + if action is None or action != "events:PutEvents": - raise JsonRESTError("InvalidParameterValue", "Action must be PutEvents") + raise JsonRESTError( + "ValidationException", + "Provided value in parameter 'action' is not supported.", + ) if principal is None or self.ACCOUNT_ID.match(principal) is None: raise JsonRESTError( @@ -255,34 +286,41 @@ class EventsBackend(BaseBackend): "InvalidParameterValue", "StatementId must match ^[a-zA-Z0-9-_]{1,64}$" ) - self.permissions[statement_id] = {"action": action, "principal": principal} + event_bus._permissions[statement_id] = { + "Action": action, + "Principal": principal, + } - def remove_permission(self, statement_id): - try: - del self.permissions[statement_id] - except KeyError: - raise JsonRESTError("ResourceNotFoundException", "StatementId not found") + def remove_permission(self, event_bus_name, statement_id): + if not event_bus_name: + event_bus_name = "default" - def describe_event_bus(self): - arn = "arn:aws:events:{0}:000000000000:event-bus/default".format( - self.region_name - ) - statements = [] - for statement_id, data in self.permissions.items(): - statements.append( - { - "Sid": statement_id, - "Effect": "Allow", - "Principal": { - "AWS": "arn:aws:iam::{0}:root".format(data["principal"]) - }, - "Action": data["action"], - "Resource": arn, - } + event_bus = self.describe_event_bus(event_bus_name) + + if not len(event_bus._permissions): + raise JsonRESTError( + "ResourceNotFoundException", "EventBus does not have a policy." ) - policy = {"Version": "2012-10-17", "Statement": statements} - policy_json = json.dumps(policy) - return {"Policy": policy_json, "Name": "default", "Arn": arn} + + if not event_bus._permissions.pop(statement_id, None): + raise JsonRESTError( + "ResourceNotFoundException", + "Statement with the provided id does not exist.", + ) + + def describe_event_bus(self, name): + if not name: + name = "default" + + event_bus = self.event_buses.get(name) + + if not event_bus: + raise JsonRESTError( + "ResourceNotFoundException", + "Event bus {} does not exist.".format(name), + ) + + return event_bus def create_event_bus(self, name, event_source_name): if name in self.event_buses: diff --git a/moto/events/responses.py b/moto/events/responses.py index f4a6dcce..896278ae 100644 --- a/moto/events/responses.py +++ b/moto/events/responses.py @@ -238,23 +238,38 @@ class EventsHandler(BaseResponse): pass def put_permission(self): + event_bus_name = self._get_param("EventBusName") action = self._get_param("Action") principal = self._get_param("Principal") statement_id = self._get_param("StatementId") - self.events_backend.put_permission(action, principal, statement_id) + self.events_backend.put_permission( + event_bus_name, action, principal, statement_id + ) return "" def remove_permission(self): + event_bus_name = self._get_param("EventBusName") statement_id = self._get_param("StatementId") - self.events_backend.remove_permission(statement_id) + self.events_backend.remove_permission(event_bus_name, statement_id) return "" def describe_event_bus(self): - return json.dumps(self.events_backend.describe_event_bus()) + name = self._get_param("Name") + + event_bus = self.events_backend.describe_event_bus(name) + response = { + "Name": event_bus.name, + "Arn": event_bus.arn, + } + + if event_bus.policy: + response["Policy"] = event_bus.policy + + return json.dumps(response), self.response_headers def create_event_bus(self): name = self._get_param("Name") diff --git a/tests/test_events/test_events.py b/tests/test_events/test_events.py index ebd224da..43ab8f31 100644 --- a/tests/test_events/test_events.py +++ b/tests/test_events/test_events.py @@ -205,6 +205,53 @@ def test_permissions(): assert resp_policy["Statement"][0]["Sid"] == "Account1" +@mock_events +def test_put_permission_errors(): + client = boto3.client("events", "us-east-1") + client.create_event_bus(Name="test-bus") + + client.put_permission.when.called_with( + EventBusName="non-existing", + Action="events:PutEvents", + Principal="762054135200", + StatementId="test", + ).should.throw(ClientError, "Event bus non-existing does not exist.") + + client.put_permission.when.called_with( + EventBusName="test-bus", + Action="events:PutPermission", + Principal="762054135200", + StatementId="test", + ).should.throw( + ClientError, "Provided value in parameter 'action' is not supported." + ) + + +@mock_events +def test_remove_permission_errors(): + client = boto3.client("events", "us-east-1") + client.create_event_bus(Name="test-bus") + + client.remove_permission.when.called_with( + EventBusName="non-existing", StatementId="test" + ).should.throw(ClientError, "Event bus non-existing does not exist.") + + client.remove_permission.when.called_with( + EventBusName="test-bus", StatementId="test" + ).should.throw(ClientError, "EventBus does not have a policy.") + + client.put_permission( + EventBusName="test-bus", + Action="events:PutEvents", + Principal="762054135200", + StatementId="test", + ) + + client.remove_permission.when.called_with( + EventBusName="test-bus", StatementId="non-existing" + ).should.throw(ClientError, "Statement with the provided id does not exist.") + + @mock_events def test_put_events(): client = boto3.client("events", "eu-central-1") @@ -257,3 +304,54 @@ def test_create_event_bus_errors(): ).should.throw( ClientError, "Event source aws.partner/test/test-bus does not exist." ) + + +@mock_events +def test_describe_event_bus(): + client = boto3.client("events", "us-east-1") + + response = client.describe_event_bus() + + response["Name"].should.equal("default") + response["Arn"].should.equal( + "arn:aws:events:us-east-1:123456789012:event-bus/default" + ) + response.should_not.have.key("Policy") + + client.create_event_bus(Name="test-bus") + client.put_permission( + EventBusName="test-bus", + Action="events:PutEvents", + Principal="762054135200", + StatementId="test", + ) + + response = client.describe_event_bus(Name="test-bus") + + response["Name"].should.equal("test-bus") + response["Arn"].should.equal( + "arn:aws:events:us-east-1:123456789012:event-bus/test-bus" + ) + json.loads(response["Policy"]).should.equal( + { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "test", + "Effect": "Allow", + "Principal": {"AWS": "arn:aws:iam::762054135200:root"}, + "Action": "events:PutEvents", + "Resource": "arn:aws:events:us-east-1:123456789012:event-bus/test-bus", + } + ], + } + ) + + +@mock_events +def test_describe_event_bus_errors(): + client = boto3.client("events", "us-east-1") + + client.describe_event_bus.when.called_with(Name="non-existing").should.throw( + ClientError, "Event bus non-existing does not exist." + )