CrowdStrike Indicator Feed
Retrieves indicators from the CrowdStrike Falcon Intel Feed.
Data Enrichment & Threat Intelligence · Crowdstrike Falcon Intel Feed · Feed
Details
| ID | CrowdStrike Indicator Feed |
|---|---|
| Provider | CrowdStrike |
| Category | Data Enrichment & Threat Intelligence |
| From Version | 5.5.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
README
CrowdStrike Falcon Intel Indicator Feed
Configure CrowdStrike Indicator Feed in Cortex
| Parameter | Description | Required |
|---|---|---|
| Fetch indicators | False | |
| CrowdStrike Base URL | True | |
| CrowdStrike API Client ID | For non 6.1 - enter your CrowdStrike API Client Secret in the password field. | True |
| Type | The indicator types to fetch. Out-of-the-box indicator types supported in XSOAR are: “Account”, “Domain”, “Email”, “File MD5”, “File SHA256”, “IP”, “Registry Key”, and “URL”. The default is “ALL”. | False |
| First fetch time | The time range to consider for the initial data fetch. Leave empty to fetch from the first available indicator. | False |
| Max. indicators per fetch | Maximum number of indicators per fetch. Value should be between 1 - 10000. A large value may result in a timeout. | False |
| Malicious confidence | Malicious confidence level to filter by. | False |
| Include deleted indicators | False | |
| Filter | Advanced: FQL query. For more information visit the CrowdStrike documentation. For example: published_date:>”now-3d” can be used to only pull indicators published in the last 3 days. | False |
| Generic phrase match | Generic phrase match search across all indicator fields. | False |
| Indicator Reputation | Indicators from this integration instance will be marked with this reputation. | False |
| Source Reliability | Reliability of the source providing the intelligence data. | True |
| Traffic Light Protocol Color | The Traffic Light Protocol (TLP) designation to apply to indicators fetched from the feed. | False |
| Indicator Expiration Method | The feed’s expiration method. | False |
| Feed Fetch Interval | The interval after which the feed expires. | False |
| Tags | Supports CSV values. | False |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False | |
| Bypass exclusion list | When selected, the exclusion list is ignored for indicators from this feed. This means that if an indicator from this feed is on the exclusion list, the indicator might still be added to the system. | False |
Note: To change the fetch start time , use the crowdstrike-reset-fetch-indicators command after setting the desired time in First Fetch Time parameter.
Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook. After you
successfully execute a command, a DBot message appears in the War Room with the command details.
crowdstrike-indicators-list
Gets indicators from the CrowdStrike Falcon Intel Feed.
Base Command
crowdstrike-indicators-list
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The maximum number of indicators to return. Default is 50. | Optional |
| offset | The index of the first indicator to fetch. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| CrowdStrikeFalconIntel.Indicators.id | String | Indicator ID. |
| CrowdStrikeFalconIntel.Indicators.value | String | Indicator value. |
| CrowdStrikeFalconIntel.Indicators.type | String | Indicator type. |
| CrowdStrikeFalconIntel.Indicators.fields.reports | Unknown | Indicator reports. |
| CrowdStrikeFalconIntel.Indicators.fields.actors | Unknown | Actors related to the indicator. |
| CrowdStrikeFalconIntel.Indicators.fields.malwarefamily | Unknown | Indicator malware families. |
| CrowdStrikeFalconIntel.Indicators.fields.stixkillchainphases | Unknown | Indicator kill chains. |
| CrowdStrikeFalconIntel.Indicators.fields.maliciousconfidence | String | Indicator malicious confidence. |
| CrowdStrikeFalconIntel.Indicators.fields.tags | Unknown | Indicator labels. |
| CrowdStrikeFalconIntel.Indicators.fields.targets | Unknown | Targets of the indicator. |
| CrowdStrikeFalconIntel.Indicators.fields.threattypes | Unknown | Indicator threat types. |
| CrowdStrikeFalconIntel.Indicators.fields.vulnerabilities | Unknown | Indicator vulnerabilities. |
| CrowdStrikeFalconIntel.Indicators.fields.ipaddress | Unknown | Indicator related IP address. |
| CrowdStrikeFalconIntel.Indicators.fields.domainname | Unknown | Indicator related domains. |
| CrowdStrikeFalconIntel.Indicators.fields.updateddate | Date | Indicator update date. |
| CrowdStrikeFalconIntel.Indicators.fields.creationdate | Unknown | Indicator creation date. |
| CrowdStrikeFalconIntel.Indicators.rawJSON | Unknown | Raw response. |
Command Example
!crowdstrike-indicators-list limit=3
Context Example
{
"CrowdStrikeFalconIntel": {
"Indicators": [
{
"fields": {
"actor": [],
"creationdate": 1600080520,
"domainname": [],
"ipaddress": [],
"confidence": "low",
"malwarefamily": [
"Remcos"
],
"reports": [],
"stixkillchainphases": [
"C2"
],
"threattypes": [
{
"threatcategory": "Criminal"
}
],
"tags": [
"MaliciousConfidence/Low",
"KillChain/C2",
"ThreatType/Commodity",
"ThreatType/Criminal",
"ThreatType/CredentialHarvesting",
"Malware/Remcos"
],
"targets": [],
"trafficlightprotocol": "AMBER",
"updateddate": 1608207378,
"vulnerabilities": []
},
"id": "ip_address_1.1.1.1",
"rawJSON": {
"_marker": "1608207378159fc77935511a2f0c9541511bd936f8",
"actors": [],
"deleted": false,
"domain_types": [],
"id": "ip_address_1.1.1.1",
"indicator": "1.1.1.1",
"ip_address_types": [],
"kill_chains": [
"C2"
],
"labels": [
{
"created_on": 1600080520,
"last_valid_on": 1608207377,
"name": "MaliciousConfidence/Low"
},
{
"created_on": 1600080520,
"last_valid_on": 1608207377,
"name": "KillChain/C2"
}
],
"last_updated": 1608207378,
"malicious_confidence": "low",
"malware_families": [
"Remcos"
],
"published_date": 1600080520,
"relations": [
{
"created_date": 1608207377,
"id": "hash_sha256_9bb12d611cb19e84f2f22791cb86a43841e95020b1e113469e5cad95b97a8d42",
"indicator": "9bb12d611cb19e84f2f22791cb86a43841e95020b1e113469e5cad95b97a8d42",
"last_valid_date": 1608207377,
"type": "hash_sha256"
},
{
"created_date": 1608207377,
"id": "hash_sha256_58a3e65de35d8da1f7955680e07a82ede43a1e677e0abc200923b484a7615494",
"indicator": "58a3e65de35d8da1f7955680e07a82ede43a1e677e0abc200923b484a7615494",
"last_valid_date": 1608207377,
"type": "hash_sha256"
}
],
"reports": [],
"targets": [],
"threat_types": [
"Criminal"
],
"type": "ip_address",
"vulnerabilities": []
},
"type": "IP",
"value": "1.1.1.1"
},
{
"fields": {
"actor": [],
"creationdate": 1608208087,
"domainname": [],
"ipaddress": [],
"confidence": "low",
"malwarefamily": [
"Remcos"
],
"reports": [],
"stixkillchainphases": [
"C2"
],
"tags": [
"MaliciousConfidence/Low",
"KillChain/C2",
"Malware/Remcos",
"ThreatType/Commodity",
"ThreatType/Criminal",
"ThreatType/CredentialHarvesting"
],
"threattypes": [
{
"threatcategory": "Criminal"
}
],
"targets": [],
"trafficlightprotocol": "AMBER",
"updateddate": 1608208109,
"vulnerabilities": []
},
"id": "ip_address_2.2.2.2",
"rawJSON": {
"_marker": "16082081092644654ac0f7738b7086d25532d38ec1",
"actors": [],
"deleted": false,
"domain_types": [],
"id": "ip_address_2.2.2.2",
"indicator": "2.2.2.2",
"ip_address_types": [],
"kill_chains": [
"C2"
],
"labels": [
{
"created_on": 1608208087,
"last_valid_on": 1608208108,
"name": "MaliciousConfidence/Low"
},
{
"created_on": 1608208087,
"last_valid_on": 1608208108,
"name": "KillChain/C2"
}
],
"last_updated": 1608208109,
"malicious_confidence": "low",
"malware_families": [
"Remcos"
],
"published_date": 1608208087,
"relations": [
{
"created_date": 1608208090,
"id": "hash_sha256_b90713f3b31f29ceb64355b3c016aa0a74e1ce90dca5570db04aff27e12b343c",
"indicator": "b90713f3b31f29ceb64355b3c016aa0a74e1ce90dca5570db04aff27e12b343c",
"last_valid_date": 1608208090,
"type": "hash_sha256"
},
{
"created_date": 1483468884,
"id": "domain_holmann02.ddns.net",
"indicator": "holmann02.ddns.net",
"last_valid_date": 1483468884,
"type": "domain"
}
],
"reports": [],
"targets": [],
"threat_types": [
"Criminal"
],
"type": "ip_address",
"vulnerabilities": []
},
"type": "IP",
"value": "1.2.3.4"
},
{
"fields": {
"actor": [
"MUMMYSPIDER"
],
"creationdate": 1592473928,
"domainname": [],
"ipaddress": [],
"confidence": "low",
"malwarefamily": [],
"reports": [],
"stixkillchainphases": [
"C2"
],
"threattypes": [],
"tags": [
"KillChain/C2",
"MaliciousConfidence/Low",
"Actor/MUMMYSPIDER"
],
"targets": [],
"trafficlightprotocol": "AMBER",
"updateddate": 1608208626,
"vulnerabilities": []
},
"id": "ip_address_1.2.3.4",
"rawJSON": {
"_marker": "1608208626d02e40678e554f71fd6c3c33cc71c5c0",
"actors": [
"MUMMYSPIDER"
],
"deleted": false,
"domain_types": [],
"id": "ip_address_1.2.3.4",
"indicator": "1.2.3.4",
"ip_address_types": [],
"kill_chains": [
"C2"
],
"labels": [
{
"created_on": 1592473928,
"last_valid_on": 1592473930,
"name": "KillChain/C2"
},
{
"created_on": 1592473928,
"last_valid_on": 1592473930,
"name": "MaliciousConfidence/Low"
},
{
"created_on": 1592473930,
"last_valid_on": 1592473930,
"name": "Actor/MUMMYSPIDER"
}
],
"last_updated": 1608208626,
"malicious_confidence": "low",
"malware_families": [],
"published_date": 1592473928,
"relations": [
{
"created_date": 1597858281,
"id": "url_http://1.1.1.1:80",
"indicator": "http://1.1.1.1:80",
"last_valid_date": 1597858281,
"type": "url"
},
{
"created_date": 1592473931,
"id": "hash_md5_6d795170965336a9006f059dd444fc8f",
"indicator": "6d795170965336a9006f059dd444fc8f",
"last_valid_date": 1592473931,
"type": "hash_md5"
}
],
"reports": [],
"targets": [],
"threat_types": [],
"type": "ip_address",
"vulnerabilities": []
},
"type": "IP",
"value": "1.2.3.4"
}
]
}
}
Human Readable Output
Indicators from CrowdStrike Falcon Intel
Type Value Id IP 1.1.1.1 ip_address_1.1.1.1 IP 2.2.2.2 ip_address_2.2.2.2 IP 1.2.3.4 ip_address_1.2.3.4
crowdstrike-reset-fetch-indicators
Resets the retrieving start time according to the First Fetch Time parameter, WARNING: This command will reset your fetch history.
Base Command
crowdstrike-reset-fetch-indicators
Input
There are no input arguments for this command.
Context Output
There is no context output for this command.
Command Example
!crowdstrike-reset-fetch-indicators
Human Readable Output
Fetch history deleted successfully
Configuration parameters
feed— Fetch indicatorsbase_url— CrowdStrike Base URL (required)credentials— CrowdStrike API Client ID (required)timeout— The amount of time (in seconds) that a request will wait for a client to establish a connection to a remote machine before a timeout occurs.type— Typefirst_fetch— First fetch time (required)max_indicator_to_fetch— Max. indicators per fetchmalicious_confidence— Malicious confidenceinclude_deleted— Include deleted indicatorsfilter— Filtergeneric_phrase— Generic phrase matchfeedReputation— Indicator ReputationfeedReliability— Source Reliability (required)tlp_color— Traffic Light Protocol ColorfeedExpirationPolicy—feedExpirationInterval—feedFetchInterval— Feed Fetch IntervalfeedTags— Tagscreate_relationships— Create relationshipsinsecure— Trust any certificate (not secure)proxy— Use system proxy settingsfeedBypassExclusionList— Bypass exclusion listfeedIncremental— Incremental Feed
Commands (2)
-
crowdstrike-indicators-listGets indicators from the CrowdStrike Falcon Intel Feed.
-
crowdstrike-reset-fetch-indicatorsResets the retrieving start time according to the `First Fetch Time` parameter, WARNING: This command will reset your fetch history.
import json import demistomock as demisto import pytest def util_load_json(path): with open(path, encoding="utf-8") as f: return json.loads(f.read()) def test_crowdstrike_indicators_list_command(requests_mock): """Tests crowdstrike_indicators_list_command function Given - The following indicator type: 'domain' that was chosen by the user. - include_deleted: False When - Calling `crowdstrike_indicators_list_command` Then - convert the result to indicators list - validate the length of the indicators list - validate the Feed tags is as expected """ from CrowdStrikeIndicatorFeed import Client, crowdstrike_indicators_list_command mock_response = util_load_json("test_data/crowdstrike_indicators_list_command.json") requests_mock.post("https://api.crowdstrike.com/oauth2/token", json={"access_token": "12345"}) requests_mock.get(url="https://api.crowdstrike.com/intel/combined/indicators/v1", json=mock_response) requests_mock.get( url="https://api.crowdstrike.com/intel/entities/actors/v1?ids=GOBLINPANDA&fields=name", json={"resources": [{"name": "GOBLIN PANDA"}]}, ) feed_tags = ["Tag1", "Tag2"] client = Client( base_url="https://api.crowdstrike.com/", credentials={"identifier": "123", "password": "123"}, type="Domain", include_deleted="false", limit=2, feed_tags=feed_tags, ) args = {"limit": "2"} response = crowdstrike_indicators_list_command(client, args) assert len(response.outputs) == 3 assert len(response.raw_response) == 3 assert "Indicators from CrowdStrike Falcon Intel" in response.readable_output assert "domain_abc" in response.readable_output assert feed_tags[0] assert feed_tags[1] in response.raw_response[0]["fields"]["tags"] @pytest.mark.parametrize( "types_list, expected", [ ( ["ALL"], "type:'username',type:'domain',type:'email_address',type:'hash_md5',type:'hash_sha1'," "type:'hash_sha256',type:'registry',type:'url',type:'ip_address',type:'reports',type:'actors'," "type:'malware_families',type:'vulnerabilities'", ), (["Domain", "Email", "Registry Key"], "type:'domain',type:'email_address',type:'registry'"), ], ) def test_build_type_fql(types_list, expected): """Tests build_type_fql function Given - Indicator types that were chosen by the user. When - Calling `build_type_fql` in order to build filter for `get_indicators` Then - validate result as expected """ from CrowdStrikeIndicatorFeed import Client res = Client.build_type_fql(types_list=types_list) assert res == expected def test_create_indicators_from_response(requests_mock, mocker): """Tests build_type_fql function Given - Indicator types that were chosen by the user. When - Calling `create_indicators_from_response` in order to build indicators from response Then - validate result as expected """ from CrowdStrikeIndicatorFeed import Client mocker.patch("CrowdStrikeIndicatorFeed.get_integration_context", return_value={"GOBLINPANDA": "GOBLIN PANDA"}) raw_response = util_load_json("test_data/crowdstrike_indicators_list_command.json") expected_result = util_load_json("test_data/create_indicators_from_response.json") res = Client.create_indicators_from_response(raw_response, Client.get_actors_names_request) assert res == expected_result def test_empty_first_fetch(mocker, requests_mock): mocker.patch.object(demisto, "params", return_value={"first_fetch": ""}) mocker.patch.object(demisto, "command", return_value="") requests_mock.post("https://api.crowdstrike.com/oauth2/token", json={"access_token": "12345"}) from CrowdStrikeIndicatorFeed import main main() assert True @pytest.mark.parametrize( "field, indicator, resource, expected_results", [ ( "relations", {"type": "hash_md5", "value": "1234567890"}, {"relations": [{"type": "password"}, {"type": "username", "indicator": "abc"}]}, [ { "name": "related-to", "reverseName": "related-to", "type": "IndicatorToIndicator", "entityA": "1234567890", "entityAFamily": "Indicator", "entityAType": "hash_md5", "entityB": "abc", "entityBFamily": "Indicator", "entityBType": "Account", "fields": {}, } ], ), ( "malware_families", {"type": "type non support", "value": "1234567890"}, {"malware_families": {"relations": "Test indicator"}}, [ { "name": "type non support", "reverseName": "related-to", "type": "IndicatorToIndicator", "entityA": "1234567890", "entityAFamily": "Indicator", "entityAType": "type non support", "entityB": "relations", "entityBFamily": "Indicator", "entityBType": "Malware", "fields": {}, } ], ), ], ) def test_create_relationships_unknown_key(field, indicator, resource, expected_results): """ Given - Field type, indicator and a resource with an unknown relation type. When - Calling `create_relationships` command. Then - validate that no Key Error exception was thrown, and that only 1 relationship was created. """ from CrowdStrikeIndicatorFeed import Client, create_relationships rs_ls = create_relationships(field, indicator, resource, Client.get_actors_names_request) assert rs_ls == expected_results assert len(rs_ls) == 1 def test_reset_last_run(mocker): """ Given - No inputs. When - Calling `reset_last_run` command. Then - Ensure that the integration context dict was cleared. """ from CrowdStrikeIndicatorFeed import reset_last_run demisto_set_context_mocker = mocker.patch.object(demisto, "setIntegrationContext") reset_last_run() assert demisto_set_context_mocker.call_args.args == ({},) def test_fetch_no_indicators(mocker, requests_mock): """ Given - no indicators api response When - fetching indicators Then - Ensure empty list is returned and no exception is raised. """ from CrowdStrikeIndicatorFeed import Client mock_response = util_load_json("test_data/crowdstrike_indicators_list_command.json") requests_mock.post("https://api.crowdstrike.com/oauth2/token", json={"access_token": "12345"}) requests_mock.get(url="https://api.crowdstrike.com/intel/combined/indicators/v1", json=mock_response) feed_tags = ["Tag1", "Tag2"] client = Client( base_url="https://api.crowdstrike.com/", credentials={"identifier": "123", "password": "123"}, type="Domain", include_deleted="false", limit=2, feed_tags=feed_tags, ) mocker.patch.object(client, "get_indicators", return_value={"resources": []}) assert client.fetch_indicators(limit=10, offset=5, fetch_command=True) == [] def test_crowdstrike_to_xsoar_types(): from CrowdStrikeIndicatorFeed import CROWDSTRIKE_TO_XSOAR_TYPES assert None not in CROWDSTRIKE_TO_XSOAR_TYPES @pytest.mark.parametrize( "first_fetch, filter, integration_context, get_indicators_response, filter_arg_call, expected_results", [ ("1662650320", "", {"last_updated": "1662650343"}, {}, "(last_updated:>=1662650343)", ("", 0)), ( "1662650320", "", {"last_updated": "1662650343"}, { "resources": [ { "id": "dummy", "indicator": "dummy", "type": "hash_md5", "deleted": "False", "published_date": 1622198010, "last_updated": 1662650343, "reports": [], "actors": ["DOPPELSPIDER"], "malware_families": ["DoppelDridex"], "kill_chains": [], "ip_address_types": [], "domain_types": [], "malicious_confidence": "high", "_marker": "test_marker_test", "labels": [], } ] }, "(last_updated:>=1662650343)", ("(_marker:>'test_marker_test')", 1), ), ( "1662650320", "", {}, { "resources": [ { "id": "dummy", "indicator": "dummy", "type": "hash_md5", "deleted": "False", "published_date": 1622198010, "last_updated": 1662650343, "reports": [], "actors": ["DOPPELSPIDER"], "malware_families": ["DoppelDridex"], "kill_chains": [], "ip_address_types": [], "domain_types": [], "malicious_confidence": "high", "_marker": "test_marker_test", "labels": [], } ] }, "(last_updated:>=1662650320)", ("(_marker:>'test_marker_test')", 1), ), ( "", "", {}, { "resources": [ { "id": "dummy", "indicator": "dummy", "type": "hash_md5", "deleted": "False", "published_date": 1622198010, "last_updated": 1662650343, "reports": [], "actors": ["DOPPELSPIDER"], "malware_families": ["DoppelDridex"], "kill_chains": [], "ip_address_types": [], "domain_types": [], "malicious_confidence": "high", "_marker": "test_marker_test", "labels": [], } ] }, None, ("(_marker:>'test_marker_test')", 1), ), ], ) def test_handling_first_fetch_and_old_integration_context( mocker, requests_mock, first_fetch, filter, integration_context, get_indicators_response, filter_arg_call, expected_results ): from CrowdStrikeIndicatorFeed import Client requests_mock.post("https://api.crowdstrike.com/oauth2/token", json={"access_token": "12345"}) client = Client( base_url="https://api.crowdstrike.com/", credentials={"identifier": "123", "password": "123"}, type="ALL", include_deleted="false", limit=2, first_fetch=first_fetch, ) mocker.patch("CrowdStrikeIndicatorFeed.demisto.getIntegrationContext", return_value=integration_context) requests_mock.get( url="https://api.crowdstrike.com/intel/entities/actors/v1?ids=DOPPELSPIDER&fields=name", json={"resources": [{"name": "DOPPEL SPIDER"}]}, ) get_indicator_call = mocker.patch.object(client, "get_indicators", return_value=get_indicators_response) results = client.handle_first_fetch_context_or_pre_2_1_0(filter) assert get_indicator_call.call_args.kwargs["params"].get("filter") == filter_arg_call assert results[0] == expected_results[0] assert len(results[1]) == expected_results[1] @pytest.mark.parametrize( "indicator, expected_results", [ ({"indicator": "1.1.1.1", "type": "ip_address"}, "IP"), ({"indicator": "fe80:0000:0000:0000:91ba:7558:26d3:acde", "type": "ip_address"}, "IPv6"), ({"indicator": "test_test", "type": "username"}, "Account"), ({"indicator": "test_test", "type": "password"}, None), ], ) def test_auto_detect_indicator_type_from_cs(indicator: dict, expected_results: str | None): from CrowdStrikeIndicatorFeed import auto_detect_indicator_type_from_cs assert auto_detect_indicator_type_from_cs(indicator["indicator"], indicator["type"]) == expected_results def test_get_actors_names_request_check_output(mocker, requests_mock): """ Given - params for get_actors_names_request http request When - calling get_actors_names_request after fetching/listing indicators Then - Ensure the result is correct """ from CrowdStrikeIndicatorFeed import Client mock_response = util_load_json("test_data/crowdstrike_indicators_list_command.json") requests_mock.post("https://api.crowdstrike.com/oauth2/token", json={"access_token": "12345"}) requests_mock.get(url="https://api.crowdstrike.com/intel/combined/indicators/v1", json=mock_response) crowdstrike_client = Client( base_url="https://api.crowdstrike.com/", credentials={"identifier": "123", "password": "123"}, type="Domain", include_deleted="false", limit=2, ) requests_mock.get(url="https://api.crowdstrike.com/intel/entities/actors/v1?", json={"resources": ""}) requests_mock.get( url="https://api.crowdstrike.com/intel/entities/actors/v1?ids=123&fields=name", json={"resources": {"name": "TEST TEST"}} ) res = crowdstrike_client.get_actors_names_request(params_string="ids=123&fields=name") assert res == {"name": "TEST TEST"} def test_get_actors_names_request_called_with(mocker, requests_mock): """ Given - params for get_actors_names_request http request When - calling get_actors_names_request after fetching/listing indicators Then - Ensure the request is called with the right args """ from CrowdStrikeIndicatorFeed import Client mock_response = util_load_json("test_data/crowdstrike_indicators_list_command.json") requests_mock.post("https://api.crowdstrike.com/oauth2/token", json={"access_token": "12345"}) requests_mock.get(url="https://api.crowdstrike.com/intel/combined/indicators/v1", json=mock_response) crowdstrike_client = Client( base_url="https://api.crowdstrike.com/", credentials={"identifier": "123", "password": "123"}, type="Domain", include_deleted="false", limit=2, ) requests_mock.get(url="https://api.crowdstrike.com/intel/entities/actors/v1?", json={"resources": ""}) http_request_mock = mocker.patch.object( crowdstrike_client, "_http_request", return_value={"resources": {"name": "TEST TEST"}} ) crowdstrike_client.get_actors_names_request(params_string="ids=123&fields=name") http_request_mock.assert_called_once_with( method="GET", url_suffix="intel/entities/actors/v1?ids=123&fields=name", timeout=30, ok_codes=(200, 401) ) def test_crowdstrike_indicators_list_command_check_actors_convert(mocker, requests_mock): """ Given - params for crowdstrike_indicators_list_command http request When - calling get_actors_names_request after fetching/listing indicators Then - Ensure the response is correct """ from CrowdStrikeIndicatorFeed import Client, crowdstrike_indicators_list_command mock_response = util_load_json("test_data/crowdstrike_test_actors_convert.json") requests_mock.post("https://api.crowdstrike.com/oauth2/token", json={"access_token": "12345"}) requests_mock.get(url="https://api.crowdstrike.com/intel/combined/indicators/v1", json=mock_response) requests_mock.get( url="https://api.crowdstrike.com/intel/entities/actors/v1?ids=TESTTEST&fields=name", json={"resources": [{"name": "TEST TEST"}]}, ) mocker.patch("CrowdStrikeIndicatorFeed.get_integration_context", return_value={}) mocker.patch("CrowdStrikeIndicatorFeed.update_integration_context") feed_tags = ["Tag1", "Tag2"] crowdstrike_client = Client( base_url="https://api.crowdstrike.com/", credentials={"identifier": "123", "password": "123"}, type="Domain", include_deleted="false", limit=2, feed_tags=feed_tags, ) args = {"limit": "2"} response = crowdstrike_indicators_list_command(crowdstrike_client, args) assert len(response.outputs) == 1 assert len(response.raw_response) == 1 assert len(response.raw_response[0].get("relationships", None)) == 2 assert response.raw_response[0].get("relationships", None)[1].get("entityB", None) == "TEST TEST" def test_change_actors_from_id_to_name(mocker, requests_mock): """ Given - params for change_actors_from_id_to_name http request When - calling get_actors_names_request after fetching/listing indicators Then - Ensure the response is correct """ from CrowdStrikeIndicatorFeed import Client, change_actors_from_id_to_name requests_mock.post("https://api.crowdstrike.com/oauth2/token", json={"access_token": "12345"}) crowdstrike_client = Client( base_url="https://api.crowdstrike.com/", credentials={"identifier": "123", "password": "123"}, type="Domain", include_deleted="false", limit=2, ) actors_unparsed_array = ["TEST", "TEST1", "TEST2"] mocker.patch("CrowdStrikeIndicatorFeed.get_integration_context", return_value={"TEST": "WAS IN CONTEXT"}) requests_mock.get( url="https://api.crowdstrike.com/intel/entities/actors/v1?ids=TEST1&ids=TEST2&fields=name", json={"resources": [{"name": "Changedtest1"}, {"name": "Changedtest2"}]}, ) result = change_actors_from_id_to_name(actors_unparsed_array, crowdstrike_client.get_actors_names_request) assert result[0] == "WAS IN CONTEXT" assert result[1] == "Changedtest1" assert result[2] == "Changedtest2" # This function will alternate the response each time it's called def mock_alternate_response(request, context): # Track the number of times the post request has been called if not hasattr(mock_alternate_response, "call_count"): mock_alternate_response.call_count = 0 mock_alternate_response.call_count += 1 if mock_alternate_response.call_count == 1: # First call: Return 401 Unauthorized context.status_code = 401 return {"errors": [{"code": 401, "message": "access denied, authorization failed"}]} else: # Second call: Return 200 OK with the access token context.status_code = 200 return {"resources": []} def test_fetch_no_indicators_regenerate_token(requests_mock): """ Given - no indicators api response When - fetching indicators when API token expired. Then - Ensure empty list is returned and no exception is raised. """ from CrowdStrikeIndicatorFeed import Client requests_mock.post("https://api.crowdstrike.com/oauth2/token", json={"access_token": "12345"}) requests_mock.get(url="https://api.crowdstrike.com/intel/combined/indicators/v1", json=mock_alternate_response) feed_tags = ["Tag1", "Tag2"] client = Client( base_url="https://api.crowdstrike.com/", credentials={"identifier": "123", "password": "123"}, type="Domain", include_deleted="false", limit=2, feed_tags=feed_tags, ) assert client.fetch_indicators(limit=10, offset=5, fetch_command=True) == [] def test_get_actors_names_request_regenerate_token(requests_mock): """ Given - no actors api response When - calling get_actors_names_request after fetching/listing indicators Then - Ensure empty list is returned and no exception is raised. """ from CrowdStrikeIndicatorFeed import Client mock_response = util_load_json("test_data/crowdstrike_indicators_list_command.json") requests_mock.post("https://api.crowdstrike.com/oauth2/token", json={"access_token": "12345"}) requests_mock.get(url="https://api.crowdstrike.com/intel/combined/indicators/v1", json=mock_response) crowdstrike_client = Client( base_url="https://api.crowdstrike.com/", credentials={"identifier": "123", "password": "123"}, type="Domain", include_deleted="false", limit=2, ) requests_mock.get(url="https://api.crowdstrike.com/intel/entities/actors/v1?", json={"resources": ""}) requests_mock.get( url="https://api.crowdstrike.com/intel/entities/actors/v1?ids=123&fields=name", json=mock_alternate_response ) res = crowdstrike_client.get_actors_names_request(params_string="ids=123&fields=name") assert res == []