def apply_patches(): # Add missing managed polices aws_managed_policies.extend([ AWSManagedPolicy.from_data(k, v) for k, v in ADDITIONAL_MANAGED_POLICIES.items() ]) def iam_response_create_user(self): user = moto_iam_backend.create_user( self._get_param('UserName'), self._get_param('Path'), self._get_multi_param('Tags.member')) template = self.response_template(USER_RESPONSE_TEMPLATE) return template.render(action='Create', user=user, request_id=str(uuid.uuid4())) IamResponse.create_user = iam_response_create_user def iam_response_get_user(self): user_name = self._get_param('UserName') if not user_name: access_key_id = self.get_current_user() user = moto_iam_backend.get_user_from_access_key_id(access_key_id) if user is None: user = User('default_user') else: user = moto_iam_backend.get_user(user_name) template = self.response_template(USER_RESPONSE_TEMPLATE) return template.render(action='Get', user=user, request_id=str(uuid.uuid4())) IamResponse.get_user = iam_response_get_user def iam_response_delete_policy(self): policy_arn = self._get_param('PolicyArn') moto_iam_backend.managed_policies.pop(policy_arn, None) template = self.response_template(GENERIC_EMPTY_TEMPLATE) return template.render(name='DeletePolicyResponse') if not hasattr(IamResponse, 'delete_policy'): IamResponse.delete_policy = iam_response_delete_policy def iam_backend_detach_role_policy(policy_arn, role_name): try: role = moto_iam_backend.get_role(role_name) policy = role.managed_policies[policy_arn] policy.detach_from(role) except KeyError: raise IAMNotFoundException( 'Policy {0} was not found.'.format(policy_arn)) moto_iam_backend.detach_role_policy = iam_backend_detach_role_policy
def apply_patches(): # Add missing managed polices aws_managed_policies.extend([ AWSManagedPolicy.from_data(k, v) for k, v in ADDITIONAL_MANAGED_POLICIES.items() ]) if "Principal" not in VALID_STATEMENT_ELEMENTS: VALID_STATEMENT_ELEMENTS.append("Principal") @patch(IAMPolicyDocumentValidator._validate_resource_syntax, pass_target=False) def _validate_resource_syntax(statement, *args, **kwargs): # Note: Serverless generates policies without "Resource" section (only "Effect"/"Principal"/"Action"), # which causes several policy validators in moto to fail if statement.get("Resource") in [None, [None]]: statement["Resource"] = ["*"] # patch get_user to include tags @patch(IamResponse.get_user) def iam_response_get_user(fn, self): result = fn(self) regex = r"(.*<UserName>\s*)([^\s]+)(\s*</UserName>.*)" regex2 = r"(.*<UserId>\s*)([^\s]+)(\s*</UserId>.*)" flags = re.MULTILINE | re.DOTALL user_name = re.match(regex, result, flags=flags).group(2) # replace default user id/name in response if config.TEST_IAM_USER_NAME: result = re.sub(regex, r"\g<1>%s\3" % config.TEST_IAM_USER_NAME, result) user_name = config.TEST_IAM_USER_NAME if config.TEST_IAM_USER_ID: result = re.sub(regex2, r"\g<1>%s\3" % config.TEST_IAM_USER_ID, result) user = moto_iam_backend.users.get(user_name) if not user: return result tags = moto_iam_backend.tagger.list_tags_for_resource(user.arn) if tags and "<Tags>" not in result: tags_str = "".join([ "<member><Key>%s</Key><Value>%s</Value></member>" % (t["Key"], t["Value"]) for t in tags["Tags"] ]) result = result.replace("</Arn>", "</Arn><Tags>%s</Tags>" % tags_str) return result # patch delete_policy @patch(IamResponse.delete_policy, pass_target=False) def iam_response_delete_policy(self): policy_arn = self._get_param("PolicyArn") if moto_iam_backend.managed_policies.get(policy_arn): moto_iam_backend.managed_policies.pop(policy_arn, None) template = self.response_template(GENERIC_EMPTY_TEMPLATE) return template.render(name="DeletePolicy") else: raise IAMNotFoundException( "Policy {0} was not found.".format(policy_arn)) # patch detach_role_policy @patch(moto_iam_backend.detach_role_policy, pass_target=False) def iam_backend_detach_role_policy(self, policy_arn, role_name): try: role = moto_iam_backend.get_role(role_name) policy = role.managed_policies[policy_arn] policy.detach_from(role) except KeyError: raise IAMNotFoundException( "Policy {0} was not found.".format(policy_arn)) # patch/implement simulate_principal_policy def iam_response_simulate_principal_policy(self): def build_evaluation(action_name, resource_name, policy_statements): for statement in policy_statements: # TODO Implement evaluation logic here if (action_name in statement["Action"] and resource_name in statement["Resource"] and statement["Effect"] == "Allow"): return { "actionName": action_name, "resourceName": resource_name, "decision": "allowed", "matchedStatements": [], } return { "actionName": action_name, "resourceName": resource_name, "decision": "explicitDeny", } policy = moto_iam_backend.get_policy( self._get_param("PolicySourceArn")) policy_statements = json.loads(policy.document)["Statement"] actions = self._get_multi_param("ActionNames.member") resource_arns = self._get_multi_param("ResourceArns.member") evaluations = [] for action in actions: for resource_arn in resource_arns: evaluations.append( build_evaluation(action, resource_arn, policy_statements)) template = self.response_template(SIMULATE_PRINCIPAL_POLICY_RESPONSE) return template.render(evaluations=evaluations) if not hasattr(IamResponse, "simulate_principal_policy"): IamResponse.simulate_principal_policy = iam_response_simulate_principal_policy # patch policy __init__ to set document as attribute @patch(Policy.__init__) def policy__init__(fn, self, name, default_version_id=None, description=None, document=None, **kwargs): fn(self, name, default_version_id, description, document, **kwargs) self.document = document # patch list_roles @patch(IamResponse.list_roles, pass_target=False) def iam_response_list_roles(self): roles = moto_iam_backend.get_roles() items = [] for role in roles: item = deepcopy(role) item.assume_role_policy_document = quote( json.dumps(item.assume_role_policy_document or {})) items.append(item) prefix = self._get_param("PathPrefix") if prefix: filtered_roles = [] for role in roles: if role.path.startswith(prefix): filtered_roles.append(role) items = filtered_roles template = self.response_template(LIST_ROLES_TEMPLATE) return template.render(roles=items) # patch unapply_policy @patch(InlinePolicy.unapply_policy) def inline_policy_unapply_policy(fn, self, backend): try: fn(self, backend) except Exception: # Actually role can be deleted before policy being deleted in cloudformation pass # support update_group def update_group(self): group_name = self._get_param("GroupName") new_path = self._get_param("NewPath") new_group_name = self._get_param("NewGroupName") or group_name group = moto_iam_backend.get_group(group_name) group.path = new_path group.name = new_group_name moto_iam_backend.groups[new_group_name] = moto_iam_backend.groups.pop( group_name) return "" # TODO: potentially extend @patch utility to allow "conditional" patches like below ... if not hasattr(IamResponse, "update_group"): IamResponse.update_group = update_group # support instance profile tags def list_instance_profile_tags(self): profile_name = self._get_param("InstanceProfileName") profile = moto_iam_backend.get_instance_profile(profile_name) result = { "ListInstanceProfileTagsResponse": { "@xmlns": XMLNS_IAM, "ListInstanceProfileTagsResult": { "Tags": profile.tags }, } } return xmltodict.unparse(result) if not hasattr(IamResponse, "list_instance_profile_tags"): IamResponse.list_instance_profile_tags = list_instance_profile_tags # patch/implement tag_instance_profile def tag_instance_profile(self): profile_name = self._get_param("InstanceProfileName") tags = self._get_multi_param("Tags.member") tags = {tag["Key"]: tag["Value"] for tag in tags or []} profile = moto_iam_backend.get_instance_profile(profile_name) profile.tags.update(tags) return "" if not hasattr(IamResponse, "tag_instance_profile"): IamResponse.tag_instance_profile = tag_instance_profile # patch/implement untag_instance_profile def untag_instance_profile(self): profile_name = self._get_param("InstanceProfileName") tag_keys = self._get_multi_param("TagKeys.member") profile = moto_iam_backend.get_instance_profile(profile_name) profile.tags = { k: v for k, v in profile.tags.items() if k not in tag_keys } return "" if not hasattr(IamResponse, "untag_instance_profile"): IamResponse.untag_instance_profile = untag_instance_profile # support policy tags def tag_policy(self): policy_arn = self._get_param("PolicyArn") tags = self._get_multi_param("Tags.member") tags = {tag["Key"]: tag["Value"] for tag in tags or []} policy = moto_iam_backend.get_policy(policy_arn) policy.tags.update(tags) return "" if not hasattr(IamResponse, "tag_policy"): IamResponse.tag_policy = tag_policy def untag_policy(self): policy_arn = self._get_param("PolicyArn") tag_keys = self._get_multi_param("TagKeys.member") policy = moto_iam_backend.get_policy(policy_arn) policy.tags = { k: v for k, v in policy.tags.items() if k not in tag_keys } return "" if not hasattr(IamResponse, "untag_policy"): IamResponse.untag_policy = untag_policy # support service linked roles if not hasattr(IamResponse, "create_service_linked_role"): @property def role_arn(self): return getattr(self, "service_linked_role_arn", None) or role_arn_orig.__get__(self) role_arn_orig = Role.arn Role.arn = role_arn def create_service_linked_role(self): service_name = self._get_param("AWSServiceName") description = self._get_param("Description") # TODO: how to support "CustomSuffix" API request parameter? policy_doc = json.dumps({ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Service": service_name }, "Action": "sts:AssumeRole", }], }) path = f"{SERVICE_LINKED_ROLE_PATH_PREFIX}/{service_name}" role_name = f"r-{short_uid()}" role = moto_iam_backend.create_role( role_name=role_name, assume_role_policy_document=policy_doc, path=path, permissions_boundary="", description=description, tags={}, max_session_duration=3600, ) template = self.response_template(GET_ROLE_TEMPLATE) role.service_linked_role_arn = "arn:aws:iam::{0}:role/aws-service-role/{1}/{2}".format( constants.TEST_AWS_ACCOUNT_ID, service_name, role.name) result = re.sub( r"<(/)?GetRole", r"<\1CreateServiceLinkedRole", template.render(role=role), ) return result IamResponse.create_service_linked_role = create_service_linked_role if not hasattr(IamResponse, "delete_service_linked_role"): def delete_service_linked_role(self): role_name = self._get_param("RoleName") moto_iam_backend.delete_role(role_name) result = { "DeleteServiceLinkedRoleResponse": { "@xmlns": XMLNS_IAM, "DeleteServiceLinkedRoleResult": { "DeletionTaskId": short_uid() }, } } return xmltodict.unparse(result) IamResponse.delete_service_linked_role = delete_service_linked_role if not hasattr(IamResponse, "get_service_linked_role_deletion_status"): def get_service_linked_role_deletion_status(self): result = { "GetServiceLinkedRoleDeletionStatusResponse": { "@xmlns": XMLNS_IAM, "GetServiceLinkedRoleDeletionStatusResult": { "Status": "SUCCEEDED" }, } } return xmltodict.unparse(result) IamResponse.get_service_linked_role_deletion_status = ( get_service_linked_role_deletion_status) managed_policies = moto_iam_backend.managed_policies if "arn:aws-us-gov:iam::aws:policy/AmazonRDSFullAccess" not in managed_policies: for name, data in aws_managed_policies_data_parsed.items(): policy = AWSManagedPolicyUSGov.from_data(name, data) if policy.arn not in moto_iam_backend.managed_policies: moto_iam_backend.managed_policies[policy.arn] = policy
def apply_patches(): # Add missing managed polices aws_managed_policies.extend([ AWSManagedPolicy.from_data(k, v) for k, v in ADDITIONAL_MANAGED_POLICIES.items() ]) if 'Principal' not in VALID_STATEMENT_ELEMENTS: VALID_STATEMENT_ELEMENTS.append('Principal') def _validate_resource_syntax(statement, *args, **kwargs): # Note: Serverless generates policies without "Resource" section (only "Effect"/"Principal"/"Action"), # which causes several policy validators in moto to fail if statement.get('Resource') in [None, [None]]: statement['Resource'] = ['*'] IAMPolicyDocumentValidator._validate_resource_syntax = _validate_resource_syntax def iam_response_get_user(self): result = iam_response_get_user_orig(self) user_name = re.sub(r'.*<UserName>\s*([^\s]+)\s*</UserName>.*', r'\1', result, flags=re.MULTILINE | re.DOTALL) user = moto_iam_backend.users[user_name] tags = moto_iam_backend.tagger.list_tags_for_resource(user.arn) if tags and '<Tags>' not in result: tags_str = ''.join([ '<member><Key>%s</Key><Value>%s</Value></member>' % (t['Key'], t['Value']) for t in tags['Tags']]) result = result.replace('</Arn>', '</Arn><Tags>%s</Tags>' % tags_str) return result iam_response_get_user_orig = IamResponse.get_user IamResponse.get_user = iam_response_get_user def iam_response_delete_policy(self): policy_arn = self._get_param('PolicyArn') moto_iam_backend.managed_policies.pop(policy_arn, None) template = self.response_template(GENERIC_EMPTY_TEMPLATE) return template.render(name='DeletePolicyResponse') if not hasattr(IamResponse, 'delete_policy'): IamResponse.delete_policy = iam_response_delete_policy def iam_backend_detach_role_policy(policy_arn, role_name): try: role = moto_iam_backend.get_role(role_name) policy = role.managed_policies[policy_arn] policy.detach_from(role) except KeyError: raise IAMNotFoundException('Policy {0} was not found.'.format(policy_arn)) moto_iam_backend.detach_role_policy = iam_backend_detach_role_policy policy_init_orig = Policy.__init__ def iam_response_simulate_principal_policy(self): def build_evaluation(action_name, resource_name, policy_statements): for statement in policy_statements: # TODO Implement evaluation logic here if action_name in statement['Action'] \ and resource_name in statement['Resource'] \ and statement['Effect'] == 'Allow': return { 'actionName': action_name, 'resourceName': resource_name, 'decision': 'allowed', 'matchedStatements': [] } return { 'actionName': action_name, 'resourceName': resource_name, 'decision': 'explicitDeny' } policy = moto_iam_backend.get_policy(self._get_param('PolicySourceArn')) policy_statements = json.loads(policy.document)['Statement'] actions = self._get_multi_param('ActionNames.member') resource_arns = self._get_multi_param('ResourceArns.member') evaluations = [] for action in actions: for resource_arn in resource_arns: evaluations.append(build_evaluation(action, resource_arn, policy_statements)) template = self.response_template(SIMULATE_PRINCIPAL_POLICY_RESPONSE) return template.render(evaluations=evaluations) def policy__init__( self, name, default_version_id=None, description=None, document=None, **kwargs ): policy_init_orig(self, name, default_version_id, description, document, **kwargs) self.document = document Policy.__init__ = policy__init__ IamResponse.simulate_principal_policy = iam_response_simulate_principal_policy def iam_response_list_roles(self): roles = moto_iam_backend.get_roles() items = [] for role in roles: item = deepcopy(role) item.assume_role_policy_document = quote(json.dumps(item.assume_role_policy_document or {})) items.append(item) prefix = self._get_param('PathPrefix') if prefix: filtered_roles = [] for role in roles: if role.path.startswith(prefix): filtered_roles.append(role) items = filtered_roles template = self.response_template(LIST_ROLES_TEMPLATE) return template.render(roles=items) IamResponse.list_roles = iam_response_list_roles inline_policy_unapply_policy_orig = InlinePolicy.unapply_policy def inline_policy_unapply_policy(self, backend): try: inline_policy_unapply_policy_orig(self, backend) except Exception: # Actually role can be deleted before policy being deleted in cloudformation pass InlinePolicy.unapply_policy = inline_policy_unapply_policy # support update_group def update_group(self): group_name = self._get_param('GroupName') new_path = self._get_param('NewPath') new_group_name = self._get_param('NewGroupName') or group_name group = moto_iam_backend.get_group(group_name) group.path = new_path group.name = new_group_name moto_iam_backend.groups[new_group_name] = moto_iam_backend.groups.pop(group_name) return '' if not hasattr(IamResponse, 'update_group'): IamResponse.update_group = update_group # support instance profile tags def list_instance_profile_tags(self): profile_name = self._get_param('InstanceProfileName') profile = moto_iam_backend.get_instance_profile(profile_name) result = { 'ListInstanceProfileTagsResponse': { '@xmlns': XMLNS_IAM, 'ListInstanceProfileTagsResult': {'Tags': profile.tags} } } return xmltodict.unparse(result) if not hasattr(IamResponse, 'list_instance_profile_tags'): IamResponse.list_instance_profile_tags = list_instance_profile_tags def tag_instance_profile(self): profile_name = self._get_param('InstanceProfileName') tags = self._get_multi_param('Tags.member') tags = {tag['Key']: tag['Value'] for tag in tags or []} profile = moto_iam_backend.get_instance_profile(profile_name) profile.tags.update(tags) return '' if not hasattr(IamResponse, 'tag_instance_profile'): IamResponse.tag_instance_profile = tag_instance_profile def untag_instance_profile(self): profile_name = self._get_param('InstanceProfileName') tag_keys = self._get_multi_param('TagKeys.member') profile = moto_iam_backend.get_instance_profile(profile_name) profile.tags = {k: v for k, v in profile.tags.items() if k not in tag_keys} return '' if not hasattr(IamResponse, 'untag_instance_profile'): IamResponse.untag_instance_profile = untag_instance_profile # support policy tags def tag_policy(self): policy_arn = self._get_param('PolicyArn') tags = self._get_multi_param('Tags.member') tags = {tag['Key']: tag['Value'] for tag in tags or []} policy = moto_iam_backend.get_policy(policy_arn) policy.tags.update(tags) return '' if not hasattr(IamResponse, 'tag_policy'): IamResponse.tag_policy = tag_policy def untag_policy(self): policy_arn = self._get_param('PolicyArn') tag_keys = self._get_multi_param('TagKeys.member') policy = moto_iam_backend.get_policy(policy_arn) policy.tags = {k: v for k, v in policy.tags.items() if k not in tag_keys} return '' if not hasattr(IamResponse, 'untag_policy'): IamResponse.untag_policy = untag_policy # support service linked roles if not hasattr(IamResponse, 'create_service_linked_role'): @property def role_arn(self): return getattr(self, 'service_linked_role_arn', None) or role_arn_orig.__get__(self) role_arn_orig = Role.arn Role.arn = role_arn def create_service_linked_role(self): name_prefix = 'service-linked-role' service_name = self._get_param('AWSServiceName') description = self._get_param('Description') # TODO: how to support "CustomSuffix" API request parameter? policy_doc = json.dumps({ 'Version': '2012-10-17', 'Statement': [ {'Effect': 'Allow', 'Principal': {'Service': service_name}, 'Action': 'sts:AssumeRole'}] }) role = moto_iam_backend.create_role( role_name='%s-%s' % (name_prefix, short_uid()), assume_role_policy_document=policy_doc, path='/', permissions_boundary='', description=description, tags={}, max_session_duration=3600) template = self.response_template(GET_ROLE_TEMPLATE) role.service_linked_role_arn = 'arn:aws:iam::{0}:role/aws-service-role/{1}/{2}'.format( constants.TEST_AWS_ACCOUNT_ID, service_name, role.name) result = re.sub(r'<(/)?GetRole', r'<\1CreateServiceLinkedRole', template.render(role=role)) return result IamResponse.create_service_linked_role = create_service_linked_role if not hasattr(IamResponse, 'delete_service_linked_role'): def delete_service_linked_role(self): role_name = self._get_param('RoleName') moto_iam_backend.delete_role(role_name) result = { 'DeleteServiceLinkedRoleResponse': { '@xmlns': XMLNS_IAM, 'DeleteServiceLinkedRoleResult': {'DeletionTaskId': short_uid()} } } return xmltodict.unparse(result) IamResponse.delete_service_linked_role = delete_service_linked_role if not hasattr(IamResponse, 'get_service_linked_role_deletion_status'): def get_service_linked_role_deletion_status(self): result = { 'GetServiceLinkedRoleDeletionStatusResponse': { '@xmlns': XMLNS_IAM, 'GetServiceLinkedRoleDeletionStatusResult': {'Status': 'SUCCEEDED'} } } return xmltodict.unparse(result) IamResponse.get_service_linked_role_deletion_status = get_service_linked_role_deletion_status # fix missing regions in managed policies (e.g., aws-us-gov) # TODO: possibly find a more efficient way for this - e.g., lazy loading of policies in special regions class AWSManagedPolicyUSGov(AWSManagedPolicy): @property def arn(self): return 'arn:aws-us-gov:iam::aws:policy{0}{1}'.format(self.path, self.name) managed_policies = moto_iam_backend.managed_policies if 'arn:aws-us-gov:iam::aws:policy/AmazonRDSFullAccess' not in managed_policies: for name, data in aws_managed_policies_data_parsed.items(): policy = AWSManagedPolicyUSGov.from_data(name, data) if policy.arn not in moto_iam_backend.managed_policies: moto_iam_backend.managed_policies[policy.arn] = policy
def apply_patches(): # Add missing managed polices aws_managed_policies.extend([ AWSManagedPolicy.from_data(k, v) for k, v in ADDITIONAL_MANAGED_POLICIES.items() ]) if 'Principal' not in VALID_STATEMENT_ELEMENTS: VALID_STATEMENT_ELEMENTS.append('Principal') def _validate_resource_syntax(statement, *args, **kwargs): # Note: Serverless generates policies without "Resource" section (only "Effect"/"Principal"/"Action"), # which causes several policy validators in moto to fail if statement.get('Resource') in [None, [None]]: statement['Resource'] = ['*'] IAMPolicyDocumentValidator._validate_resource_syntax = _validate_resource_syntax def iam_response_create_user(self): user = moto_iam_backend.create_user( self._get_param('UserName'), self._get_param('Path'), self._get_multi_param('Tags.member')) template = self.response_template(USER_RESPONSE_TEMPLATE) return template.render(action='Create', user=user, request_id=str(uuid.uuid4())) IamResponse.create_user = iam_response_create_user def iam_response_get_user(self): user_name = self._get_param('UserName') if not user_name: access_key_id = self.get_current_user() user = moto_iam_backend.get_user_from_access_key_id(access_key_id) if user is None: user = User('default_user') else: user = moto_iam_backend.get_user(user_name) template = self.response_template(USER_RESPONSE_TEMPLATE) return template.render(action='Get', user=user, request_id=str(uuid.uuid4())) IamResponse.get_user = iam_response_get_user def iam_response_delete_policy(self): policy_arn = self._get_param('PolicyArn') moto_iam_backend.managed_policies.pop(policy_arn, None) template = self.response_template(GENERIC_EMPTY_TEMPLATE) return template.render(name='DeletePolicyResponse') if not hasattr(IamResponse, 'delete_policy'): IamResponse.delete_policy = iam_response_delete_policy def iam_backend_detach_role_policy(policy_arn, role_name): try: role = moto_iam_backend.get_role(role_name) policy = role.managed_policies[policy_arn] policy.detach_from(role) except KeyError: raise IAMNotFoundException( 'Policy {0} was not found.'.format(policy_arn)) moto_iam_backend.detach_role_policy = iam_backend_detach_role_policy policy_init_orig = Policy.__init__ def iam_response_simulate_principal_policy(self): def build_evaluation(action_name, resource_name, policy_statements): for statement in policy_statements: # TODO Implement evaluation logic here if action_name in statement['Action'] \ and resource_name in statement['Resource'] \ and statement['Effect'] == 'Allow': return { 'actionName': action_name, 'resourceName': resource_name, 'decision': 'allowed', 'matchedStatements': [] } return { 'actionName': action_name, 'resourceName': resource_name, 'decision': 'explicitDeny' } policy = moto_iam_backend.get_policy( self._get_param('PolicySourceArn')) policy_statements = json.loads(policy.document)['Statement'] actions = self._get_multi_param('ActionNames.member') resource_arns = self._get_multi_param('ResourceArns.member') evaluations = [] for action in actions: for resource_arn in resource_arns: evaluations.append( build_evaluation(action, resource_arn, policy_statements)) template = self.response_template(SIMULATE_PRINCIPAL_POLICY_RESPONSE) return template.render(evaluations=evaluations) def policy__init__(self, name, default_version_id=None, description=None, document=None, path=None, create_date=None, update_date=None): policy_init_orig(self, name, default_version_id, description, document, path, create_date, update_date) self.document = document Policy.__init__ = policy__init__ IamResponse.simulate_principal_policy = iam_response_simulate_principal_policy def iam_response_list_roles(self): roles = moto_iam_backend.get_roles() items = [] for role in roles: item = deepcopy(role) item.assume_role_policy_document = quote( json.dumps(item.assume_role_policy_document or {})) items.append(item) prefix = self._get_param('PathPrefix') if prefix: filtered_roles = [] for role in roles: if role.path.startswith(prefix): filtered_roles.append(role) items = filtered_roles template = self.response_template(LIST_ROLES_TEMPLATE) return template.render(roles=items) IamResponse.list_roles = iam_response_list_roles inline_policy_unapply_policy_orig = InlinePolicy.unapply_policy def inline_policy_unapply_policy(self, backend): try: inline_policy_unapply_policy_orig(self, backend) except Exception: # Actually role can be deleted before policy being deleted in cloudformation pass InlinePolicy.unapply_policy = inline_policy_unapply_policy
def apply_patches(): # support service linked roles @property def moto_role_arn(self): return getattr(self, "service_linked_role_arn", None) or moto_role_og_arn_prop.__get__(self) moto_role_og_arn_prop = MotoRole.arn MotoRole.arn = moto_role_arn # Add missing managed polices aws_managed_policies.extend([ AWSManagedPolicy.from_data(k, v) for k, v in ADDITIONAL_MANAGED_POLICIES.items() ]) if "Principal" not in VALID_STATEMENT_ELEMENTS: VALID_STATEMENT_ELEMENTS.append("Principal") @patch(IAMPolicyDocumentValidator._validate_resource_syntax, pass_target=False) def _validate_resource_syntax(statement, *args, **kwargs): # Note: Serverless generates policies without "Resource" section (only "Effect"/"Principal"/"Action"), # which causes several policy validators in moto to fail if statement.get("Resource") in [None, [None]]: statement["Resource"] = ["*"] # patch get_user to include tags # TODO: remove this patch in favour of IamProvider.get_user. @patch(IamResponse.get_user) def iam_response_get_user(fn, self): result = fn(self) regex = r"(.*<UserName>\s*)([^\s]+)(\s*</UserName>.*)" regex2 = r"(.*<UserId>\s*)([^\s]+)(\s*</UserId>.*)" flags = re.MULTILINE | re.DOTALL user_name = re.match(regex, result, flags=flags).group(2) # replace default user id/name in response if config.TEST_IAM_USER_NAME: result = re.sub(regex, r"\g<1>%s\3" % config.TEST_IAM_USER_NAME, result) user_name = config.TEST_IAM_USER_NAME if config.TEST_IAM_USER_ID: result = re.sub(regex2, r"\g<1>%s\3" % config.TEST_IAM_USER_ID, result) user = moto_iam_backend.users.get(user_name) if not user: return result tags = moto_iam_backend.tagger.list_tags_for_resource(user.arn) if tags and "<Tags>" not in result: tags_str = "".join([ "<member><Key>%s</Key><Value>%s</Value></member>" % (t["Key"], t["Value"]) for t in tags["Tags"] ]) result = result.replace("</Arn>", "</Arn><Tags>%s</Tags>" % tags_str) return result # patch policy __init__ to set document as attribute @patch(Policy.__init__) def policy__init__(fn, self, name, default_version_id=None, description=None, document=None, **kwargs): fn(self, name, default_version_id, description, document, **kwargs) self.document = document # patch unapply_policy @patch(InlinePolicy.unapply_policy) def inline_policy_unapply_policy(fn, self, backend): try: fn(self, backend) except Exception: # Actually role can be deleted before policy being deleted in cloudformation pass
def apply_patches(): # Add missing managed polices aws_managed_policies.extend([ AWSManagedPolicy.from_data(k, v) for k, v in ADDITIONAL_MANAGED_POLICIES.items() ]) def iam_response_create_user(self): user = moto_iam_backend.create_user( self._get_param('UserName'), self._get_param('Path'), self._get_multi_param('Tags.member') ) template = self.response_template(USER_RESPONSE_TEMPLATE) return template.render( action='Create', user=user, request_id=str(uuid.uuid4()) ) IamResponse.create_user = iam_response_create_user def iam_response_get_user(self): user_name = self._get_param('UserName') if not user_name: access_key_id = self.get_current_user() user = moto_iam_backend.get_user_from_access_key_id(access_key_id) if user is None: user = User('default_user') else: user = moto_iam_backend.get_user(user_name) template = self.response_template(USER_RESPONSE_TEMPLATE) return template.render( action='Get', user=user, request_id=str(uuid.uuid4()) ) IamResponse.get_user = iam_response_get_user def iam_response_delete_policy(self): policy_arn = self._get_param('PolicyArn') moto_iam_backend.managed_policies.pop(policy_arn, None) template = self.response_template(GENERIC_EMPTY_TEMPLATE) return template.render(name='DeletePolicyResponse') if not hasattr(IamResponse, 'delete_policy'): IamResponse.delete_policy = iam_response_delete_policy def iam_backend_detach_role_policy(policy_arn, role_name): try: role = moto_iam_backend.get_role(role_name) policy = role.managed_policies[policy_arn] policy.detach_from(role) except KeyError: raise IAMNotFoundException('Policy {0} was not found.'.format(policy_arn)) moto_iam_backend.detach_role_policy = iam_backend_detach_role_policy policy_init_orig = Policy.__init__ def iam_response_simulate_principal_policy(self): def build_evaluation(action_name, resource_name, policy_statements): for statement in policy_statements: # TODO Implement evaluation logic here if action_name in statement['Action'] \ and resource_name in statement['Resource'] \ and statement['Effect'] == 'Allow': return { 'actionName': action_name, 'resourceName': resource_name, 'decision': 'allowed', 'matchedStatements': [] } return { 'actionName': action_name, 'resourceName': resource_name, 'decision': 'explicitDeny' } policy = moto_iam_backend.get_policy(self._get_param('PolicySourceArn')) policy_statements = json.loads(policy.document)['Statement'] actions = self._get_multi_param('ActionNames.member') resource_arns = self._get_multi_param('ResourceArns.member') evaluations = [] for action in actions: for resource_arn in resource_arns: evaluations.append(build_evaluation(action, resource_arn, policy_statements)) template = self.response_template(SIMULATE_PRINCIPAL_POLICY_RESPONSE) return template.render(evaluations=evaluations) def policy__init__( self, name, default_version_id=None, description=None, document=None, path=None, create_date=None, update_date=None ): policy_init_orig(self, name, default_version_id, description, document, path, create_date, update_date) self.document = document Policy.__init__ = policy__init__ IamResponse.simulate_principal_policy = iam_response_simulate_principal_policy def iam_response_list_roles(self): roles = moto_iam_backend.get_roles() items = [] for role in roles: item = deepcopy(role) item.assume_role_policy_document = quote(json.dumps(item.assume_role_policy_document or {})) items.append(item) template = self.response_template(LIST_ROLES_TEMPLATE) return template.render(roles=items) IamResponse.list_roles = iam_response_list_roles
def apply_patches(): # Add missing managed polices aws_managed_policies.extend([ AWSManagedPolicy.from_data(k, v) for k, v in ADDITIONAL_MANAGED_POLICIES.items() ]) if 'Principal' not in VALID_STATEMENT_ELEMENTS: VALID_STATEMENT_ELEMENTS.append('Principal') def _validate_resource_syntax(statement, *args, **kwargs): # Note: Serverless generates policies without "Resource" section (only "Effect"/"Principal"/"Action"), # which causes several policy validators in moto to fail if statement.get('Resource') in [None, [None]]: statement['Resource'] = ['*'] IAMPolicyDocumentValidator._validate_resource_syntax = _validate_resource_syntax def iam_response_get_user(self): result = iam_response_get_user_orig(self) user_name = re.sub(r'.*<UserName>\s*([^\s]+)\s*</UserName>.*', r'\1', result, flags=re.MULTILINE | re.DOTALL) user = moto_iam_backend.users[user_name] tags = moto_iam_backend.tagger.list_tags_for_resource(user.arn) if tags and '<Tags>' not in result: tags_str = ''.join([ '<member><Key>%s</Key><Value>%s</Value></member>' % (t['Key'], t['Value']) for t in tags['Tags'] ]) result = result.replace('</Arn>', '</Arn><Tags>%s</Tags>' % tags_str) return result iam_response_get_user_orig = IamResponse.get_user IamResponse.get_user = iam_response_get_user def iam_response_delete_policy(self): policy_arn = self._get_param('PolicyArn') moto_iam_backend.managed_policies.pop(policy_arn, None) template = self.response_template(GENERIC_EMPTY_TEMPLATE) return template.render(name='DeletePolicyResponse') if not hasattr(IamResponse, 'delete_policy'): IamResponse.delete_policy = iam_response_delete_policy def iam_backend_detach_role_policy(policy_arn, role_name): try: role = moto_iam_backend.get_role(role_name) policy = role.managed_policies[policy_arn] policy.detach_from(role) except KeyError: raise IAMNotFoundException( 'Policy {0} was not found.'.format(policy_arn)) moto_iam_backend.detach_role_policy = iam_backend_detach_role_policy policy_init_orig = Policy.__init__ def iam_response_simulate_principal_policy(self): def build_evaluation(action_name, resource_name, policy_statements): for statement in policy_statements: # TODO Implement evaluation logic here if action_name in statement['Action'] \ and resource_name in statement['Resource'] \ and statement['Effect'] == 'Allow': return { 'actionName': action_name, 'resourceName': resource_name, 'decision': 'allowed', 'matchedStatements': [] } return { 'actionName': action_name, 'resourceName': resource_name, 'decision': 'explicitDeny' } policy = moto_iam_backend.get_policy( self._get_param('PolicySourceArn')) policy_statements = json.loads(policy.document)['Statement'] actions = self._get_multi_param('ActionNames.member') resource_arns = self._get_multi_param('ResourceArns.member') evaluations = [] for action in actions: for resource_arn in resource_arns: evaluations.append( build_evaluation(action, resource_arn, policy_statements)) template = self.response_template(SIMULATE_PRINCIPAL_POLICY_RESPONSE) return template.render(evaluations=evaluations) def policy__init__(self, name, default_version_id=None, description=None, document=None, path=None, create_date=None, update_date=None): policy_init_orig(self, name, default_version_id, description, document, path, create_date, update_date) self.document = document Policy.__init__ = policy__init__ IamResponse.simulate_principal_policy = iam_response_simulate_principal_policy def iam_response_list_roles(self): roles = moto_iam_backend.get_roles() items = [] for role in roles: item = deepcopy(role) item.assume_role_policy_document = quote( json.dumps(item.assume_role_policy_document or {})) items.append(item) prefix = self._get_param('PathPrefix') if prefix: filtered_roles = [] for role in roles: if role.path.startswith(prefix): filtered_roles.append(role) items = filtered_roles template = self.response_template(LIST_ROLES_TEMPLATE) return template.render(roles=items) IamResponse.list_roles = iam_response_list_roles inline_policy_unapply_policy_orig = InlinePolicy.unapply_policy def inline_policy_unapply_policy(self, backend): try: inline_policy_unapply_policy_orig(self, backend) except Exception: # Actually role can be deleted before policy being deleted in cloudformation pass InlinePolicy.unapply_policy = inline_policy_unapply_policy