def _handle_check_results(self, param): self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) location = param['location'] ret_val, response = self._make_rest_call(location, action_result, params=None, headers=None) if (phantom.is_fail(ret_val)): return action_result.get_status() action_result.add_data(response) return action_result.set_status(phantom.APP_SUCCESS)
def _handle_list_intel_framework(self, param): self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) response = self._fetch_list_intel_framework(action_result) if response is None: return action_result.get_status() action_result.add_data(response) return action_result.set_status(phantom.APP_SUCCESS)
def _handle_list_input_framework(self, param): self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) ret_val, response = self._make_rest_call('/api/bro/input', action_result, params=None, headers=None) if (phantom.is_fail(ret_val)): return action_result.get_status() action_result.add_data(response) return action_result.set_status(phantom.APP_SUCCESS)
def _handle_send_email(self, param, action_result=None): if (action_result is None): action_result = self.add_action_result(ActionResult(dict(param))) try: status_code = self._send_email(param, action_result) except Exception as e: return action_result.set_status( phantom.APP_ERROR, "{} {}".format(SMTP_ERR_SMTP_SEND_EMAIL, self._get_error_message_from_exception(e))) return status_code
def _handle_domain_category(self, param): # Adding action handler message self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) # Add an action result object to self (BaseConnector) to represent the action for this param action_result = self.add_action_result(ActionResult(dict(param))) # Pass domain to the search domain = param['domain'] # Issue request to the tags endpoint endpoint = '/domain/{}/tags'.format(domain) # Make connection to the SecurityTrails endpoint ret_val, response = self._make_rest_call(endpoint, action_result) # Connect to Phantom Endpoint self.save_progress("Connecting to endpoint") if (phantom.is_fail(ret_val)): # the call to the 3rd party device or service failed, action result should contain all the error details # so just return from here message = "Failed Response to domain category." return action_result.set_status(phantom.APP_ERROR, status_message=message) # If domain has no tags try: response['tags'][0] except: response['tags'] = "No Results" # Create new python dictionary to store output data_output = {} # Create new python dictionary to store output data_output = response # Add the response into the data section action_result.add_data(data_output) # Add a dictionary that is made up of the most important values from data into the summary summary = action_result.update_summary({}) summary['domain'] = domain summary['tags'] = data_output['tags'] # Return success, no need to set the message, only the status # BaseConnector will create a textual message based off of the summary dictionary return action_result.set_status(phantom.APP_SUCCESS)
def _handle_lookup_ip(self, param): # Implement the handler here # use self.save_progress(...) to send progress messages back to the platform self.save_progress("In action handler for: {0}".format( self.get_action_identifier())) # Add an action result object to self (BaseConnector) to represent the action for this param action_result = self.add_action_result(ActionResult(dict(param))) """ # Access action parameters passed in the 'param' dictionary # Required values can be accessed directly required_parameter = param['required_parameter'] # Optional values should use the .get() function optional_parameter = param.get('optional_parameter', 'default_value') """ # make rest call ret_val, response = self._make_rest_call('/hostname', action_result, params=None, headers=None) if (phantom.is_fail(ret_val)): # the call to the 3rd party device or service failed, action result should contain all the error details # so just return from here return action_result.get_status() # Now post process the data, uncomment code as you deem fit # Add the response into the data section # action_result.add_data(response) response_dict = {'host_name': response} action_result.add_data(response_dict) action_result.add_data({}) # Add a dictionary that is made up of the most important values from data into the summary summary = action_result.update_summary({}) summary['host_name'] = response # Return success, no need to set the message, only the status # BaseConnector will create a textual message based off of the summary dictionary return action_result.set_status(phantom.APP_SUCCESS) # For now return Error with a message, in case of success we don't set the message, but use the summary return action_result.set_status(phantom.APP_ERROR, "Action not yet implemented")
def _get_file_from_url(self, param): action_result = self.add_action_result(ActionResult(dict(param))) disassembled = urlparse(param['url']) filename, file_ext = splitext(basename(disassembled.path)) guid = uuid.uuid4() local_dir = '/vault/tmp/{}'.format(guid) self.save_progress("Using temp directory: {0}".format(guid)) try: os.makedirs(local_dir) except Exception as e: return action_result.set_status( phantom.APP_ERROR, "Unable to create temporary folder '/vault/tmp'.", e) f_out_name = local_dir + '/online_file_{}_{}{}'.format( str(time.time()).replace('.', ''), filename, file_ext) self.save_progress('Fetching data from given url') file_resp = urllib.urlopen(param['url']) f_out = open(f_out_name, 'wb') f_out.write(file_resp.read()) f_out.close() vault_ret_dict = Vault.add_attachment( f_out_name, self.get_container_id(), file_name=os.path.basename(f_out_name)) data = {} if vault_ret_dict['succeeded']: data = { 'vault_id': vault_ret_dict[phantom.APP_JSON_HASH], 'file_name': os.path.basename(f_out_name), 'file_type': file_ext[1:], } action_result.set_status(phantom.APP_SUCCESS) else: action_result.set_status(phantom.APP_ERROR, phantom.APP_ERR_FILE_ADD_TO_VAULT) action_result.append_to_message(vault_ret_dict['message']) shutil.rmtree(local_dir) action_result.add_data(data) action_result.set_summary(data) return action_result.get_status()
def get_campaign_details(self, param): action_result = self.add_action_result(ActionResult(param)) campaign_id = self._handle_py_ver_compat_for_input_str(param.get('campaign_id')) campaign_url = PP_API_PATH_CAMPAIGN.format(campaign_id) params = {'format': 'json'} ret_val, data = self._make_rest_call(action_result, campaign_url, params=params) if phantom.is_fail(ret_val): return action_result.get_status() action_result.add_data(data) return action_result.set_status(phantom.APP_SUCCESS)
def _handle_lookup_hash(self, param): self.save_progress("In action handler for: {0}".format( self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) file_hash = param['file_hash'] data = {} if len(file_hash) == 64: data['sha256_hash'] = file_hash elif len(file_hash) == 32: data['md5_hash'] = file_hash else: return action_result.set_status( phantom.APP_ERROR, "File Hash length not supported. Please verify hash is sha256 (64 char) or md5 (32)" ) ret_val, response = self._make_rest_call('/payload', action_result, params=None, headers=None, method="post", data=data) if phantom.is_fail(ret_val): self.save_progress("Failed to contact URLhaus") return action_result.get_status() action_result.add_data(response) try: summary = action_result.update_summary({}) if response['query_status'] == "no_results": summary['message'] = "No results found for: {0}".format( file_hash) elif response['query_status'] == "ok": summary['firstseen'] = response['firstseen'] url_count = len(response['urls']) summary['url_count'] = url_count signature = response['signature'] summary[ 'message'] = "File Hash {0} observed being served by {1} URLs. Possible signature {2}".format( file_hash, url_count, signature) summary['query_status'] = response['query_status'] except Exception as e: error_msg = self._get_error_message_from_exception(e) return action_result.set_status(phantom.APP_ERROR, error_msg) return action_result.set_status(phantom.APP_SUCCESS)
def _whois_ip(self, param): action_result = self.add_action_result(ActionResult(dict(param))) ip = param[PASSIVETOTAL_JSON_IP] # Validation for checking valid IP or not (IPV4 as well as IPV6) if not self._is_ip(ip): return action_result.set_status( phantom.APP_ERROR, 'Please provide a valid IPV4 or IPV6 address') # Progress self.save_progress(PASSIVETOTAL_USING_BASE_URL, base_url=self._base_url) # Connectivity self.save_progress(phantom.APP_PROG_CONNECTING_TO_ELLIPSES, self._host) # Whois info ret_val, response, status_code = self._make_rest_call( '/whois', {'query': ip}, action_result) if (phantom.is_fail(ret_val)): # We don't seem to have any data _and_ the last call failed return action_result.get_status() if (not response): # return with a message return action_result.set_status(phantom.APP_SUCCESS, "No registrant info found") action_result.add_data(response) registrant = response.get('registrant') if (not registrant): # return with a message return action_result.set_status(phantom.APP_SUCCESS, "No registrant info found") action_result.update_summary({ 'city': registrant.get('city'), 'country': registrant.get('country'), 'organization': registrant.get('organization') }) return action_result.set_status(phantom.APP_SUCCESS)
def _handle_test_connectivity(self, param): action_result = self.add_action_result(ActionResult(dict(param))) self.save_progress("Connecting to endpoint") ret_val, response = self._make_rest_call('/', action_result, params=None, headers=None) if (phantom.is_fail(ret_val)): self.save_progress("Test Connectivity Failed.") return action_result.get_status() self.save_progress("Test Connectivity Passed") return action_result.set_status(phantom.APP_SUCCESS)
def _make_rest_call_abstract(self, endpoint, action_result, data=None, params=None, auth_mode="Bearer", method="post"): # Use this object for make_rest_call # Final status of action_result would be determined # after retry if token expired intermediate_action_result = ActionResult() response = None headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } # Generate new token if not available if not self._token: ret_code = self._generate_api_token(action_result) if phantom.is_fail(ret_code): return action_result.get_status(), response # Make rest call rest_ret_code, response = self._make_rest_call( endpoint, intermediate_action_result, headers, data, params, auth_mode, method) # If token is invalid in case of api calls other than generate token, generate new token and retry if auth_mode != "Basic" and 'Detail: invalid_token' in str( intermediate_action_result.get_message()): ret_code = self._generate_api_token(action_result) if phantom.is_fail(ret_code): return action_result.get_status(), response # Retry the rest call with new token generated rest_ret_code, response = self._make_rest_call( endpoint, intermediate_action_result, headers, data, params, auth_mode, method) # Assigning intermediate action_result to action_result, # since no further invocation required if phantom.is_fail(rest_ret_code): action_result.set_status(rest_ret_code, intermediate_action_result.get_message()) return action_result.get_status(), response return phantom.APP_SUCCESS, response
def _handle_update_finding(self, param): """ Updates the finding by adding or changing the feedback and comment of the finding :param detector_id: The ID of the detector :param finding_id: The ID of the finding :param feedback: Feedback value of the finding :param comment: Additional feedback about the finding return: Details of updated finding """ action_result = self.add_action_result(ActionResult(dict(param))) if phantom.is_fail(self._create_client(action_result)): return action_result.get_status() detector_id = param['detector_id'] finding_ids = param['finding_id'] feedback = param['feedback'] comments = param.get('comment') if comments: ret_val, response = self._make_boto_call( action_result, 'update_findings_feedback', DetectorId=detector_id, FindingIds=[finding_ids], Feedback=feedback, Comments=comments) else: ret_val, response = self._make_boto_call( action_result, 'update_findings_feedback', DetectorId=detector_id, FindingIds=[finding_ids], Feedback=feedback) if phantom.is_fail(ret_val): return action_result.get_status() try: del response['ResponseMetadata'] except: pass action_result.add_data(response) summary = action_result.update_summary({}) summary['total_updated_findings'] = action_result.get_data_size() return action_result.set_status(phantom.APP_SUCCESS)
def _handle_update_incident(self, param): # Implement the handler here # use self.save_progress(...) to send progress messages back to the platform self.save_progress("In action handler for: {0}".format( self.get_action_identifier())) # Add an action result object to self (BaseConnector) to represent the action for this param action_result = self.add_action_result(ActionResult(dict(param))) incident = param['incident'] params = {'incident': incident} incidentState = param['incident_state'] if incidentState == "acknowledge": endpoint = "/incident/acknowledge" if incidentState == "unacknowledge": endpoint = "/incident/unacknowledge" # Optional values should use the .get() function # optional_parameter = param.get('optional_parameter', 'default_value') # make rest call ret_val, response = self._make_rest_call(endpoint, action_result, params=params, headers=None, method="post") if (phantom.is_fail(ret_val)): return action_result.get_status() # Now post process the data, uncomment code as you deem fit # Add the response into the data section if response: action_result.add_data(response) summary = action_result.update_summary({}) summary['result'] = response.get('result') if response.get('result') == "success": return action_result.set_status(phantom.APP_SUCCESS) else: return action_result.set_status( phantom.APP_ERROR, "Error while communicating with Canary API") else: return action_result.set_status( phantom.APP_ERROR, "Error while communicating with Canary API")
def _handle_add_ip(self, param): self.save_progress( AWSWAF_INFO_ACTION.format(self.get_action_identifier())) # Add an action result object to self (BaseConnector) to represent the action for this param action_result = self.add_action_result(ActionResult(dict(param))) ip_set_id = param.get('ip_set_id') ip_set_name = param.get('ip_set_name') ip_address = param.get('ip_address') ip_address_list = [ x.strip() for x in ip_address.split(',') if x.strip() ] ip_type = self.validate_params(action_result, ip_set_id, ip_set_name, ip_address_list) ip_set = self.paginator(AWSWAF_DEFAULT_LIMIT, action_result, param) ip_set_id, ip_set_name = self._verify_ip_set(action_result, ip_set, ip_set_id, ip_set_name) if not ip_set_id: ip_set_name = param.get('ip_set_name') # create a new IP set with given IP addresses ret_val, resp_json = self._make_boto_call( action_result, 'create_ip_set', Name=ip_set_name, IPAddressVersion=ip_type, Addresses=ip_address_list) if phantom.is_fail(ret_val): return action_result.set_status(phantom.APP_ERROR, AWSWAF_ERR_CREATE_IPSET) action_result.set_status(phantom.APP_SUCCESS) ip_set_id = resp_json.get('Summary', {}).get('Id') action_result.add_data({'Id': ip_set_id}) else: ret_val = self._ip_update(action_result, ip_address_list, ip_set_id, ip_set_name) summary = action_result.update_summary({}) if phantom.is_fail(ret_val): summary['ip_status'] = AWSWAF_ADD_IP_FAILED summary['ip_status'] = AWSWAF_ADD_IP_SUCCESS return action_result.get_status()
def _handle_unarchive_finding(self, param): """ Unarchive Amazon GuardDuty findings specified by the detector ID and list of finding IDs :param detector_id: The ID of the detector :param finding_id: The ID of the finding return: Details of unarchived findings """ action_result = self.add_action_result(ActionResult(dict(param))) if phantom.is_fail(self._create_client(action_result)): return action_result.get_status() detector_id = param['detector_id'] finding_ids = param['finding_id'] # Comma separated list handling for 'finding_id' finding_ids = [x.strip() for x in finding_ids.split(',')] finding_ids = list(filter(None, finding_ids)) if not finding_ids: return action_result.set_status( phantom.APP_ERROR, AWSGUARDDUTY_INVALID_FINDING_ID_ERR_MSG) ret_val, valid_findings_ids = self._validate_findings_id( finding_ids, 'UNARCHIVED', action_result, detector_id) if not ret_val: return action_result.get_status() self.debug_print( "Valid finding IDs are: \n{}".format(valid_findings_ids)) while valid_findings_ids: ret_val, response = self._make_boto_call( action_result, 'unarchive_findings', DetectorId=detector_id, FindingIds=valid_findings_ids[:min(50, len(valid_findings_ids) )]) if phantom.is_fail(ret_val): return action_result.get_status() try: del response['ResponseMetadata'] except: pass action_result.add_data(response) del valid_findings_ids[:min(50, len(valid_findings_ids))] return action_result.set_status( phantom.APP_SUCCESS, AWSGUARDDUTY_UNARCHIVE_FINDING_SUCC_MSG)
def _handle_copy_contact(self, param): self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) scopes = [GOOGLE_CONTACTS_SCOPE, GOOGLE_OTHER_CONTACTS_SCOPE_READ_ONLY] ret_val, client = self._create_client(action_result, scopes) if phantom.is_fail(ret_val): self.debug_print(GOOGLE_CREATE_CLIENT_FAILED_MSG) return action_result.get_status() resource_name = param['resource_name'] if OTHER_CONTACTS_RESOURCE_NAME_PREFIX not in resource_name: return action_result.set_status(phantom.APP_ERROR, "Resource name of contact to be copied must be 'otherContact'") data = {} copy_mask = param.get('copy_mask', 'names,emailAddresses,phoneNumbers') # Validation for comma-separated value masks = [x.strip() for x in copy_mask.split(",")] masks = list(filter(None, masks)) if not masks: return action_result.set_status(phantom.APP_ERROR, INVALID_COMMA_SEPARATED_ERR_MSG.format('copy mask')) copy_mask = ",".join(masks) data.update({'copyMask': copy_mask}) try: response = client.otherContacts().copyOtherContactToMyContactsGroup(resourceName=resource_name, body=data).execute() except HttpError as e: if "_get_reason" in dir(e): return action_result.set_status(phantom.APP_ERROR, "{}. {}".format(GOOGLE_COPY_CONTACT_FAILED_MSG, e._get_reason())) err_msg = self._get_error_message_from_exception(e) self.debug_print("Exception message: {}".format(err_msg)) return action_result.set_status(phantom.APP_ERROR, GOOGLE_COPY_CONTACT_FAILED_MSG) except Exception as e: err_msg = self._get_error_message_from_exception(e) self.debug_print("Exception message: {}".format(err_msg)) return action_result.set_status(phantom.APP_ERROR, GOOGLE_COPY_CONTACT_FAILED_MSG) action_result.add_data(response) action_result.update_summary({'total_contacts_copied': 1}) return action_result.set_status(phantom.APP_SUCCESS, 'Successfully copied 1 contact')
def _test_connectivity(self, param): """ Called when the user depresses the test connectivity button on the Phantom UI. """ action_result = ActionResult( dict(param)) # Add an action result to the App Run self.add_action_result(action_result) self.debug_print("%s TEST_CONNECTIVITY %s" % (CSR_Connector.BANNER, param)) config = self.get_config() try: self.username = config["username"] self.password = config["password"] self.device = config["trigger_host"] except KeyError: self.debug_print("Error: {0}".format(KeyError)) return self.set_status_save_progress( phantom.APP_ERROR, "KeyError attempting to parse organization ID and name") self.debug_print("Username: {0}, Password: {1}".format( self.username, self.password)) ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(self.device, username=self.username, password=self.password, allow_agent=False, look_for_keys=False) csr_conn = ssh.invoke_shell() self.debug_print(type(csr_conn)) csr_conn.send('show version\n') time.sleep(1) resp = csr_conn.recv(99999) csr_conn.close() ssh.close() self.debug_print( "Initial test connectivity to device resp: {0}".format(resp)) if resp: self.debug_print("Connected to device: {0}".format(resp)) return self.set_status_save_progress( phantom.APP_SUCCESS, "SUCCESS! Connected to device") else: self.debug_print("Unable to connect to device: {0}".format(resp)) return self.set_status_save_progress( phantom.APP_ERROR, "FAILURE! Unable to connect to device")
def _handle_get_endpoint_info(self, param): self.save_progress("In action handler for: {0}".format( self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) ip_hostname = param['ip_hostname'] try: ret_val = self._get_agent_id(ip_hostname, action_result) except Exception as e: return action_result.set_status( phantom.APP_ERROR, "Error occurred while getting agent id : {0}".format(e)) self.save_progress('Agent query: ' + ret_val) if ret_val == '0': return action_result.set_status(phantom.APP_SUCCESS, "Endpoint not found") elif ret_val == '99': return action_result.set_status(phantom.APP_SUCCESS, "More than one endpoint found") else: summary = action_result.update_summary({}) summary['ip_hostname'] = ip_hostname summary['agent_id'] = ret_val # make rest call # GET /web/api/v1.6/agents/{id} headers = self.HEADER headers["Authorization"] = "APIToken %s" % self.token try: ret_val, response = self._make_rest_call( '/web/api/v2.0/agents?ids=' + ret_val, action_result, headers=headers) if (phantom.is_fail(ret_val)): return action_result.get_status() self.save_progress("ret_val: {0}".format(ret_val)) except Exception as ee: return action_result.set_status( phantom.APP_ERROR, "Error occurred while getting endpoint info : {0}".format( ee)) if not response.get('data'): return action_result.set_status( phantom.APP_ERROR, 'Found no details for the given endpoint') else: action_result.add_data(response.get('data')[0]) return action_result.set_status(phantom.APP_SUCCESS)
def _handle_add_category(self, param): """ Add an API-managed category in Forcepoint and build action_results. Args: param (dict): Action parameters Returns: ActionResult status: success/failure """ self.save_progress("In action handler for: {0}".format( self.get_action_identifier())) # Add an action result object to self (BaseConnector) to represent the action for this param action_result = self.add_action_result(ActionResult(dict(param))) summary = action_result.update_summary({}) cat = param['category'] desc = param.get('description') # Start transaction ret_val, transaction_id = self._start_transaction(action_result) if phantom.is_fail(ret_val): # Starting transaction failed, no rollback is required return action_result.get_status() summary['transaction_id'] = transaction_id # Create Category ret_val, response = self._create_category(action_result, transaction_id, cat, desc) if phantom.is_fail(ret_val): # Adding category failed, attempt rollback and return error ret_val, rollback_time = self._rollback_transaction( action_result, transaction_id) summary['rollback_time'] = rollback_time return action_result.get_status() action_result.add_data(response) # Commit changes ret_val, commit_time = self._commit_transaction( action_result, transaction_id) if phantom.is_fail(ret_val): # Commit failed, attempt rollback and return error ret_val, rollback_time = self._rollback_transaction( action_result, transaction_id) summary['rollback_time'] = rollback_time return action_result.get_status() summary['commit_time'] = commit_time message = 'Added category: {}'.format(cat) return action_result.set_status(phantom.APP_SUCCESS, message)
def _handle_list_groups(self, param): self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) uri = '/api/directory/find-groups' headers = self._get_request_headers(uri=uri, action_result=action_result) data = { 'meta': { 'pagination': { 'pageToken': None } }, 'data': [ ] } # Build request body params one by one. These params are optional data_object = {} if param.get('query') is not None: data_object['query'] = param.get('query') if param.get('source') is not None: data_object['source'] = param.get('source') if data_object: data['data'].append(data_object) limit = param.get('page_size') if limit is not None: limit = self._validate_integers(action_result, limit, "page_size") if limit is None: return action_result.get_status() ret_val, response = self._paginator(uri, action_result, limit=limit, headers=headers, method="post", data=data) if phantom.is_fail(ret_val): return ret_val response['groups'] = response.pop('data') action_result.add_data(response) summary = action_result.update_summary({}) summary['num_groups'] = len(response['groups'][0]['folders']) return action_result.set_status(phantom.APP_SUCCESS)
def _handle_whitelist_url(self, param): self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) uri = '/api/ttp/url/create-managed-url' headers = self._get_request_headers(uri=uri, action_result=action_result) # Flipping logic to make 'enable' checkboxes for better UX if param.get("enable_log_click"): log_click = False else: log_click = True if param.get("enable_rewrite"): rewrite = False else: rewrite = True if param.get("enable_user_awareness"): user_awareness = False else: user_awareness = True data = { "data": [ { "comment": param.get("comment"), "disableRewrite": rewrite, "url": param.get("url"), "disableUserAwareness": user_awareness, "disableLogClick": log_click, "action": "permit", "matchType": param.get("match_type", "explicit") } ] } ret_val, response = self._make_rest_call_helper(uri, action_result, headers=headers, method="post", data=data) if phantom.is_fail(ret_val): return ret_val action_result.add_data(response['data'][0]) summary = action_result.update_summary({}) summary['status'] = "Successfully added URL to whitelist" return action_result.set_status(phantom.APP_SUCCESS)
def locate_device(self, param): """ Locating client devices means walking a tree based on the API Key. The key is associated with one or more organizations, an organization can have one or more networks, each network can have multiple devices, and each device can have one or more client machines. Depending on the timespan specified, you may see differing results. Larger timespans may show the same client connected to multiple devices. Small timespans, may not return any results. """ self.debug_print("%s LOCATE_DEVICE parameters:\n%s" % (Meraki_Connector.BANNER, param)) action_result = ActionResult( dict(param)) # Add an action result to the App Run self.add_action_result(action_result) try: param["search_string"] # User left search_string empty except KeyError: param["search_string"] = "*" org_id_list = self.get_org_ids() for organization in org_id_list: networks_list = self.get_networks(organization["id"]) for network in networks_list: device_list = self.get_devices(network["id"]) for device in device_list: client_list = self.get_clients(device["serial"], param["timespan"]) for client in client_list: response = self.build_output_record( param["search_string"], organization, network, device, client) if response: action_result.add_data(response) if action_result.get_data_size() > 0: action_result.set_status(phantom.APP_SUCCESS) self.set_status_save_progress( phantom.APP_SUCCESS, "Returned: %s clients" % action_result.get_data_size()) else: action_result.set_status(phantom.APP_ERROR) self.set_status_save_progress( phantom.APP_ERROR, "Returned: %s clients" % action_result.get_data_size()) self.debug_print( "%s Data size: %s" % (Meraki_Connector.BANNER, action_result.get_data_size())) return action_result.get_status()
def _handle_users_by_sq(self, param, obj_type) -> bool: """Get users by the name of a Saved Query in Axonius.""" action_result: phantom.ActionResult = ActionResult(dict(param)) self.add_action_result(action_result) if not self._start_client(action_result): return action_result.get_status() try: sq_name: str = get_str_arg(key=SQ_NAME_KEY, param=param, required=True) max_rows: int = get_int_arg(key=MAX_ROWS_KEY, param=param, default=MAX_ROWS) except Exception as exc: err_msg = self._get_error_message_from_exception(exc) status = f"Failed to parse parameters: {err_msg}" return action_result.set_status(phantom.APP_ERROR, status) try: apiobj: AssetMixin = getattr(self._client, obj_type) except AttributeError: error_msg = "Error occurred while creating API object" return action_result.set_status(phantom.APP_ERROR, error_msg) progress = f"Fetching {obj_type} from Saved Query {sq_name!r}" self.save_progress(progress) try: assets: List[dict] = apiobj.get_by_saved_query(name=sq_name, max_rows=max_rows, field_null=True, field_null_value=[]) except Exception as exc: err_msg = self._get_error_message_from_exception(exc) status = f"Failed to fetch Saved Query: {err_msg}" return action_result.set_status(phantom.APP_ERROR, status) progress = f"Fetched {len(assets)} {obj_type} from Saved Query {sq_name!r}" self.save_progress(progress) for asset in assets: action_result.add_data(parse_asset(asset=asset)) summary: dict = action_result.update_summary({}) summary[f"total_{obj_type}"] = action_result.get_data_size() return action_result.set_status(phantom.APP_SUCCESS)
def _handle_create_ticket(self, param): self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) data = dict() fields = dict() ret_val, fields = self._get_fields(param, action_result) if phantom.is_fail(ret_val): return action_result.get_status() if fields: data.update(fields) title = param['title'] description = param['description'] data.update({'title': title, 'description': description}) severity = param.get('severity', 'Medium') try: int_severity = THEHIVE_SEVERITY_DICT[severity] except KeyError: return action_result.set_status(phantom.APP_ERROR, THEHIVE_ERR_INVALID_SEVERITY) data.update({'severity': int_severity}) tlp = param.get('tlp', 'Amber') try: int_tlp = THEHIVE_TLP_DICT[tlp] except KeyError: return action_result.set_status(phantom.APP_ERROR, THEHIVE_ERR_INVALID_TLP) data.update({'tlp': int_tlp}) if 'owner' in param: data.update({'owner': param.get('owner')}) # make rest call authToken = "Bearer {}".format(self._api_key) headers = {'Content-Type': 'application/json', 'Authorization': authToken} ret_val, response = self._make_rest_call('api/case', action_result, params=None, data=data, headers=headers, method="post") if phantom.is_fail(ret_val): return action_result.get_status() action_result.add_data(response) action_result.update_summary({'new_case_id': response.get('caseId')}) return action_result.set_status(phantom.APP_SUCCESS, "Successfully created a new case")
def _get_report(self, param): action_result = self.add_action_result(ActionResult(dict(param))) summary_data = action_result.update_summary({}) # Getting mandatory input params mati_id = param[DEEPSIGHT_JSON_MATI_ID] return_val, resp = self._make_rest_call( DEEPSIGHT_ENDPOINT_MATI_REPORT.format(mati_id=mati_id), action_result) # Something went wrong with the request if phantom.is_fail(return_val): return action_result.get_status() # Resource not found is treated as app success if (resp.get(DEEPSIGHT_JSON_RESOURCE_NOT_FOUND)): return action_result.set_status( phantom.APP_SUCCESS, DEEPSIGHT_REST_RESP_RESOURCE_NOT_FOUND_MSG) json_resp = resp.get(DEEPSIGHT_JSON_RESPONSE) # Fetching summary data summ_return_val, summ_resp = self._make_rest_call( DEEPSIGHT_ENDPOINT_MATI_REPORT_SUMMARY.format(mati_id=mati_id), action_result) # Something went wrong with the request if phantom.is_fail(summ_return_val): return action_result.get_status() if (summ_resp.get(DEEPSIGHT_JSON_RESPONSE)): summ_json_resp = summ_resp.get(DEEPSIGHT_JSON_RESPONSE) json_resp[DEEPSIGHT_JSON_REPORT_SUMMARY_DATA] = summ_json_resp summary_data['summary_title'] = summ_json_resp['title'] action_result.add_data(json_resp) # Download pdf and save to vault if enabled if param.get(DEEPSIGHT_JSON_DOWNLOAD_REPORT, False): download_ret_value = self._download_report_pdf( mati_id, self.get_container_id(), action_result, summary_data) # Something went wrong with the request if phantom.is_fail(download_ret_value): return action_result.get_status() return action_result.set_status(phantom.APP_SUCCESS)
def _modify_number(self, param, action_id): num_to_modify = param.get("number", param.get("default_number")) expression = param["expression"] action_result = self.add_action_result(ActionResult(dict(param))) if not num_to_modify: return action_result.set_status( phantom.APP_ERROR, 'A "number to modify" or "default number" must be provided' ) parser = Parser() try: result = parser.parse( expression.format(num_to_modify) ).evaluate({}) except Exception as err: try: return action_result.set_status( phantom.APP_ERROR, ( 'Error evaluating expression ' + expression.format(num_to_modify) + '. Error Details - ' + err.message ) ) except Exception as err2: return action_result.set_status( phantom.APP_ERROR, ( 'Expression format is invalid. ' + 'Error Details - ' + err2.message ) ) data = { 'expression': expression.format(num_to_modify), 'result': result } action_result.update_summary({'result': result}) action_result.add_data(data) return action_result.set_status( phantom.APP_SUCCESS, 'Operation successfully completed.' )
def _handle_tag_instance(self, param): self.save_progress( "In action handler for: {0}".format(self.get_action_identifier()) ) action_result = self.add_action_result(ActionResult(dict(param))) if not self._create_discovery_client(action_result): self.save_progress("Could not create API client") return action_result.get_status() zone = param["zone"] resourceid = param["id"] tags = param["tags"] tags = [tags.strip() for tags in tags.split(',')] tags = list(filter(None, tags)) if not tags: tags = "" else: tags = ",".join(tags) try: request = self._client.instances().get( project=self._project, zone=zone, instance=resourceid ) except Exception as e: err = self._get_error_message_from_exception(e) return action_result.set_status(phantom.APP_ERROR, err) ret_val, instance_details = self._send_request(request, action_result) if phantom.is_fail(ret_val): return ret_val tags_body = { "fingerprint": instance_details.get("tags", {}).get("fingerprint"), "items": tags.split(","), } try: request = self._client.instances().setTags( project=self._project, zone=zone, instance=resourceid, body=tags_body ) except Exception as e: err = self._get_error_message_from_exception(e) return action_result.set_status(phantom.APP_ERROR, err) ret_val, instance_details = self._send_request(request, action_result) action_result.add_data(instance_details) return action_result.set_status(phantom.APP_SUCCESS, "Success")
def _handle_reset_password(self, param): """ This method resets a users password. """ action_result = self.add_action_result(ActionResult(dict(param))) summary = action_result.update_summary({}) self.save_progress("In action handler for: {0}".format( self.get_action_identifier())) self.debug_print("[DEBUG] handle_reset_password") user = param['user'] pwd = param['password'] ar_data = {} if not self._ldap_bind(): self.debug_print("[DEBUG] handle_reset_password - no bind") return RetVal( action_result.set_status(phantom.APP_ERROR, self._ldap_bind.result)) if param.get("use_samaccountname", False): user_dn = self._sam_to_dn([user]) # _sam_to_dn requires a list. if len(user_dn) == 0 or user_dn[user] is False: return RetVal(action_result.set_status(phantom.APP_ERROR)) ar_data["user_dn"] = user_dn[user] ar_data["samaccountname"] = user user = user_dn[user] else: ar_data["user_dn"] = user try: self.debug_print("[DEBUG] about to attempt password reset...") ret = self._ldap_connection.extend.microsoft.modify_password( user, pwd) except Exception as e: self.debug_print("[DEBUG] handle_reset_password, e = {}".format( str(e))) return RetVal( action_result.set_status(phantom.APP_ERROR, "[DEBUG]", e)) self.debug_print("[DEBUG] handle_reset_password, ret = {}".format(ret)) if ret: ar_data["reset"] = summary["reset"] = True action_result.add_data(ar_data) return RetVal(action_result.set_status(phantom.APP_SUCCESS)) else: ar_data["reset"] = summary["reset"] = False action_result.add_data(ar_data) return RetVal(action_result.set_status(phantom.APP_ERROR))
def _add_comment(self, param): """ This function is used to add comment/work log to an incident. :param param: includes ID of incident to add comment :return: status phantom.APP_SUCCESS/phantom.APP_ERROR (along with appropriate message) """ action_result = self.add_action_result(ActionResult(dict(param))) add_attachment_details_param = dict() attachment_data = dict() # List of optional parameters optional_parameters = {"comment": "Detailed Description", "view_access": "View Access", "secure_work_log": "Secure Work Log"} # Get optional parameters attachment_list = param.get(consts.BMCREMEDY_JSON_VAULT_ID, '') if attachment_list: # Getting attachment related information vault_details_status, add_attachment_details_param, attachment_data = \ self._provide_attachment_details(attachment_list, action_result) # Something went wrong while executing request if phantom.is_fail(vault_details_status): return action_result.get_status() # Adding mandatory parameters add_attachment_details_param.update({ "Incident Number": param[consts.BMCREMEDY_INCIDENT_NUMBER], "Work Log Type": param[consts.BMCREMEDY_COMMENT_ACTIVITY_TYPE] }) # Adding optional parameters in 'fields' for key_param, api_key in optional_parameters.iteritems(): if param.get(key_param) and api_key not in add_attachment_details_param: add_attachment_details_param[str(api_key)] = str(param.get(key_param)) if attachment_list: attachment_data["entry"] = {"values": add_attachment_details_param} else: attachment_data["values"] = add_attachment_details_param add_attachment_status, add_attachment_response_data = self._add_attachment(attachment_data, action_result) if phantom.is_fail(add_attachment_status): return action_result.get_status() return action_result.set_status(phantom.APP_SUCCESS, consts.BMCREMEDY_ADD_COMMENT_MESSAGE)