diff --git a/playbooks/Azure_AD_Account_Locking.json b/playbooks/Azure_AD_Account_Locking.json new file mode 100644 index 0000000000..6b9a92df22 --- /dev/null +++ b/playbooks/Azure_AD_Account_Locking.json @@ -0,0 +1,274 @@ +{ + "blockly": false, + "blockly_xml": "", + "category": "Account Locking", + "coa": { + "data": { + "description": "Accepts user name that needs to be disabled in Azure Active Directory. Generates an observable output based on the status of account locking or disabling.", + "edges": [ + { + "id": "port_0_to_port_2", + "sourceNode": "0", + "sourcePort": "0_out", + "targetNode": "2", + "targetPort": "2_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_2_to_port_3", + "sourceNode": "2", + "sourcePort": "2_out", + "targetNode": "3", + "targetPort": "3_in" + }, + { + "id": "port_4_to_port_1", + "sourceNode": "4", + "sourcePort": "4_out", + "targetNode": "1", + "targetPort": "1_in" + }, + { + "id": "port_3_to_port_5", + "sourceNode": "3", + "sourcePort": "3_out", + "targetNode": "5", + "targetPort": "5_in" + }, + { + "conditions": [ + { + "index": 0 + } + ], + "id": "port_5_to_port_4", + "sourceNode": "5", + "sourcePort": "5_out", + "targetNode": "4", + "targetPort": "4_in" + } + ], + "hash": "76828347e693a60201c3b9342e6f493ee5253566", + "nodes": { + "0": { + "data": { + "advanced": { + "join": [] + }, + "functionName": "on_start", + "id": "0", + "type": "start" + }, + "errors": {}, + "id": "0", + "type": "start", + "warnings": {}, + "x": 19.999999999999986, + "y": -3.197442310920451e-13 + }, + "1": { + "data": { + "advanced": { + "join": [] + }, + "functionName": "on_finish", + "id": "1", + "type": "end" + }, + "errors": {}, + "id": "1", + "type": "end", + "warnings": {}, + "x": 19.999999999999986, + "y": 860 + }, + "2": { + "data": { + "advanced": { + "customName": "user name filter", + "customNameId": 0, + "description": "Filter user name inputs to route inputs to appropriate actions.", + "join": [], + "note": "Filter user name inputs to route inputs to appropriate actions." + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "!=", + "param": "playbook_input:user", + "value": "" + } + ], + "conditionIndex": 0, + "customName": "user_name_check", + "logic": "and" + } + ], + "functionId": 1, + "functionName": "user_name_filter", + "id": "2", + "type": "filter" + }, + "errors": {}, + "id": "2", + "type": "filter", + "warnings": { + "config": [ + "Reconfigure invalid datapath." + ] + }, + "x": 60, + "y": 140 + }, + "3": { + "data": { + "action": "disable user", + "actionType": "generic", + "advanced": { + "customName": "disable user account", + "customNameId": 0, + "description": "Disable the user attributes for filtered playbook inputs.", + "join": [], + "note": "Disable the user attributes for filtered playbook inputs." + }, + "connector": "Azure AD Graph", + "connectorConfigs": [ + "azure_ad_graph" + ], + "connectorId": "c6d3b801-5c26-4abd-9e89-6d8007e2778f", + "connectorVersion": "v1", + "functionId": 1, + "functionName": "disable_user_account", + "id": "3", + "parameters": { + "user_id": "filtered-data:user_name_filter:condition_1:playbook_input:user" + }, + "requiredParameters": [ + { + "data_type": "string", + "field": "user_id" + } + ], + "type": "action" + }, + "errors": {}, + "id": "3", + "type": "action", + "warnings": {}, + "x": 0, + "y": 320 + }, + "4": { + "data": { + "advanced": { + "customName": "username observables", + "customNameId": 0, + "description": "Format a normalized output for each user.", + "join": [], + "note": "Format a normalized output for each user." + }, + "functionId": 1, + "functionName": "username_observables", + "id": "4", + "inputParameters": [ + "filtered-data:filter_disable_result:condition_1:disable_user_account:action_result.parameter.user_id", + "filtered-data:filter_disable_result:condition_1:disable_user_account:action_result.status", + "filtered-data:filter_disable_result:condition_1:disable_user_account:action_result.message" + ], + "outputVariables": [ + "observable_array" + ], + "type": "code" + }, + "errors": {}, + "id": "4", + "type": "code", + "userCode": "\n # Write your custom code here...\n username_observables__observable_array = []\n \n for user_id, status, msg in zip(filtered_result_0_parameter_user_id, filtered_result_0_status, filtered_result_0_message):\n user_acc_status = {\n \"type\": \"Azure AD Account\",\n \"value\": user_id,\n \"message\": msg,\n \"status\": status\n }\n username_observables__observable_array.append(user_acc_status)\n #phantom.debug(username_observables__observable_array)\n", + "warnings": {}, + "x": 0, + "y": 680 + }, + "5": { + "data": { + "advanced": { + "customName": "filter disable result", + "customNameId": 0, + "description": "filter check if the user is disabled successfully.", + "join": [], + "note": "filter check if the user is disabled successfully." + }, + "conditions": [ + { + "comparisons": [ + { + "conditionIndex": 0, + "op": "==", + "param": "disable_user_account:action_result.status", + "value": "success" + } + ], + "conditionIndex": 0, + "customName": "disabled_success", + "logic": "and" + } + ], + "functionId": 2, + "functionName": "filter_disable_result", + "id": "5", + "type": "filter" + }, + "errors": {}, + "id": "5", + "type": "filter", + "warnings": {}, + "x": 60, + "y": 500 + } + }, + "notes": "Inputs: users\nInteractions: Azure AD Graph\nActions: Account Locking/Disabling\nOutputs: observables" + }, + "input_spec": [ + { + "contains": [ + "user name", + "azure user principal name" + ], + "description": "A user name provided to be disable - Azure AD", + "name": "user" + } + ], + "output_spec": [ + { + "contains": [], + "datapaths": [ + "username_observables:custom_function:observable_array" + ], + "deduplicate": false, + "description": "An array of observable dictionaries ", + "metadata": {}, + "name": "observable" + } + ], + "playbook_type": "data", + "python_version": "3", + "schema": "5.0.9", + "version": "6.0.0.114895" + }, + "create_time": "2023-05-25T07:40:09.337037+00:00", + "draft_mode": false, + "labels": [ + "*" + ], + "tags": [ + "user", + "azure_ad_graph", + "disable_account", + "D3-AL" + ] +} \ No newline at end of file diff --git a/playbooks/Azure_AD_Account_Locking.png b/playbooks/Azure_AD_Account_Locking.png new file mode 100644 index 0000000000..61329eb164 Binary files /dev/null and b/playbooks/Azure_AD_Account_Locking.png differ diff --git a/playbooks/Azure_AD_Account_Locking.py b/playbooks/Azure_AD_Account_Locking.py new file mode 100644 index 0000000000..725e08f17f --- /dev/null +++ b/playbooks/Azure_AD_Account_Locking.py @@ -0,0 +1,165 @@ +""" +Accepts user name that needs to be disabled in Azure Active Directory. Generates an observable output based on the status of account locking or disabling. +""" + + +import phantom.rules as phantom +import json +from datetime import datetime, timedelta + + +@phantom.playbook_block() +def on_start(container): + phantom.debug('on_start() called') + + # call 'user_name_filter' block + user_name_filter(container=container) + + return + +@phantom.playbook_block() +def user_name_filter(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("user_name_filter() called") + + ################################################################################ + # Filter user name inputs to route inputs to appropriate actions. + ################################################################################ + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["playbook_input:user", "!=", ""] + ], + name="user_name_filter:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + disable_user_account(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + return + + +@phantom.playbook_block() +def disable_user_account(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("disable_user_account() called") + + # phantom.debug('Action: {0} {1}'.format(action['name'], ('SUCCEEDED' if success else 'FAILED'))) + + ################################################################################ + # Disable the user attributes for filtered playbook inputs. + ################################################################################ + + filtered_input_0_user = phantom.collect2(container=container, datapath=["filtered-data:user_name_filter:condition_1:playbook_input:user"]) + + parameters = [] + + # build parameters list for 'disable_user_account' call + for filtered_input_0_user_item in filtered_input_0_user: + if filtered_input_0_user_item[0] is not None: + parameters.append({ + "user_id": filtered_input_0_user_item[0], + }) + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.act("disable user", parameters=parameters, name="disable_user_account", assets=["azure_ad_graph"], callback=filter_disable_result) + + return + + +@phantom.playbook_block() +def username_observables(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("username_observables() called") + + ################################################################################ + # Format a normalized output for each user. + ################################################################################ + + filtered_result_0_data_filter_disable_result = phantom.collect2(container=container, datapath=["filtered-data:filter_disable_result:condition_1:disable_user_account:action_result.parameter.user_id","filtered-data:filter_disable_result:condition_1:disable_user_account:action_result.status","filtered-data:filter_disable_result:condition_1:disable_user_account:action_result.message"]) + + filtered_result_0_parameter_user_id = [item[0] for item in filtered_result_0_data_filter_disable_result] + filtered_result_0_status = [item[1] for item in filtered_result_0_data_filter_disable_result] + filtered_result_0_message = [item[2] for item in filtered_result_0_data_filter_disable_result] + + username_observables__observable_array = None + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + username_observables__observable_array = [] + + for user_id, status, msg in zip(filtered_result_0_parameter_user_id, filtered_result_0_status, filtered_result_0_message): + user_acc_status = { + "type": "Azure AD Account", + "value": user_id, + "message": msg, + "status": status + } + username_observables__observable_array.append(user_acc_status) + #phantom.debug(username_observables__observable_array) + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_run_data(key="username_observables:observable_array", value=json.dumps(username_observables__observable_array)) + + return + + +@phantom.playbook_block() +def filter_disable_result(action=None, success=None, container=None, results=None, handle=None, filtered_artifacts=None, filtered_results=None, custom_function=None, **kwargs): + phantom.debug("filter_disable_result() called") + + ################################################################################ + # filter check if the user is disabled successfully. + ################################################################################ + + # collect filtered artifact ids and results for 'if' condition 1 + matched_artifacts_1, matched_results_1 = phantom.condition( + container=container, + conditions=[ + ["disable_user_account:action_result.status", "==", "success"] + ], + name="filter_disable_result:condition_1") + + # call connected blocks if filtered artifacts or results + if matched_artifacts_1 or matched_results_1: + username_observables(action=action, success=success, container=container, results=results, handle=handle, filtered_artifacts=matched_artifacts_1, filtered_results=matched_results_1) + + return + + +@phantom.playbook_block() +def on_finish(container, summary): + phantom.debug("on_finish() called") + + username_observables__observable_array = json.loads(_ if (_ := phantom.get_run_data(key="username_observables:observable_array")) != "" else "null") # pylint: disable=used-before-assignment + + output = { + "observable": username_observables__observable_array, + } + + ################################################################################ + ## Custom Code Start + ################################################################################ + + # Write your custom code here... + + ################################################################################ + ## Custom Code End + ################################################################################ + + phantom.save_playbook_output_data(output=output) + + return \ No newline at end of file diff --git a/playbooks/Azure_AD_Account_Locking.yml b/playbooks/Azure_AD_Account_Locking.yml new file mode 100644 index 0000000000..8835daf6c5 --- /dev/null +++ b/playbooks/Azure_AD_Account_Locking.yml @@ -0,0 +1,24 @@ +name: Azure AD Locking Account +id: c3c0157d-7da0-46cb-8b97-327ee92f591c +version: 1 +date: '2023-05-08' +author: Teoderick Contreras, Splunk +type: Investigation +description: "Accepts user, to be disabled using Azure AD Graph connector. This playbook produces a normalized observables output for each user and device." +playbook: Azure_AD_Locking_Account +how_to_implement: This input playbook requires the Azure AD Graph connector to be configured. + It is designed to work in conjunction with the Dynamic Attribute Lookup playbook or other playbooks in the same style. +references: [] +app_list: + - Azure AD Graph API +tags: + platform_tags: + - user + - D3-AL + - azure_ad_graph + - disable_account + playbook_type: Input + vpe_type: Modern + playbook_fields: [] + product: + - Splunk SOAR