Skip to content

Commit

Permalink
Add support for Slack Apps in addition to webhook URLs (#28)
Browse files Browse the repository at this point in the history
* Updating CONTRIBUTING.md to reference the new default 'main' branch

* Adding support for Slack App OAuth Tokens and adding a note about Webhook URLs being deprecated

* Updating packages.json version

* Wording suggestions

Co-authored-by: Shane Welcher <32134114+swelcher@users.noreply.github.com>

* Updating the UI with more information and using tabs to separate OAuth and Webhook methods

* Minor wording touch ups

Co-authored-by: Shane Welcher <32134114+swelcher@users.noreply.github.com>
  • Loading branch information
bclarkejr and swelcher authored Oct 3, 2022
1 parent bf6b53c commit 9f183ef
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 78 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ If you want to learn more, please consult this [tutorial on how pull requests wo
Here's an overview of how you can make a pull request against this project:

1. Fork the [Slack Alerts GitHub repository](https://github.com/splunk/slack-alerts)
2. Clone your fork using git and create a branch off master
2. Clone your fork using git and create a branch off `main`
3. Run all the tests to verify your environment
4. Make your changes, commit and push once your tests have passed
5. Submit a pull request through the GitHub website using the changes from your forked codebase
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "splunk-slack-alerts",
"version": "2.2.0",
"version": "2.3.0",
"description": "Slack alert action for Splunk Enterprise",
"private": true,
"splunk": {
Expand Down
17 changes: 15 additions & 2 deletions src/app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,24 @@ App installation requires admin privileges.

In order to setup the app, navigate to "Settings" -> "Alert actions". Click on "Setup Slack Alerts".

On the setup screen, you'll need to supply a Slack App OAuth token. To set up a new Slack App for your
workspace, follow the instructions on https://api.slack.com/apps.

Once you have the Slack App created, you **must** give the app permission to the `chat:write` and
`chat:write.public` OAuth scopes in your Slack workspace. These scopes allow your app to write messages
to every public channel and user in your workspace. The app will also be able to write to any private
channel that it is added to.

#### Deprecated configuration option

> This alert action was originally built using the Slack Webhook URL functionality. Slack has recently
> deprecated this feature in favor of the Slack App method above. **Webhook URL support may be
> removed in a future release of Slack.** For more information see
> https://slack.com/apps/A0F7XDUAZ-incoming-webhooks
On the setup screen you'll want to supply a Webhook URL. You can obtain this URL by configuring a
custom integration for you Slack workspace.

For more information see https://slack.com/apps/A0F7XDUAZ-incoming-webhooks

## Troubleshooting

### Known issue with Setup
Expand Down
9 changes: 9 additions & 0 deletions src/app/README/alert_actions.conf.spec
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
[slack]

param.slack_app_oauth_token = <string>
* The Slack App OAuth token that Splunk should use to send Slack alerts. This
* can be obtained by create a new Slack App for your workspace at
* https://api.slack.com/apps.
* This takes precendence over the deprecated webhook_url parameter (below).

param.webhook_url = <string>
* DEPRECATED - Slack has deprecated this feature and will possibly be removed in the future.
* The webhook URL to send the Slack message requests to. This can be obtained
* by creating a new "Incoming webhook" integration in Slack.

param.from_user = <string>
* DEPRECATED - This is only used in the deprecated webhook_url parameter.
* The name of the user sending the Slack message. By default this is "Splunk".

param.from_user_icon = <string>
* DEPRECATED - This is only used in the deprecated webhook_url parameter.
* URL to an icon to show as the avatar for the Slack message. By default this is
* a Splunk icon.

Expand Down
4 changes: 4 additions & 0 deletions src/app/README/savedsearches.conf.spec
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ action.slack.param.fields = <csv-list>
* It is possible to use wildcards, such as "*" for all fields or "foo*" for
* prefixed fields, etc.

action.slack.param.slack_app_oauth_token_override = <string>
* Override the Slack App OAuth token for a single alert. This is useful when wanting
* to send some alerts to different Slack teams.

action.slack.param.webhook_url_override = <string>
* Override the Slack webhook URL for a single alert. This useful when wanting
* to send some alerts to different Slack teams.
61 changes: 43 additions & 18 deletions src/app/bin/slack.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,34 +99,59 @@ def build_slack_message(payload):

def send_slack_message(payload):
try:
req = {}
config = payload.get('configuration')
url = config.get('webhook_url', '')
if config.get('webhook_url_override'):
url = config.get('webhook_url_override', '')
log("INFO Using webhook URL from webhook_url_override: %s" % url)
elif not url:
log("FATAL No webhook URL configured and no override specified")
return ERROR_CODE_VALIDATION_FAILED
else:
log("INFO Using configured webhook URL: %s" % url)
body = json.dumps(build_slack_message(payload))

if not url.startswith('https:'):
log("FATAL Invalid webhook URL specified. The URL must use HTTPS.")
return ERROR_CODE_VALIDATION_FAILED
# Since Slack webhook URLs are deprecated, we will bias towards using Slack Apps, if they are provided
is_using_slack_app = (("slack_app_oauth_token" in config and config["slack_app_oauth_token"]) or ("slack_app_oauth_token_override" in config and config["slack_app_oauth_token_override"]))
if is_using_slack_app:
token = config.get("slack_app_oauth_token", "")
if config.get("slack_app_oauth_token_override"):
token = config.get("slack_app_oauth_token_override")
log("INFO Using Slack App OAuth token from slack_app_oauth_token_override: %s" % token)
else:
log("INFO Using configured Slack App OAuth token: %s" % token)

body = json.dumps(build_slack_message(payload))
log('DEBUG Calling url="https://slack.com/api/chat.postMessage" with token=%s and body=%s' % (token, body))
req = urllib.request.Request("https://slack.com/api/chat.postMessage", ensure_binary(body), {"Content-Type": "application/json", 'Authorization': "Bearer %s" % token})

# To preserve backwards compatibility, we will fallback to the webhook_url configuration, if a Slack App OAuth token is not provided
else:
url = config.get('webhook_url', '')
if config.get('webhook_url_override'):
url = config.get('webhook_url_override', '')
log("INFO Using webhook URL from webhook_url_override: %s" % url)
elif not url:
log("FATAL No webhook URL configured and no override specified")
return ERROR_CODE_VALIDATION_FAILED
else:
log("INFO Using configured webhook URL: %s" % url)

if not url.startswith('https:'):
log("FATAL Invalid webhook URL specified. The URL must use HTTPS.")
return ERROR_CODE_VALIDATION_FAILED

log('DEBUG Calling url="%s" with body=%s' % (url, body))
req = urllib.request.Request(url, ensure_binary(body), {"Content-Type": "application/json"})

log('DEBUG Calling url="%s" with body=%s' % (url, body))
req = urllib.request.Request(url, ensure_binary(body), {"Content-Type": "application/json"})
try:
res = urllib.request.urlopen(req)
body = res.read()
res_body = str(res.read())
log("INFO Slack API responded with HTTP status=%d" % res.code)
log("DEBUG Slack API response: %s" % body)
log("DEBUG Slack API response: %s" % res_body)
if 200 <= res.code < 300:
if "invalid_auth" in res_body:
log("FATAL The Slack App OAuth token provided is invalid or does not have the permission to post messages to the channel provided.")
return ERROR_CODE_FORBIDDEN
if "channel_not_found" in res_body or "channel_is_archived" in res_body:
log("FATAL The channel provided was not found or is archived. If the channel is private, please make sure the Slack App is added to the channel.")
return ERROR_CODE_CHANNEL_NOT_FOUND
if "error" in res_body:
return ERROR_CODE_UNKNOWN
return OK
except urllib.error.HTTPError as e:
log("ERROR HTTP request to Slack webhook URL failed: %s" % e)
log("ERROR HTTP request to Slack API failed: %s" % e)
try:
res = e.read()
log("ERROR Slack error response: %s" % res)
Expand Down
1 change: 1 addition & 0 deletions src/app/default/alert_actions.slap.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ description = Send a message to a Slack channel
icon_path = slack.png
python.version = python3
payload_format = json
param.slack_app_oauth_token =<@= process.env.NODE_ENV !== 'production' && process.env.SLACK_APP_OAUTH_TOKEN ? " " + process.env.SLACK_APP_OAUTH_TOKEN : "" @>
param.webhook_url =<@= process.env.NODE_ENV !== 'production' && process.env.SLACK_WEBHOOK_URL ? " " + process.env.SLACK_WEBHOOK_URL : "" @>
param.from_user = Splunk
param.from_user_icon = https://s3-us-west-1.amazonaws.com/ziegfried-apps/slack-alerts/splunk-icon.png
Expand Down
12 changes: 12 additions & 0 deletions src/app/default/data/ui/alerts/slack.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@
</div>
<br clear="both" />
<div style="clear: both; color: #888; margin: 25px 0 10px 0;">Advanced settings:</div>
<div style="clear: both" class="control-group">
<label class="control-label" for="slack_app_token_override">Slack App OAuth Token</label>

<div class="controls">
<input type="text" name="action.slack.param.slack_app_oauth_token_override" id="slack_fields" placeholder="Optional" />
<span class="help-block">
You can override the <a href="https://api.slack.com/apps" target="_blank" noreferer>Slack App OAuth Token</a> here
if you need to send the alert message to a different Slack team.
</span>
</div>
</div>
<br clear="both" />
<div style="clear: both" class="control-group">
<label class="control-label" for="slack_url_override">Webhook URL</label>

Expand Down
2 changes: 2 additions & 0 deletions src/ui/pages/slack_alerts_setup/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function loadAlertActionConfig() {
.then((data) => {
const d = data.entry[0].content;
return {
slack_app_oauth_token: d['param.slack_app_oauth_token'],
webhook_url: d['param.webhook_url'],
from_user: d['param.from_user'],
from_user_icon: d['param.from_user_icon'],
Expand All @@ -26,6 +27,7 @@ export function updateAlertActionConfig(data) {
{
method: 'POST',
body: [
`param.slack_app_oauth_token=${encodeURIComponent(data.slack_app_oauth_token)}`,
`param.webhook_url=${encodeURIComponent(data.webhook_url)}`,
`param.from_user=${encodeURIComponent(data.from_user)}`,
`param.from_user_icon=${encodeURIComponent(data.from_user_icon)}`,
Expand Down
Loading

0 comments on commit 9f183ef

Please sign in to comment.