Skip to content

Commit ca7462b

Browse files
committed
added oauth2 to authenticate with azure oauth2
1 parent 547bd79 commit ca7462b

File tree

6 files changed

+132
-6
lines changed

6 files changed

+132
-6
lines changed

CHANGELOG

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
0.6.0
2+
* Add oauth2 to authenticate with azure oauth2
13
0.5.1
24
* fix on curl line, add --fail to fail on every HTTP response that is non OK
35
0.1

curlnagios/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.5.1
1+
0.6.0

curlnagios/__main__.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
# Import required libs for sharepointhealth
55
from .plugin_check import curlCheck # Change this to your own class
6+
from .oauth2_token import GetOauth2Token as Azureoauth
67
import argparse
78
import sys
89

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

3841
parser.add_argument('-u', '--url', dest='url', nargs='?', default=None, const=None,
3942
help='url to check \n')
4043
parser.add_argument('-e', '--extra_args', dest='extra_args', nargs='?', default=None, const=None,
4144
help='extra args to add to curl, see curl manpage \n')
45+
46+
# Arguments to check using OAuth2
47+
parser.add_argument('--client_id', dest='client_id', nargs='?', default=None, const=None,
48+
help='oauth2 client_id example client id: 6731de76-14a6-49ae-97bc-6eba6914391e \n')
49+
parser.add_argument('--scope', dest='scope', nargs='?', default=None, const=None,
50+
help='oauth2 scope https://company.onmicrosoft.com/some-unique-number-for-scope/.default \n')
51+
parser.add_argument('--client_secret', dest='client_secret', nargs='?', default=None, const=None,
52+
help='oauth2 client_secret client password \n')
53+
parser.add_argument('--grant_type', dest='grant_type', nargs='?', default='client_credentials', const=None,
54+
help='oauth2 grant_type \n')
55+
parser.add_argument('--auth_url', dest='auth_url', nargs='?', default=None, const=None,
56+
help='oauth2 auth_url example: https://login.microsoftonline.com/company.onmicrosoft.com/oauth2/v2.0/token \n')
57+
parser.add_argument('--oauth2', action='store_true',
58+
help='''Flag to use or not token for oauth2 before creating the request, used to check published services that uses azure oauth2 \n
59+
See https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#refresh-the-access-token \n''')
4260

4361
if not args:
4462
raise SystemExit(parser.print_help())
@@ -50,8 +68,36 @@ def cli_execution(options):
5068
"""
5169
: param: options: arguments from parse.parse_args(args) (see parse_args function)
5270
"""
71+
auth_args = ''
72+
# Creating access_token to authenticate with azure oauth2
73+
if options.oauth2:
74+
if not options.client_id:
75+
sys.exit('param client_id is required when using oauth2')
76+
if not options.scope:
77+
sys.exit('param scope is required when using oauth2')
78+
if not options.client_secret:
79+
sys.exit('param client_secret is required when using oauth2')
80+
if not options.auth_url:
81+
sys.exit('param auth_url is required when using oauth2')
82+
83+
oauth_obj = Azureoauth(client_id = options.client_id,
84+
scope = options.scope,
85+
client_secret = options.client_secret,
86+
grant_type = options.grant_type,
87+
auth_url = options.auth_url)
88+
auth_tuple = oauth_obj.get_token()
89+
auth_http_code = auth_tuple[1]
90+
if auth_http_code != 200:
91+
sys.exit('Error getting access_token, http_code != 200, http_code: {}'.format(auth_http_code))
92+
93+
access_token = auth_tuple[0]['access_token']
94+
header_token = {"Authorization": "Bearer {}".format(access_token)}
95+
# https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#use-the-access-token
96+
auth_args = "--header 'Authorization: {}'".format(header_token['Authorization'])
97+
5398
curlnagiosobj = curlCheck(URL=options.url,
54-
extra_args=options.extra_args)
99+
extra_args=options.extra_args,
100+
auth_args=auth_args)
55101

56102
def collect_data():
57103
# use new object class HealthMonitor

curlnagios/oauth2_token.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#
2+
# documentation:
3+
# https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
4+
import requests
5+
import json
6+
7+
# Will support with access token
8+
9+
class GetOauth2Token:
10+
def __init__(self, client_id, scope, client_secret,
11+
grant_type = 'client_credentials',
12+
auth_url = 'https://login.microsoftonline.com/company.onmicrosoft.com/oauth2/v2.0/token'):
13+
"""
14+
reference: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-access-token
15+
The Authority configured on the client MUST match the one configured on the server.
16+
The Scope configured on the client MUST match the one configured on the server, followed by the .default suffix.
17+
The Client Id is the ApplicationId of the client application configured on the Microsoft Application Registration Portal.
18+
The Client Key is the Password generated on the client.
19+
20+
param client_id: example client id: 6731de76-14a6-49ae-97bc-6eba6914391e
21+
param scope: example: https://company.onmicrosoft.com/some-unique-number-for-scope/.default
22+
param client_secret: "client password secret here"
23+
param grant_type: default is "client_credentials"
24+
param auth_url: use the correct one for your organization and application server, default example
25+
https://login.microsoftonline.com/company.onmicrosoft.com/oauth2/v2.0/token
26+
"""
27+
self.client_id = client_id
28+
self.scope = scope
29+
self.client_secret = client_secret
30+
self.grant_type = grant_type
31+
self.auth_url = auth_url
32+
33+
def get_token(self):
34+
"""
35+
36+
return: tuple dict with access_token, status_code
37+
{'access_token': 'tokenid'
38+
'expires_in': 3600,
39+
'ext_expires_in': 0,
40+
'token_type': 'Bearer'}, 200
41+
"""
42+
# Request access token:
43+
# https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-access-token
44+
45+
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
46+
url = self.auth_url
47+
data = { "client_id": self.client_id,
48+
"scope": self.scope,
49+
"client_secret": self.client_secret,
50+
"grant_type": self.grant_type
51+
}
52+
# requests doc http://docs.python-requests.org/en/v0.10.7/user/quickstart/#custom-headers
53+
r = requests.post(url=url, data=data, headers=headers)
54+
55+
return r.json(), r.status_code
56+
57+
def url_check(self, url_check):
58+
"""
59+
Just example howto proceed with the token got
60+
61+
param url_check: url to check with authenticated token
62+
63+
"""
64+
# Use the access token:
65+
# https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#use-the-access-token
66+
67+
get_token = self.get_token()
68+
access_token = get_token[0]['access_token']
69+
header_token = {"Authorization": "Bearer {}".format(access_token)}
70+
rt = requests.get(url=url_check, headers=header_token)
71+
72+
return rt.json(), rt.status_code
73+
74+
# Refresh? will need to check if we are going to do it (don't think so)
75+
# https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#refresh-the-access-token

curlnagios/plugin_check.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
import subprocess
55

66
class curlCheck:
7-
def __init__(self, URL, extra_args):
7+
def __init__(self, URL, extra_args, auth_args=''):
88
"""
99
:param URL: provide url to get/put data.
1010
:param extra_args: any argument for curl command
11+
:param auth_args: normally used internally by the code to add HEADERS with authentication args.
1112
"""
1213
self.url = URL
1314
self.extra_args = extra_args
15+
self.auth_args = auth_args
1416

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

3941
retrcode, retroutput = subprocess.getstatusoutput(cmdline)
4042
jsonoutput = json.loads(retroutput)

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
rstcheck
1+
rstcheck
2+
requests>=2.19.1

0 commit comments

Comments
 (0)