def __init__(self, config, session, logger): if config.get('slack_token'): config['slack_token'] = kms_decrypt(config, logger, session, 'slack_token') self.client = SlackClient(config['slack_token']) self.caching = self.cache_factory(config, config.get('cache_engine', None)) self.config = config self.logger = logger self.session = session self.email_handler = EmailDelivery(config, session, logger)
def __init__(self, config, session, logger): if config.get('slack_token'): config['slack_token'] = kms_decrypt(config, logger, session, 'slack_token') self.caching = self.cache_factory(config, config.get('cache_engine', None)) self.config = config self.logger = logger self.session = session self.email_handler = EmailDelivery(config, session, logger)
def run(self, dry_run=False, print_only=False): emd = EmailDelivery(self.config, self.session, logger) addrs_to_msgs = emd.get_to_addrs_email_messages_map(self.data) logger.info('Would send email to: %s', addrs_to_msgs.keys()) if print_only: mime = get_mimetext_message(self.config, logger, self.data, self.data['resources'], ['*****@*****.**']) logger.info('Send mail with subject: "%s"', mime['Subject']) print(mime.get_payload(None, True).decode('utf-8')) return if dry_run: for to_addrs, mimetext_msg in addrs_to_msgs.items(): print('-> SEND MESSAGE TO: %s' % '; '.join(to_addrs)) print(mimetext_msg.get_payload(None, True).decode('utf-8')) return # else actually send the message... for to_addrs, mimetext_msg in addrs_to_msgs.items(): logger.info('Actually sending mail to: %s', to_addrs) emd.send_c7n_email(self.data, list(to_addrs), mimetext_msg)
def setUp(self): self.config = { 'slack_token': SLACK_TOKEN, 'templates_folders': [ os.path.abspath(os.path.dirname(__file__)), os.path.abspath('/'), os.path.join(os.path.abspath(os.path.dirname(__file__)), "test-templates/") ] } self.session = MagicMock() self.logger = MagicMock() self.email_delivery = EmailDelivery(self.config, self.session, self.logger) self.message = copy.deepcopy(SQS_MESSAGE_5) self.resource = copy.deepcopy(RESOURCE_3) self.message['resources'] = [self.resource] self.target_channel = 'test-channel'
class SlackDelivery(object): def __init__(self, config, session, logger): if config.get('slack_token'): config['slack_token'] = kms_decrypt(config, logger, session, 'slack_token') self.caching = self.cache_factory(config, config.get('cache_engine', None)) self.config = config self.logger = logger self.session = session self.email_handler = EmailDelivery(config, session, logger) def cache_factory(self, config, type): if type == 'redis': return Redis(redis_host=config.get('redis_host'), redis_port=int(config.get('redis_port', 6379)), db=0) else: return None def get_to_addrs_slack_messages_map(self, sqs_message): resource_list = [] for resource in sqs_message['resources']: resource_list.append(resource) slack_messages = {} # Check for Slack targets in 'to' action and render appropriate template. for target in sqs_message.get('action', ()).get('to'): if target == 'slack://owners': to_addrs_to_resources_map = \ self.email_handler.get_email_to_addrs_to_resources_map(sqs_message) for to_addrs, resources in six.iteritems( to_addrs_to_resources_map): resolved_addrs = self.retrieve_user_im(list(to_addrs)) if not resolved_addrs: continue for address, slack_target in resolved_addrs.items(): slack_messages[address] = get_rendered_jinja( slack_target, sqs_message, resources, self.logger, 'slack_template', 'slack_default') self.logger.debug( "Generating messages for recipient list produced by resource owner resolution." ) elif target.startswith('https://hooks.slack.com/'): slack_messages[target] = get_rendered_jinja( target, sqs_message, resource_list, self.logger, 'slack_template', 'slack_default') elif target.startswith('slack://webhook/#') and self.config.get( 'slack_webhook'): webhook_target = self.config.get('slack_webhook') slack_messages[webhook_target] = get_rendered_jinja( target.split('slack://webhook/#', 1)[1], sqs_message, resource_list, self.logger, 'slack_template', 'slack_default') self.logger.debug("Generating message for webhook %s." % self.config.get('slack_webhook')) elif target.startswith( 'slack://') and self.email_handler.target_is_email( target.split('slack://', 1)[1]): resolved_addrs = self.retrieve_user_im( [target.split('slack://', 1)[1]]) for address, slack_target in resolved_addrs.items(): slack_messages[address] = get_rendered_jinja( slack_target, sqs_message, resource_list, self.logger, 'slack_template', 'slack_default') elif target.startswith('slack://#'): resolved_addrs = target.split('slack://#', 1)[1] slack_messages[resolved_addrs] = get_rendered_jinja( resolved_addrs, sqs_message, resource_list, self.logger, 'slack_template', 'slack_default') self.logger.debug( "Generating message for specified Slack channel.") return slack_messages def slack_handler(self, sqs_message, slack_messages): for key, payload in slack_messages.items(): self.logger.info( "Sending account:%s policy:%s %s:%s slack:%s to %s" % (sqs_message.get('account', ''), sqs_message['policy']['name'], sqs_message['policy']['resource'], str(len(sqs_message['resources'])), sqs_message['action'].get( 'slack_template', 'slack_default'), key)) self.send_slack_msg(key, payload) def retrieve_user_im(self, email_addresses): list = {} if not self.config['slack_token']: self.logger.info("No Slack token found.") for address in email_addresses: if self.caching and self.caching.get(address): self.logger.debug('Got Slack metadata from cache for: %s' % address) list[address] = self.caching.get(address) continue response = requests.post( url='https://slack.com/api/users.lookupByEmail', data={ 'email': address }, headers={ 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Bearer %s' % self.config.get('slack_token') }).json() if not response["ok"]: if "headers" in response.keys( ) and "Retry-After" in response["headers"]: self.logger.info( "Slack API rate limiting. Waiting %d seconds", int(response.headers['retry-after'])) time.sleep(int(response.headers['Retry-After'])) continue elif response["error"] == "invalid_auth": raise Exception("Invalid Slack token.") elif response["error"] == "users_not_found": self.logger.info("Slack user ID not found.") if self.caching: self.caching.set(address, {}) continue else: slack_user_id = response['user']['id'] if 'enterprise_user' in response['user'].keys(): slack_user_id = response['user']['enterprise_user']['id'] self.logger.debug("Slack account %s found for user %s", slack_user_id) if self.caching: self.logger.debug('Writing user: %s metadata to cache.', address) self.caching.set(address, slack_user_id) list[address] = slack_user_id return list def send_slack_msg(self, key, message_payload): if key.startswith('https://hooks.slack.com/'): response = requests.post( url=key, data=message_payload, headers={'Content-Type': 'application/json'}) else: response = requests.post( url='https://slack.com/api/chat.postMessage', data=message_payload, headers={ 'Content-Type': 'application/json;charset=utf-8', 'Authorization': 'Bearer %s' % self.config.get('slack_token') }) if response.status_code == 429 and "Retry-After" in response.headers: self.logger.info("Slack API rate limiting. Waiting %d seconds", int(response.headers['retry-after'])) time.sleep(int(response.headers['Retry-After'])) return elif response.status_code != 200: self.logger.info("Error in sending Slack message: %s" % response.json()) return
class SlackDelivery(object): def __init__(self, config, session, logger): if config.get('slack_token'): config['slack_token'] = kms_decrypt(config, logger, session, 'slack_token') self.caching = self.cache_factory(config, config.get('cache_engine', None)) self.config = config self.logger = logger self.session = session self.email_handler = EmailDelivery(config, session, logger) def cache_factory(self, config, type): if type == 'redis': return Redis(redis_host=config.get('redis_host'), redis_port=int(config.get('redis_port', 6379)), db=0) else: return None def get_to_addrs_slack_messages_map(self, sqs_message): resource_list = [] for resource in sqs_message['resources']: resource_list.append(resource) slack_messages = {} # Check for Slack targets in 'to' action and render appropriate template. for target in sqs_message.get('action', ()).get('to'): if target == 'slack://owners': to_addrs_to_resources_map = \ self.email_handler.get_email_to_addrs_to_resources_map(sqs_message) for to_addrs, resources in six.iteritems(to_addrs_to_resources_map): resolved_addrs = self.retrieve_user_im(list(to_addrs)) if not resolved_addrs: continue for address, slack_target in resolved_addrs.iteritems(): slack_messages[address] = get_rendered_jinja( slack_target, sqs_message, resources, self.logger, 'slack_template', 'slack_default') self.logger.debug( "Generating messages for recipient list produced by resource owner resolution.") elif target.startswith('slack://webhook/#') and self.config.get('slack_webhook'): webhook_target = self.config.get('slack_webhook') slack_messages[webhook_target] = get_rendered_jinja( target.split('slack://webhook/#', 1)[1], sqs_message, resource_list, self.logger, 'slack_template', 'slack_default') self.logger.debug( "Generating message for webhook %s." % self.config.get('slack_webhook')) elif target.startswith('slack://') and self.email_handler.target_is_email( target.split('slack://', 1)[1]): resolved_addrs = self.retrieve_user_im([target.split('slack://', 1)[1]]) for address, slack_target in resolved_addrs.iteritems(): slack_messages[address] = get_rendered_jinja( slack_target, sqs_message, resource_list, self.logger, 'slack_template', 'slack_default') elif target.startswith('slack://#'): resolved_addrs = target.split('slack://#', 1)[1] slack_messages[resolved_addrs] = get_rendered_jinja( resolved_addrs, sqs_message, resource_list, self.logger, 'slack_template', 'slack_default') self.logger.debug("Generating message for specified Slack channel.") return slack_messages def slack_handler(self, sqs_message, slack_messages): for key, payload in slack_messages.iteritems(): self.logger.info("Sending account:%s policy:%s %s:%s slack:%s to %s" % ( sqs_message.get('account', ''), sqs_message['policy']['name'], sqs_message['policy']['resource'], str(len(sqs_message['resources'])), sqs_message['action'].get('slack_template', 'slack_default'), json.loads(payload, strict=False)["channel"]) ) self.send_slack_msg(key, payload) def retrieve_user_im(self, email_addresses): list = {} if not self.config['slack_token']: self.logger.info("No Slack token found.") for address in email_addresses: if self.caching and self.caching.get(address): self.logger.debug('Got Slack metadata from cache for: %s' % address) list[address] = self.caching.get(address) continue response = requests.post( url='https://slack.com/api/users.lookupByEmail', data={'email': address}, headers={'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Bearer %s' % self.config.get('slack_token')}).json() if not response["ok"]: if "headers" in response.keys() and "Retry-After" in response["headers"]: self.logger.info( "Slack API rate limiting. Waiting %d seconds", int(response.headers['retry-after'])) time.sleep(int(response.headers['Retry-After'])) continue elif response["error"] == "invalid_auth": raise Exception("Invalid Slack token.") elif response["error"] == "users_not_found": self.logger.info("Slack user ID not found.") if self.caching: self.caching.set(address, {}) continue else: slack_user_id = response['user']['id'] if 'enterprise_user' in response['user'].keys(): slack_user_id = response['user']['enterprise_user']['id'] self.logger.debug( "Slack account %s found for user %s", slack_user_id) if self.caching: self.logger.debug('Writing user: %s metadata to cache.', address) self.caching.set(address, slack_user_id) list[address] = slack_user_id return list def send_slack_msg(self, key, message_payload): if key.startswith('https://hooks.slack.com/'): response = requests.post( url=key, data=message_payload, headers={'Content-Type': 'application/json'}) else: response = requests.post( url='https://slack.com/api/chat.postMessage', data=message_payload, headers={'Content-Type': 'application/json;charset=utf-8', 'Authorization': 'Bearer %s' % self.config.get('slack_token')}) if response.status_code == 429 and "Retry-After" in response.headers: self.logger.info( "Slack API rate limiting. Waiting %d seconds", int(response.headers['retry-after'])) time.sleep(int(response.headers['Retry-After'])) return elif response.status_code != 200: self.logger.info("Error in sending Slack message: %s" % response.json()) return