ExportIndicators Deprecated

Deprecated. Use the Generic Export Indicators Service integration instead. Use the Export Indicators Service integration to provide an endpoint with a list of indicators as a service for the system indicators.

Data Enrichment & Threat Intelligence · Export Indicators (Deprecated)

Details

IDExportIndicators
ProviderOpen Source
CategoryData Enrichment & Threat Intelligence
From Version5.5.0
Docker Imagedemisto/flask-nginx:1.0.0.23674

README

Use the Export Indicators Service integration to provide an endpoint with a list of indicators as a service for the system indicators.

Use Cases


  1. Export a list of malicious IPs to block via a firewall.
  2. Export a list of indicators to a service such as Splunk, using a supported output format.

Configure ExportIndicators on Cortex XSOAR


  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for ExportIndicators.
  3. Click Add instance to create and configure a new integration instance.
    • Name: a textual name for the integration instance.
    • Indicator Query: The query to run to update its list. To view expected results, you can run the following command from the Cortex XSOAR CLI
      !findIndicators query=<your query>
    • Outbound Format: The default format of the entries in the service. Supported formats: text, json, json-seq, csv, XSOAR json, XSOAR json-seq, XSOAR csv, PAN-OS URL, Symantec ProxySG and McAfee Web Gateway.
    • List Size: Max amount of entries in the service instance.
    • Update On Demand Only: When set to true, will only update the service indicators via eis-update command.
    • Refresh Rate: How often to refresh the export indicators list (<number> <time unit>, e.g., 12 hours, 7 days, 3
      months, 1 year)
    • Collapse IPs: Whether to collapse IPs and if so - to ranges or CIDRs.
    • Show CSV Formats as Text: If checked, csv and XSOAR-csv formats will create a textual web page instead of downloading a csv file.
    • Listen Port: Will run the Export Indicators Service on this port from within Cortex XSOAR. If you have multiple Export Indicators Service integration instances, make sure to use different listening ports to separate the outbound feeds.
    • Certificate (Required for HTTPS): HTTPS Certificate provided by pasting its values into this field.
    • Private Key (Required for HTTPS): HTTPS private key provided by pasting its values into this field.
    • HTTP Server: Ignores certificate and private key, and will run the export indicators service
      in HTTP. (Not recommended.)
    • Username: The username with which to authenticate when fetching the indicators.
    • Password: The password with which to authenticate when fetching the indicators.
    • Mcafee Gateway Indicator List Type: For use with McAfee Web Gateway format to indicate the list type.
    • PAN-OS URL Format Port Strip: For use with PAN-OS URL format - if checked will strip the port off
      urls. If not checked - url with ports will be ignored.
    • PAN-OS URL Format Drop Invalid Entries: For use with PAN-OS URL format - if checked any URL entry which is
      not compliant with PAN-OS EDL URL format the entry is dropped instead of being
      rewritten.
    • Symantec ProxySG Default Category: For use with Symantec ProxySG format - set the default category
      for the output.
    • Symantec ProxySG Listed Categories: For use with Symantec ProxySG format - set the categories that should
      be listed in the output. If not set will list all existing categories.
  4. Click Test to validate the URLs, token, and connection.

Access the Export Indicators Service by Instance Name (HTTPS)

Note: By default, the route will be open without security hardening and might expose you to network risks. Cortex XSOAR recommends that you use credentials to connect to connect to the integration.

To access the Export Indicators service by instance name, make sure Instance execute external is enabled.

  1. In Cortex XSOAR, go to Settings > About > Troubleshooting.
  2. In the Server Configuration section, verify that the instance.execute.external key is set to true. If this key does not exist, click + Add Server Configuration and add the instance.execute.external and set the value to true. See this documentation for further information.
  3. In a web browser, go to https://*<demisto_address>*/instance/execute/*<instance_name>* .

Update values in the export indicators service


Updates values stored in the export indicators service (only avaialable On-Demand).

URL Inline Arguments


Use the following arguments in the URL to change the request:

