def get_token(self) -> Tuple[str, str]: """Get a token for the connection. Returns: token , cookie for the connection. """ token = '' cookie = '' data = {"userName": self._username, "password": self._password} login_url = f"{self._url}/ams/shared/api/security/login" body = json.dumps(data) headers = {'Content-Type': 'application/json'} response = self.token_request(login_url, headers=headers, data=body) # Extracting Token response_cookies = response.get('cookies').__dict__.get('_cookies') if response_cookies: cookie_key = list(response_cookies.keys())[0] if cookie_key: ret_cookie = response_cookies.get(cookie_key).get("/") cookie = self.get_cookie(ret_cookie) token = ret_cookie.get("KACE_CSRF_TOKEN").__dict__.get('value') sleep(100) sleep(4) if not token: raise DemistoException("Could not get token") if not cookie: raise DemistoException("Could not get cookie") return token, cookie
def token_request(self, url: str, headers: Optional[dict] = None, data: Optional[str] = None) -> dict: """login request for initiating a connection with the product. Args: url: full url that the request will be sent to. headers: headers of the request. data: data of the request which includes username and password. Returns: Dictionary of the response from the product. """ try: response = requests.request("POST", url, headers=headers, data=data, verify=self._verify) except requests.exceptions.SSLError: err_msg = 'SSL Certificate Verification Failed - try selecting \'Trust any certificate\' checkbox in' \ ' the integration configuration.' raise DemistoException(err_msg) except requests.exceptions.ConnectionError: raise DemistoException( "Invalid url , Failed to establish a connection") if response.status_code == 401: raise DemistoException("Error Code 401 - Invalid user or password") return response.__dict__
def delete_ticket_command(client, args) -> Tuple[str, dict, dict]: """Function which deleted a specific ticket by ticket id. Args: client : Integretion client which communicates with the api. args: Users arguments of the command. Returns: human readable, context, raw response of this command. """ ticket_id = args.get('ticket_id') try: response = client.delete_ticket_request(ticket_id) except Exception as e: raise DemistoException(e) if response.get('Result') == 'Success': context = {} old_context = demisto.dt(demisto.context(), f'QuestKace.Ticket(val.ID === {ticket_id})') if old_context: if isinstance(old_context, list): old_context = old_context[0] old_context['IsDeleted'] = True context = {'QuestKace.Ticket(val.ID === obj.ID)': old_context} return f'Ticket was deleted successfully. Ticket number {ticket_id}', context, {} else: raise DemistoException('Error while deleting the ticket.')
def test_parse_demisto_exception_api_error(self): from Infoblox import parse_demisto_exception api_err = f'Error in API call [400] - Bad Request\n {json.dumps(API_ERROR_OBJ)}' parsed_err = parse_demisto_exception(DemistoException(api_err)) assert str(parsed_err) == str( DemistoException( "Duplicate object 'test123.com' of type zone exists in the database." ))
def test_parse_demisto_exception_unauthorized_error(self): from Infoblox import parse_demisto_exception json_err = f'Expecting value: line 1 column 1 (char 0)' api_err = 'Error in API call [401] - Authorization Required' parsed_err = parse_demisto_exception( DemistoException(api_err, json_err)) assert str(parsed_err) == str( DemistoException("Authorization error, check your credentials."))
def test_parse_demisto_exception_json_parse_error(self): from Infoblox import parse_demisto_exception json_err = 'Expecting value: line 1 column 1 (char 0)' api_err = f'Failed to parse json object from response: {SSL_ERROR}' parsed_err = parse_demisto_exception( DemistoException(api_err, json_err)) assert str(parsed_err) == str( DemistoException( "Cannot connect to Infoblox server, check your proxy and connection." ))
def test_http_request_other_demisto_exception(mock_base_http_request, client): """ When http request return other custom Demisto exception then appropriate error message should match. """ # Configure mock_base_http_request.side_effect = DemistoException('custom') # Execute with pytest.raises(Exception) as e: client.http_request('GET', '/test/url/suffix') # Assert assert 'custom' == str(e.value)
def update_ticket_command(client, args) -> Tuple[str, dict, dict]: """Function which updates the body of the request from user arguments. Args: client : Integretion client which communicates with the api. args: Users arguments of the command. Returns: human readable, context, raw response of this command. """ impact = None category = None status = None priority = None ticket_id = args.get('ticket_id') title = args.get("title") summary = args.get('summary') if args.get('impact'): impact = TICKETS_OBJECTS['impact'][args.get('impact')] if args.get('category'): category = TICKETS_OBJECTS['category'][args.get('category')] if args.get('status'): status = TICKETS_OBJECTS['status'][args.get('status')] if args.get('priority'): priority = TICKETS_OBJECTS['priority'][args.get('priority')] machine = args.get('machine') asset = args.get('asset') custom_fields = args.get('custom_fields') body_from_args = create_body_from_args(title=title, summary=summary, impact=impact, category=category, status=status, priority=priority, machine=machine, asset=asset) if custom_fields: splited = split_fields(custom_fields) body_from_args.update(splited) temp_data = {'Tickets': [body_from_args]} data = json.dumps(temp_data) response = client.update_ticket_request(ticket_id, data) if response.get('Result') != 'Success': raise DemistoException('Error while updating the ticket.') client.update_token() res = client.ticket_by_id_request(ticket_id) ticket = res.get('Tickets') ticket_view = tableToMarkdown( f'Ticket number {ticket_id} was updated successfully.\n', ticket) return ticket_view, {}, {}
def test_http_request_proxy_error(mock_base_http_request, client): """ When http request return proxy error with exception then appropriate error message should match. """ # Configure mock_base_http_request.side_effect = DemistoException('Proxy Error') # Execute with pytest.raises(ConnectionError) as e: client.http_request('GET', '/test/url/suffix') # Assert assert 'Proxy Error - cannot connect to proxy. Either try clearing the \'Use system proxy\' check-box or' \ ' check the host, authentication details and connection details for the proxy.' == str(e.value)
def test_http_request_connection_error(mock_base_http_request, client): """ When http request return connection error with Demisto exception then appropriate error message should match. """ # Configure mock_base_http_request.side_effect = DemistoException('ConnectionError') # Execute with pytest.raises(ConnectionError) as e: client.http_request('GET', '/test/url/suffix') # Assert assert 'Connectivity failed. Check your internet connection, the API URL or try increasing the HTTP(s) Request' \ ' Timeout.' == str(e.value)
def test_exception_in__generate_token(mocker): """ Check exception handling in _generate_token func Given: A FireEyeClient When: Generating new token Then: Ensure that Exceptions are caught and parsed correctly. """ err = "Some error" mocker.patch.object(BaseClient, '_http_request', side_effect=DemistoException(err)) with pytest.raises(DemistoException, match=f'Token request failed. message: {err}'): FireEyeClient(base_url='https://test.com', username='******', password='******', verify=False, proxy=False)
def test_update_session_fail_parsing(self, mocker): """ Given: an exception raised from _http_request who failed to pares json object When: - initiating session Then: - Raise exception with message to check the provided url """ mocker.patch.object(Client, '_http_request', side_effect=DemistoException("Failed to parse json object from " "response: b\"<html><head><script>" "window.top.location='/Default.aspx';" "</script></head><body>" "</body></html>")) client = Client(BASE_URL, '', '', '', '') with pytest.raises(DemistoException) as e: client.update_session() assert "Check the given URL, it can be a redirect issue" in str(e.value)
def test_task_id_exists_task_does_not_exist(requests_mock): """ Given: - Task Id. - Nutanix client. When: Task to be polled does not exist in Nutanix. Then: False is returned """ task_id = 'abcd1234-ab12-cd34-1a2s3d5f7hh4' requests_mock.get( f'{MOCKED_BASE_URL}/tasks/{task_id}', exc=DemistoException(f'Task with id {task_id} is not found') ) assert not task_exists(client, task_id)
def test_task_id_exists_unexpected_exception(requests_mock): """ Given: - Task Id. - Nutanix client. When: Unexpected exception is thrown during call to Nutanix service. Then: The unexpected exception is raised and not passed silently """ task_id = 'abcd1234-ab12-cd34-1a2s3d5f7hh4' requests_mock.get( f'{MOCKED_BASE_URL}/tasks/{task_id}', exc=DemistoException('Unexpected exception') ) with pytest.raises(DemistoException, match='Unexpected exception'): task_exists(client, task_id)
def main(args): value = args['value'] replace_with = args['replace_with'] output = list() start = 0 try: regex = re.compile(args['regex']) except (re.error, TypeError): raise DemistoException('Could not compile regex.') for match in regex.finditer(value): for index, _ in enumerate(match.groups(), start=1): end = match.start(index) output.append(value[start:end]) output.append(replace_with) start = match.end(index) output.append(value[start:]) # Handling the tail of the string return ''.join(output)
def mock_client(mocker, http_request_result=None, throw_error=False): mocker.patch.object( demisto, 'getIntegrationContext', return_value={'current_refresh_token': 'refresh_token'}) client = Client(server_url=BASE_URL, verify=False, proxy=False, auth=None, headers=headers) if http_request_result: mocker.patch.object(client, '_http_request', return_value=http_request_result) if throw_error: err_msg = "Error in API call [400] - BAD REQUEST}" mocker.patch.object(client, '_http_request', side_effect=DemistoException(err_msg, res={})) return client
def create_ticket_command(client, args) -> Tuple[str, dict, dict]: """Function which creates a new ticket to the system according to users arguments. Args: client : Integretion client which communicates with the api. args: Users arguments of the command. Returns: human readable, context, raw response of this command. """ impact = None category = None status = None priority = None hd_queue_id = args.get('queue_id') custom_fields = args.get('custom_fields') if (custom_fields and "hd_queue_id" not in custom_fields) and (not hd_queue_id): raise DemistoException( "hd_queue_id is a mandatory value, please add it.") title = args.get("title") summary = args.get('summary') if args.get('impact'): dict_of_obj = TICKETS_OBJECTS.get('impact') impact = args.get('impact') if dict_of_obj: impact = dict_of_obj.get(args.get('impact'), args.get('impact')) if args.get('category'): dict_of_obj = TICKETS_OBJECTS.get('category') impact = args.get('category') if dict_of_obj: impact = dict_of_obj.get(args.get('category'), args.get('category')) if args.get('status'): dict_of_obj = TICKETS_OBJECTS.get('status') impact = args.get('status') if dict_of_obj: impact = dict_of_obj.get(args.get('status'), args.get('status')) if args.get('priority'): dict_of_obj = TICKETS_OBJECTS.get('priority') impact = args.get('priority') if dict_of_obj: impact = dict_of_obj.get(args.get('priority'), args.get('priority')) machine = args.get('machine') asset = args.get('asset') body_from_args = create_body_from_args(hd_queue_id, title, summary, impact, category, status, priority, machine, asset) if custom_fields: splited = split_fields(custom_fields) body_from_args.update(splited) temp_data = {'Tickets': [body_from_args]} data = json.dumps(temp_data) response = client.create_ticket_request(data) if response.get('Result') != 'Success': raise DemistoException('Error while adding a new ticket.') try: id = response.get('IDs')[0] except Exception as e: raise DemistoException(e) client.update_token() res = client.ticket_by_id_request(id) ticket = res.get('Tickets') ticket_view = tableToMarkdown( f'New ticket was added successfully, ticket number {id}.\n', ticket) return ticket_view, {}, {}
Then: - Ensure enrichment asset object returned is as expected. """ assets = asset_enrich_data['assets'] enriched_assets = [create_single_asset_for_offense_enrichment(asset) for asset in assets] assert enriched_assets == asset_enrich_data['offense_enrich'] @pytest.mark.parametrize('status_exception, status_response, results_response, search_id, expected', [(None, command_test_data['search_status_get']['response'], command_test_data['search_results_get']['response'], '19e90792-1a17-403b-ae5b-d0e60740b95e', sanitize_outputs(command_test_data['search_results_get']['response']['events'])), (DemistoException('error occurred'), None, None, None, []) ]) def test_poll_offense_events_with_retry(requests_mock, status_exception, status_response, results_response, search_id, expected): """ Given: - Client to perform API calls. - Search ID of the query to enrich events. When: - Case a: QRadar returns a valid and terminated results to the search. - Case b: Error occurred in request to QRadar during poll.
""" assets = asset_enrich_data['assets'] enriched_assets = [ create_single_asset_for_offense_enrichment(asset) for asset in assets ] assert enriched_assets == asset_enrich_data['offense_enrich'] @pytest.mark.parametrize( 'status_exception, status_response, results_response, search_id, expected', [(None, command_test_data['search_status_get']['response'], command_test_data['search_results_get']['response'], '19e90792-1a17-403b-ae5b-d0e60740b95e', sanitize_outputs( command_test_data['search_results_get']['response']['events'])), (DemistoException('error occurred'), None, None, None, [])]) def test_poll_offense_events_with_retry(requests_mock, status_exception, status_response, results_response, search_id, expected): """ Given: - Client to perform API calls. - Search ID of the query to enrich events. When: - Case a: QRadar returns a valid and terminated results to the search. - Case b: Error occurred in request to QRadar during poll. Then: - Case a: Ensure that expected events are returned. - Case b: Ensure that None is returned.
import pytest from Lastline_v2 import * from CommonServerPython import DemistoException data_test_hash_type_checker = [ ('4e492e797ccfc808715c2278484517b1', 'md5'), ('e18e9ebfc7204712ee6f27903e1e7a4256fccba0', 'sha1'), ('7f3aa0fda6513c9fc6803fbebb0100e3a3d2ded503317d325eb2bccc097cf27b', 'sha256'), ('0123456789', f'{INTEGRATION_NAME} File command support md5/ sha1/ sha256 only.') ] data_test_exception_handler = [ ( {"success": 0, "error_code": 115, "error": "Submission limit exceeded"}, str(DemistoException('error (115) Submission limit exceeded')) ), ( {}, str(DemistoException('No response')) ), ( {'test': 'nothing'}, str(DemistoException('No response')) ), ( {'success': None}, str(DemistoException('No response')) ), ( {}, str(DemistoException('No response'))
'host_ip': '172.217.7.163', 'host_port': 80, 'method': 'GET', 'url': 'url' }], 'incidents': [{ 'details': ['Contacts 4 domains and 4 hosts'], 'name': 'Network Behavior' }], 'processes': [{ 'command_line': 'command_line', 'icon_artifact_id': 'icon_artifact_id', 'name': 'rundll32.exe', 'normalized_path': 'normalized_path.exe', 'pid': 6648, 'process_flags': [{ 'name': 'Reduced Monitoring' }], 'sha256': 'sha256', 'uid': '00074182-00006648' }], 'screenshots_artifact_ids': [ 'screenshots_artifact_ids1', 'screenshots_artifact_ids2', 'screenshots_artifact_ids3', 'screenshots_artifact_ids4' ] } } MULTIPLE_ERRORS_RESULT = DemistoException( '403: access denied, authorization failed\n401: test error #1\n402: test error #2' )
def raise_exception(): raise DemistoException('Authentication Error.')