Hi,
Instead of configuring the output schema within the plugin step, I’ve found that the easiest way to use Python output as input in following steps is to create a loop and add your Python 3 plugin step within the loop:
Return the GraphQL data you want to use in following steps:
def run(params={}):
import json
from falconpy import IdentityProtection
falcon = IdentityProtection(client_id='{{$workflow.[cs_id]}}',client_secret=secret_key)
# When default values are provided for all variables, you can call the query without passing any variables.
idp_query = '''
query($primaryDisplayNames: [String!] = \"{{["Parse Username"].[output]}}\")
{entities(primaryDisplayNames: $primaryDisplayNames first:1) {
nodes {
primaryDisplayName
secondaryDisplayName
riskScoreSeverity
riskScore
roles {
type
}
riskFactors {
type
score
severity
}
accounts {
description
... on ActiveDirectoryAccountDescriptor {
ou
department
samAccountName
}
}
openIncidents(first:5 sortKey:START_TIME sortOrder:DESCENDING) {
nodes {
type
startTime
alertEvents {
eventSeverity
startTime
alertType
}
}
}
}
}}'''
response = falcon.graphql(query=idp_query)
r = json.dumps(response)
rr = json.loads(r)
return {'idpAzureUser': rr['body']['data']['entities']['nodes'][0]['riskScore'], 'idpAzureSamAcctName': rr['body']['data']['entities']['nodes'][0]['accounts'][0]['samAccountName']}
Configure a loop output variable with Output type = array, and Value to include in array = your python step:
Exit this loop. Add a new loop and select your output variable you just configured as the variable to repeat over:
After running the workflow we can see in the “Loop Output Variables” section the entire output from the Python step. Everything is now available from your Python step as input in following steps:
If I want to look at the response headers, I’d access it like this:
Instead of returning everything, if I want to return just 2 variables from the Python script: the account’s risk score (idpAzureUser) and SAM account name (idpAzureSamAcctName):
return {'idpAzureUser': rr['body']['data']['entities']['nodes'][0]['riskScore'], 'idpAzureSamAcctName': rr['body']['data']['entities']['nodes'][0]['accounts'][0]['samAccountName']}
I can then use the “idpAzureSamAcctName” loop output variable in my next loop:
If I want to grab a failed login count for the SAM account name, I could pass “idpAzureSamAcctName” to another Python step and return a total failed login count:
def run(params={}):
from falconpy import Discover
falcon = Discover(client_id='{{$workflow.[cs_id]}}',client_secret=secret_key)
max_rows = 10
all_ids = []
login_ts = '{{["Set Datetime Range - 1"].[date]}}'
filter_string = "{{["Loop Azure"].[$item].[idpAzureSamAcctName]}}"
logins_lookup = falcon.query_logins(limit=max_rows,filter=f"username:'{filter_string}'+login_timestamp:>'{login_ts}'")
if logins_lookup["status_code"] == 200:
identified_logins = logins_lookup["body"]["resources"]
if not identified_logins:
return {'CS_Discover_FailedLogins_Count': 0}
else:
logins_detail = falcon.get_logins(ids=identified_logins)["body"]["resources"]
# loop over the results and append all failed logins to our list
for login in logins_detail:
if login["login_status"] == "Failed":
all_ids.append(login)
else:
continue
# return total fail count using the len function
return {'CS_Discover_FailedLogins_Count': len(all_ids)}
else:
error_detail = logins_lookup["body"]["errors"]
for err in error_detail:
ecode = err["code"]
emsg = err["message"]
return {'ecode': ecode, 'emsg': emsg}
There is probably a better way to do all this but this works for me!
Chris