Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Modify auth0 cron script to obtain bearer token (#1674)
Browse files Browse the repository at this point in the history
  • Loading branch information
pwnbus committed Aug 25, 2020
1 parent d5c54b3 commit 33f138d
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 14 deletions.
6 changes: 3 additions & 3 deletions cron/auth02mozdef.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"mozdef": {
"url": "http://localhost:8080/events"
},
// Generate the token on https://manage{-dev}.{mozilla.}auth0.com/#/apis (Management API)
// url should be in the form of ttps://auth.{mozilla.}auth0.com/api/v2/logs
// Url should be in the form of https://auth.{mozilla.}auth0.com
"auth0": {
"reqnr": 100,
"token": "<add_token>",
"client_id": "<add_client_id>",
"client_secret": "<add_client_secret>",
"url": "<add_url>"
},
"state_file": "/opt/mozdef/envs/mozdef/cron/auth02mozdef.state",
Expand Down
67 changes: 56 additions & 11 deletions cron/auth02mozdef.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
import os
import requests
import traceback
import pickle
from jose import jwt, exceptions
from datetime import datetime, timedelta

import mozdef_client as mozdef

Expand Down Expand Up @@ -309,22 +312,23 @@ def load_state(fpath):
"""Load last msg id we've read from auth0 (log index).
@fpath string (path to state file)
"""
state = 0
try:
with open(fpath) as fd:
state = fd.read().split("\n")[0]
state = pickle.load(open(fpath, "rb"))
except IOError:
pass
# Oh, you're new.
state = {
'fromid': 0,
'bearer': None,
}
return state


def save_state(fpath, state):
"""Saves last msg id we've read from auth0 (log index).
@fpath string (path to state file)
@state int (state value)
@state dict (state value)
"""
with open(fpath, mode="w") as fd:
fd.write(str(state) + "\n")
pickle.dump(state, open(fpath, "wb"))


def byteify(input):
Expand All @@ -343,7 +347,7 @@ def fetch_auth0_logs(config, headers, fromid):
lastid = fromid

r = requests.get(
"{url}?take={reqnr}&sort=date:1&per_page={reqnr}&from={fromid}&include_totals=true".format(
"{url}/api/v2/logs?take={reqnr}&sort=date:1&per_page={reqnr}&from={fromid}&include_totals=true".format(
url=config.auth0.url, reqnr=config.auth0.reqnr, fromid=fromid
),
headers=headers,
Expand Down Expand Up @@ -403,6 +407,37 @@ def fetch_auth0_logs(config, headers, fromid):
return (-1, -1, -1, lastid)


def fetch_new_bearer(config):
data = {
"client_id": config.auth0.client_id,
"client_secret": config.auth0.client_secret,
"audience": "{}/api/v2/".format(config.auth0.url),
"grant_type": "client_credentials",
}
headers = {
"content-type": "application/json"
}
resp = requests.post("{}/oauth/token".format(config.auth0.url), json=data, headers=headers)
if not resp.ok:
raise Exception(resp.text)

resp_data = hjson.loads(resp.text)
return resp_data['access_token']


def verify_bearer(bearer):
# Verify the bearer token is not expired
try:
id_token = jwt.get_unverified_claims(token=bearer)
token_expiry = datetime.fromtimestamp(id_token['exp'])
# To ensure the bearer token doesn't run out during execution
# we pad the time comparision with 30 minutes
return (datetime.now() + timedelta(minutes=30)) < token_expiry
except exceptions.JOSEError as e:
logger.error("Unable to parse token : {} : {}".format(bearer, e))
return False


def main():
# Configuration loading
config_location = os.path.dirname(sys.argv[0]) + "/" + "auth02mozdef.json"
Expand All @@ -413,9 +448,18 @@ def main():
logger.error("No configuration file 'auth02mozdef.json' found.")
sys.exit(1)

headers = {"Authorization": "Bearer {}".format(config.auth0.token), "Accept": "application/json"}
state = load_state(config.state_file)
# If bearer isn't set, reach out to auth0 for it
if state['bearer'] is None:
state['bearer'] = fetch_new_bearer(config)
else:
# Verify bearer token is still valid
if not verify_bearer(state['bearer']):
state['bearer'] = fetch_new_bearer(config)

headers = {"Authorization": "Bearer {}".format(state['bearer']), "Accept": "application/json"}

fromid = load_state(config.state_file)
fromid = state['fromid']
# Auth0 will interpret a 0 state as an error on our hosted instance, but will accept an empty parameter "as if it was 0"
if fromid == 0 or fromid == "0":
fromid = ""
Expand All @@ -433,7 +477,8 @@ def main():
break
fromid = lastid

save_state(config.state_file, lastid)
state['fromid'] = lastid
save_state(config.state_file, state)


if __name__ == "__main__":
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pycparser==2.17
pymongo==3.6.1
pynsive==0.2.6
python-dateutil==2.6.1
python-jose==3.2.0
pytz==2017.3
PyYAML==5.1.1
requests-jwt==0.5.3
Expand Down

0 comments on commit 33f138d

Please sign in to comment.