From 3ddfc0db40a64621ae91de15c1f5f3841f57846b Mon Sep 17 00:00:00 2001 From: Daniel Fangl Date: Wed, 5 Jul 2023 17:00:19 +0200 Subject: [PATCH] IAM: fix keyerror result when attaching non-existent policy, add tests, fix error message for user as well (#6482) --- moto/iam/models.py | 12 ++++++++-- tests/test_iam/test_iam.py | 49 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/moto/iam/models.py b/moto/iam/models.py index a41c76214..a837fa797 100644 --- a/moto/iam/models.py +++ b/moto/iam/models.py @@ -1823,7 +1823,13 @@ class IAMBackend(BaseBackend): def attach_role_policy(self, policy_arn: str, role_name: str) -> None: arns = dict((p.arn, p) for p in self.managed_policies.values()) - policy = arns[policy_arn] + try: + policy = arns[policy_arn] + except KeyError: + raise IAMNotFoundException( + f"Policy {policy_arn} does not exist or is not attachable." + ) + policy.attach_to(self.get_role(role_name)) def update_role_description(self, role_name: str, role_description: str) -> Role: @@ -1891,7 +1897,9 @@ class IAMBackend(BaseBackend): try: policy = arns[policy_arn] except KeyError: - raise IAMNotFoundException(f"Policy {policy_arn} was not found.") + raise IAMNotFoundException( + f"Policy {policy_arn} does not exist or is not attachable." + ) policy.attach_to(self.get_user(user_name)) def detach_user_policy(self, policy_arn: str, user_name: str) -> None: diff --git a/tests/test_iam/test_iam.py b/tests/test_iam/test_iam.py index a73c40064..3d98cf53b 100644 --- a/tests/test_iam/test_iam.py +++ b/tests/test_iam/test_iam.py @@ -2063,6 +2063,16 @@ def test_attach_detach_user_policy(): Description="my user attached policy", ) + # try a non-existent policy + non_existent_policy_arn = f"arn:aws:iam::{ACCOUNT_ID}:policy/not-existent" + with pytest.raises(ClientError) as exc: + client.attach_user_policy(UserName=user.name, PolicyArn=non_existent_policy_arn) + err = exc.value.response["Error"] + err["Code"].should.equal("NoSuchEntity") + err["Message"].should.equal( + f"Policy {non_existent_policy_arn} does not exist or is not attachable." + ) + client.attach_user_policy(UserName=user.name, PolicyArn=policy.arn) resp = client.list_attached_user_policies(UserName=user.name) @@ -2077,6 +2087,45 @@ def test_attach_detach_user_policy(): resp["AttachedPolicies"].should.have.length_of(0) +@mock_iam() +def test_attach_detach_role_policy(): + iam = boto3.resource("iam", region_name="us-east-1") + client = boto3.client("iam", region_name="us-east-1") + + role = iam.create_role(RoleName="test-role", AssumeRolePolicyDocument="{}") + + policy_name = "RoleAttachedPolicy" + policy = iam.create_policy( + PolicyName=policy_name, + PolicyDocument=MOCK_POLICY, + Path="/mypolicy/", + Description="my role attached policy", + ) + + # try a non-existent policy + non_existent_policy_arn = f"arn:aws:iam::{ACCOUNT_ID}:policy/not-existent" + with pytest.raises(ClientError) as exc: + client.attach_role_policy(RoleName=role.name, PolicyArn=non_existent_policy_arn) + err = exc.value.response["Error"] + err["Code"].should.equal("NoSuchEntity") + err["Message"].should.equal( + f"Policy {non_existent_policy_arn} does not exist or is not attachable." + ) + + client.attach_role_policy(RoleName=role.name, PolicyArn=policy.arn) + + resp = client.list_attached_role_policies(RoleName=role.name) + resp["AttachedPolicies"].should.have.length_of(1) + attached_policy = resp["AttachedPolicies"][0] + attached_policy["PolicyArn"].should.equal(policy.arn) + attached_policy["PolicyName"].should.equal(policy_name) + + client.detach_role_policy(RoleName=role.name, PolicyArn=policy.arn) + + resp = client.list_attached_role_policies(RoleName=role.name) + resp["AttachedPolicies"].should.have.length_of(0) + + @mock_iam() def test_only_detach_user_policy(): iam = boto3.resource("iam", region_name="us-east-1")