Argument Name Description Example
n The maximum number of entries in the output. If no value is provided, will use the value specified in the List Size parameter configured in the instance configuration. https://{server_host}/instance/execute/{instance_name}?n=50
s The starting entry index from which to export the indicators. https://{server_host}/instance/execute/{instance_name}?s=10&n=50
v The output format. Supports text, csv, json, json-seq,xsoar-json, xsoar-seq, xsoar-csv, mwg, panosurl and proxysg (alias: bluecoat). https://{server_host}/instance/execute/{instance_name}?v=json
q The query used to retrieve indicators from the system. https://{server_host}/instance/execute/{instance_name}?q="type:ip and sourceBrand:my_source"
t Only with mwg format. The type indicated on the top of the exported list. Supports: string, applcontrol, dimension, category, ip, mediatype, number and regex. https://{server_host}/instance/execute/{instance_name}?v=mwg&t=ip
sp Only with panosurl format. If set will strip ports off URLs, otherwise will ignore URLs with ports. https://{server_host}/instance/execute/{instance_name}?v=panosurl&sp
di Only with panosurl format. If set will ignore urls which are not compliant with PAN-OS URL format instead of being re-written. https://{server_host}/instance/execute/{instance_name}?v=panosurl&di
cd Only with proxysg format. The default category for the exported indicators. https://{server_host}/instance/execute/{instance_name}?v=proxysg&cd=default_category
ca Only with proxysg format. The categories which will be exported. Indicators not falling to these categories will be classified as the default category. https://{server_host}/instance/execute/{instance_name}?v=proxysg&ca=category1,category2
tr Whether to collapse IPs. 0 - to not collapse, 1 - collapse to ranges or 2 - collapse to CIDRs https://{server_host}/instance/execute/{instance_name}?q="type:ip and sourceBrand:my_source"&tr=1
tx Whether to output csv or xsoar-csv formats as textual web pages. https://{server_host}/instance/execute/{instance_name}?v=xsoar-csv&tx
sf The field by which to sort the indicators by. Only applicable with the so argument. lastSeen
so The direction by which to order the indicators. The options are asc or desc. Only applicable with the sf argument. asc
Base Command

eis-update

Input
Argument Name Description Required
query The query used to retrieve indicators from the system. Leave empty to use the query from the integration parameters. Optional
format The output format. Optional
list_size The maximum number of entries in the output. If no value is provided, will use the value specified in the List Size parameter configured in the instance configuration. Optional
offset The starting entry index from which to export the indicators. Optional
print_indicators If set to true will print the indicators the that were saved to the export indicators service Required
mwg_type For use with McAfee Web Gateway format to indicate the list type. Optional
strip_port For use with PAN-OS URL format - if True will strip the port off urls. If not checked - url with ports will be ignored. Optional
drop_invalids For use with PAN-OS URL format - if checked any URL entry which is not compliant with PAN-OS EDL URL format the entry is dropped instead of being rewritten. Optional
category_attribute For use with Symantec ProxySG format - set the categories that should be listed in the output. If not set will list all existing categories. Optional
category_default For use with Symantec ProxySG format - set the default category for the output. Optional
collapse_ips Whether to collapse IPs, and if so - to ranges or CIDRs Optional
csv_text If True, will output csv and XSOAR-csv formats as textual web pages Optional
sort_field The field by which to sort the indicators by. Only applicable with the sort_order argument. Optional
sort_order The direction by which to order the indicators. The options are asc or desc. Only applicable with the sort_field argument. Optional
Context Output

There is no context output for this command.

Command Example

!eis-update print_indicators=true query=type:IP format=text list_size=4

Human Readable Output
Indicators
1.1.1.1
2.2.2.2
3.3.3.3
4.4.4.4

Configuration parameters

  • indicators_query — Indicator Query
  • format — Outbound Format
  • collapse_ips — Should Collapse IPs
  • csv_text — Show CSV Formats as Text
  • list_size — List Size (required)
  • on_demand — Update On-Demand Only
  • cache_refresh_rate — Refresh Rate
  • longRunning — Long Running Instance
  • longRunningPort — Listen Port (required)
  • certificate — Certificate (Required for HTTPS)
  • append_string — Append String To EDL
  • prepend_string — Prepend String To EDL
  • key — Private Key (Required for HTTPS)
  • credentials — Username
  • mwg_type — Mcafee Gateway Indicator List Type
  • hsts_header — Add HSTS header
  • strip_port — PAN-OS URL Format Port Strip
  • drop_invalids — PAN-OS URL Format Drop Invalid Entries
  • category_default — Symantec ProxySG Default Category
  • category_attribute — Symantec ProxySG Listed Categories
  • nginx_global_directives — NGINX Global Directives
  • nginx_server_conf — NGINX Server Conf

Commands (1)

  • eis-update

    Updates values stored in the Export Indicators Service (only avaialable On-Demand).

"""Imports"""
import json
import pytest
import demistomock as demisto
from netaddr import IPAddress

IOC_RES_LEN = 38

'''Tests'''


