diff --git a/lemur/plugins/bases/notification.py b/lemur/plugins/bases/notification.py index 410e65ec..36e94ef3 100644 --- a/lemur/plugins/bases/notification.py +++ b/lemur/plugins/bases/notification.py @@ -45,7 +45,7 @@ class ExpirationNotificationPlugin(NotificationPlugin): ] @property - def plugin_options(self): + def options(self): return list(self.default_options) + self.additional_options def send(self): diff --git a/lemur/plugins/lemur_slack/plugin.py b/lemur/plugins/lemur_slack/plugin.py index 4505b18b..3db831b3 100644 --- a/lemur/plugins/lemur_slack/plugin.py +++ b/lemur/plugins/lemur_slack/plugin.py @@ -5,7 +5,10 @@ :license: Apache, see LICENSE for more details. .. moduleauthor:: Harm Weites +.. moduleauthor:: Kevin Glisson """ +import json +import arrow from flask import current_app from lemur.plugins.bases import ExpirationNotificationPlugin from lemur.plugins import lemur_slack as slack @@ -13,10 +16,42 @@ from lemur.plugins import lemur_slack as slack import requests -def find_value(name, options): - for o in options: - if o['name'] == name: - return o['value'] +def create_certificate_url(name): + return 'https://{hostname}/#/certificates/{name}'.format( + hostname=current_app.config.get('LEMUR_HOSTNAME'), + name=name + ) + + +def create_expiration_attachments(messages): + attachments = [] + for message in messages: + attachments.append({ + 'title': message['name'], + 'title_link': create_certificate_url(message['name']), + 'color': 'danger', + 'fallback': '', + 'fields': [ + { + 'title': 'Owner', + 'value': message['owner'], + 'short': True + }, + { + 'title': 'Expires', + 'value': arrow.get(message['not_after']).format('dddd, MMMM D, YYYY'), + 'short': True + }, + { + 'title': 'Endpoints Detected', + 'value': len(message['endpoints']), + 'short': True + } + ], + 'text': '', + 'mrkdwn_in': ['text'] + }) + return attachments class SlackNotificationPlugin(ExpirationNotificationPlugin): @@ -38,9 +73,9 @@ class SlackNotificationPlugin(ExpirationNotificationPlugin): }, { 'name': 'username', 'type': 'str', - 'required': True, 'validation': '^.+$', 'helpMessage': 'The great storyteller', + 'default': 'Lemur' }, { 'name': 'recipients', 'type': 'str', @@ -50,19 +85,25 @@ class SlackNotificationPlugin(ExpirationNotificationPlugin): }, ] - @staticmethod - def send(event_type, message, targets, options, **kwargs): + def send(self, event_type, message, targets, options, **kwargs): """ A typical check can be performed using the notify command: `lemur notify` """ - msg = 'Certificate expiry pending for certificate:\n*%s*\nCurrent state is: _%s_' % (message[0]['name'], event_type) - body = '{"text": "%s", "channel": "%s", "username": "%s"}' % (msg, find_value('recipients', options), find_value('username', options)) + if event_type == 'expiration': + attachments = create_expiration_attachments(message) - current_app.logger.info("Sending message to Slack: %s" % body) - current_app.logger.debug("Sending data to Slack endpoint at %s" % find_value('webhook', options)) + if not attachments: + raise Exception('Unable to create message attachments') - r = requests.post(find_value('webhook', options), body) + body = { + 'text': 'Lemur Expiration Notification', + 'attachments': attachments, + 'channel': self.get_option('recipients', options), + 'username': self.get_option('username', options) + } + + r = requests.post(self.get_option('webhook', options), json.dumps(body)) if r.status_code not in [200]: - current_app.logger.error("Slack response: %s" % r.status_code) - raise + raise Exception('Failed to send message') + current_app.logger.error("Slack response: {0} Message Body: {1}".format(r.status_code, body)) diff --git a/lemur/plugins/lemur_slack/tests/conftest.py b/lemur/plugins/lemur_slack/tests/conftest.py new file mode 100644 index 00000000..0e1cd89f --- /dev/null +++ b/lemur/plugins/lemur_slack/tests/conftest.py @@ -0,0 +1 @@ +from lemur.tests.conftest import * # noqa diff --git a/lemur/plugins/lemur_slack/tests/test_slack.py b/lemur/plugins/lemur_slack/tests/test_slack.py new file mode 100644 index 00000000..d9983ac9 --- /dev/null +++ b/lemur/plugins/lemur_slack/tests/test_slack.py @@ -0,0 +1,34 @@ + + +def test_formatting(certificate): + from lemur.plugins.lemur_slack.plugin import create_expiration_attachments + from lemur.notifications.service import _get_message_data + data = [_get_message_data(certificate)] + + attachments = [ + { + 'title': 'certificate0', + 'color': 'danger', + 'fields': [ + { + 'short': True, + 'value': 'joe@example.com', + 'title': 'Owner' + }, + { + 'short': True, + 'value': u'Wednesday, January 1, 2020', + 'title': 'Expires' + }, { + 'short': True, + 'value': 0, + 'title': 'Endpoints Detected' + } + ], + 'title_link': 'https://lemur.example.com/#/certificates/certificate0', + 'mrkdwn_in': ['text'], + 'text': '', + 'fallback': '' + } + ] + assert attachments == create_expiration_attachments(data) diff --git a/lemur/tests/conf.py b/lemur/tests/conf.py index c146ca02..fa175519 100644 --- a/lemur/tests/conf.py +++ b/lemur/tests/conf.py @@ -33,6 +33,8 @@ LEMUR_RESTRICTED_DOMAINS = [] LEMUR_EMAIL = '' LEMUR_SECURITY_TEAM_EMAIL = ['security@example.com'] +LEMUR_HOSTNAME = 'lemur.example.com' + # Logging LOG_LEVEL = "DEBUG"