def _url_void_function(self, event, *args, **kwargs): """Function: Retrieves information of a URL from the URL Void database.""" try: yield StatusMessage("URL Void function started...") rp = ResultPayload("fn_url_void", **kwargs) # Add support for Requests Common req_common = RequestsCommon(self.opts, self.options) api_key = self.options.get("api_key") identifier = self.options.get("identifier", "api1000") # Get the function parameters: artifact_value = kwargs.get("artifact_value") # text url_void_endpoint = self.get_select_param(kwargs.get("url_void_endpoint", "Retrieve")) # select validate_fields(["artifact_value", "url_void_endpoint"], kwargs) log.info("artifact_value: %s", artifact_value) log.info("url_void_endpoint: %s", url_void_endpoint) response = call_url_void_api(req_common, artifact_value, identifier, api_key, url_void_endpoint) yield StatusMessage("URL Void function completed successfully...") results = rp.done(True, response) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception as e: yield FunctionError(e)
def _panorama_get_address_groups_function(self, event, *args, **kwargs): """Function: Panorama get address groups returns the list of address groups """ try: yield StatusMessage("Getting list of Address Groups") rp = ResultPayload("fn_pa_panorama", **kwargs) validate_fields(["panorama_name_parameter"], kwargs) # Get the function parameters: location = self.get_select_param( kwargs.get("panorama_location")) # select vsys = kwargs.get("panorama_vsys") # text name = kwargs.get( "panorama_name_parameter") # text (optional parameter) # Log inputs if location is None: raise ValueError("panorama_location needs to be set.") log.info("panorama_location: {}".format(location)) log.info("panorama_vsys: {}".format(vsys)) log.info("panorama_name_parameter: {}".format(name)) panorama_util = PanoramaClient(self.opts, location, vsys) response = panorama_util.get_address_groups(name) yield StatusMessage("{} groups returned.".format( response["result"]["@count"])) results = rp.done(True, response) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception as e: yield FunctionError(e)
def _panorama_edit_address_group_function(self, event, *args, **kwargs): """Function: Panorama edit address group edits an address group, ie: add or remove ip addresses from the group""" try: yield StatusMessage("Editing address group...") rp = ResultPayload("fn_pa_panorama", **kwargs) validate_fields(["panorama_name_parameter", "panorama_request_body"], kwargs) # Get the function parameters: location = self.get_select_param(kwargs.get("panorama_location")) # select vsys = kwargs.get("panorama_vsys") # text name = kwargs.get("panorama_name_parameter") # text body = self.get_textarea_param(kwargs.get("panorama_request_body")) # textarea # Log inputs if location is None: raise ValueError("panorama_location needs to be set.") log.info("panorama_location: {}".format(location)) log.info("panorama_vsys: {}".format(vsys)) log.info("panorama_name_parameter: {}".format(name)) log.info("panorama_request_body: {}".format(body)) panorama_util = PanoramaClient(self.opts, location, vsys) response = panorama_util.edit_address_groups(name, body) yield StatusMessage("Address Group Updated") results = rp.done(True, response) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception as e: yield FunctionError(e)
def selftest_function(opts): """ Placeholder for selftest function. An example use would be to test package api connectivity. Suggested return values are be unimplemented, success, or failure. """ try: options = opts.get("hibp", {}) hibp_api_key = options.get("hibp_api_key") validate_fields(["[hibp_api_key]"], options) HAVE_I_BEEN_PWNED_API_KEY_URL: "https://haveibeenpwned.com/api/v3/" api_key_url = "{0}/{1}".format(HAVE_I_BEEN_PWNED_API_KEY_URL, hibp_api_key) breaches_response = requests.get(api_key_url) if breaches_response.status_code != 401: yield StatusMessage("Have I Been Pwned API Key has been found") else: yield StatusMessage( "Have I Been Pwned API Key has not been found. Please add API Key to app.config" ) return {"state": "success"} except Exception: return {"state": "failed"}
def selftest_function(opts): """test if host exists, if using TLS sends an empty email""" try: smtp_config_section = opts.get(CONFIG_DATA_SECTION, {}) smtp_server = smtp_config_section.get("smtp_server") smtp_port = str(smtp_config_section.get("smtp_port", SMTP_DEFAULT_PORT)) smtp_cafile = smtp_config_section.get("smtp_ssl_cafile", False) smtp_user = smtp_config_section.get("smtp_user") smtp_password = smtp_config_section.get("smtp_password") from_email_address = smtp_config_section.get("from_email_address", smtp_user) smtp_ssl_mode = smtp_config_section.get("smtp_ssl_mode") smtp_conn_timeout = int( smtp_config_section.get("smtp_conn_timeout", SMTP_DEFAULT_CONN_TIMEOUT)) validate_fields(["smtp_server", "smtp_port"], smtp_config_section) LOG.info("Validating connection to mail server") if smtp_ssl_mode == "ssl": LOG.info("Building SSL connection object") smtp_connection = smtplib.SMTP_SSL( host=smtp_server, port=smtp_port, certfile=smtp_cafile, context=SendSMTPEmail.get_smtp_ssl_context, timeout=smtp_conn_timeout) else: LOG.info("Building generic connection object") smtp_connection = smtplib.SMTP(host=smtp_server, port=smtp_port, timeout=smtp_conn_timeout) if smtp_ssl_mode == "starttls" and smtp_user: LOG.info("Starting TLS...") smtp_connection.ehlo() smtp_connection.starttls() smtp_connection.ehlo() LOG.info("Logging in to SMTP...") if not smtp_password: raise Exception( 'An SMTP user has been set; the SMTP password from app.config cannot be null' ) smtp_connection.login(user=smtp_user, password=smtp_password) if from_email_address: smtp_connection.sendmail(from_email_address, from_email_address, 'this is a test email') return {"state": "success"} except Exception as err: LOG.error(err) return {"state": "failure"} finally: if smtp_connection: smtp_connection.quit()
def _panorama_edit_users_in_a_group_function(self, event, *args, **kwargs): """Function: Panorama get address groups returns the list of address groups """ try: # Response code should equal 20 indicating the call went through successfully PASS_CONSTANT = "20" yield StatusMessage("Editing list of users in a group") rp = ResultPayload("fn_pa_panorama", **kwargs) validate_fields( ["panorama_user_group_xpath", "panorama_user_group_xml"], kwargs) # Get the function parameters: user_group_xpath = kwargs.get("panorama_user_group_xpath") # text user_group_xml = self.get_textarea_param( kwargs.get("panorama_user_group_xml")) # textarea location = self.get_select_param( kwargs.get("panorama_location")) # select # Log inputs log.info(u"panorama_user_group_xpath: {}".format(user_group_xpath)) log.info(u"panorama_user_group_xml: {}".format(user_group_xml)) panorama_util = PanoramaClient(self.opts, location, None) xml_response = panorama_util.edit_users_in_a_group( user_group_xpath, user_group_xml) dict_response = xmltodict.parse(xml_response) try: if dict_response["response"].get("@code") == PASS_CONSTANT: yield StatusMessage("User group was successfully edited.") else: raise FunctionError( "Editing the user group was unsuccessful with code {}, raising FunctionError." .format(dict_response["response"]["@code"])) except KeyError as e: yield StatusMessage("Editing the user group was unsuccessful.") raise FunctionError(e) # add to dict_response to allow for more options in Resilient scripting and make some actions easier dict_response["xml_response"] = xml_response results = rp.done(True, dict_response) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception as e: yield FunctionError(e)
def __init__(self, opts, location, vsys=None): pan_config = opts.get("fn_pa_panorama") pan_config["location"] = location # validate config fields validate_fields(["panorama_host", "api_key", "location"], pan_config) self.__key = pan_config["api_key"] self.__location = pan_config["location"] self.__vsys = vsys self.__output_format = "json" self.verify = str_to_bool(pan_config.get("cert", "True")) self.host = pan_config["panorama_host"] self.rc = RequestsCommon(opts, pan_config) self.query_parameters = self.__build_query_parameters()
def _panorama_get_users_in_a_group_function(self, event, *args, **kwargs): """Function: Panorama get address groups returns the list of address groups """ try: yield StatusMessage("Getting list of users in a group") rp = ResultPayload("fn_pa_panorama", **kwargs) validate_fields(["panorama_user_group_xpath"], kwargs) # Get the function parameters: user_group_xpath = kwargs.get("panorama_user_group_xpath") # text location = self.get_select_param( kwargs.get("panorama_location")) # select # Log inputs log.info("panorama_user_group_xpath: {}".format(user_group_xpath)) panorama_util = PanoramaClient(self.opts, location, None) xml_response = panorama_util.get_users_in_a_group(user_group_xpath) dict_response = xmltodict.parse(xml_response) user_list = [] try: members = dict_response["response"]["result"]["entry"]["user"][ "member"] if isinstance(members, list): # Multiple existing users for m in members: user_list.append(m) else: # Single user in group user_list.append(members.get("#text")) except KeyError: # No users returned yield StatusMessage("No users returned.") yield StatusMessage("{} users returned.".format(len(user_list))) # add to dict_response to allow for more options in Resilient scripting and make some actions easier dict_response["user_list"] = user_list dict_response["xml_response"] = xml_response results = rp.done(True, dict_response) # Produce a FunctionResult with the results yield FunctionResult(results) except Exception as e: yield FunctionError(e)
def selftest_function(opts): try: options = opts.get("fn_res_to_icd", {}) icd_email = options.get("icd_email") icd_pass = options.get("icd_pass") icd_url = options.get('icd_url') test_endpoint = '/oslc/ping/' log.info(icd_email) params = {"_lid": icd_email, "_lpwd": icd_pass} validate_fields(['icd_email', 'icd_pass', 'icd_url'], options) log.info('executing api call with credentials') response = requests.post(icd_url + test_endpoint, params=params, verify=False) log.info(response.status_code) return {"state": "success"} except Exception as err: log.error(err) return {"state": "failure"}
def test_validate_fields(self): # validate_fields(fieldList, kwargs) test_dict = {"a": "a", "b": "b", "c": ''} validate_fields(("a", "b"), test_dict) with self.assertRaises(ValueError): validate_fields(("c"), test_dict) validate_fields(("d"), test_dict)
def __init__(self, opts): """constructor provides access to the configuration options""" super(FunctionComponent, self).__init__(opts) self.options = opts.get("fn_url_void", {}) validate_fields(["api_key"], self.options)
def test_validate_fields(self): # validate_fields(fieldList, kwargs) inputs = { "bool_input_true": True, "bool_input_false": False, "unicode_input": u" դ ե զ է ը թ ժ ի լ խ ծ կ հ ձ ղ ճ մ յ ն ", "str_input": "some text", "num_input": 123, "select_input": {"id": 111, "name": "select choice"}, "multi_select_input": [{"id": 111, "name": "select choice one"}, {"id": 111, "name": "select choice two"}], "text_with_value_string": {"content": "mock text", "format": "text"}, "empty_input": '' } mandatory_fields = [ {"name": "str_input", "placeholder": "some text"} ] expected_output = { "bool_input_true": True, "bool_input_false": False, "unicode_input": u" դ ե զ է ը թ ժ ի լ խ ծ կ հ ձ ղ ճ մ յ ն ", "str_input": "some text", "num_input": 123, "select_input": "select choice", "multi_select_input": ["select choice one", "select choice two"], "text_with_value_string": "mock text", "empty_input": '' } # Test its runs as expected validate_fields(("bool_input_true", "unicode_input"), inputs) with self.assertRaisesRegex(ValueError, "'field_list' must be of type list/tuple"): validate_fields({}, inputs) # Test mandatory fields missing with self.assertRaisesRegex(ValueError, "'cx' is mandatory and is not set. You must set this value to run this function"): validate_fields(("cx"), inputs) # Test mandatory field is empty string with self.assertRaisesRegex(ValueError, "'empty_input' is mandatory and is not set. You must set this value to run this function"): validate_fields(("empty_input"), inputs) # Test no mandatory fields self.assertEquals(validate_fields([], inputs), expected_output) # Test getting single input from returned dict self.assertEquals(validate_fields(("bool_input_true"), inputs).get("bool_input_true"), True) self.assertEquals(validate_fields([], inputs).get("bool_input_true"), True) # Test getting value defined as False self.assertEquals(validate_fields(["bool_input_false"], inputs).get("bool_input_false"), False) # Test select + multi-select type fields self.assertEquals(validate_fields(["select_input"], inputs).get("select_input"), "select choice") self.assertEquals(validate_fields([], inputs).get("multi_select_input"), ["select choice one", "select choice two"]) # Test 'Text with value string Input' type self.assertEquals(validate_fields(["text_with_value_string"], inputs).get("text_with_value_string"), "mock text") # Test placeholder with self.assertRaisesRegex(ValueError, "'str_input' is mandatory and still has its placeholder value of 'some text'. You must set this value correctly to run this function"): validate_fields(mandatory_fields, inputs) # Test works with a namedtuple inputs_as_named_tuple = namedtuple("fn_inputs", inputs.keys())(*inputs.values()) self.assertEquals(validate_fields(("bool_input_true"), inputs_as_named_tuple).get("bool_input_true"), True) validated_named_tuple_inputs_i = validate_fields([], inputs_as_named_tuple) self.assertEquals(validated_named_tuple_inputs_i, expected_output) # Test called again on a normalized dict validated_named_tuple_inputs_ii = validate_fields([], validated_named_tuple_inputs_i) self.assertEquals(validated_named_tuple_inputs_ii, expected_output)
def _res_to_icd_function_function(self, event, *args, **kwargs): try: # taken from config section icd_email = self.options.get("icd_email") icd_pass = self.options.get("icd_pass") icd_priority = self.options.get("icd_priority") icd_field_severity = self.options.get('icd_field_severity') icd_url = self.options.get('icd_url') incident_id = kwargs.get("incident_id") # Payload and validation payload = ResultPayload('fn_res_to_icd', **kwargs) validate_fields( ['icd_email', 'icd_pass', 'icd_url', 'icd_field_severity'], self.options) validate_fields(['incident_id'], kwargs) #logging log = logging.getLogger(__name__) log.info("icd_email: %s", icd_email) log.info("icd_field_severity: %s", icd_field_severity) log.info("icd_priority: %s", icd_priority) log.info("incident_id: %s", incident_id) log.info("icd_url: %s", icd_url) # Resilient client and api calls res_client = self.rest_client() incident_str = '/incidents/{incident_id}/'.format( incident_id=incident_id) artifact_str = '/incidents/{incident_id}/artifacts'.format( incident_id=incident_id) field_severity = {} if icd_field_severity: # If api call for custom severity field is not successful, Ticket defaults to minimum priority try: fieldsev_str = '/types/{type}/fields/{field}'.format( type='incident', field=icd_field_severity) field_severity = res_client.get(fieldsev_str) except: field_severity['values'] = MIN_PRIORITY_ICD content = res_client.get(incident_str) art_content = res_client.get(artifact_str) # Time and date timestamp = content['create_date'] timeval = readable_datetime(timestamp, milliseconds=True, rtn_format='%Y-%m-%dT%H:%M:%SZ') time = "Date and Time: {0}".format(timeval) #artifact population to icd ticket details_payload = '' i = 0 j = 0 if icd_field_severity: try: for i in range(0, len(art_content)): if art_content[i].get('properties', False): if art_content[i]['properties'][0]['name'] in ( 'source', 'destination'): j += 1 details_payload += 'ID: {1} IP Address {2}: {0} \n'.format( art_content[i]['value'], art_content[i]['id'], art_content[i] ['properties'][0]['name'].capitalize()) log.info("Artifacts added to ICD ticket: {0}". format(j)) except Exception as artifact_error: log.error(artifact_error) log.error("Encountered an error parsing artifacts") ##If you custom field isn't specified, it defaults to min priority if icd_field_severity: try: field_sev = field_severity['values'] except: field_sev = field_severity['name'] if not field_sev: field_sev = 1 # number log.info("field_severity: %s", field_sev) icd_priority_lookup = [0, 4, 4, 4, 3, 2, 2, 1] try: icd_priority = icd_priority_lookup[field_sev] log.info("icd_priority: %s", field_sev) except: log.warning( "You have not set a priority, icd priority will be set to min value (4)" ) icd_priority = MIN_PRIORITY_ICD # Params and Desk call params = { "DESCRIPTION": time, "DESCRIPTION_LONGDESCRIPTION": details_payload, "REPORTEDBYID": icd_email, "logtype": "CLIENTNOTE", "worklog.1.description": "SECURITY ISSUE", "worklog.1.DESCRIPTION_LONGDESCRIPTION": "SECURITY ISSUE", "INTERNALPRIORITY": icd_priority, "SITEID": "APPOPINT", "CLASSIFICATIONID": "SECURITY ISSUE", "_lid": icd_email, "_lpwd": icd_pass } endpoint = "/rest/os/MXINCIDENT/" base_url = icd_url + endpoint response = requests.post(url=base_url, params=params, verify=False) xmldata = bsoup(response.text, "html.parser") icd_id = '{0}'.format(xmldata.createmxincidentresponse. mxincidentset.incident.ticketid) icd_id = re.sub('[ticket<>/d]', '', icd_id) yield StatusMessage("Completed successfully") results = payload.done(success=True, content={ "incident_escalated": incident_id, "icd_id": icd_id, "details": details_payload }) # Produce a FunctionResult with the results yield FunctionResult(results) log.info("Complete") except Exception: yield FunctionError()