Neighborhood watch for your SaaS apps.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

73 lines
2.8 KiB

import logging
from collections import Iterable
from apiclient import discovery
from oauth2client.service_account import ServiceAccountCredentials
logger = logging.getLogger(__name__)
TIMESTAMP_FIELD = "id.time"
USER_FIELD = "actor.email"
IP_FIELD = "ipAddress"
USER_AGENT_FIELD = "events.0.login_type"
FILTER_FIELD = "events.0.name"
FILTERED_EVENTS = ["login_failure"]
def poll(config):
data = []
scopes = ['https://www.googleapis.com/auth/admin.reports.audit.readonly']
credentials = ServiceAccountCredentials.from_json_keyfile_name(config["pollers"]["gsuite"]["credential_file"], scopes=scopes)
credentials = credentials.create_delegated(config["pollers"]["gsuite"]["admin_email"])
service = discovery.build('admin', 'reports_v1', credentials=credentials)
request = service.activities().list(userKey='all', applicationName='login')
for i in range(1, 101):
logger.info("Polling page %s..." % i)
results = request.execute()
activities = results.get('items', [])
for event in activities:
flattened = flatten(event)
if flattened[TIMESTAMP_FIELD] > str(config["last_polled"]["gsuite"]["last_polled_time"]):
data.append(flattened)
elif flattened[TIMESTAMP_FIELD] == str(config["last_polled"]["gsuite"]["last_polled_time"]):
if flattened["id.uniqueQualifier"] == config["last_polled"]["gsuite"]["last_polled_event"]["id.uniqueQualifier"]:
caught_up = True
break
else:
data.append(flattened)
else:
caught_up = True
break
request = service.activities().list_next(request, results)
if caught_up or request is None:
break
return data
def notify(config, alerts):
return
def flatten(event, prefix=''):
flattened = {}
for field_no, field in enumerate(event):
if 'keys' in dir(event):
# Special case "parameters" values. We should to treat those as dicts.
if field == "parameters":
for param in event[field]:
if isinstance(param["value"], Iterable) and not isinstance(param["value"], str):
flattened.update(param["value"], prefix + param["name"] + ".")
else:
flattened[prefix + param["name"]] = param["value"]
continue
else:
nextLevel = event[field]
currEntry = prefix + str(field)
else:
nextLevel = event[field_no]
currEntry = prefix + str(field_no)
if isinstance(nextLevel, Iterable) and not isinstance(nextLevel, str):
flattened.update(flatten(nextLevel, currEntry + "."))
else:
flattened[currEntry] = nextLevel
return flattened