From 7d7eea8d700601c7d978a2bdde4e620a22eee5a5 Mon Sep 17 00:00:00 2001 From: Danny Elliott Date: Tue, 22 Jan 2019 16:58:53 -0400 Subject: [PATCH] Update dummy module (#96) --- ...{dummy_data_mapping.py => data_mapping.py} | 2 +- .../src/modules/dummy/dummy_translator.py | 4 +- .../src/modules/dummy/json/from_stix_map.json | 28 ++-- .../src/modules/dummy/json/to_stix_map.json | 88 +++++++---- ...ry_constructor.py => query_constructor.py} | 114 ++++++++++---- ...tix_to_dummy_query.py => stix_to_query.py} | 10 +- .../src/modules/async_dummy/apiclient.py | 31 ++++ .../async_dummy/async_dummy_connector.py | 112 ++++++++++++-- .../modules/async_dummy/async_dummy_ping.py | 11 -- .../async_dummy_query_connector.py | 32 ---- .../async_dummy_results_connector.py | 52 ------- .../async_dummy_status_connector.py | 42 ----- .../src/modules/bigfix/Utilities.py | 41 ----- .../src/modules/qradar/Utilities.py | 41 ----- .../src/modules/qradar/qradar_connector.py | 143 ++++++++++++++++-- .../modules/qradar/qradar_delete_connector.py | 25 --- .../src/modules/qradar/qradar_ping.py | 27 ---- .../modules/qradar/qradar_query_connector.py | 28 ---- .../qradar/qradar_results_connector.py | 29 ---- .../modules/qradar/qradar_status_connector.py | 52 ------- .../src/modules/splunk/Utilities.py | 41 ----- .../synchronous_dummy_connector.py | 54 ++++++- .../synchronous_dummy_ping.py | 6 - .../synchronous_dummy_results_connector.py | 50 ------ tests/stix_transmission/test_async_dummy.py | 69 ++------- .../test_synchronous_dummy.py | 11 +- 26 files changed, 496 insertions(+), 647 deletions(-) rename stix_shifter/stix_translation/src/modules/dummy/{dummy_data_mapping.py => data_mapping.py} (97%) rename stix_shifter/stix_translation/src/modules/dummy/{dummy_query_constructor.py => query_constructor.py} (61%) rename stix_shifter/stix_translation/src/modules/dummy/{stix_to_dummy_query.py => stix_to_query.py} (77%) create mode 100644 stix_shifter/stix_transmission/src/modules/async_dummy/apiclient.py delete mode 100644 stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_ping.py delete mode 100644 stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_query_connector.py delete mode 100644 stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_results_connector.py delete mode 100644 stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_status_connector.py delete mode 100644 stix_shifter/stix_transmission/src/modules/bigfix/Utilities.py delete mode 100644 stix_shifter/stix_transmission/src/modules/qradar/Utilities.py delete mode 100644 stix_shifter/stix_transmission/src/modules/qradar/qradar_delete_connector.py delete mode 100644 stix_shifter/stix_transmission/src/modules/qradar/qradar_ping.py delete mode 100644 stix_shifter/stix_transmission/src/modules/qradar/qradar_query_connector.py delete mode 100644 stix_shifter/stix_transmission/src/modules/qradar/qradar_results_connector.py delete mode 100644 stix_shifter/stix_transmission/src/modules/qradar/qradar_status_connector.py delete mode 100644 stix_shifter/stix_transmission/src/modules/splunk/Utilities.py delete mode 100644 stix_shifter/stix_transmission/src/modules/synchronous_dummy/synchronous_dummy_ping.py delete mode 100644 stix_shifter/stix_transmission/src/modules/synchronous_dummy/synchronous_dummy_results_connector.py diff --git a/stix_shifter/stix_translation/src/modules/dummy/dummy_data_mapping.py b/stix_shifter/stix_translation/src/modules/dummy/data_mapping.py similarity index 97% rename from stix_shifter/stix_translation/src/modules/dummy/dummy_data_mapping.py rename to stix_shifter/stix_translation/src/modules/dummy/data_mapping.py index dcaa3341c..5d1da4b66 100644 --- a/stix_shifter/stix_translation/src/modules/dummy/dummy_data_mapping.py +++ b/stix_shifter/stix_translation/src/modules/dummy/data_mapping.py @@ -17,7 +17,7 @@ def _fetch_mapping(): return {} -class DummyDataMapper: +class DataMapper: def __init__(self, options): mapping_json = options['mapping'] if 'mapping' in options else {} diff --git a/stix_shifter/stix_translation/src/modules/dummy/dummy_translator.py b/stix_shifter/stix_translation/src/modules/dummy/dummy_translator.py index 9c7b889d6..4f653032b 100644 --- a/stix_shifter/stix_translation/src/modules/dummy/dummy_translator.py +++ b/stix_shifter/stix_translation/src/modules/dummy/dummy_translator.py @@ -1,5 +1,5 @@ from ..base.base_translator import BaseTranslator -from .stix_to_dummy_query import StixToDummyQuery +from .stix_to_query import StixToQuery from ...json_to_stix.json_to_stix import JSONToStix from os import path @@ -12,4 +12,4 @@ def __init__(self): path.join(basepath, "json", "to_stix_map.json")) self.mapping_filepath = filepath self.result_translator = JSONToStix(filepath) - self.query_translator = StixToDummyQuery() + self.query_translator = StixToQuery() diff --git a/stix_shifter/stix_translation/src/modules/dummy/json/from_stix_map.json b/stix_shifter/stix_translation/src/modules/dummy/json/from_stix_map.json index 3d8d940c5..16a623bca 100644 --- a/stix_shifter/stix_translation/src/modules/dummy/json/from_stix_map.json +++ b/stix_shifter/stix_translation/src/modules/dummy/json/from_stix_map.json @@ -1,51 +1,53 @@ { "ipv4-addr": { "fields": { - "value": ["dummySourceIpField", "dummyDestinationIpField"] + "value": ["SourceIpV4", "DestinationIpV4"] } }, "ipv6-addr": { "fields": { - "value": ["dummyIpField"] + "value": ["SourceIpV6", "DestinationIpV6"] } }, "url": { "fields": { - "value": ["dummyUrlField"] + "value": ["Url"] } }, "mac-addr": { "fields": { - "value": ["dummySourceMacField", "dummyDestinationMacField"] + "value": ["SourceMac", "DestinationMac"] } }, "file": { "fields": { - "name": ["dummyFileNameField"] + "name": ["FileName"] } }, "network-traffic": { "fields": { - "src_port": ["dummySourcePortField"], - "dst_port": ["dummyDestinationPortField"], - "start": ["dummyStartTimeField"], - "end": ["dummyEndTimeField"], - "protocols[*]": ["dummyNetworkProtocolField"] + "src_port": ["SourcePort"], + "dst_port": ["DestinationPort"], + "start": ["StartTime"], + "end": ["EndTime"], + "protocols[*]": ["NetworkProtocol"], + "src_ref.value": ["SourceIpV4", "SourceIpV6"], + "dst_ref.value": ["DestinationIpV4", "DestinationIpV6"] } }, "user-account": { "fields": { - "user_id": ["dummyUserNameField"] + "user_id": ["UserName"] } }, "artifact": { "fields": { - "payload_bin": ["dummyPayloadField"] + "payload_bin": ["Payload"] } }, "domain-name": { "fields": { - "value": ["dummyDomainNameField"] + "value": ["DomainName"] } } } diff --git a/stix_shifter/stix_translation/src/modules/dummy/json/to_stix_map.json b/stix_shifter/stix_translation/src/modules/dummy/json/to_stix_map.json index e781a14fb..262613923 100644 --- a/stix_shifter/stix_translation/src/modules/dummy/json/to_stix_map.json +++ b/stix_shifter/stix_translation/src/modules/dummy/json/to_stix_map.json @@ -1,20 +1,49 @@ { - "dummyUserNameField": { + "UserName": { "key": "user-account.user_id" }, - "dummyLogSourceIdField": { - "key": "x_dummy_custom_property.log_source_id", + "LogSourceId": { + "key": "x__custom_property.log_source_id", "cybox": false }, - "dummyMagnitudeField": { - "key": "x_dummy_custom_property.magnitude", + "Magnitude": { + "key": "x__custom_property.magnitude", "cybox": false }, - "dummyDestinationIpField": [ + "SourceIpV4": [ + { + "key": "ipv4-addr.value", + "object": "src_ip" + }, + { + "key": "network-traffic.src_ref", + "object": "nt", + "references": "src_ip" + } + ], + "DestinationIpV4": [ { "key": "ipv4-addr.value", "object": "dst_ip" }, + { + "key": "network-traffic.dst_ref", + "object": "nt", + "references": "dst_ip" + } + ], + "SourceIpV6": [ + { + "key": "ipv6-addr.value", + "object": "src_ip" + }, + { + "key": "network-traffic.src_ref", + "object": "nt", + "references": "src_ip" + } + ], + "DestinationIpV6": [ { "key": "ipv6-addr.value", "object": "dst_ip" @@ -25,12 +54,12 @@ "references": "dst_ip" } ], - "dummyEventCountField": { + "EventCount": { "key": "number_observed", "cybox": false, "transformer": "ToInteger" }, - "dummyStartTimeField": [ + "StartTime": [ { "key": "created", "transformer": "EpochToTimestamp", @@ -52,46 +81,45 @@ "cybox": false } ], - "dummySourceIpField": [ - { - "key": "ipv4-addr.value", - "object": "src_ip" - }, - { - "key": "ipv6-addr.value", - "object": "src_ip" - }, - { - "key": "network-traffic.src_ref", - "object": "nt", - "references": "src_ip" - } - ], - "dummyUrlField": { + "Url": { "key": "url.value" }, - "dummyFileNameField": { + "FileName": { "key": "file.name" }, - "dummyPayloadField": { + "Payload": { "key": "artifact.payload_bin" }, - "dummyDestinationPortField": { + "DestinationPort": { "key": "network-traffic.dst_port", "object": "nt", "transformer": "ToInteger" }, - "dummySourcePortField": { + "SourcePort": { "key": "network-traffic.src_port", "object": "nt", "transformer": "ToInteger" }, - "dummyNetworkProtocolField": { + "NetworkProtocol": { "key": "network-traffic.protocols", "object": "nt", "transformer": "ToLowercaseArray" }, - "dummyDomainNameField": { + "DomainName": { "key": "domain-name.value" + }, + "Process": { + "Path": [ + { + "object": "proc", + "key": "process.command_line" + } + ], + "Pid": [ + { + "object": "proc", + "key": "process.id" + } + ] } } diff --git a/stix_shifter/stix_translation/src/modules/dummy/dummy_query_constructor.py b/stix_shifter/stix_translation/src/modules/dummy/query_constructor.py similarity index 61% rename from stix_shifter/stix_translation/src/modules/dummy/dummy_query_constructor.py rename to stix_shifter/stix_translation/src/modules/dummy/query_constructor.py index b6704a665..04c37e627 100644 --- a/stix_shifter/stix_translation/src/modules/dummy/dummy_query_constructor.py +++ b/stix_shifter/stix_translation/src/modules/dummy/query_constructor.py @@ -2,13 +2,21 @@ ComparisonExpressionOperators, ComparisonComparators, Pattern, \ CombinedComparisonExpression, CombinedObservationExpression, ObservationOperators from stix_shifter.stix_translation.src.transformers import TimestampToMilliseconds +from stix_shifter.stix_translation.src.json_to_stix import observable import logging import re +# Source and destination reference mapping for ip and mac addresses. +# Change the keys to match the data source fields. The value array indicates the possible data type that can come into from field. +REFERENCE_DATA_TYPES = {"SourceIpV4": ["ipv4", "ipv4_cidr"], + "SourceIpV6": ["ipv6"], + "DestinationIpV4": ["ipv4", "ipv4_cidr"], + "DestinationIpV6": ["ipv6"]} + logger = logging.getLogger(__name__) -class DummyQueryStringPatternTranslator: +class QueryStringPatternTranslator: # Change comparator values to match with supported data source operators comparator_lookup = { ComparisonExpressionOperators.And: "AND", @@ -21,8 +29,9 @@ class DummyQueryStringPatternTranslator: ComparisonComparators.NotEqual: "!=", ComparisonComparators.Like: "LIKE", ComparisonComparators.In: "IN", - ComparisonComparators.Matches: 'MATCHES', - ComparisonComparators.IsSubSet: 'INCIDR', + ComparisonComparators.Matches: 'LIKE', + # ComparisonComparators.IsSubSet: '', + # ComparisonComparators.IsSuperSet: '', ObservationOperators.Or: 'OR', # Treat AND's as OR's -- Unsure how two ObsExps wouldn't cancel each other out. ObservationOperators.And: 'OR' @@ -36,11 +45,11 @@ def __init__(self, pattern: Pattern, data_model_mapper): @staticmethod def _format_set(values) -> str: gen = values.element_iterator() - return "({})".format(' OR '.join([DummyQueryStringPatternTranslator._escape_value(value) for value in gen])) + return "({})".format(' OR '.join([QueryStringPatternTranslator._escape_value(value) for value in gen])) @staticmethod def _format_match(value) -> str: - raw = DummyQueryStringPatternTranslator._escape_value(value) + raw = QueryStringPatternTranslator._escape_value(value) if raw[0] == "^": raw = raw[1:] else: @@ -58,7 +67,7 @@ def _format_equality(value) -> str: @staticmethod def _format_like(value) -> str: value = "'%{value}%'".format(value=value) - return DummyQueryStringPatternTranslator._escape_value(value) + return QueryStringPatternTranslator._escape_value(value) @staticmethod def _escape_value(value, comparator=None) -> str: @@ -71,6 +80,48 @@ def _escape_value(value, comparator=None) -> str: def _negate_comparison(comparison_string): return "NOT({})".format(comparison_string) + @staticmethod + def _check_value_type(value): + value = str(value) + for key, pattern in observable.REGEX.items(): + if key != 'date' and bool(re.search(pattern, value)): + return key + return None + + @staticmethod + def _parse_reference(self, stix_field, value_type, mapped_field, value, comparator): + if value_type not in REFERENCE_DATA_TYPES["{}".format(mapped_field)]: + return None + else: + return "{mapped_field} {comparator} {value}".format( + mapped_field=mapped_field, comparator=comparator, value=value) + + @staticmethod + def _parse_mapped_fields(self, expression, value, comparator, stix_field, mapped_fields_array): + comparison_string = "" + is_reference_value = self._is_reference_value(stix_field) + # Need to use expression.value to match against regex since the passed-in value has already been formated. + value_type = self._check_value_type(expression.value) if is_reference_value else None + mapped_fields_count = 1 if is_reference_value else len(mapped_fields_array) + + for mapped_field in mapped_fields_array: + if is_reference_value: + parsed_reference = self._parse_reference(self, stix_field, value_type, mapped_field, value, comparator) + if not parsed_reference: + continue + comparison_string += parsed_reference + else: + comparison_string += "{mapped_field} {comparator} {value}".format(mapped_field=mapped_field, comparator=comparator, value=value) + + if (mapped_fields_count > 1): + comparison_string += " OR " + mapped_fields_count -= 1 + return comparison_string + + @staticmethod + def _is_reference_value(stix_field): + return stix_field == 'src_ref.value' or stix_field == 'dst_ref.value' + def _parse_expression(self, expression, qualifier=None) -> str: if isinstance(expression, ComparisonExpression): # Base Case # Resolve STIX Object Path to a field in the target Data Model @@ -99,24 +150,8 @@ def _parse_expression(self, expression, qualifier=None) -> str: else: value = self._escape_value(expression.value) - comparison_string = "" - mapped_fields_count = len(mapped_fields_array) - for mapped_field in mapped_fields_array: - # TODO: REMOVE THESE SPECIAL CASES - # if its a set operator() query construction will be different. - if expression.comparator == ComparisonComparators.IsSubSet: - comparison_string += comparator + "(" + "'" + value + "'," + mapped_field + ")" - else: - comparison_string += "{mapped_field} {comparator} {value}".format( - mapped_field=mapped_field, comparator=comparator, value=value) - - # Separate each conditional statement that maps to the same STIX attribute. - # Use whatever syntax/operator is required by the data source ('OR', ',', ' ', etc.) - if (mapped_fields_count > 1): - comparison_string += " OR " - mapped_fields_count -= 1 - - if(len(mapped_fields_array) > 1): + comparison_string = self._parse_mapped_fields(self, expression, value, comparator, stix_field, mapped_fields_array) + if(len(mapped_fields_array) > 1 and not self._is_reference_value(stix_field)): # More than one data source field maps to the STIX attribute, so group comparisons together. grouped_comparison_string = "(" + comparison_string + ")" comparison_string = grouped_comparison_string @@ -132,9 +167,16 @@ def _parse_expression(self, expression, qualifier=None) -> str: return "{}".format(comparison_string) elif isinstance(expression, CombinedComparisonExpression): - query_string = "{} {} {}".format(self._parse_expression(expression.expr1), - self.comparator_lookup[expression.operator], - self._parse_expression(expression.expr2)) + operator = self.comparator_lookup[expression.operator] + expression_01 = self._parse_expression(expression.expr1) + expression_02 = self._parse_expression(expression.expr2) + if not expression_01 or not expression_02: + return '' + if isinstance(expression.expr1, CombinedComparisonExpression): + expression_01 = "({})".format(expression_01) + if isinstance(expression.expr2, CombinedComparisonExpression): + expression_02 = "({})".format(expression_02) + query_string = "{} {} {}".format(expression_01, operator, expression_02) if qualifier is not None: return "{} {}".format(query_string, qualifier) else: @@ -152,9 +194,16 @@ def _parse_expression(self, expression, qualifier=None) -> str: return self._parse_expression(expression.observation_expression.comparison_expression, expression.qualifier) elif isinstance(expression, CombinedObservationExpression): operator = self.comparator_lookup[expression.operator] - return "{expr1} {operator} {expr2}".format(expr1=self._parse_expression(expression.expr1), - operator=operator, - expr2=self._parse_expression(expression.expr2)) + expression_01 = self._parse_expression(expression.expr1) + expression_02 = self._parse_expression(expression.expr2) + if expression_01 and expression_02: + return "({}) {} ({})".format(expression_01, operator, expression_02) + elif expression_01: + return "{}".format(expression_01) + elif expression_02: + return "{}".format(expression_02) + else: + return '' elif isinstance(expression, Pattern): return "{expr}".format(expr=self._parse_expression(expression.expression)) else: @@ -166,11 +215,12 @@ def parse_expression(self, pattern: Pattern): def translate_pattern(pattern: Pattern, data_model_mapping): - query = DummyQueryStringPatternTranslator(pattern, data_model_mapping).translated + query = QueryStringPatternTranslator(pattern, data_model_mapping).translated # Add space around START STOP qualifiers query = re.sub("START", "START ", query) query = re.sub("STOP", " STOP ", query) # Change return statement as required to fit with data source query language. # If supported by the language, a limit on the number of results may be desired. - return "SELECT * FROM dummyTableName WHERE {}".format(query) + # A single query string, or an array of query strings may be returned + return "SELECT * FROM tableName WHERE {}".format(query) diff --git a/stix_shifter/stix_translation/src/modules/dummy/stix_to_dummy_query.py b/stix_shifter/stix_translation/src/modules/dummy/stix_to_query.py similarity index 77% rename from stix_shifter/stix_translation/src/modules/dummy/stix_to_dummy_query.py rename to stix_shifter/stix_translation/src/modules/dummy/stix_to_query.py index 5adb693ea..e2d616251 100644 --- a/stix_shifter/stix_translation/src/modules/dummy/stix_to_dummy_query.py +++ b/stix_shifter/stix_translation/src/modules/dummy/stix_to_query.py @@ -2,13 +2,13 @@ from ...patterns.parser import generate_query from ..base.base_query_translator import BaseQueryTranslator -from . import dummy_data_mapping -from . import dummy_query_constructor +from . import data_mapping +from . import query_constructor logger = logging.getLogger(__name__) -class StixToDummyQuery(BaseQueryTranslator): +class StixToQuery(BaseQueryTranslator): def transform_query(self, data, options, mapping=None): """ @@ -24,8 +24,8 @@ def transform_query(self, data, options, mapping=None): logger.info("Converting STIX2 Pattern to data source query") query_object = generate_query(data) - data_model_mapper = dummy_data_mapping.DummyDataMapper(options) + data_model_mapper = data_mapping.DataMapper(options) - query_string = dummy_query_constructor.translate_pattern( + query_string = query_constructor.translate_pattern( query_object, data_model_mapper) return query_string diff --git a/stix_shifter/stix_transmission/src/modules/async_dummy/apiclient.py b/stix_shifter/stix_transmission/src/modules/async_dummy/apiclient.py new file mode 100644 index 000000000..d6839c7cd --- /dev/null +++ b/stix_shifter/stix_transmission/src/modules/async_dummy/apiclient.py @@ -0,0 +1,31 @@ +from ..utils.RestApiClient import RestApiClient + + +class APIClient(): + + def __init__(self, connection, configuration): + self.client = "data source API client" + + def ping_data_source(self): + # Pings the data source + return "async ping" + + def create_search(self, query_expression): + # Queries the data source + return { + "code": 200, + "query_id": "uuid_1234567890" + } + + def get_search_status(self, search_id): + # Check the current status of the search + return {"code": 200, "search_id": search_id, "status": "COMPLETED"} + + def get_search_results(self, search_id, range_start=None, range_end=None): + # Return the search results. Results must be in JSON format before being translated into STIX + return {"code": 200, "search_id": search_id, "data": "Results for search"} + + def delete_search(self, search_id): + # Optional since this may not be supported by the data source API + # Delete the search + return "Deleted query: {}".format(search_id) diff --git a/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_connector.py b/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_connector.py index 79f199d40..457b10c6e 100644 --- a/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_connector.py +++ b/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_connector.py @@ -1,17 +1,107 @@ from ..base.base_connector import BaseConnector -from .async_dummy_ping import AsyncDummyPing -from .async_dummy_query_connector import AsyncDummyQueryConnector -from .async_dummy_status_connector import AsyncDummyStatusConnector -from .async_dummy_results_connector import AsyncDummyResultsConnector +from .apiclient import APIClient +from ..base.base_status_connector import Status +from json import loads +from enum import Enum + + +class DatasourceStatus(Enum): + # WAIT, EXECUTE, SORTING, COMPLETED, CANCELED, ERROR + WAIT = 'WAIT' + EXECUTE = 'EXECUTE' + SORTING = 'SORTING' + COMPLETED = 'COMPLETED' + CANCELED = 'CANCELED' + ERROR = 'ERROR' class Connector(BaseConnector): def __init__(self, connection, configuration): - host = connection.get('host') - port = connection.get('port') - path = connection.get('path') - self.query_connector = AsyncDummyQueryConnector(host, port, path) - self.status_connector = AsyncDummyStatusConnector(host, port, path) - self.results_connector = AsyncDummyResultsConnector(host, port, path) + self.api_client = APIClient(connection, configuration) self.is_async = True - self.ping_connector = AsyncDummyPing(host, port, path) + + self.results_connector = self + self.query_connector = self + self.ping_connector = self + self.delete_connector = self + self.status_connector = self + + def ping(self): + try: + response = self.api_client.ping_data_source() + return response + except Exception as err: + print('error when pinging datasource {}:'.format(err)) + raise + + def create_query_connection(self, query): + try: + response = self.api_client.create_search(query) + return response + except Exception as err: + print('error when creating search: {}'.format(err)) + raise + + # Map data source status to connector status + def __getStatus(self, status): + switcher = { + DatasourceStatus.WAIT.value: Status.RUNNING, + DatasourceStatus.EXECUTE.value: Status.RUNNING, + DatasourceStatus.SORTING.value: Status.RUNNING, + DatasourceStatus.COMPLETED.value: Status.COMPLETED, + DatasourceStatus.CANCELED.value: Status.CANCELED, + DatasourceStatus.ERROR.value: Status.ERROR + } + return switcher.get(status).value + + def create_status_connection(self, search_id): + try: + response = self.api_client.get_search_status(search_id) + # Based on the response + # return_obj['success'] = True or False + # return_obj['status'] = One of the statuses as defined in the Status class: + # Status.RUNNING, Status.COMPLETED, Status.CANCELED, Status.ERROR + # return_obj['progress'] = Some progress code if returned from the API + # Construct a response object + response_code = response["code"] + return_obj = dict() + + if response_code == 200: + return_obj['success'] = True + return_obj['status'] = self.__getStatus(response["status"]) + else: + return_obj['success'] = False + return_obj['error'] = response['message'] + return return_obj + except Exception as err: + print('error when getting search status: {}'.format(err)) + raise + + def create_results_connection(self, search_id, offset, length): + try: + min_range = offset + max_range = offset + length + # Grab the response, extract the response code, and convert it to readable json + response = self.api_client.get_search_results(search_id, min_range, max_range) + response_code = response["code"] + + # Construct a response object + return_obj = dict() + if response_code == 200: + return_obj['success'] = True + return_obj['data'] = response['data'] + else: + return_obj['success'] = False + return_obj['error'] = response['message'] + return return_obj + except Exception as err: + print('error when getting search results: {}'.format(err)) + raise + + def delete_query_connection(self, search_id): + try: + response = self.api_client.delete_search(search_id) + return response + except Exception as err: + print('error when deleting search {}:'.format(err)) + raise diff --git a/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_ping.py b/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_ping.py deleted file mode 100644 index 8fe0c57b4..000000000 --- a/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_ping.py +++ /dev/null @@ -1,11 +0,0 @@ -from ..base.base_ping import BasePing - - -class AsyncDummyPing(BasePing): - def __init__(self, host, port, path): - self.host = host - self.port = port - self.path = path - - def ping(self): - return 'async ping' diff --git a/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_query_connector.py b/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_query_connector.py deleted file mode 100644 index 6324bbfeb..000000000 --- a/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_query_connector.py +++ /dev/null @@ -1,32 +0,0 @@ -from ..base.base_query_connector import BaseQueryConnector - - -class AsyncDummyQueryConnector(BaseQueryConnector): - def __init__(self, host, port, path): - self.host = host - self.port = port - self.path = path - - def create_query_connection(self, query): - # set headers - headers = { - "Content-Type": "application/json", - "Accept": "application/json" - } - - # construct request object, purely for visual purposes in dummy implementation - request = { - "host": self.host, - "path": self.path + query, - "port": self.port, - "headers": headers, - "method": "POST" - } - - # return a mocked request - print(request) - - return { - "response_code": 200, - "query_id": "uuid_1234567890" - } diff --git a/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_results_connector.py b/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_results_connector.py deleted file mode 100644 index e142fb6b9..000000000 --- a/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_results_connector.py +++ /dev/null @@ -1,52 +0,0 @@ -from ..base.base_results_connector import BaseResultsConnector -from ..base.base_status_connector import Status -import time - -QUERY_ID_TABLE = { - "uuid_1234567890": Status.COMPLETED.value, - "uuid_not_done": Status.RUNNING.value, - "uuid_should_error": Status.ERROR.value -} - -RETURN_DUMMY_DATA = { - "uuid_1234567890": "some data" -} - - -class AsyncDummyResultsConnector(BaseResultsConnector): - def __init__(self, host, port, path): - self.host = host - self.port = port - self.path = path - - def create_results_connection(self, query_id, offset, length): - # set headers - headers = { - "Content-Type": "application/json", - "Accept": "application/json" - } - - # construct request object, purely for visual purposes in dummy implementation - request = { - "host": self.host, - "path": self.path + query_id, - "port": self.port, - "headers": headers, - "method": "GET" - } - - print(request) - time.sleep(3) - return_obj = {} - - if QUERY_ID_TABLE[query_id] == Status.COMPLETED.value and RETURN_DUMMY_DATA[query_id]: - return_obj["success"] = True - return_obj["data"] = RETURN_DUMMY_DATA[query_id] - elif QUERY_ID_TABLE[query_id] == Status.RUNNING.value: - return_obj["success"] = False - return_obj["error"] = "Query is not finished processing" - else: - return_obj["success"] = False - return_obj["error"] = "Error: query results not found" - - return return_obj diff --git a/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_status_connector.py b/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_status_connector.py deleted file mode 100644 index 8a3a893b9..000000000 --- a/stix_shifter/stix_transmission/src/modules/async_dummy/async_dummy_status_connector.py +++ /dev/null @@ -1,42 +0,0 @@ -from ..base.base_status_connector import BaseStatusConnector -from ..base.base_status_connector import Status - -QUERY_ID_TABLE = { - "uuid_1234567890": Status.COMPLETED.value, - "uuid_not_done": Status.RUNNING.value, -} - - -class AsyncDummyStatusConnector(BaseStatusConnector): - def __init__(self, host, port, path): - self.host = host - self.port = port - self.path = path - - def create_status_connection(self, query_id): - # set headers - headers = { - "Content-Type": "application/json", - "Accept": "application/json" - } - - # construct request object, purely for visual purposes in dummy implementation - request = { - "host": self.host, - "path": self.path + query_id, - "port": self.port, - "headers": headers, - "method": "GET" - } - - print(request) - return_obj = {} - - if query_id not in QUERY_ID_TABLE: - return_obj["success"] = False - return_obj["error"] = "query id does not exist" - else: - return_obj["success"] = True - return_obj["status"] = QUERY_ID_TABLE[query_id] - - return return_obj diff --git a/stix_shifter/stix_transmission/src/modules/bigfix/Utilities.py b/stix_shifter/stix_transmission/src/modules/bigfix/Utilities.py deleted file mode 100644 index 93391756c..000000000 --- a/stix_shifter/stix_transmission/src/modules/bigfix/Utilities.py +++ /dev/null @@ -1,41 +0,0 @@ -import sys -import json - - -# This function prints out the response from an endpoint in a consistent way. -def pretty_print_response(response): - print(response.code) - parsed_response = json.loads(response.read().decode('utf-8')) - print(json.dumps(parsed_response, indent=4)) - return - - -# this function prints out information about a request that will be made -# to the API. -def pretty_print_request(client, path, method, headers=None): - ip = client.get_server_ip() - base_uri = client.get_base_uri() - - header_copy = client.get_headers().copy() - if headers is not None: - header_copy.update(headers) - - url = 'https://' + ip + base_uri + path - print('Sending a ' + method + ' request to:') - print(url) - print('with these headers:') - print(header_copy) - print() - - -# this function sets up data to be used by a sample. If the data already exists -# it prefers to use the existing data. -def data_setup(client, path, method, params=[]): - response = client.call_api(path, method, params=params) - if (response.code == 409): - print("Data already exists, using existing data") - elif(response.code >= 400): - print("An error occurred setting up sample data:") - pretty_print_response(response) - sys.exit(1) - return response \ No newline at end of file diff --git a/stix_shifter/stix_transmission/src/modules/qradar/Utilities.py b/stix_shifter/stix_transmission/src/modules/qradar/Utilities.py deleted file mode 100644 index 93391756c..000000000 --- a/stix_shifter/stix_transmission/src/modules/qradar/Utilities.py +++ /dev/null @@ -1,41 +0,0 @@ -import sys -import json - - -# This function prints out the response from an endpoint in a consistent way. -def pretty_print_response(response): - print(response.code) - parsed_response = json.loads(response.read().decode('utf-8')) - print(json.dumps(parsed_response, indent=4)) - return - - -# this function prints out information about a request that will be made -# to the API. -def pretty_print_request(client, path, method, headers=None): - ip = client.get_server_ip() - base_uri = client.get_base_uri() - - header_copy = client.get_headers().copy() - if headers is not None: - header_copy.update(headers) - - url = 'https://' + ip + base_uri + path - print('Sending a ' + method + ' request to:') - print(url) - print('with these headers:') - print(header_copy) - print() - - -# this function sets up data to be used by a sample. If the data already exists -# it prefers to use the existing data. -def data_setup(client, path, method, params=[]): - response = client.call_api(path, method, params=params) - if (response.code == 409): - print("Data already exists, using existing data") - elif(response.code >= 400): - print("An error occurred setting up sample data:") - pretty_print_response(response) - sys.exit(1) - return response \ No newline at end of file diff --git a/stix_shifter/stix_transmission/src/modules/qradar/qradar_connector.py b/stix_shifter/stix_transmission/src/modules/qradar/qradar_connector.py index c1708b3d3..cc30f7aa8 100644 --- a/stix_shifter/stix_transmission/src/modules/qradar/qradar_connector.py +++ b/stix_shifter/stix_transmission/src/modules/qradar/qradar_connector.py @@ -1,18 +1,141 @@ from ..base.base_connector import BaseConnector -from .qradar_ping import QRadarPing -from .qradar_query_connector import QRadarQueryConnector -from .qradar_status_connector import QRadarStatusConnector -from .qradar_delete_connector import QRadarDeleteConnector -from .qradar_results_connector import QRadarResultsConnector +from ..base.base_status_connector import Status from .arielapiclient import APIClient +from json import loads +from enum import Enum + + +class QRadarStatus(Enum): + # WAIT, EXECUTE, SORTING, COMPLETED, CANCELED, ERROR + WAIT = 'WAIT' + EXECUTE = 'EXECUTE' + SORTING = 'SORTING' + COMPLETED = 'COMPLETED' + CANCELED = 'CANCELED' + ERROR = 'ERROR' class Connector(BaseConnector): def __init__(self, connection, configuration): self.api_client = APIClient(connection, configuration) - self.results_connector = QRadarResultsConnector(self.api_client) - self.status_connector = QRadarStatusConnector(self.api_client) - self.delete_connector = QRadarDeleteConnector(self.api_client) - self.query_connector = QRadarQueryConnector(self.api_client) - self.ping_connector = QRadarPing(self.api_client) self.is_async = True + + self.results_connector = self + self.query_connector = self + self.ping_connector = self + self.delete_connector = self + self.status_connector = self + + def ping(self): + try: + response = self.api_client.ping_box() + response_code = response.code + + response_json = loads(response.read()) + + return_obj = dict() + return_obj['success'] = False + + if len(response_json) > 0 and response_code == 200: + return_obj['success'] = True + else: + return_obj['error'] = response_json['message'] + + return return_obj + except Exception as err: + print('error when pinging datasource {}:'.format(err)) + raise + + def create_query_connection(self, query): + # Grab the response, extract the response code, and convert it to readable json + try: + response = self.api_client.create_search(query) + response_code = response.code + response_json = loads(response.read()) + + # Construct a response object + return_obj = dict() + + if response_code == 201: + return_obj['success'] = True + return_obj['search_id'] = response_json['search_id'] + else: + return_obj['success'] = False + return_obj['error'] = response_json['message'] + return return_obj + except Exception as err: + print('error when creating search: {}'.format(err)) + raise + + def __getStatus(self, qradar_status): + switcher = { + QRadarStatus.WAIT.value: Status.RUNNING, + QRadarStatus.EXECUTE.value: Status.RUNNING, + QRadarStatus.SORTING.value: Status.RUNNING, + QRadarStatus.COMPLETED.value: Status.COMPLETED, + QRadarStatus.CANCELED.value: Status.CANCELED, + QRadarStatus.ERROR.value: Status.ERROR + } + return switcher.get(qradar_status).value + + def create_status_connection(self, search_id): + # Grab the response, extract the response code, and convert it to readable json + try: + response = self.api_client.get_search(search_id) + response_code = response.code + response_json = loads(response.read()) + + # Construct a response object + return_obj = dict() + + if response_code == 200: + return_obj['success'] = True + return_obj['status'] = self.__getStatus(response_json['status']) + return_obj['progress'] = response_json['progress'] + else: + return_obj['success'] = False + return_obj['error'] = response_json['message'] + return return_obj + except Exception as err: + print('error when getting search status: {}'.format(err)) + raise + + def create_results_connection(self, search_id, offset, length): + min_range = offset + max_range = offset + length + # Grab the response, extract the response code, and convert it to readable json + try: + response = self.api_client.get_search_results(search_id, 'application/json', min_range, max_range) + response_code = response.code + + # Construct a response object + response_json = loads(response.read()) + return_obj = dict() + if response_code == 200: + return_obj['success'] = True + return_obj['data'] = response_json['events'] + else: + return_obj['success'] = False + return_obj['error'] = response_json['message'] + return return_obj + except Exception as err: + print('error when getting search results: {}'.format(err)) + raise + + def delete_query_connection(self, search_id): + try: + response = self.api_client.delete_search(search_id) + response_code = response.code + response_json = loads(response.read()) + # Construct a response object + return_obj = dict() + if response_code == 202: + return_obj['success'] = True + else: + return_obj['success'] = False + return_obj['error'] = response_json['message'] + + return return_obj + except Exception as err: + print('error when deleting search {}:'.format(err)) + raise diff --git a/stix_shifter/stix_transmission/src/modules/qradar/qradar_delete_connector.py b/stix_shifter/stix_transmission/src/modules/qradar/qradar_delete_connector.py deleted file mode 100644 index ed03d9fa4..000000000 --- a/stix_shifter/stix_transmission/src/modules/qradar/qradar_delete_connector.py +++ /dev/null @@ -1,25 +0,0 @@ -from ..base.base_delete_connector import BaseDeleteConnector -import json - - -class QRadarDeleteConnector(BaseDeleteConnector): - def __init__(self, api_client): - self.api_client = api_client - - def delete_query_connection(self, search_id): - try: - response = self.api_client.delete_search(search_id) - response_code = response.code - response_json = json.loads(response.read()) - # Construct a response object - return_obj = dict() - if response_code == 202: - return_obj['success'] = True - else: - return_obj['success'] = False - return_obj['error'] = response_json['message'] - - return return_obj - except Exception as err: - print('error when deleting search {}:'.format(err)) - raise diff --git a/stix_shifter/stix_transmission/src/modules/qradar/qradar_ping.py b/stix_shifter/stix_transmission/src/modules/qradar/qradar_ping.py deleted file mode 100644 index 47588e39e..000000000 --- a/stix_shifter/stix_transmission/src/modules/qradar/qradar_ping.py +++ /dev/null @@ -1,27 +0,0 @@ -from ..base.base_ping import BasePing -import json - - -class QRadarPing(BasePing): - def __init__(self, api_client): - self.api_client = api_client - - def ping(self): - try: - response = self.api_client.ping_box() - response_code = response.code - - response_json = json.loads(response.read()) - - return_obj = dict() - return_obj['success'] = False - - if len(response_json) > 0 and response_code == 200: - return_obj['success'] = True - else: - return_obj['error'] = response_json['message'] - - return return_obj - except Exception as err: - print('error when pinging datasource {}:'.format(err)) - raise diff --git a/stix_shifter/stix_transmission/src/modules/qradar/qradar_query_connector.py b/stix_shifter/stix_transmission/src/modules/qradar/qradar_query_connector.py deleted file mode 100644 index 5f83da236..000000000 --- a/stix_shifter/stix_transmission/src/modules/qradar/qradar_query_connector.py +++ /dev/null @@ -1,28 +0,0 @@ -from ..base.base_query_connector import BaseQueryConnector -import json - - -class QRadarQueryConnector(BaseQueryConnector): - def __init__(self, api_client): - self.api_client = api_client - - def create_query_connection(self, query): - # Grab the response, extract the response code, and convert it to readable json - try: - response = self.api_client.create_search(query) - response_code = response.code - response_json = json.loads(response.read()) - - # Construct a response object - return_obj = dict() - - if response_code == 201: - return_obj['success'] = True - return_obj['search_id'] = response_json['search_id'] - else: - return_obj['success'] = False - return_obj['error'] = response_json['message'] - return return_obj - except Exception as err: - print('error when creating search: {}'.format(err)) - raise diff --git a/stix_shifter/stix_transmission/src/modules/qradar/qradar_results_connector.py b/stix_shifter/stix_transmission/src/modules/qradar/qradar_results_connector.py deleted file mode 100644 index 91dc8820c..000000000 --- a/stix_shifter/stix_transmission/src/modules/qradar/qradar_results_connector.py +++ /dev/null @@ -1,29 +0,0 @@ -from ..base.base_results_connector import BaseResultsConnector -import json - - -class QRadarResultsConnector(BaseResultsConnector): - def __init__(self, api_client): - self.api_client = api_client - - def create_results_connection(self, search_id, offset, length): - min_range = offset - max_range = offset + length - # Grab the response, extract the response code, and convert it to readable json - try: - response = self.api_client.get_search_results(search_id, 'application/json', min_range, max_range) - response_code = response.code - - # Construct a response object - response_json = json.loads(response.read()) - return_obj = dict() - if response_code == 200: - return_obj['success'] = True - return_obj['data'] = response_json['events'] - else: - return_obj['success'] = False - return_obj['error'] = response_json['message'] - return return_obj - except Exception as err: - print('error when getting search results: {}'.format(err)) - raise diff --git a/stix_shifter/stix_transmission/src/modules/qradar/qradar_status_connector.py b/stix_shifter/stix_transmission/src/modules/qradar/qradar_status_connector.py deleted file mode 100644 index aab6c6448..000000000 --- a/stix_shifter/stix_transmission/src/modules/qradar/qradar_status_connector.py +++ /dev/null @@ -1,52 +0,0 @@ -from ..base.base_status_connector import BaseStatusConnector -from ..base.base_status_connector import Status -from enum import Enum -import json - - -class QRadarStatus(Enum): - # WAIT, EXECUTE, SORTING, COMPLETED, CANCELED, ERROR - WAIT = 'WAIT' - EXECUTE = 'EXECUTE' - SORTING = 'SORTING' - COMPLETED = 'COMPLETED' - CANCELED = 'CANCELED' - ERROR = 'ERROR' - - -class QRadarStatusConnector(BaseStatusConnector): - def __init__(self, api_client): - self.api_client = api_client - - def __getStatus(self, qradar_status): - switcher = { - QRadarStatus.WAIT.value: Status.RUNNING, - QRadarStatus.EXECUTE.value: Status.RUNNING, - QRadarStatus.SORTING.value: Status.RUNNING, - QRadarStatus.COMPLETED.value: Status.COMPLETED, - QRadarStatus.CANCELED.value: Status.CANCELED, - QRadarStatus.ERROR.value: Status.ERROR - } - return switcher.get(qradar_status).value - - def create_status_connection(self, search_id): - # Grab the response, extract the response code, and convert it to readable json - try: - response = self.api_client.get_search(search_id) - response_code = response.code - response_json = json.loads(response.read()) - - # Construct a response object - return_obj = dict() - - if response_code == 200: - return_obj['success'] = True - return_obj['status'] = self.__getStatus(response_json['status']) - return_obj['progress'] = response_json['progress'] - else: - return_obj['success'] = False - return_obj['error'] = response_json['message'] - return return_obj - except Exception as err: - print('error when getting search status: {}'.format(err)) - raise diff --git a/stix_shifter/stix_transmission/src/modules/splunk/Utilities.py b/stix_shifter/stix_transmission/src/modules/splunk/Utilities.py deleted file mode 100644 index 6a31c5c92..000000000 --- a/stix_shifter/stix_transmission/src/modules/splunk/Utilities.py +++ /dev/null @@ -1,41 +0,0 @@ -import sys -import json - - -# This function prints out the response from an endpoint in a consistent way. -def pretty_print_response(response): - print(response.code) - parsed_response = json.loads(response.read().decode('utf-8')) - print(json.dumps(parsed_response, indent=4)) - return - - -# this function prints out information about a request that will be made -# to the API. -def pretty_print_request(client, path, method, headers=None): - ip = client.get_server_ip() - base_uri = client.get_base_uri() - - header_copy = client.get_headers().copy() - if headers is not None: - header_copy.update(headers) - - url = 'https://' + ip + path - print('Sending a ' + method + ' request to:') - print(url) - print('with these headers:') - print(header_copy) - print() - - -# this function sets up data to be used by a sample. If the data already exists -# it prefers to use the existing data. -def data_setup(client, path, method, params=[]): - response = client.call_api(path, method, params=params) - if (response.code == 409): - print("Data already exists, using existing data") - elif(response.code >= 400): - print("An error occurred setting up sample data:") - pretty_print_response(response) - sys.exit(1) - return response \ No newline at end of file diff --git a/stix_shifter/stix_transmission/src/modules/synchronous_dummy/synchronous_dummy_connector.py b/stix_shifter/stix_transmission/src/modules/synchronous_dummy/synchronous_dummy_connector.py index d9ebef1e0..63446c7a9 100644 --- a/stix_shifter/stix_transmission/src/modules/synchronous_dummy/synchronous_dummy_connector.py +++ b/stix_shifter/stix_transmission/src/modules/synchronous_dummy/synchronous_dummy_connector.py @@ -1,10 +1,56 @@ from ..base.base_connector import BaseConnector -from .synchronous_dummy_results_connector import SynchronousDummyResultsConnector -from .synchronous_dummy_ping import SynchronousDummyPing +# from .synchronous_dummy_results_connector import SynchronousDummyResultsConnector +# from .synchronous_dummy_ping import SynchronousDummyPing +import time class Connector(BaseConnector): def __init__(self): - self.results_connector = SynchronousDummyResultsConnector() self.is_async = False - self.ping = SynchronousDummyPing() + + self.results_connector = self + self.ping_connector = self + + def ping(self): + return "synchronous ping" + + def create_results_connection(self, params, options): + """ + Creates a connection to the specified datasource to send a query + + :param params: the parameters for the query + :param options: CLI options passed in + + :return: in dummy connectors, just returns passed in parameters + """ + config = params['config'] + + # The post-processed query, already translated from STIX SCO + query = params['query'] + + # set headers + headers = { + "Content-Type": "application/json", + "Accept": "application/json" + } + + # construct request object, purely for visual purposes in dummy implementation + request = { + "host": config['host'], + "path": config['path'] + query, + "port": config['port'], + "headers": headers, + "method": "GET" + } + + print(request) + time.sleep(3) + + dummy_data = {"obj_1": {}, "obj_2": {}, "obj_3": {}, "obj_4": {}, "obj_5": {}} + + return_obj = { + "response_code": 200, + "query_results": dummy_data + } + + return return_obj diff --git a/stix_shifter/stix_transmission/src/modules/synchronous_dummy/synchronous_dummy_ping.py b/stix_shifter/stix_transmission/src/modules/synchronous_dummy/synchronous_dummy_ping.py deleted file mode 100644 index 8fa400b01..000000000 --- a/stix_shifter/stix_transmission/src/modules/synchronous_dummy/synchronous_dummy_ping.py +++ /dev/null @@ -1,6 +0,0 @@ -from ..base.base_ping import BasePing - - -class SynchronousDummyPing(BasePing): - def ping(self): - return "synchronous ping" diff --git a/stix_shifter/stix_transmission/src/modules/synchronous_dummy/synchronous_dummy_results_connector.py b/stix_shifter/stix_transmission/src/modules/synchronous_dummy/synchronous_dummy_results_connector.py deleted file mode 100644 index e4fc1576a..000000000 --- a/stix_shifter/stix_transmission/src/modules/synchronous_dummy/synchronous_dummy_results_connector.py +++ /dev/null @@ -1,50 +0,0 @@ -from ..base.base_results_connector import BaseResultsConnector -import time - -RETURN_DUMMY_DATA = { - "obj_1": {}, - "obj_2": {}, - "obj_3": {}, - "obj_4": {}, - "obj_5": {}, -} - - -class SynchronousDummyResultsConnector(BaseResultsConnector): - def create_results_connection(self, params, options): - """ - Creates a connection to the specified datasource to send a query - - :param params: the parameters for the query - :param options: CLI options passed in - - :return: in dummy connectors, just returns passed in parameters - """ - config = params['config'] - - # The post-processed query, already translated from STIX SCO - query = params['query'] - - # set headers - headers = { - "Content-Type": "application/json", - "Accept": "application/json" - } - - # construct request object, purely for visual purposes in dummy implementation - request = { - "host": config['host'], - "path": config['path'] + query, - "port": config['port'], - "headers": headers, - "method": "GET" - } - - print(request) - time.sleep(3) - return_obj = { - "response_code": 200, - "query_results": RETURN_DUMMY_DATA - } - - return return_obj diff --git a/tests/stix_transmission/test_async_dummy.py b/tests/stix_transmission/test_async_dummy.py index 099cc70c5..ae984c891 100644 --- a/tests/stix_transmission/test_async_dummy.py +++ b/tests/stix_transmission/test_async_dummy.py @@ -10,14 +10,12 @@ def test_dummy_async_query(self): "port": "8080", "path": "/" } - query_interface = async_dummy_connector.Connector(connection, None) - + interface = async_dummy_connector.Connector(connection, None) query = "placeholder query text" + query_response = interface.create_query_connection(query) - query_response = query_interface.create_query_connection(query) - query_id = query_response['query_id'] - - assert query_id == "uuid_1234567890" + assert query_response['query_id'] == "uuid_1234567890" + assert query_response['code'] == 200 def test_dummy_async_status(self): connection = { @@ -25,68 +23,29 @@ def test_dummy_async_status(self): "port": "8080", "path": "/" } - status_interface = async_dummy_connector.Connector(connection, None) - + interface = async_dummy_connector.Connector(connection, None) query_id = "uuid_1234567890" + status_response = interface.create_status_connection(query_id) - status_response = status_interface.create_status_connection(query_id) + success = status_response["success"] + assert success == True status = status_response["status"] assert status == Status.COMPLETED.value - def test_dummy_async_results_error(self): - connection = { - "host": "hostbla", - "port": "8080", - "path": "/" - } - results_interface = async_dummy_connector.Connector(connection, None) - - query_id = "uuid_should_error" - offset = 0 - length = 1 - results_response = results_interface.create_results_connection(query_id, offset, length) - - success = results_response["success"] - assert success is not True - query_results = results_response["error"] - assert query_results == "Error: query results not found" - - def test_dummy_async_results_running(self): + def test_dummy_async_results(self): connection = { "host": "hostbla", "port": "8080", "path": "/" } - results_interface = async_dummy_connector.Connector(connection, None) - - query_id = "uuid_not_done" - offset = 0 - length = 1 - results_response = results_interface.create_results_connection(query_id, offset, length) - - query_results = results_response["error"] - success = results_response["success"] - assert success is not True - assert query_results == "Query is not finished processing" - - def test_dummy_async_results_success(self): - connection = { - "host": "hostbla", - "port": "8080", - "path": "/" - } - results_interface = async_dummy_connector.Connector(connection, None) - + interface = async_dummy_connector.Connector(connection, None) query_id = "uuid_1234567890" - offset = 0 - length = 1 - - results_response = results_interface.create_results_connection(query_id, offset, length) - query_results = results_response["data"] + results_response = interface.create_results_connection(query_id, 1, 1) success = results_response["success"] - assert success - assert query_results + assert success == True + data = results_response["data"] + assert data == "Results for search" def test_is_async(self): connection = { diff --git a/tests/stix_transmission/test_synchronous_dummy.py b/tests/stix_transmission/test_synchronous_dummy.py index e17098e0f..3303e212c 100644 --- a/tests/stix_transmission/test_synchronous_dummy.py +++ b/tests/stix_transmission/test_synchronous_dummy.py @@ -1,6 +1,4 @@ from stix_shifter.stix_transmission.src.modules.synchronous_dummy import synchronous_dummy_connector -from stix_shifter.stix_transmission.src.modules.synchronous_dummy import synchronous_dummy_results_connector -from stix_shifter.stix_transmission.src.modules.synchronous_dummy import synchronous_dummy_ping import unittest @@ -11,13 +9,11 @@ def test_is_async(self): assert check_async == False def test_ping(self): - ping_interface = synchronous_dummy_ping.SynchronousDummyPing() - ping_result = ping_interface.ping() - + interface = synchronous_dummy_connector.Connector() + ping_result = interface.ping() assert ping_result == "synchronous ping" def test_dummy_sync_results(self): - results_interface = synchronous_dummy_results_connector.SynchronousDummyResultsConnector() options = {} params = { "config": { @@ -29,7 +25,8 @@ def test_dummy_sync_results(self): "query": "placeholder query text" } - results_response = results_interface.create_results_connection(params, options) + interface = synchronous_dummy_connector.Connector() + results_response = interface.create_results_connection(params, options) response_code = results_response["response_code"] query_results = results_response["query_results"]