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_open_id_connect_providers
|
||||||
- [X] list_policies
|
- [X] list_policies
|
||||||
- [ ] list_policies_granting_service_access
|
- [ ] list_policies_granting_service_access
|
||||||
- [ ] list_policy_tags
|
- [X] list_policy_tags
|
||||||
- [X] list_policy_versions
|
- [X] list_policy_versions
|
||||||
- [X] list_role_policies
|
- [X] list_role_policies
|
||||||
- [X] list_role_tags
|
- [X] list_role_tags
|
||||||
@ -2397,7 +2397,7 @@
|
|||||||
- [ ] tag_instance_profile
|
- [ ] tag_instance_profile
|
||||||
- [ ] tag_mfa_device
|
- [ ] tag_mfa_device
|
||||||
- [ ] tag_open_id_connect_provider
|
- [ ] tag_open_id_connect_provider
|
||||||
- [ ] tag_policy
|
- [X] tag_policy
|
||||||
- [X] tag_role
|
- [X] tag_role
|
||||||
- [ ] tag_saml_provider
|
- [ ] tag_saml_provider
|
||||||
- [ ] tag_server_certificate
|
- [ ] tag_server_certificate
|
||||||
@ -2405,7 +2405,7 @@
|
|||||||
- [ ] untag_instance_profile
|
- [ ] untag_instance_profile
|
||||||
- [ ] untag_mfa_device
|
- [ ] untag_mfa_device
|
||||||
- [ ] untag_open_id_connect_provider
|
- [ ] untag_open_id_connect_provider
|
||||||
- [ ] untag_policy
|
- [X] untag_policy
|
||||||
- [X] untag_role
|
- [X] untag_role
|
||||||
- [ ] untag_saml_provider
|
- [ ] untag_saml_provider
|
||||||
- [ ] untag_server_certificate
|
- [ ] untag_server_certificate
|
||||||
|
@ -108,7 +108,7 @@ class Policy(CloudFormationModel):
|
|||||||
self.description = description or ""
|
self.description = description or ""
|
||||||
self.id = random_policy_id()
|
self.id = random_policy_id()
|
||||||
self.path = path or "/"
|
self.path = path or "/"
|
||||||
self.tags = {tag["Key"]: tag["Value"] for tag in tags or []}
|
self.tags = tags
|
||||||
|
|
||||||
if default_version_id:
|
if default_version_id:
|
||||||
self.default_version_id = default_version_id
|
self.default_version_id = default_version_id
|
||||||
@ -141,6 +141,9 @@ class Policy(CloudFormationModel):
|
|||||||
def updated_iso_8601(self):
|
def updated_iso_8601(self):
|
||||||
return iso_8601_datetime_with_milliseconds(self.update_date)
|
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):
|
class SAMLProvider(BaseModel):
|
||||||
def __init__(self, name, saml_metadata_document=None):
|
def __init__(self, name, saml_metadata_document=None):
|
||||||
@ -284,6 +287,7 @@ class ManagedPolicy(Policy, CloudFormationModel):
|
|||||||
"awsRegion": "global",
|
"awsRegion": "global",
|
||||||
"availabilityZone": "Not Applicable",
|
"availabilityZone": "Not Applicable",
|
||||||
"resourceCreationTime": str(self.create_date),
|
"resourceCreationTime": str(self.create_date),
|
||||||
|
"tags": self.tags,
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"policyName": self.name,
|
"policyName": self.name,
|
||||||
"policyId": self.id,
|
"policyId": self.id,
|
||||||
@ -296,6 +300,12 @@ class ManagedPolicy(Policy, CloudFormationModel):
|
|||||||
"description": self.description,
|
"description": self.description,
|
||||||
"createDate": str(self.create_date.isoformat()),
|
"createDate": str(self.create_date.isoformat()),
|
||||||
"updateDate": 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(
|
"policyVersionList": list(
|
||||||
map(
|
map(
|
||||||
lambda version: {
|
lambda version: {
|
||||||
@ -331,12 +341,14 @@ class ManagedPolicy(Policy, CloudFormationModel):
|
|||||||
group_names = properties.get("Groups", [])
|
group_names = properties.get("Groups", [])
|
||||||
user_names = properties.get("Users", [])
|
user_names = properties.get("Users", [])
|
||||||
role_names = properties.get("Roles", [])
|
role_names = properties.get("Roles", [])
|
||||||
|
tags = properties.get("Tags", {})
|
||||||
|
|
||||||
policy = iam_backend.create_policy(
|
policy = iam_backend.create_policy(
|
||||||
description=description,
|
description=description,
|
||||||
path=path,
|
path=path,
|
||||||
policy_document=policy_document,
|
policy_document=policy_document,
|
||||||
policy_name=name,
|
policy_name=name,
|
||||||
|
tags=tags,
|
||||||
)
|
)
|
||||||
for group_name in group_names:
|
for group_name in group_names:
|
||||||
iam_backend.attach_group_policy(
|
iam_backend.attach_group_policy(
|
||||||
@ -1568,16 +1580,17 @@ class IAMBackend(BaseBackend):
|
|||||||
raise IAMNotFoundException("Policy {0} was not found.".format(policy_arn))
|
raise IAMNotFoundException("Policy {0} was not found.".format(policy_arn))
|
||||||
policy.detach_from(self.get_user(user_name))
|
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 = IAMPolicyDocumentValidator(policy_document)
|
||||||
iam_policy_document_validator.validate()
|
iam_policy_document_validator.validate()
|
||||||
|
|
||||||
|
clean_tags = self._tag_verification(tags)
|
||||||
policy = ManagedPolicy(
|
policy = ManagedPolicy(
|
||||||
policy_name,
|
policy_name,
|
||||||
description=description,
|
description=description,
|
||||||
document=policy_document,
|
document=policy_document,
|
||||||
path=path,
|
path=path,
|
||||||
tags=tags,
|
tags=clean_tags,
|
||||||
)
|
)
|
||||||
if policy.arn in self.managed_policies:
|
if policy.arn in self.managed_policies:
|
||||||
raise EntityAlreadyExists(
|
raise EntityAlreadyExists(
|
||||||
@ -1849,6 +1862,42 @@ class IAMBackend(BaseBackend):
|
|||||||
|
|
||||||
role.tags.pop(ref_key, None)
|
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):
|
def create_policy_version(self, policy_arn, policy_document, set_as_default):
|
||||||
iam_policy_document_validator = IAMPolicyDocumentValidator(policy_document)
|
iam_policy_document_validator = IAMPolicyDocumentValidator(policy_document)
|
||||||
iam_policy_document_validator.validate()
|
iam_policy_document_validator.validate()
|
||||||
|
@ -308,6 +308,34 @@ class IamResponse(BaseResponse):
|
|||||||
template = self.response_template(LIST_POLICY_VERSIONS_TEMPLATE)
|
template = self.response_template(LIST_POLICY_VERSIONS_TEMPLATE)
|
||||||
return template.render(policy_versions=policy_versions)
|
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):
|
def delete_policy_version(self):
|
||||||
policy_arn = self._get_param("PolicyArn")
|
policy_arn = self._get_param("PolicyArn")
|
||||||
version_id = self._get_param("VersionId")
|
version_id = self._get_param("VersionId")
|
||||||
@ -1129,14 +1157,16 @@ GET_POLICY_TEMPLATE = """<GetPolicyResponse>
|
|||||||
<AttachmentCount>{{ policy.attachment_count }}</AttachmentCount>
|
<AttachmentCount>{{ policy.attachment_count }}</AttachmentCount>
|
||||||
<CreateDate>{{ policy.created_iso_8601 }}</CreateDate>
|
<CreateDate>{{ policy.created_iso_8601 }}</CreateDate>
|
||||||
<UpdateDate>{{ policy.updated_iso_8601 }}</UpdateDate>
|
<UpdateDate>{{ policy.updated_iso_8601 }}</UpdateDate>
|
||||||
|
{% if policy.tags %}
|
||||||
<Tags>
|
<Tags>
|
||||||
{% for tag_key, tag_value in policy.tags.items() %}
|
{% for tag in policy.get_tags() %}
|
||||||
<member>
|
<member>
|
||||||
<Key>{{ tag_key }}</Key>
|
<Key>{{ tag['Key'] }}</Key>
|
||||||
<Value>{{ tag_value }}</Value>
|
<Value>{{ tag['Value'] }}</Value>
|
||||||
</member>
|
</member>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</Tags>
|
</Tags>
|
||||||
|
{% endif %}
|
||||||
</Policy>
|
</Policy>
|
||||||
</GetPolicyResult>
|
</GetPolicyResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
@ -2495,6 +2525,41 @@ UNTAG_ROLE_TEMPLATE = """<UntagRoleResponse xmlns="https://iam.amazonaws.com/doc
|
|||||||
</UntagRoleResponse>"""
|
</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/">
|
CREATE_OPEN_ID_CONNECT_PROVIDER_TEMPLATE = """<CreateOpenIDConnectProviderResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
|
||||||
<CreateOpenIDConnectProviderResult>
|
<CreateOpenIDConnectProviderResult>
|
||||||
<OpenIDConnectProviderArn>{{ open_id_provider.arn }}</OpenIDConnectProviderArn>
|
<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
|
# Has boto3 equivalent
|
||||||
@mock_iam_deprecated()
|
@mock_iam_deprecated()
|
||||||
def test_create_user():
|
def test_create_user():
|
||||||
@ -3473,6 +4010,7 @@ def test_role_config_dict():
|
|||||||
path="/",
|
path="/",
|
||||||
policy_document=json.dumps(basic_policy),
|
policy_document=json.dumps(basic_policy),
|
||||||
policy_name="basic_policy",
|
policy_name="basic_policy",
|
||||||
|
tags=[],
|
||||||
)
|
)
|
||||||
.arn
|
.arn
|
||||||
)
|
)
|
||||||
@ -3974,6 +4512,7 @@ def test_policy_list_config_discovered_resources():
|
|||||||
path="",
|
path="",
|
||||||
policy_document=json.dumps(basic_policy),
|
policy_document=json.dumps(basic_policy),
|
||||||
policy_name="policy{}".format(ix),
|
policy_name="policy{}".format(ix),
|
||||||
|
tags=[],
|
||||||
)
|
)
|
||||||
policies.append(
|
policies.append(
|
||||||
{"id": this_policy.id, "name": this_policy.name,}
|
{"id": this_policy.id, "name": this_policy.name,}
|
||||||
@ -4057,6 +4596,7 @@ def test_policy_config_dict():
|
|||||||
path="/",
|
path="/",
|
||||||
policy_document=json.dumps(basic_policy),
|
policy_document=json.dumps(basic_policy),
|
||||||
policy_name="basic_policy",
|
policy_name="basic_policy",
|
||||||
|
tags=[],
|
||||||
)
|
)
|
||||||
.arn
|
.arn
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user