Added policy tagging that was previously marked as missing (#4520)
This commit is contained in:
parent
ccd216dfe5
commit
ff6d7a13c0
@ -2364,7 +2364,7 @@
|
||||
- [X] list_open_id_connect_providers
|
||||
- [X] list_policies
|
||||
- [ ] list_policies_granting_service_access
|
||||
- [ ] list_policy_tags
|
||||
- [X] list_policy_tags
|
||||
- [X] list_policy_versions
|
||||
- [X] list_role_policies
|
||||
- [X] list_role_tags
|
||||
@ -2397,7 +2397,7 @@
|
||||
- [ ] tag_instance_profile
|
||||
- [ ] tag_mfa_device
|
||||
- [ ] tag_open_id_connect_provider
|
||||
- [ ] tag_policy
|
||||
- [X] tag_policy
|
||||
- [X] tag_role
|
||||
- [ ] tag_saml_provider
|
||||
- [ ] tag_server_certificate
|
||||
@ -2405,7 +2405,7 @@
|
||||
- [ ] untag_instance_profile
|
||||
- [ ] untag_mfa_device
|
||||
- [ ] untag_open_id_connect_provider
|
||||
- [ ] untag_policy
|
||||
- [X] untag_policy
|
||||
- [X] untag_role
|
||||
- [ ] untag_saml_provider
|
||||
- [ ] untag_server_certificate
|
||||
|
@ -108,7 +108,7 @@ class Policy(CloudFormationModel):
|
||||
self.description = description or ""
|
||||
self.id = random_policy_id()
|
||||
self.path = path or "/"
|
||||
self.tags = {tag["Key"]: tag["Value"] for tag in tags or []}
|
||||
self.tags = tags
|
||||
|
||||
if default_version_id:
|
||||
self.default_version_id = default_version_id
|
||||
@ -141,6 +141,9 @@ class Policy(CloudFormationModel):
|
||||
def updated_iso_8601(self):
|
||||
return iso_8601_datetime_with_milliseconds(self.update_date)
|
||||
|
||||
def get_tags(self):
|
||||
return [self.tags[tag] for tag in self.tags]
|
||||
|
||||
|
||||
class SAMLProvider(BaseModel):
|
||||
def __init__(self, name, saml_metadata_document=None):
|
||||
@ -284,6 +287,7 @@ class ManagedPolicy(Policy, CloudFormationModel):
|
||||
"awsRegion": "global",
|
||||
"availabilityZone": "Not Applicable",
|
||||
"resourceCreationTime": str(self.create_date),
|
||||
"tags": self.tags,
|
||||
"configuration": {
|
||||
"policyName": self.name,
|
||||
"policyId": self.id,
|
||||
@ -296,6 +300,12 @@ class ManagedPolicy(Policy, CloudFormationModel):
|
||||
"description": self.description,
|
||||
"createDate": str(self.create_date.isoformat()),
|
||||
"updateDate": str(self.create_date.isoformat()),
|
||||
"tags": list(
|
||||
map(
|
||||
lambda key: {"key": key, "value": self.tags[key]["Value"]},
|
||||
self.tags,
|
||||
)
|
||||
),
|
||||
"policyVersionList": list(
|
||||
map(
|
||||
lambda version: {
|
||||
@ -331,12 +341,14 @@ class ManagedPolicy(Policy, CloudFormationModel):
|
||||
group_names = properties.get("Groups", [])
|
||||
user_names = properties.get("Users", [])
|
||||
role_names = properties.get("Roles", [])
|
||||
tags = properties.get("Tags", {})
|
||||
|
||||
policy = iam_backend.create_policy(
|
||||
description=description,
|
||||
path=path,
|
||||
policy_document=policy_document,
|
||||
policy_name=name,
|
||||
tags=tags,
|
||||
)
|
||||
for group_name in group_names:
|
||||
iam_backend.attach_group_policy(
|
||||
@ -1568,16 +1580,17 @@ class IAMBackend(BaseBackend):
|
||||
raise IAMNotFoundException("Policy {0} was not found.".format(policy_arn))
|
||||
policy.detach_from(self.get_user(user_name))
|
||||
|
||||
def create_policy(self, description, path, policy_document, policy_name, tags=None):
|
||||
def create_policy(self, description, path, policy_document, policy_name, tags):
|
||||
iam_policy_document_validator = IAMPolicyDocumentValidator(policy_document)
|
||||
iam_policy_document_validator.validate()
|
||||
|
||||
clean_tags = self._tag_verification(tags)
|
||||
policy = ManagedPolicy(
|
||||
policy_name,
|
||||
description=description,
|
||||
document=policy_document,
|
||||
path=path,
|
||||
tags=tags,
|
||||
tags=clean_tags,
|
||||
)
|
||||
if policy.arn in self.managed_policies:
|
||||
raise EntityAlreadyExists(
|
||||
@ -1849,6 +1862,42 @@ class IAMBackend(BaseBackend):
|
||||
|
||||
role.tags.pop(ref_key, None)
|
||||
|
||||
def list_policy_tags(self, policy_arn, marker, max_items=100):
|
||||
policy = self.get_policy(policy_arn)
|
||||
|
||||
max_items = int(max_items)
|
||||
tag_index = sorted(policy.tags)
|
||||
start_idx = int(marker) if marker else 0
|
||||
|
||||
tag_index = tag_index[start_idx : start_idx + max_items]
|
||||
|
||||
if len(policy.tags) <= (start_idx + max_items):
|
||||
marker = None
|
||||
else:
|
||||
marker = str(start_idx + max_items)
|
||||
|
||||
# Make the tag list of dict's:
|
||||
tags = [policy.tags[tag] for tag in tag_index]
|
||||
|
||||
return tags, marker
|
||||
|
||||
def tag_policy(self, policy_arn, tags):
|
||||
clean_tags = self._tag_verification(tags)
|
||||
policy = self.get_policy(policy_arn)
|
||||
policy.tags.update(clean_tags)
|
||||
|
||||
def untag_policy(self, policy_arn, tag_keys):
|
||||
if len(tag_keys) > 50:
|
||||
raise TooManyTags(tag_keys, param="tagKeys")
|
||||
|
||||
policy = self.get_policy(policy_arn)
|
||||
|
||||
for key in tag_keys:
|
||||
ref_key = key.lower()
|
||||
self._validate_tag_key(key, exception_param="tagKeys")
|
||||
|
||||
policy.tags.pop(ref_key, None)
|
||||
|
||||
def create_policy_version(self, policy_arn, policy_document, set_as_default):
|
||||
iam_policy_document_validator = IAMPolicyDocumentValidator(policy_document)
|
||||
iam_policy_document_validator.validate()
|
||||
|
@ -308,6 +308,34 @@ class IamResponse(BaseResponse):
|
||||
template = self.response_template(LIST_POLICY_VERSIONS_TEMPLATE)
|
||||
return template.render(policy_versions=policy_versions)
|
||||
|
||||
def list_policy_tags(self):
|
||||
policy_arn = self._get_param("PolicyArn")
|
||||
marker = self._get_param("Marker")
|
||||
max_items = self._get_param("MaxItems", 100)
|
||||
|
||||
tags, marker = iam_backend.list_policy_tags(policy_arn, marker, max_items)
|
||||
|
||||
template = self.response_template(LIST_POLICY_TAG_TEMPLATE)
|
||||
return template.render(tags=tags, marker=marker)
|
||||
|
||||
def tag_policy(self):
|
||||
policy_arn = self._get_param("PolicyArn")
|
||||
tags = self._get_multi_param("Tags.member")
|
||||
|
||||
iam_backend.tag_policy(policy_arn, tags)
|
||||
|
||||
template = self.response_template(TAG_POLICY_TEMPLATE)
|
||||
return template.render()
|
||||
|
||||
def untag_policy(self):
|
||||
policy_arn = self._get_param("PolicyArn")
|
||||
tag_keys = self._get_multi_param("TagKeys.member")
|
||||
|
||||
iam_backend.untag_policy(policy_arn, tag_keys)
|
||||
|
||||
template = self.response_template(UNTAG_POLICY_TEMPLATE)
|
||||
return template.render()
|
||||
|
||||
def delete_policy_version(self):
|
||||
policy_arn = self._get_param("PolicyArn")
|
||||
version_id = self._get_param("VersionId")
|
||||
@ -1129,14 +1157,16 @@ GET_POLICY_TEMPLATE = """<GetPolicyResponse>
|
||||
<AttachmentCount>{{ policy.attachment_count }}</AttachmentCount>
|
||||
<CreateDate>{{ policy.created_iso_8601 }}</CreateDate>
|
||||
<UpdateDate>{{ policy.updated_iso_8601 }}</UpdateDate>
|
||||
{% if policy.tags %}
|
||||
<Tags>
|
||||
{% for tag_key, tag_value in policy.tags.items() %}
|
||||
{% for tag in policy.get_tags() %}
|
||||
<member>
|
||||
<Key>{{ tag_key }}</Key>
|
||||
<Value>{{ tag_value }}</Value>
|
||||
<Key>{{ tag['Key'] }}</Key>
|
||||
<Value>{{ tag['Value'] }}</Value>
|
||||
</member>
|
||||
{% endfor %}
|
||||
</Tags>
|
||||
{% endif %}
|
||||
</Policy>
|
||||
</GetPolicyResult>
|
||||
<ResponseMetadata>
|
||||
@ -2495,6 +2525,41 @@ UNTAG_ROLE_TEMPLATE = """<UntagRoleResponse xmlns="https://iam.amazonaws.com/doc
|
||||
</UntagRoleResponse>"""
|
||||
|
||||
|
||||
TAG_POLICY_TEMPLATE = """<TagPolicyResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>EXAMPLE8-90ab-cdef-fedc-ba987EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</TagPolicyResponse>"""
|
||||
|
||||
|
||||
LIST_POLICY_TAG_TEMPLATE = """<ListPolicyTagsResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
|
||||
<ListPolicyTagsResult>
|
||||
<IsTruncated>{{ 'true' if marker else 'false' }}</IsTruncated>
|
||||
{% if marker %}
|
||||
<Marker>{{ marker }}</Marker>
|
||||
{% endif %}
|
||||
<Tags>
|
||||
{% for tag in tags %}
|
||||
<member>
|
||||
<Key>{{ tag['Key'] }}</Key>
|
||||
<Value>{{ tag['Value'] }}</Value>
|
||||
</member>
|
||||
{% endfor %}
|
||||
</Tags>
|
||||
</ListPolicyTagsResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>EXAMPLE8-90ab-cdef-fedc-ba987EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</ListPolicyTagsResponse>"""
|
||||
|
||||
|
||||
UNTAG_POLICY_TEMPLATE = """<UntagPolicyResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
|
||||
<ResponseMetadata>
|
||||
<RequestId>EXAMPLE8-90ab-cdef-fedc-ba987EXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</UntagPolicyResponse>"""
|
||||
|
||||
|
||||
CREATE_OPEN_ID_CONNECT_PROVIDER_TEMPLATE = """<CreateOpenIDConnectProviderResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
|
||||
<CreateOpenIDConnectProviderResult>
|
||||
<OpenIDConnectProviderArn>{{ open_id_provider.arn }}</OpenIDConnectProviderArn>
|
||||
|
@ -960,6 +960,543 @@ def test_delete_default_policy_version():
|
||||
)
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_create_policy_with_tags():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_policy(
|
||||
PolicyName="TestCreatePolicyWithTags1",
|
||||
PolicyDocument=MOCK_POLICY,
|
||||
Tags=[
|
||||
{"Key": "somekey", "Value": "somevalue"},
|
||||
{"Key": "someotherkey", "Value": "someothervalue"},
|
||||
],
|
||||
Description="testing",
|
||||
)
|
||||
|
||||
# Get policy:
|
||||
policy = conn.get_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(
|
||||
ACCOUNT_ID, "TestCreatePolicyWithTags1"
|
||||
)
|
||||
)["Policy"]
|
||||
assert len(policy["Tags"]) == 2
|
||||
assert policy["Tags"][0]["Key"] == "somekey"
|
||||
assert policy["Tags"][0]["Value"] == "somevalue"
|
||||
assert policy["Tags"][1]["Key"] == "someotherkey"
|
||||
assert policy["Tags"][1]["Value"] == "someothervalue"
|
||||
assert policy["Description"] == "testing"
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_create_policy_with_empty_tag_value():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
|
||||
# Empty is good:
|
||||
conn.create_policy(
|
||||
PolicyName="TestCreatePolicyWithTags2",
|
||||
PolicyDocument=MOCK_POLICY,
|
||||
Tags=[{"Key": "somekey", "Value": ""}],
|
||||
)
|
||||
tags = conn.list_policy_tags(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(
|
||||
ACCOUNT_ID, "TestCreatePolicyWithTags2"
|
||||
)
|
||||
)
|
||||
assert len(tags["Tags"]) == 1
|
||||
assert tags["Tags"][0]["Key"] == "somekey"
|
||||
assert tags["Tags"][0]["Value"] == ""
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_create_policy_with_too_many_tags():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
|
||||
# With more than 50 tags:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
too_many_tags = list(
|
||||
map(lambda x: {"Key": str(x), "Value": str(x)}, range(0, 51))
|
||||
)
|
||||
conn.create_policy(
|
||||
PolicyName="TestCreatePolicyWithTags3",
|
||||
PolicyDocument=MOCK_POLICY,
|
||||
Tags=too_many_tags,
|
||||
)
|
||||
assert (
|
||||
"failed to satisfy constraint: Member must have length less than or equal to 50."
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_create_policy_with_duplicate_tag():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
|
||||
# With a duplicate tag:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
conn.create_policy(
|
||||
PolicyName="TestCreatePolicyWithTags3",
|
||||
PolicyDocument=MOCK_POLICY,
|
||||
Tags=[{"Key": "0", "Value": ""}, {"Key": "0", "Value": ""}],
|
||||
)
|
||||
assert (
|
||||
"Duplicate tag keys found. Please note that Tag keys are case insensitive."
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_create_policy_with_duplicate_tag_different_casing():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
|
||||
# Duplicate tag with different casing:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
conn.create_policy(
|
||||
PolicyName="TestCreatePolicyWithTags3",
|
||||
PolicyDocument=MOCK_POLICY,
|
||||
Tags=[{"Key": "a", "Value": ""}, {"Key": "A", "Value": ""}],
|
||||
)
|
||||
assert (
|
||||
"Duplicate tag keys found. Please note that Tag keys are case insensitive."
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_create_policy_with_tag_containing_large_key():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
|
||||
# With a really big key:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
conn.create_policy(
|
||||
PolicyName="TestCreatePolicyWithTags3",
|
||||
PolicyDocument=MOCK_POLICY,
|
||||
Tags=[{"Key": "0" * 129, "Value": ""}],
|
||||
)
|
||||
assert (
|
||||
"Member must have length less than or equal to 128."
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_create_policy_with_tag_containing_large_value():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
|
||||
# With a really big value:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
conn.create_policy(
|
||||
PolicyName="TestCreatePolicyWithTags3",
|
||||
PolicyDocument=MOCK_POLICY,
|
||||
Tags=[{"Key": "0", "Value": "0" * 257}],
|
||||
)
|
||||
assert (
|
||||
"Member must have length less than or equal to 256."
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_create_policy_with_tag_containing_invalid_character():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
|
||||
# With an invalid character:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
conn.create_policy(
|
||||
PolicyName="TestCreatePolicyWithTags3",
|
||||
PolicyDocument=MOCK_POLICY,
|
||||
Tags=[{"Key": "NOWAY!", "Value": ""}],
|
||||
)
|
||||
assert (
|
||||
"Member must satisfy regular expression pattern: [\\p{L}\\p{Z}\\p{N}_.:/=+\\-@]+"
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_create_policy_with_no_tags():
|
||||
"""Tests both the tag_policy and get_policy_tags capability"""
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_policy(PolicyName="TestTagPolicy", PolicyDocument=MOCK_POLICY)
|
||||
|
||||
# Get without tags:
|
||||
policy = conn.get_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy")
|
||||
)["Policy"]
|
||||
assert not policy.get("Tags")
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_get_policy_with_tags():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_policy(PolicyName="TestTagPolicy", PolicyDocument=MOCK_POLICY)
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[
|
||||
{"Key": "somekey", "Value": "somevalue"},
|
||||
{"Key": "someotherkey", "Value": "someothervalue"},
|
||||
],
|
||||
)
|
||||
|
||||
# Get policy:
|
||||
policy = conn.get_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy")
|
||||
)["Policy"]
|
||||
assert len(policy["Tags"]) == 2
|
||||
assert policy["Tags"][0]["Key"] == "somekey"
|
||||
assert policy["Tags"][0]["Value"] == "somevalue"
|
||||
assert policy["Tags"][1]["Key"] == "someotherkey"
|
||||
assert policy["Tags"][1]["Value"] == "someothervalue"
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_list_policy_tags():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_policy(PolicyName="TestTagPolicy", PolicyDocument=MOCK_POLICY)
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[
|
||||
{"Key": "somekey", "Value": "somevalue"},
|
||||
{"Key": "someotherkey", "Value": "someothervalue"},
|
||||
],
|
||||
)
|
||||
|
||||
# List_policy_tags:
|
||||
tags = conn.list_policy_tags(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy")
|
||||
)
|
||||
assert len(tags["Tags"]) == 2
|
||||
assert tags["Tags"][0]["Key"] == "somekey"
|
||||
assert tags["Tags"][0]["Value"] == "somevalue"
|
||||
assert tags["Tags"][1]["Key"] == "someotherkey"
|
||||
assert tags["Tags"][1]["Value"] == "someothervalue"
|
||||
assert not tags["IsTruncated"]
|
||||
assert not tags.get("Marker")
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_list_policy_tags_pagination():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_policy(PolicyName="TestTagPolicy", PolicyDocument=MOCK_POLICY)
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[
|
||||
{"Key": "somekey", "Value": "somevalue"},
|
||||
{"Key": "someotherkey", "Value": "someothervalue"},
|
||||
],
|
||||
)
|
||||
|
||||
# Test pagination:
|
||||
tags = conn.list_policy_tags(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
MaxItems=1,
|
||||
)
|
||||
assert len(tags["Tags"]) == 1
|
||||
assert tags["IsTruncated"]
|
||||
assert tags["Tags"][0]["Key"] == "somekey"
|
||||
assert tags["Tags"][0]["Value"] == "somevalue"
|
||||
assert tags["Marker"] == "1"
|
||||
|
||||
tags = conn.list_policy_tags(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Marker=tags["Marker"],
|
||||
)
|
||||
assert len(tags["Tags"]) == 1
|
||||
assert tags["Tags"][0]["Key"] == "someotherkey"
|
||||
assert tags["Tags"][0]["Value"] == "someothervalue"
|
||||
assert not tags["IsTruncated"]
|
||||
assert not tags.get("Marker")
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_updating_existing_tag():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_policy(PolicyName="TestTagPolicy", PolicyDocument=MOCK_POLICY)
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[
|
||||
{"Key": "somekey", "Value": "somevalue"},
|
||||
{"Key": "someotherkey", "Value": "someothervalue"},
|
||||
],
|
||||
)
|
||||
|
||||
# Test updating an existing tag:
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[{"Key": "somekey", "Value": "somenewvalue"}],
|
||||
)
|
||||
tags = conn.list_policy_tags(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy")
|
||||
)
|
||||
assert len(tags["Tags"]) == 2
|
||||
assert tags["Tags"][0]["Key"] == "somekey"
|
||||
assert tags["Tags"][0]["Value"] == "somenewvalue"
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_updating_existing_tag_with_empty_value():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_policy(PolicyName="TestTagPolicy", PolicyDocument=MOCK_POLICY)
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[
|
||||
{"Key": "somekey", "Value": "somevalue"},
|
||||
{"Key": "someotherkey", "Value": "someothervalue"},
|
||||
],
|
||||
)
|
||||
|
||||
# Empty is good:
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[{"Key": "somekey", "Value": ""}],
|
||||
)
|
||||
tags = conn.list_policy_tags(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy")
|
||||
)
|
||||
assert len(tags["Tags"]) == 2
|
||||
assert tags["Tags"][0]["Key"] == "somekey"
|
||||
assert tags["Tags"][0]["Value"] == ""
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_updating_existing_tagged_policy_with_too_many_tags():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_policy(PolicyName="TestTagPolicy", PolicyDocument=MOCK_POLICY)
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[
|
||||
{"Key": "somekey", "Value": "somevalue"},
|
||||
{"Key": "someotherkey", "Value": "someothervalue"},
|
||||
],
|
||||
)
|
||||
|
||||
# With more than 50 tags:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
too_many_tags = list(
|
||||
map(lambda x: {"Key": str(x), "Value": str(x)}, range(0, 51))
|
||||
)
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=too_many_tags,
|
||||
)
|
||||
assert (
|
||||
"failed to satisfy constraint: Member must have length less than or equal to 50."
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_updating_existing_tagged_policy_with_duplicate_tag():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_policy(PolicyName="TestTagPolicy", PolicyDocument=MOCK_POLICY)
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[
|
||||
{"Key": "somekey", "Value": "somevalue"},
|
||||
{"Key": "someotherkey", "Value": "someothervalue"},
|
||||
],
|
||||
)
|
||||
|
||||
# With a duplicate tag:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[{"Key": "0", "Value": ""}, {"Key": "0", "Value": ""}],
|
||||
)
|
||||
assert (
|
||||
"Duplicate tag keys found. Please note that Tag keys are case insensitive."
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_updating_existing_tagged_policy_with_duplicate_tag_different_casing():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_policy(PolicyName="TestTagPolicy", PolicyDocument=MOCK_POLICY)
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[
|
||||
{"Key": "somekey", "Value": "somevalue"},
|
||||
{"Key": "someotherkey", "Value": "someothervalue"},
|
||||
],
|
||||
)
|
||||
|
||||
# Duplicate tag with different casing:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[{"Key": "a", "Value": ""}, {"Key": "A", "Value": ""}],
|
||||
)
|
||||
assert (
|
||||
"Duplicate tag keys found. Please note that Tag keys are case insensitive."
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_updating_existing_tagged_policy_with_large_key():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_policy(PolicyName="TestTagPolicy", PolicyDocument=MOCK_POLICY)
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[
|
||||
{"Key": "somekey", "Value": "somevalue"},
|
||||
{"Key": "someotherkey", "Value": "someothervalue"},
|
||||
],
|
||||
)
|
||||
|
||||
# With a really big key:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[{"Key": "0" * 129, "Value": ""}],
|
||||
)
|
||||
assert (
|
||||
"Member must have length less than or equal to 128."
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_updating_existing_tagged_policy_with_large_value():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_policy(PolicyName="TestTagPolicy", PolicyDocument=MOCK_POLICY)
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[
|
||||
{"Key": "somekey", "Value": "somevalue"},
|
||||
{"Key": "someotherkey", "Value": "someothervalue"},
|
||||
],
|
||||
)
|
||||
|
||||
# With a really big value:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[{"Key": "0", "Value": "0" * 257}],
|
||||
)
|
||||
assert (
|
||||
"Member must have length less than or equal to 256."
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_updating_existing_tagged_policy_with_invalid_character():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_policy(PolicyName="TestTagPolicy", PolicyDocument=MOCK_POLICY)
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[
|
||||
{"Key": "somekey", "Value": "somevalue"},
|
||||
{"Key": "someotherkey", "Value": "someothervalue"},
|
||||
],
|
||||
)
|
||||
|
||||
# With an invalid character:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestTagPolicy"),
|
||||
Tags=[{"Key": "NOWAY!", "Value": ""}],
|
||||
)
|
||||
assert (
|
||||
"Member must satisfy regular expression pattern: [\\p{L}\\p{Z}\\p{N}_.:/=+\\-@]+"
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_tag_non_existant_policy():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
|
||||
# With a policy that doesn't exist:
|
||||
with pytest.raises(ClientError):
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "NotAPolicy"),
|
||||
Tags=[{"Key": "some", "Value": "value"}],
|
||||
)
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_untag_policy():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_policy(PolicyName="TestUnTagPolicy", PolicyDocument=MOCK_POLICY)
|
||||
|
||||
# With proper tag values:
|
||||
conn.tag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestUnTagPolicy"),
|
||||
Tags=[
|
||||
{"Key": "somekey", "Value": "somevalue"},
|
||||
{"Key": "someotherkey", "Value": "someothervalue"},
|
||||
],
|
||||
)
|
||||
|
||||
# Remove them:
|
||||
conn.untag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestUnTagPolicy"),
|
||||
TagKeys=["somekey"],
|
||||
)
|
||||
tags = conn.list_policy_tags(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestUnTagPolicy")
|
||||
)
|
||||
assert len(tags["Tags"]) == 1
|
||||
assert tags["Tags"][0]["Key"] == "someotherkey"
|
||||
assert tags["Tags"][0]["Value"] == "someothervalue"
|
||||
|
||||
# And again:
|
||||
conn.untag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestUnTagPolicy"),
|
||||
TagKeys=["someotherkey"],
|
||||
)
|
||||
tags = conn.list_policy_tags(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestUnTagPolicy")
|
||||
)
|
||||
assert not tags["Tags"]
|
||||
|
||||
# Test removing tags with invalid values:
|
||||
# With more than 50 tags:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
conn.untag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestUnTagPolicy"),
|
||||
TagKeys=[str(x) for x in range(0, 51)],
|
||||
)
|
||||
assert (
|
||||
"failed to satisfy constraint: Member must have length less than or equal to 50."
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
assert "tagKeys" in ce.value.response["Error"]["Message"]
|
||||
|
||||
# With a really big key:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
conn.untag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestUnTagPolicy"),
|
||||
TagKeys=["0" * 129],
|
||||
)
|
||||
assert (
|
||||
"Member must have length less than or equal to 128."
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
assert "tagKeys" in ce.value.response["Error"]["Message"]
|
||||
|
||||
# With an invalid character:
|
||||
with pytest.raises(ClientError) as ce:
|
||||
conn.untag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "TestUnTagPolicy"),
|
||||
TagKeys=["NOWAY!"],
|
||||
)
|
||||
assert (
|
||||
"Member must satisfy regular expression pattern: [\\p{L}\\p{Z}\\p{N}_.:/=+\\-@]+"
|
||||
in ce.value.response["Error"]["Message"]
|
||||
)
|
||||
assert "tagKeys" in ce.value.response["Error"]["Message"]
|
||||
|
||||
# With a policy that doesn't exist:
|
||||
with pytest.raises(ClientError):
|
||||
conn.untag_policy(
|
||||
PolicyArn="arn:aws:iam::{}:policy/{}".format(ACCOUNT_ID, "NotAPolicy"),
|
||||
TagKeys=["somevalue"],
|
||||
)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_iam_deprecated()
|
||||
def test_create_user():
|
||||
@ -3473,6 +4010,7 @@ def test_role_config_dict():
|
||||
path="/",
|
||||
policy_document=json.dumps(basic_policy),
|
||||
policy_name="basic_policy",
|
||||
tags=[],
|
||||
)
|
||||
.arn
|
||||
)
|
||||
@ -3974,6 +4512,7 @@ def test_policy_list_config_discovered_resources():
|
||||
path="",
|
||||
policy_document=json.dumps(basic_policy),
|
||||
policy_name="policy{}".format(ix),
|
||||
tags=[],
|
||||
)
|
||||
policies.append(
|
||||
{"id": this_policy.id, "name": this_policy.name,}
|
||||
@ -4057,6 +4596,7 @@ def test_policy_config_dict():
|
||||
path="/",
|
||||
policy_document=json.dumps(basic_policy),
|
||||
policy_name="basic_policy",
|
||||
tags=[],
|
||||
)
|
||||
.arn
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user