Skip to content

Commit

Permalink
added oauth2 to authenticate with azure oauth2
Browse files Browse the repository at this point in the history
  • Loading branch information
pablodav committed Sep 12, 2018
1 parent 547bd79 commit ca7462b
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 6 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
0.6.0
* Add oauth2 to authenticate with azure oauth2
0.5.1
* fix on curl line, add --fail to fail on every HTTP response that is non OK
0.1
Expand Down
2 changes: 1 addition & 1 deletion curlnagios/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.5.1
0.6.0
50 changes: 48 additions & 2 deletions curlnagios/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

# Import required libs for sharepointhealth
from .plugin_check import curlCheck # Change this to your own class
from .oauth2_token import GetOauth2Token as Azureoauth
import argparse
import sys

Expand All @@ -28,17 +29,34 @@
def parse_args(args):
"""
Information extracted from: https://mkaz.com/2014/07/26/python-argparse-cookbook/
https://docs.python.org/3/library/argparse.html
:return: parse.parse_args(args) object
You can use obj.option, example:
options = parse_args(args)
options.user # to read username
"""
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter,
description='nagios plugin to check some url using curl and some other code')

parser.add_argument('-u', '--url', dest='url', nargs='?', default=None, const=None,
help='url to check \n')
parser.add_argument('-e', '--extra_args', dest='extra_args', nargs='?', default=None, const=None,
help='extra args to add to curl, see curl manpage \n')

# Arguments to check using OAuth2
parser.add_argument('--client_id', dest='client_id', nargs='?', default=None, const=None,
help='oauth2 client_id example client id: 6731de76-14a6-49ae-97bc-6eba6914391e \n')
parser.add_argument('--scope', dest='scope', nargs='?', default=None, const=None,
help='oauth2 scope https://company.onmicrosoft.com/some-unique-number-for-scope/.default \n')
parser.add_argument('--client_secret', dest='client_secret', nargs='?', default=None, const=None,
help='oauth2 client_secret client password \n')
parser.add_argument('--grant_type', dest='grant_type', nargs='?', default='client_credentials', const=None,
help='oauth2 grant_type \n')
parser.add_argument('--auth_url', dest='auth_url', nargs='?', default=None, const=None,
help='oauth2 auth_url example: https://login.microsoftonline.com/company.onmicrosoft.com/oauth2/v2.0/token \n')
parser.add_argument('--oauth2', action='store_true',
help='''Flag to use or not token for oauth2 before creating the request, used to check published services that uses azure oauth2 \n
See https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#refresh-the-access-token \n''')

if not args:
raise SystemExit(parser.print_help())
Expand All @@ -50,8 +68,36 @@ def cli_execution(options):
"""
: param: options: arguments from parse.parse_args(args) (see parse_args function)
"""
auth_args = ''
# Creating access_token to authenticate with azure oauth2
if options.oauth2:
if not options.client_id:
sys.exit('param client_id is required when using oauth2')
if not options.scope:
sys.exit('param scope is required when using oauth2')
if not options.client_secret:
sys.exit('param client_secret is required when using oauth2')
if not options.auth_url:
sys.exit('param auth_url is required when using oauth2')

oauth_obj = Azureoauth(client_id = options.client_id,
scope = options.scope,
client_secret = options.client_secret,
grant_type = options.grant_type,
auth_url = options.auth_url)
auth_tuple = oauth_obj.get_token()
auth_http_code = auth_tuple[1]
if auth_http_code != 200:
sys.exit('Error getting access_token, http_code != 200, http_code: {}'.format(auth_http_code))

access_token = auth_tuple[0]['access_token']
header_token = {"Authorization": "Bearer {}".format(access_token)}
# https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#use-the-access-token
auth_args = "--header 'Authorization: {}'".format(header_token['Authorization'])

curlnagiosobj = curlCheck(URL=options.url,
extra_args=options.extra_args)
extra_args=options.extra_args,
auth_args=auth_args)

def collect_data():
# use new object class HealthMonitor
Expand Down
75 changes: 75 additions & 0 deletions curlnagios/oauth2_token.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#
# documentation:
# https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
import requests
import json

# Will support with access token

class GetOauth2Token:
def __init__(self, client_id, scope, client_secret,
grant_type = 'client_credentials',
auth_url = 'https://login.microsoftonline.com/company.onmicrosoft.com/oauth2/v2.0/token'):
"""
reference: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-access-token
The Authority configured on the client MUST match the one configured on the server.
The Scope configured on the client MUST match the one configured on the server, followed by the .default suffix.
The Client Id is the ApplicationId of the client application configured on the Microsoft Application Registration Portal.
The Client Key is the Password generated on the client.
param client_id: example client id: 6731de76-14a6-49ae-97bc-6eba6914391e
param scope: example: https://company.onmicrosoft.com/some-unique-number-for-scope/.default
param client_secret: "client password secret here"
param grant_type: default is "client_credentials"
param auth_url: use the correct one for your organization and application server, default example
https://login.microsoftonline.com/company.onmicrosoft.com/oauth2/v2.0/token
"""
self.client_id = client_id
self.scope = scope
self.client_secret = client_secret
self.grant_type = grant_type
self.auth_url = auth_url

def get_token(self):
"""
return: tuple dict with access_token, status_code
{'access_token': 'tokenid'
'expires_in': 3600,
'ext_expires_in': 0,
'token_type': 'Bearer'}, 200
"""
# Request access token:
# https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-access-token

headers = {'Content-Type': 'application/x-www-form-urlencoded'}
url = self.auth_url
data = { "client_id": self.client_id,
"scope": self.scope,
"client_secret": self.client_secret,
"grant_type": self.grant_type
}
# requests doc http://docs.python-requests.org/en/v0.10.7/user/quickstart/#custom-headers
r = requests.post(url=url, data=data, headers=headers)

return r.json(), r.status_code

def url_check(self, url_check):
"""
Just example howto proceed with the token got
param url_check: url to check with authenticated token
"""
# Use the access token:
# https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#use-the-access-token

get_token = self.get_token()
access_token = get_token[0]['access_token']
header_token = {"Authorization": "Bearer {}".format(access_token)}
rt = requests.get(url=url_check, headers=header_token)

return rt.json(), rt.status_code

# Refresh? will need to check if we are going to do it (don't think so)
# https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#refresh-the-access-token
6 changes: 4 additions & 2 deletions curlnagios/plugin_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
import subprocess

class curlCheck:
def __init__(self, URL, extra_args):
def __init__(self, URL, extra_args, auth_args=''):
"""
:param URL: provide url to get/put data.
:param extra_args: any argument for curl command
:param auth_args: normally used internally by the code to add HEADERS with authentication args.
"""
self.url = URL
self.extra_args = extra_args
self.auth_args = auth_args

self.std_args = '''" {\\"response_code\\": \\"%{http_code}\\",
\\"dns_time\\": \\"%{time_namelookup}\\",
Expand All @@ -34,7 +36,7 @@ def collect_data(self):
"""
### some code here
### or calling external modules
cmdline = "curl {} --fail -s -o /dev/null {} -w \\ {}".format(self.url, self.extra_args, self.std_args)
cmdline = "curl {} {} --fail -s -o /dev/null {} -w \\ {}".format(self.url, self.auth_args, self.extra_args, self.std_args)

retrcode, retroutput = subprocess.getstatusoutput(cmdline)
jsonoutput = json.loads(retroutput)
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
rstcheck
rstcheck
requests>=2.19.1

0 comments on commit ca7462b

Please sign in to comment.