Skip to content

Commit

Permalink
Add basic auth support via URL
Browse files Browse the repository at this point in the history
  • Loading branch information
flands committed Nov 17, 2017
1 parent b1fd952 commit 24b189b
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 16 deletions.
16 changes: 16 additions & 0 deletions loginsightwebhookdemo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import requests
import logging
import re
import base64


app = Flask(__name__)
Expand Down Expand Up @@ -231,6 +232,21 @@ def callapi(url, method='post', payload=None, headers=None, auth=None, check=Tru
return ("%s" % r.text, r.status_code, None)


def basicauth(payload=None):
"""
Decode basic auth if applicable
"""
bauth = None
try:
bauth = str.split(str(payload.headers['Authorization']))
bauth = base64.b64decode(bauth[1])
bauth = bauth.split(':')
logging.info(bauth)
except:
pass
return bauth


@app.route("/")
def _introduction():
"""This help text."""
Expand Down
11 changes: 9 additions & 2 deletions loginsightwebhookdemo/bugzilla.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python


from loginsightwebhookdemo import app, parse, callapi
from loginsightwebhookdemo import app, parse, callapi, basicauth
from flask import request, json
import logging

Expand All @@ -13,7 +13,7 @@

# Parameters
BUGZILLAURL = ''
# Basic auth -- required if TOKEN is not passed in URL
# Basic auth -- required if BASIC or TOKEN is not passed in URL
BUGZILLAUSER = ''
BUGZILLAPASS = ''
# Required fields -- if not passed in URL
Expand All @@ -39,6 +39,13 @@ def bugzilla(ALERTID=None, TOKEN=None, PRODUCT=None, COMPONENT=None, VERSION=Non
Requires BUGZILLA* parameters to be defined.
You can pass an authentication token in the URL. For basic auth, pass `-` as the token.
"""
bauth = basicauth(request)
if bauth is not None:
global BUGZILLAUSER
global BUGZILLAPASS
BUGZILLAUSER = bauth[0]
BUGZILLAPASS = bauth[1]

if (not BUGZILLAURL or
((not BUGZILLAUSER or not BUGZILLAPASS) and (not TOKEN or TOKEN == '-')) or
((not BUGZILLAPRODUCT or not BUGZILLACOMPONENT or not BUGZILLAVERSION) and not VERSION)):
Expand Down
9 changes: 8 additions & 1 deletion loginsightwebhookdemo/jira.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python

from loginsightwebhookdemo import app, parse, callapi
from loginsightwebhookdemo import app, parse, callapi, basicauth
from flask import request, json
import logging

Expand All @@ -12,6 +12,7 @@

# jira parameters
JIRAURL = ''
# Only required if not passed in URL
JIRAUSER = ''
JIRAPASS = ''

Expand All @@ -28,6 +29,12 @@ def jira(ALERTID=None, PROJECT=None, ISSUETYPE='Bug'):
Requires JIRA* parameters to be defined.
"""

bauth = basicauth(request)
if bauth is not None:
global JIRAUSER
global JIRAPASS
JIRAUSER = bauth[0]
JIRAPASS = bauth[1]
if not JIRAURL or not JIRAUSER or not JIRAPASS or not PROJECT:
return ("JIRA* parameters must be set, please edit the shim!", 500, None)

Expand Down
23 changes: 14 additions & 9 deletions loginsightwebhookdemo/moogsoft.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@

"""
This shim only supports vROps payloads due to requirements for Moogsoft payload (resourceId, criticality/severity,
and update status such as "closed" or "updated". If alerting from Log Insight is required, it should be handled
and update status such as "closed" or "updated". If alerting from Log Insight is required, it should be handled
through forwarding the query alert to vROps.
The recommendations are not part of the alert payload so callbacks to vROps are made to retreive them and include
The recommendations are not part of the alert payload so callbacks to vROps are made to retreive them and include
them in the payload for Moog. Additionally, the impacted resource properties are also provided in the moog payload.
Moog expects a severity of 0 when an alert is cancelled.
Moog expects a severity of 0 when an alert is cancelled.
Moog expects timestamp in seconds.
See Moogsoft documentation for payload key descriptions and expected values. Thanks to Ray Webb with Moogsoft for
help testing this shim.
"""
help testing this shim.
"""

from loginsightwebhookdemo import app, parse, callapi
from loginsightwebhookdemo import app, parse, callapi, basicauth
from flask import request, json
import logging

Expand All @@ -28,7 +28,7 @@


# This shim also calls back to vROps for additional info so
# the vROps parameters are required
# the vROps parameters are required

# Parameters
# Example: https://<IP of moog server>:<port>
Expand All @@ -46,7 +46,7 @@
VERIFY = True

###########################################
# Call backs for getting more information
# Call backs for getting more information
# from vROps for impacted resource
###########################################

Expand Down Expand Up @@ -98,7 +98,12 @@ def moogsoft(ALERTID=None):
Information about this shim.
Requires moogsoft* parameters to be defined.
"""

bauth = basicauth(request)
if bauth is not none:
global moogsoftUSER
global moogsoftPASS
moogsoftUSER = bauth[0]
moogsoftPASS = bauth[1]
if (not moogsoftURL or (not moogsoftUSER ) or (not moogsoftPASS) or (not vropsURL) or (not vropsUser) or (not vropsPass)):
return ("moogsoft* and vrops* parameters must be set, please edit the shim!", 500, None)

Expand Down
9 changes: 8 additions & 1 deletion loginsightwebhookdemo/servicenow.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python

from loginsightwebhookdemo import app, parse, callapi
from loginsightwebhookdemo import app, parse, callapi, basicauth
from flask import request, json
import logging

Expand All @@ -12,6 +12,7 @@

# ServiceNow parameters
SERVICENOWURL = ''
# Only required if not passed in URL
SERVICENOWUSER = ''
SERVICENOWPASS = ''

Expand All @@ -26,6 +27,12 @@ def servicenow(ALERTID=None):
Requires SERVICENOW* parameters to be defined.
"""

bauth = basicauth(request)
if bauth is not None:
global SERVICENOWUSER
global SERVICENOWPASS
SERVICENOWUSER = bauth[0]
SERVICENOWPASS = bauth[1]
if not SERVICENOWURL or not SERVICENOWUSER or not SERVICENOWPASS:
return ("SERVICENOW* parameters must be set, please edit the shim!", 500, None)

Expand Down
8 changes: 7 additions & 1 deletion loginsightwebhookdemo/vrealizeorchestrator.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python

from loginsightwebhookdemo import app, parse, callapi
from loginsightwebhookdemo import app, parse, callapi, basicauth
from flask import request, json
import base64
import re
Expand Down Expand Up @@ -47,6 +47,12 @@ def vro(WORKFLOWID=None, TOKEN=None, HOK=None, ALERTID=None):
The `WORKFLOWID` and optionally `TOKEN` is passed in the webhook URL.
The workflow is responsible for parsing base64 -> json -> messages
"""
bauth = basicauth(request)
if bauth is not None:
global VROUSER
global VROPASS
VROUSER = bauth[0]
VROPASS = bauth[1]
if not WORKFLOWID:
return ("WORKFLOWID must be set in the URL (e.g. /endpoint/vro/<WORKFLOWID>", 500, None)
if not re.match('[a-z0-9-]+', WORKFLOWID, flags=re.IGNORECASE):
Expand Down
8 changes: 7 additions & 1 deletion loginsightwebhookdemo/zendesk.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python

from loginsightwebhookdemo import app, parse, callapi
from loginsightwebhookdemo import app, parse, callapi, basicauth
from flask import request, json
import logging

Expand Down Expand Up @@ -29,6 +29,12 @@ def zendesk(ALERTID=None, EMAIL=None, TOKEN=None):
Requires ZENDESK* parameters to be defined.
"""

bauth = basicauth(request)
if bauth is not None:
global ZENDESKUSER
global ZENDESKPASS
ZENDESKUSER = bauth[0]
ZENDESKPASS = bauth[1]
if (not ZENDESKURL or (not ZENDESKUSER and not EMAIL) or (not ZENDESKPASS and not ZENDESKTOKEN and not TOKEN)):
return ("ZENDESK* parameters must be set, please edit the shim!", 500, None)
if not ZENDESKUSER:
Expand Down
11 changes: 10 additions & 1 deletion tests/bugzilla_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def test_bugzilla_wrongpass():
loginsightwebhookdemo.bugzilla.VERIFY = True
payload = generate_alertname()

rsp = client.post('/endpoint/bugzilla/' + TOKEN, data=payload, content_type="application/json")
rsp = client.post('/endpoint/bugzilla/' + TOKEN, data=payload, content_type="application/json", headers={'authorization': 'Basic YWJjOjEyMw=='})
assert rsp.status == '200 OK'

payload = generate_alertname()
Expand All @@ -96,6 +96,15 @@ def test_bugzilla_nopass():
assert rsp.status == '500 INTERNAL SERVER ERROR'


def test_bugzilla_basicauth():
payload = generate_alertname()

rsp = client.post('/endpoint/bugzilla/-/' + PRODUCT + '/' + COMPONENT + '/' + VERSION, data=payload, content_type="application/json", headers={'authorization': 'Basic YWJjOjEyMw=='})
assert rsp.status == '401 UNAUTHORIZED'
rsp = client.post('/endpoint/bugzilla/-/' + PRODUCT + '/' + COMPONENT + '/' + VERSION, data=payload, content_type="application/json", headers={'authorization': 'Basic bG9naW5zaWdodC1tYXJrZXRwbGFjZUB2bXdhcmUuY29tOkwwZzFuczFnaHQh'})
assert rsp.status == '200 OK'


def test_bugzilla_wrongtoken():
loginsightwebhookdemo.bugzilla.BUGZILLAPASS = 'L0g1ns1ght!'
payload = generate_alertname()
Expand Down
19 changes: 19 additions & 0 deletions tests/init_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import json
import requests
import requests_mock

import loginsightwebhookdemo

Expand Down Expand Up @@ -204,6 +205,24 @@ def test_callapi():
assert 400 == loginsightwebhookdemo.callapi('http://httpbin.org/status/400', 'get', 'test')[1]


def test_basicauth():
adapter = requests_mock.Adapter()
session = requests.Session()
session.mount('mock', adapter)
adapter.register_uri('GET', 'mock://test.com/headers', headers={'a': 'b'}, text='resp')
request = session.get('mock://test.com/headers')
bauth = loginsightwebhookdemo.basicauth(request)
assert bauth is None
adapter = requests_mock.Adapter()
session = requests.Session()
session.mount('mock', adapter)
adapter.register_uri('GET', 'mock://test.com/headers', headers={'Authorization': 'Basic YWJjOjEyMw=='}, text='resp')
request = session.get('mock://test.com/headers')
bauth = loginsightwebhookdemo.basicauth(request)
assert bauth[0] == 'abc'
assert bauth[1] == '123'


def test_homepage():
rsp = conftest.client.get('/')
assert rsp.status == '200 OK'
Expand Down

0 comments on commit 24b189b

Please sign in to comment.