class TestHelperFunctions:
    def test_get_outbound_ioc_values_1(self, mocker):
        """Test on_demand"""
        from ExportIndicators import get_outbound_ioc_values, RequestArguments
        with open('ExportIndicators_test/TestHelperFunctions/iocs_cache_values_text.json', 'r') as iocs_text_values_f:
            iocs_text_dict = json.loads(iocs_text_values_f.read())
            mocker.patch.object(demisto, 'getIntegrationContext', return_value={"last_output": iocs_text_dict})
            request_args = RequestArguments(query='', out_format='text', limit=50, offset=0)
            ioc_list = get_outbound_ioc_values(
                on_demand=True,
                request_args=request_args
            )
            for ioc_row in ioc_list:
                assert ioc_row in iocs_text_dict

    def test_get_outbound_ioc_values_2(self, mocker):
        """Test update by not on_demand with no refresh"""
        import CommonServerPython as CSP
        mocker.patch.object(CSP, 'parse_date_range', return_value=(1578383899, 1578383899))
        import ExportIndicators as ei
        with open('ExportIndicators_test/TestHelperFunctions/iocs_cache_values_text.json', 'r') as iocs_text_values_f:
            iocs_text_dict = json.loads(iocs_text_values_f.read())
            mocker.patch.object(demisto, 'getIntegrationContext', return_value={"last_output": iocs_text_dict})
            mocker.patch.object(ei, 'refresh_outbound_context', return_value=iocs_text_dict)
            mocker.patch.object(demisto, 'getLastRun', return_value={'last_run': 1578383898000})
            request_args = ei.RequestArguments(query='', out_format='text', limit=50, offset=0)
            ioc_list = ei.get_outbound_ioc_values(
                on_demand=False,
                request_args=request_args,
                cache_refresh_rate='1 minute'
            )
            for ioc_row in ioc_list:
                assert ioc_row in iocs_text_dict

    def test_get_outbound_ioc_values_3(self, mocker):
        """Test update by not on_demand with refresh"""
        import CommonServerPython as CSP
        mocker.patch.object(CSP, 'parse_date_range', return_value=(1578383898, 1578383898))
        import ExportIndicators as ei
        with open('ExportIndicators_test/TestHelperFunctions/iocs_cache_values_text.json', 'r') as iocs_text_values_f:
            iocs_text_dict = json.loads(iocs_text_values_f.read())
            mocker.patch.object(demisto, 'getIntegrationContext', return_value={"last_output": iocs_text_dict})
            mocker.patch.object(ei, 'refresh_outbound_context', return_value=iocs_text_dict)
            mocker.patch.object(demisto, 'getLastRun', return_value={'last_run': 1578383898000})
            request_args = ei.RequestArguments(query='', out_format='text', limit=50, offset=0)
            ioc_list = ei.get_outbound_ioc_values(
                on_demand=False,
                request_args=request_args,
                cache_refresh_rate='1 minute'
            )
            for ioc_row in ioc_list:
                assert ioc_row in iocs_text_dict

    def test_get_outbound_ioc_values_4(self, mocker):
        """Test update by request params change - limit"""
        import CommonServerPython as CSP
        mocker.patch.object(CSP, 'parse_date_range', return_value=(1578383898, 1578383898))
        import ExportIndicators as ei
        with open('ExportIndicators_test/TestHelperFunctions/iocs_cache_values_text.json', 'r') as iocs_text_values_f:
            iocs_text_dict = json.loads(iocs_text_values_f.read())
            mocker.patch.object(demisto, 'getIntegrationContext', return_value={"last_output": iocs_text_dict,
                                                                                "last_limit": 1, "last_offset": 0,
                                                                                "last_query": "type:ip",
                                                                                "last_format": "text"})
            mocker.patch.object(ei, 'refresh_outbound_context', return_value=iocs_text_dict)
            mocker.patch.object(demisto, 'getLastRun', return_value={'last_run': 1578383898000})
            request_args = ei.RequestArguments(query='type:ip', out_format='text', limit=50, offset=0)
            ioc_list = ei.get_outbound_ioc_values(
                on_demand=False,
                request_args=request_args,
                cache_refresh_rate='1 minute'
            )
            for ioc_row in ioc_list:
                assert ioc_row in iocs_text_dict

    def test_get_outbound_ioc_values_5(self, mocker):
        """Test update by request params change - offset"""
        import CommonServerPython as CSP
        mocker.patch.object(CSP, 'parse_date_range', return_value=(1578383898, 1578383898))
        import ExportIndicators as ei
        with open('ExportIndicators_test/TestHelperFunctions/iocs_cache_values_text.json', 'r') as iocs_text_values_f:
            iocs_text_dict = json.loads(iocs_text_values_f.read())
            mocker.patch.object(demisto, 'getIntegrationContext', return_value={"last_output": iocs_text_dict,
                                                                                "last_limit": 50, "last_offset": 1,
                                                                                "last_query": "type:ip",
                                                                                "last_format": "text"})
            mocker.patch.object(ei, 'refresh_outbound_context', return_value=iocs_text_dict)
            mocker.patch.object(demisto, 'getLastRun', return_value={'last_run': 1578383898000})
            request_args = ei.RequestArguments(query='type:ip', out_format='text', limit=50, offset=0)
            ioc_list = ei.get_outbound_ioc_values(
                on_demand=False,
                request_args=request_args,
                cache_refresh_rate='1 minute'
            )
            for ioc_row in ioc_list:
                assert ioc_row in iocs_text_dict

    def test_get_outbound_ioc_values_6(self, mocker):
        """Test update by request params change - query"""
        import CommonServerPython as CSP
        mocker.patch.object(CSP, 'parse_date_range', return_value=(1578383898, 1578383898))
        import ExportIndicators as ei
        with open('ExportIndicators_test/TestHelperFunctions/iocs_cache_values_text.json', 'r') as iocs_text_values_f:
            iocs_text_dict = json.loads(iocs_text_values_f.read())
            mocker.patch.object(demisto, 'getIntegrationContext', return_value={"last_output": iocs_text_dict,
                                                                                "last_limit": 50, "last_offset": 0,
                                                                                "last_query": "type:URL",
                                                                                "last_format": "text"})
            mocker.patch.object(ei, 'refresh_outbound_context', return_value=iocs_text_dict)
            mocker.patch.object(demisto, 'getLastRun', return_value={'last_run': 1578383898000})
            request_args = ei.RequestArguments(query='type:ip', out_format='text', limit=50, offset=0)
            ioc_list = ei.get_outbound_ioc_values(
                on_demand=False,
                request_args=request_args,
                cache_refresh_rate='1 minute'
            )
            for ioc_row in ioc_list:
                assert ioc_row in iocs_text_dict

    def test_list_to_str_1(self):
        """Test invalid"""
        from ExportIndicators import list_to_str
        with pytest.raises(AttributeError):
            invalid_list_value = 2
            list_to_str(invalid_list_value)

        with pytest.raises(AttributeError):
            invalid_list_value = {'invalid': 'invalid'}
            list_to_str(invalid_list_value)

    def test_list_to_str_2(self):
        """Test empty"""
        from ExportIndicators import list_to_str
        assert list_to_str(None) == ''
        assert list_to_str([]) == ''
        assert list_to_str({}) == ''

    def test_list_to_str_3(self):
        """Test non empty fields"""
        from ExportIndicators import list_to_str
        valid_list_value = [1, 2, 3, 4]
        assert list_to_str(valid_list_value) == '1,2,3,4'
        assert list_to_str(valid_list_value, '.') == '1.2.3.4'
        assert list_to_str(valid_list_value, map_func=lambda x: f'{x}a') == '1a,2a,3a,4a'

    def test_get_params_port_1(self):
        """Test invalid"""
        from CommonServerPython import DemistoException
        from ExportIndicators import get_params_port
        params = {'longRunningPort': 'invalid'}
        with pytest.raises(DemistoException):
            get_params_port(params)

    def test_get_params_port_2(self):
        """Test empty"""
        from ExportIndicators import get_params_port
        params = {'longRunningPort': ''}
        with pytest.raises(ValueError):
            get_params_port(params)

    def test_get_params_port_3(self):
        """Test valid"""
        from ExportIndicators import get_params_port
        params = {'longRunningPort': '80'}
        assert get_params_port(params) == 80

    def test_refresh_outbound_context_1(self, mocker):
        """Test out_format=text"""
        import ExportIndicators as ei
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            mocker.patch.object(ei, 'find_indicators_with_limit', return_value=iocs_json)
            request_args = ei.RequestArguments(query='', out_format='text', limit=38)
            ei_vals = ei.refresh_outbound_context(request_args)
            for ioc in iocs_json:
                ip = ioc.get('value')
                if ip:
                    assert ip in ei_vals

    def test_refresh_outbound_context_2(self, mocker):
        """Test out_format= XSOAR json"""
        import ExportIndicators as ei
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            iocs_json_result = {'iocs': iocs_json, 'total': 100}
            mocker.patch.object(demisto, 'searchIndicators', return_value=iocs_json_result)
            request_args = ei.RequestArguments(query='', out_format='XSOAR json', limit=39)
            ei_vals = ei.refresh_outbound_context(request_args)
            assert isinstance(ei_vals, str)
            ei_vals = json.loads(ei_vals)
            assert iocs_json == ei_vals

    def test_refresh_outbound_context_3(self, mocker):
        """Test out_format=xsoar-csv"""
        import ExportIndicators as ei
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            mocker.patch.object(ei, 'find_indicators_with_limit', return_value=iocs_json)
            request_args = ei.RequestArguments(query='', out_format='XSOAR csv', limit=38)
            ei_vals = ei.refresh_outbound_context(request_args)
            with open('ExportIndicators_test/TestHelperFunctions/iocs_out_csv.txt', 'r') as iocs_out_f:
                iocs_out = iocs_out_f.read()
                for ioc in iocs_out.split('\n'):
                    assert ioc in ei_vals

    def test_refresh_outbound_context_4(self, mocker):
        """Test out_format=XSOAR json-seq"""
        import ExportIndicators as ei
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            iocs_json_result = {'iocs': iocs_json, 'total': 100}
            mocker.patch.object(demisto, 'searchIndicators', return_value=iocs_json_result)
            request_args = ei.RequestArguments(query='', out_format='XSOAR json-seq', limit=38)
            ei_vals = ei.refresh_outbound_context(request_args)
            with open('ExportIndicators_test/TestHelperFunctions/iocs_out_json_seq.txt', 'r') as iocs_out_f:
                iocs_out = iocs_out_f.read()
                assert iocs_out == ei_vals

    def test_refresh_outbound_context_5(self, mocker):
        """Test out_format=json"""
        import ExportIndicators as ei
        with open('ExportIndicators_test/TestHelperFunctions/demisto_url_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            iocs_json_result = {'iocs': iocs_json, 'total': 100}
            mocker.patch.object(demisto, 'searchIndicators', return_value=iocs_json_result)
            request_args = ei.RequestArguments(query='', out_format='json', limit=2)
            ei_vals = ei.refresh_outbound_context(request_args)
            ei_vals = json.loads(ei_vals)
            with open('ExportIndicators_test/TestHelperFunctions/iocs_out_json.json', 'r') as iocs_json_out_f:
                iocs_json_out = json.loads(iocs_json_out_f.read())
                assert iocs_json_out == ei_vals

    def test_refresh_outbound_context_6(self, mocker):
        """Test out_format=json-seq"""
        import ExportIndicators as ei
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            iocs_json_result = {'iocs': iocs_json, 'total': 100}
            mocker.patch.object(demisto, 'searchIndicators', return_value=iocs_json_result)
            request_args = ei.RequestArguments(query='', out_format='json-seq', limit=38)
            ei_vals = ei.refresh_outbound_context(request_args)
            with open('ExportIndicators_test/TestHelperFunctions/iocs_out_json_seq_old.txt', 'r') as iocs_out_f:
                iocs_out = iocs_out_f.read()
                for iocs_out_line in iocs_out.split('\n'):
                    assert iocs_out_line in ei_vals

    def test_refresh_outbound_context_7(self, mocker):
        """Test out_format=csv"""
        import ExportIndicators as ei
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            mocker.patch.object(ei, 'find_indicators_with_limit', return_value=iocs_json)
            request_args = ei.RequestArguments(query='', out_format='csv', limit=38)
            ei_vals = ei.refresh_outbound_context(request_args)
            with open('ExportIndicators_test/TestHelperFunctions/iocs_out_csv_old.txt', 'r') as iocs_out_f:
                iocs_out = iocs_out_f.read()
                for ioc in iocs_out.split('\n'):
                    assert ioc in ei_vals

    def test_find_indicators_with_limit_1(self, mocker):
        """Test find indicators limit"""
        import ExportIndicators as ei
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            limit = 30
            indicator_searcher_res = [{'iocs': iocs_json[:limit]}, {'iocs': []}]
            indicator_searcher = ei.IndicatorsSearcher(
                limit=limit
            )
            mocker.patch.object(indicator_searcher, 'search_indicators_by_version', side_effect=indicator_searcher_res)
            ei_vals = ei.find_indicators_with_limit(indicator_searcher)
            assert len(ei_vals) == limit

    def test_create_values_for_returned_dict_1(self):
        """Test XSOAR CSV out"""
        from ExportIndicators import create_values_for_returned_dict, FORMAT_XSOAR_CSV, RequestArguments, CTX_VALUES_KEY
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            request_args = RequestArguments(query='', out_format=FORMAT_XSOAR_CSV)
            returned_dict, _ = create_values_for_returned_dict(iocs_json, request_args)
            csv_out = returned_dict.get(CTX_VALUES_KEY)
            # assert len(csv_out) == IOC_RES_LEN + 1
            with open('ExportIndicators_test/TestHelperFunctions/iocs_out_csv.txt', 'r') as iocs_out_f:
                expected_csv_out = iocs_out_f.read()
                for csv_line in csv_out.split('\n'):
                    assert csv_line in expected_csv_out

    def test_create_values_for_returned_dict_2(self):
        """Test XSOAR JSON out"""
        from ExportIndicators import create_values_for_returned_dict, FORMAT_XSOAR_JSON, CTX_VALUES_KEY, \
            RequestArguments
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.load(iocs_json_f)
            request_args = RequestArguments(query='', out_format=FORMAT_XSOAR_JSON)
            returned_dict, _ = create_values_for_returned_dict(iocs_json, request_args)
            json_out = json.loads(returned_dict.get(CTX_VALUES_KEY))
            assert json_out == iocs_json

    def test_create_values_for_returned_dict_3(self):
        """Test XSOAR JSON_SEQ out"""
        from ExportIndicators import create_values_for_returned_dict, FORMAT_XSOAR_JSON_SEQ, CTX_VALUES_KEY, \
            RequestArguments
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            request_args = RequestArguments(query='', out_format=FORMAT_XSOAR_JSON_SEQ)
            returned_dict, _ = create_values_for_returned_dict(iocs_json, request_args)
            json_seq_out = returned_dict.get(CTX_VALUES_KEY)
            for seq_line in json_seq_out.split('\n'):
                assert json.loads(seq_line) in iocs_json

    def test_create_values_for_returned_dict_4(self):
        """Test TEXT out"""
        from ExportIndicators import create_values_for_returned_dict, FORMAT_TEXT, CTX_VALUES_KEY, RequestArguments
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            request_args = RequestArguments(query='', out_format=FORMAT_TEXT)
            returned_dict, _ = create_values_for_returned_dict(iocs_json, request_args)
            text_out = returned_dict.get(CTX_VALUES_KEY)
            with open('ExportIndicators_test/TestHelperFunctions/iocs_cache_values_text.json', 'r') as iocs_txt_f:
                iocs_txt_json = json.load(iocs_txt_f)
                for line in text_out.split('\n'):
                    assert line in iocs_txt_json

    def test_create_values_for_returned_dict_5(self):
        """Test JSON out"""
        from ExportIndicators import create_values_for_returned_dict, FORMAT_JSON, CTX_VALUES_KEY, RequestArguments
        with open('ExportIndicators_test/TestHelperFunctions/demisto_url_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            request_args = RequestArguments(query='', out_format=FORMAT_JSON)
            returned_dict, _ = create_values_for_returned_dict(iocs_json, request_args)
            json_out = json.loads(returned_dict.get(CTX_VALUES_KEY))
            with open('ExportIndicators_test/TestHelperFunctions/iocs_out_json.json', 'r') as iocs_json_out_f:
                iocs_json_out = json.loads(iocs_json_out_f.read())
                assert iocs_json_out == json_out

    def test_create_values_for_returned_dict_6(self):
        """Test JSON_SEQ out"""
        from ExportIndicators import create_values_for_returned_dict, FORMAT_JSON_SEQ, CTX_VALUES_KEY, RequestArguments
        with open('ExportIndicators_test/TestHelperFunctions/demisto_url_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            request_args = RequestArguments(query='', out_format=FORMAT_JSON_SEQ)
            returned_dict, _ = create_values_for_returned_dict(iocs_json, request_args)
            json_seq_out = returned_dict.get(CTX_VALUES_KEY)
            with open('ExportIndicators_test/TestHelperFunctions/iocs_out_json.json', 'r') as iocs_json_out_f:
                iocs_json_out = json.load(iocs_json_out_f)
                for seq_line in json_seq_out.split('\n'):
                    assert json.loads(seq_line) in iocs_json_out

    def test_create_values_for_returned_dict_7(self):
        """Test CSV out"""
        from ExportIndicators import create_values_for_returned_dict, FORMAT_CSV, RequestArguments, CTX_VALUES_KEY
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            request_args = RequestArguments(query='', out_format=FORMAT_CSV)
            returned_dict, _ = create_values_for_returned_dict(iocs_json, request_args)
            csv_out = returned_dict.get(CTX_VALUES_KEY)
            # assert len(csv_out) == IOC_RES_LEN + 1
            with open('ExportIndicators_test/TestHelperFunctions/iocs_out_csv_old.txt', 'r') as iocs_out_f:
                expected_csv_out = iocs_out_f.read()
                for csv_lint in csv_out.split('\n'):
                    assert csv_lint in expected_csv_out

    def test_validate_basic_authentication(self):
        """Test Authentication"""
        from ExportIndicators import validate_basic_authentication
        username, password = 'user', 'pwd'
        data = {
            "empty_auth": {},
            "basic_missing_auth": {
                "Authorization": "missing basic"
            },
            "colon_missing_auth": {
                "Authorization": "Basic bWlzc2luZ19jb2xvbg=="
            },
            "wrong_length_auth": {
                "Authorization": "Basic YTpiOmM="
            },
            "wrong_credentials_auth": {
                "Authorization": "Basic YTpi"
            },
            "right_credentials_auth": {
                "Authorization": "Basic dXNlcjpwd2Q="
            }
        }
        assert not validate_basic_authentication(data.get('empty_auth'), username, password)
        assert not validate_basic_authentication(data.get('basic_missing_auth'), username, password)
        assert not validate_basic_authentication(data.get('colon_missing_auth'), username, password)
        assert not validate_basic_authentication(data.get('wrong_length_auth'), username, password)
        assert not validate_basic_authentication(data.get('wrong_credentials_auth'), username, password)
        assert validate_basic_authentication(data.get('right_credentials_auth'), username, password)

    def test_panos_url_formatting(self):
        from ExportIndicators import panos_url_formatting, CTX_VALUES_KEY
        with open('ExportIndicators_test/TestHelperFunctions/demisto_url_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())

            # strips port numbers
            returned_dict, num_of_indicators = panos_url_formatting(iocs=iocs_json, drop_invalids=True, strip_port=True)
            returned_output = returned_dict.get(CTX_VALUES_KEY)
            assert returned_output == "1.2.3.4/wget\nwww.demisto.com/cool"
            assert num_of_indicators == 2

            # should ignore indicators with port numbers
            returned_dict, num_of_indicators = panos_url_formatting(iocs=iocs_json, drop_invalids=True,
                                                                    strip_port=False)
            returned_output = returned_dict.get(CTX_VALUES_KEY)
            assert returned_output == 'www.demisto.com/cool'
            assert num_of_indicators == 1

    def test_create_proxysg_out_format(self):
        from ExportIndicators import create_proxysg_out_format, CTX_VALUES_KEY
        with open('ExportIndicators_test/TestHelperFunctions/demisto_url_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())

            # classify all categories
            returned_dict, num_of_indicators = create_proxysg_out_format(iocs=iocs_json, category_default="default",
                                                                         category_attribute='')
            returned_output = returned_dict.get(CTX_VALUES_KEY)
            assert returned_output == "define category category2\n1.2.3.4:89/wget\nend\n" \
                                      "define category category1\nwww.demisto.com/cool\nend\n"

            assert num_of_indicators == 2

            # listed category does not exist - all results should be in default category
            returned_dict, num_of_indicators = create_proxysg_out_format(iocs=iocs_json, category_default="default",
                                                                         category_attribute="category3")
            returned_output = returned_dict.get(CTX_VALUES_KEY)
            assert returned_output == "define category default\n1.2.3.4:89/wget\n" \
                                      "www.demisto.com/cool\nend\n"
            assert num_of_indicators == 2

            # list category2 only, the rest go to default
            returned_dict, num_of_indicators = create_proxysg_out_format(iocs=iocs_json, category_default="default",
                                                                         category_attribute="category2")
            returned_output = returned_dict.get(CTX_VALUES_KEY)
            assert returned_output == "define category category2\n1.2.3.4:89/wget\nend\n" \
                                      "define category default\nwww.demisto.com/cool\nend\n"

            assert num_of_indicators == 2

    def test_create_mwg_out_format(self):
        from ExportIndicators import create_mwg_out_format, CTX_VALUES_KEY
        with open('ExportIndicators_test/TestHelperFunctions/demisto_url_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())

            # listed category does not exist - all results should be in default category
            returned_dict = create_mwg_out_format(iocs=iocs_json, mwg_type="ip")
            returned_output = returned_dict.get(CTX_VALUES_KEY)

            assert returned_output == "type=ip\n\"1.2.3.4:89/wget\" \"AutoFocus Feed\"\n\"" \
                                      "https://www.demisto.com/cool\" \"AutoFocus V2,VirusTotal," \
                                      "Alien Vault OTX TAXII Feed\""

    def test_create_json_out_format(self):
        from ExportIndicators import create_json_out_format, CTX_VALUES_KEY
        with open('ExportIndicators_test/TestHelperFunctions/demisto_url_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())

            # listed category does not exist - all results should be in default category
            returned_dict = create_json_out_format(iocs=iocs_json)
            returned_output = json.loads(returned_dict.get(CTX_VALUES_KEY))

            assert returned_output[0].get('indicator') == '1.2.3.4:89/wget'
            assert isinstance(returned_output[0].get('value'), dict)

            assert returned_output[1].get('indicator') == 'https://www.demisto.com/cool'
            assert isinstance(returned_output[1].get('value'), dict)

    def test_ips_to_ranges_range(self):
        from ExportIndicators import ips_to_ranges, COLLAPSE_TO_RANGES
        ip_list = [IPAddress("1.1.1.1"), IPAddress("25.24.23.22"), IPAddress("22.21.20.19"),
                   IPAddress("1.1.1.2"), IPAddress("1.2.3.4"), IPAddress("1.1.1.3"), IPAddress("2.2.2.2"),
                   IPAddress("1.2.3.5")]

        ip_range_list = ips_to_ranges(ip_list, COLLAPSE_TO_RANGES)
        assert "1.1.1.1-1.1.1.3" in ip_range_list
        assert "1.2.3.4-1.2.3.5" in ip_range_list
        assert "1.1.1.2" not in ip_range_list
        assert "2.2.2.2" in ip_range_list
        assert "25.24.23.22" in ip_range_list

    def test_ips_to_ranges_cidr(self):
        from ExportIndicators import ips_to_ranges, COLLAPSE_TO_CIDR
        ip_list = [IPAddress("1.1.1.1"), IPAddress("25.24.23.22"), IPAddress("22.21.20.19"),
                   IPAddress("1.1.1.2"), IPAddress("1.2.3.4"), IPAddress("1.1.1.3"), IPAddress("2.2.2.2"),
                   IPAddress("1.2.3.5")]

        ip_range_list = ips_to_ranges(ip_list, COLLAPSE_TO_CIDR)
        assert "1.1.1.1" in ip_range_list
        assert "1.1.1.2/31" in ip_range_list
        assert "1.2.3.4/31" in ip_range_list
        assert "1.2.3.5" not in ip_range_list
        assert "1.1.1.3" not in ip_range_list
        assert "2.2.2.2" in ip_range_list
        assert "25.24.23.22" in ip_range_list

    def test_empty_integartion_context_mimtype(self, mocker):
        from ExportIndicators import get_outbound_mimetype
        mocker.patch.object(demisto, 'getIntegrationContext', return_value={})
        mimtype = get_outbound_mimetype()
        assert mimtype == 'text/plain'

    @pytest.mark.parametrize('sort_field, sort_order, expected_first_result', [
        ('lastSeen', 'asc', '200.77.186.170'),
        ('lastSeen', 'desc', '188.166.23.215'),
    ])
    def test_sort_iocs(self, mocker, sort_field, sort_order, expected_first_result):
        """Test IoCs sorting"""
        import ExportIndicators as ei
        from ExportIndicators import refresh_outbound_context, RequestArguments
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            mocker.patch.object(ei, 'find_indicators_with_limit', side_effect=[iocs_json, []])
            request_args = RequestArguments(query='', out_format='text', sort_field=sort_field, sort_order=sort_order)
            ei_vals = refresh_outbound_context(request_args)

            assert ei_vals.split('\n', 1)[0] == expected_first_result

    def test_sort_iocs_with_invalid_order(self, mocker):
        """Test IoCs sorting with invalid order"""
        import ExportIndicators as ei
        from ExportIndicators import refresh_outbound_context, RequestArguments
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            mocker.patch.object(ei, 'find_indicators_with_limit', side_effect=[iocs_json, []])
            request_args = RequestArguments(query='', out_format='text', sort_field='lastSeen',
                                            sort_order='invalid_sort_order')
            ei_vals = refresh_outbound_context(request_args)

            assert ei_vals.split('\n', 1)[0] == '213.182.138.224'

    def test_sort_iocs_invalid_field(self, mocker):
        """Test IoCs sorting wit invalid field"""
        import ExportIndicators as ei
        from ExportIndicators import refresh_outbound_context, RequestArguments
        with open('ExportIndicators_test/TestHelperFunctions/demisto_iocs.json', 'r') as iocs_json_f:
            iocs_json = json.loads(iocs_json_f.read())
            mocker.patch.object(ei, 'find_indicators_with_limit', side_effect=[iocs_json, []])
            request_args = RequestArguments(query='', out_format='text', sort_field='invalid_field_name',
                                            sort_order='asc')
            mocker.patch.object(demisto, 'debug')
            refresh_outbound_context(request_args)

            debug_list = [call[0][0] for call in demisto.debug.call_args_list]
            assert 'ExportIndicators - Could not sort IoCs, please verify that you entered the correct field name.\n' \
                   'Field used: invalid_field_name' in debug_list