From 7f6af025f3c633189c223ff22d9fa1368c4852df Mon Sep 17 00:00:00 2001 From: Kevin Glisson Date: Sun, 30 Nov 2014 11:16:29 -0800 Subject: [PATCH 1/3] Create role does not allow for document policies to be passed to it --- moto/iam/models.py | 8 ++++---- tests/test_iam/test_iam.py | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/moto/iam/models.py b/moto/iam/models.py index a9bd4eb71..d1c805117 100644 --- a/moto/iam/models.py +++ b/moto/iam/models.py @@ -8,12 +8,12 @@ from datetime import datetime class Role(object): - def __init__(self, role_id, name, assume_role_policy_document, path, policies): + def __init__(self, role_id, name, assume_role_policy_document, path): self.id = role_id self.name = name self.assume_role_policy_document = assume_role_policy_document self.path = path - self.policies = policies + self.policies = {} @classmethod def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name): @@ -185,9 +185,9 @@ class IAMBackend(BaseBackend): self.users = {} super(IAMBackend, self).__init__() - def create_role(self, role_name, assume_role_policy_document, path, policies): + def create_role(self, role_name, assume_role_policy_document, path): role_id = random_resource_id() - role = Role(role_id, role_name, assume_role_policy_document, path, policies) + role = Role(role_id, role_name, assume_role_policy_document, path) self.roles[role_id] = role return role diff --git a/tests/test_iam/test_iam.py b/tests/test_iam/test_iam.py index e9121a5aa..500e74ada 100644 --- a/tests/test_iam/test_iam.py +++ b/tests/test_iam/test_iam.py @@ -61,6 +61,12 @@ def test_create_role_and_instance_profile(): conn.list_roles().roles[0].role_name.should.equal('my-role') conn.list_instance_profiles().instance_profiles[0].instance_profile_name.should.equal("my-profile") +@mock_iam() +def test_create_role(): + conn = boto.connect_iam() + conn.create_role('test') + with assert_raises(BotoServerError): + conn.create_role('test') @mock_iam() def test_create_group(): From cc312d29fc65e6b2390a817d7c7af9f3c5884887 Mon Sep 17 00:00:00 2001 From: Kevin Glisson Date: Sun, 30 Nov 2014 20:11:13 -0800 Subject: [PATCH 2/3] Adding put_role_policy, get_role_policy, and list_role_policies, update_assume_role_policy --- moto/iam/models.py | 26 +++++++++++++++++ moto/iam/responses.py | 58 +++++++++++++++++++++++++++++++++++++- tests/test_iam/test_iam.py | 29 ++++++++++++++++--- 3 files changed, 108 insertions(+), 5 deletions(-) diff --git a/moto/iam/models.py b/moto/iam/models.py index d1c805117..376469ce8 100644 --- a/moto/iam/models.py +++ b/moto/iam/models.py @@ -26,6 +26,9 @@ class Role(object): policies=properties.get('Policies', []), ) + def put_policy(self, policy_name, policy_json): + self.policies[policy_name] = policy_json + @property def physical_resource_id(self): return self.id @@ -202,6 +205,29 @@ class IAMBackend(BaseBackend): def get_roles(self): return self.roles.values() + def put_role_policy(self, role_name, policy_name, policy_json): + role = self.get_role(role_name) + if role: + role.put_policy(policy_name, policy_json) + else: + raise BotoServerError(404, 'Not Found') + + def get_role_policy(self, role_name, policy_name): + role = self.get_role(role_name) + if role: + for p, d in role.policies.iteritems(): + if p == policy_name: + return p, d + else: + raise BotoServerError(404, 'Not Found') + + def list_role_policies(self, role_name): + role = self.get_role(role_name) + if role: + return role.policies.keys() + else: + raise BotoServerError(404, 'Not Found') + def create_instance_profile(self, name, path, role_ids): instance_profile_id = random_resource_id() diff --git a/moto/iam/responses.py b/moto/iam/responses.py index 422977bfe..e0381d405 100644 --- a/moto/iam/responses.py +++ b/moto/iam/responses.py @@ -1,4 +1,5 @@ from __future__ import unicode_literals +from __future__ import unicode_literals from jinja2 import Template from moto.core.responses import BaseResponse @@ -15,7 +16,7 @@ class IamResponse(BaseResponse): path = self._get_param('Path') assume_role_policy_document = self._get_param('AssumeRolePolicyDocument') - role = iam_backend.create_role(role_name, assume_role_policy_document, path, policies=[]) + role = iam_backend.create_role(role_name, assume_role_policy_document, path) template = Template(CREATE_ROLE_TEMPLATE) return template.render(role=role) @@ -26,6 +27,36 @@ class IamResponse(BaseResponse): template = Template(GET_ROLE_TEMPLATE) return template.render(role=role) + def list_role_policies(self): + role_name = self._get_param('RoleName') + role_policies_names = iam_backend.list_role_policies(role_name) + template = Template(LIST_ROLE_POLICIES) + return template.render(role_policies=role_policies_names) + + def put_role_policy(self): + role_name = self._get_param('RoleName') + policy_name = self._get_param('PolicyName') + policy_document = self._get_param('PolicyDocument') + iam_backend.put_role_policy(role_name, policy_name, policy_document) + template = Template(GENERIC_EMPTY_TEMPLATE) + return template.render(name="PutRolePolicyResponse") + + def get_role_policy(self): + role_name = self._get_param('RoleName') + policy_name = self._get_param('PolicyName') + policy_name, policy_document = iam_backend.get_role_policy(role_name, policy_name) + template = Template(GET_ROLE_POLICY_TEMPLATE) + return template.render(role_name=role_name, + policy_name=policy_name, + policy_document=policy_document) + + def update_assume_role_policy(self): + role_name = self._get_param('RoleName') + role = iam_backend.get_role(role_name) + role.assume_role_policy_document = self._get_param('PolicyDocument') + template = Template(GENERIC_EMPTY_TEMPLATE) + return template.render(name="UpdateAssumeRolePolicyResponse") + def create_instance_profile(self): profile_name = self._get_param('InstanceProfileName') path = self._get_param('Path') @@ -259,6 +290,17 @@ CREATE_ROLE_TEMPLATE = """ + + {{ policy_name }} + {{ role_name }} + {{ policy_document }} + + + 7e7cd8bc-99ef-11e1-a4c3-27EXAMPLE804 + +""" + GET_ROLE_TEMPLATE = """ @@ -302,6 +344,20 @@ LIST_ROLES_TEMPLATE = """ + + + {% for policy_name in role_policies %} + {{ policy_name }} + {% endfor %} + + false + + + 8c7e1816-99f0-11e1-a4c3-27EXAMPLE804 + +""" + LIST_INSTANCE_PROFILES_TEMPLATE = """ false diff --git a/tests/test_iam/test_iam.py b/tests/test_iam/test_iam.py index 500e74ada..11863d83d 100644 --- a/tests/test_iam/test_iam.py +++ b/tests/test_iam/test_iam.py @@ -61,12 +61,33 @@ def test_create_role_and_instance_profile(): conn.list_roles().roles[0].role_name.should.equal('my-role') conn.list_instance_profiles().instance_profiles[0].instance_profile_name.should.equal("my-profile") + @mock_iam() -def test_create_role(): +def test_list_role_policies(): conn = boto.connect_iam() - conn.create_role('test') - with assert_raises(BotoServerError): - conn.create_role('test') + conn.create_role("my-role") + conn.put_role_policy("my-role", "test policy", "my policy") + role = conn.list_role_policies("my-role") + role.policy_names[0].should.equal("test policy") + + +@mock_iam() +def test_put_role_policy(): + conn = boto.connect_iam() + conn.create_role("my-role", assume_role_policy_document="some policy", path="my-path") + conn.put_role_policy("my-role", "test policy", "my policy") + policy = conn.get_role_policy("my-role", "test policy")['get_role_policy_response']['get_role_policy_result']['policy_name'] + policy.should.equal("test policy") + + +@mock_iam() +def test_update_assume_role_policy(): + conn = boto.connect_iam() + role = conn.create_role("my-role") + conn.update_assume_role_policy(role.role_name, "my-policy") + role = conn.get_role("my-role") + role.assume_role_policy_document.should.equal("my-policy") + @mock_iam() def test_create_group(): From 3e45758663b3acd612b7ee5dc9901cfea372ae46 Mon Sep 17 00:00:00 2001 From: Kevin Glisson Date: Sun, 30 Nov 2014 20:23:56 -0800 Subject: [PATCH 3/3] Removing duplicate import --- moto/iam/responses.py | 1 - 1 file changed, 1 deletion(-) diff --git a/moto/iam/responses.py b/moto/iam/responses.py index e0381d405..1f4036ddf 100644 --- a/moto/iam/responses.py +++ b/moto/iam/responses.py @@ -1,5 +1,4 @@ from __future__ import unicode_literals -from __future__ import unicode_literals from jinja2 import Template from moto.core.responses import BaseResponse