Skip to content

Commit

Permalink
[Palo Alto] Return 401 correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
nmccullagh-r7 committed Nov 8, 2024
1 parent 2e4ec59 commit 02fafbc
Show file tree
Hide file tree
Showing 13 changed files with 72 additions and 13 deletions.
6 changes: 3 additions & 3 deletions plugins/palo_alto_cortex_xdr/.CHECKSUM
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"spec": "5f65f97ed0704bd87cb78e24eb9dc1b3",
"manifest": "094c90db12918a2d28277d8b94124397",
"setup": "67c9748687eb5d9ea0eccfccb53610e1",
"spec": "1a737630103c5a3fb2d61444c2fefbb9",
"manifest": "58618c879c00000568c7d1e4da6bc0a1",
"setup": "cb9fd1212032e1f3d1d0246bf663c090",
"schemas": [
{
"identifier": "allow_file/schema.py",
Expand Down
2 changes: 1 addition & 1 deletion plugins/palo_alto_cortex_xdr/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM --platform=linux/amd64 rapid7/insightconnect-python-3-slim-plugin:6.1.4
FROM --platform=linux/amd64 rapid7/insightconnect-python-3-slim-plugin:6.2.0

LABEL organization=rapid7
LABEL sdk=python
Expand Down
2 changes: 1 addition & 1 deletion plugins/palo_alto_cortex_xdr/bin/icon_palo_alto_cortex_xdr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ from sys import argv

Name = "Palo Alto Cortex XDR"
Vendor = "rapid7"
Version = "4.0.3"
Version = "4.0.4"
Description = "Stop modern attacks with the industry's first extended detection and response platform that spans your endpoints, network and cloud data"


Expand Down
1 change: 1 addition & 0 deletions plugins/palo_alto_cortex_xdr/help.md
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,7 @@ Isolate Endpoint fails with 500 error - This will happen if an isolation action

# Version History

* 4.0.4 - Raise authentication errors if provided invalid credentials
* 4.0.3 - `Monitor Incidents` - Add custom config exception handling
* 4.0.2 - SDK bump to 6.1.4
* 4.0.1 - SDK Bump to 6.1.3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
Component,
)
from datetime import datetime, timedelta, timezone
from insightconnect_plugin_runtime.exceptions import PluginException
from insightconnect_plugin_runtime.exceptions import PluginException, APIException
from insightconnect_plugin_runtime.helper import hash_sha1
from typing import Any, Dict, Tuple, Union, Optional

Expand Down Expand Up @@ -61,6 +61,15 @@ def run(self, params={}, state={}, custom_config: dict = {}): # pylint: disable

return response, state, has_more_pages, 200, None

except APIException as error:
return (
[],
{},
False,
error.status_code,
PluginException(data=error, cause=error.cause, assistance=error.assistance),
)

except PluginException as error:
if isinstance(error.data, Response):
# if there is response data in the error then use it in the exception
Expand Down
14 changes: 12 additions & 2 deletions plugins/palo_alto_cortex_xdr/icon_palo_alto_cortex_xdr/util/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
ConnectionTestException,
ResponseExceptionData,
HTTPStatusCodes,
APIException,
)
from insightconnect_plugin_runtime.helper import extract_json, make_request
from requests import Response
Expand Down Expand Up @@ -473,12 +474,21 @@ def _handle_401(self, response: Response, url: str, post_body: dict):
re-run the creds generation
"""

if response.status_code == 401:
self.logger.info(f"Received HTTP {response.status_code}, re-authenticating to Palo Alto Cortex XDR")
if response.status_code in [401, 403]:
self.logger.info(f"Received HTTP {response.status_code}, attempting to refresh token")

new_headers = self._advanced_authentication(api_key=self.api_key, api_key_id=self.api_key_id)
new_response = self.build_request(url=url, headers=new_headers, post_body=post_body)

if new_response.status_code in [401, 403]:
self.logger.info("Token is still invalid, raising exception")
raise APIException(
cause=PluginException.causes.get(PluginException.Preset.API_KEY),
assistance=PluginException.assistances.get(PluginException.Preset.API_KEY),
status_code=401,
data=response.text,
)

return new_response

else:
Expand Down
5 changes: 3 additions & 2 deletions plugins/palo_alto_cortex_xdr/plugin.spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ products: [insightconnect]
name: palo_alto_cortex_xdr
title: Palo Alto Cortex XDR
description: Stop modern attacks with the industry's first extended detection and response platform that spans your endpoints, network and cloud data
version: 4.0.3
version: 4.0.4
connection_version: 2
cloud_ready: true
sdk:
type: slim
version: 6.1.4
version: 6.2.0
user: nobody
supported_versions: ["2024-07-15 Palo Alto Cortex XDR API"]
vendor: rapid7
Expand Down Expand Up @@ -38,6 +38,7 @@ key_features:
- "Add files to the block or allow lists"
troubleshooting: "Isolate Endpoint fails with 500 error - This will happen if an isolation action (Isolate or Unisolate) is in progress on the selected endpoint. Wait a few minutes and try again."
version_history:
- "4.0.4 - Raise authentication errors if provided invalid credentials"
- "4.0.3 - `Monitor Incidents` - Add custom config exception handling"
- "4.0.2 - SDK bump to 6.1.4"
- "4.0.1 - SDK Bump to 6.1.3"
Expand Down
3 changes: 2 additions & 1 deletion plugins/palo_alto_cortex_xdr/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# List third-party dependencies here, separated by newlines.
# All dependencies must be version-pinned, eg. requests==1.2.0
# See: https://pip.pypa.io/en/stable/user_guide/#requirements-files
parameterized==0.8.1
parameterized==0.9.0
timeout-decorator==0.5.0
freezegun==1.5.1
timeout_decorator==0.5.0
2 changes: 1 addition & 1 deletion plugins/palo_alto_cortex_xdr/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


setup(name="palo_alto_cortex_xdr-rapid7-plugin",
version="4.0.3",
version="4.0.4",
description="Stop modern attacks with the industry's first extended detection and response platform that spans your endpoints, network and cloud data",
author="rapid7",
author_email="",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import sys
import os

sys.path.append(os.path.abspath("../"))

from unittest import TestCase
from icon_palo_alto_cortex_xdr.connection.connection import Connection
from icon_palo_alto_cortex_xdr.actions.get_file_quarantine_status import GetFileQuarantineStatus
import json
import logging


class TestGetFileQuarantineStatus(TestCase):
def test_get_file_quarantine_status(self):
"""
DO NOT USE PRODUCTION/SENSITIVE DATA FOR UNIT TESTS
TODO: Implement test cases here
"""
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from icon_palo_alto_cortex_xdr.triggers.get_query_results import GetQueryResults
from icon_palo_alto_cortex_xdr.triggers.get_query_results.schema import Input

from mock import mock_request_200
from mock_helper import mock_request_200
from util import MockTrigger, Util


Expand Down
18 changes: 18 additions & 0 deletions plugins/palo_alto_cortex_xdr/unit_test/test_monitor_alerts.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from taskutil import TaskUtil, mock_conditions, mocked_response_type
from insightconnect_plugin_runtime.exceptions import PluginException
from typing import Union
from mock_helper import MockResponse

STUB_STATE_EXPECTED_SECOND_PAGE = {
"current_count": 2,
Expand Down Expand Up @@ -141,6 +142,16 @@ def test_monitor_alerts_pagination(
),
402,
],
[
"Unauthorized",
{},
PluginException(
cause=PluginException.causes.get(PluginException.Preset.API_KEY),
assistance=PluginException.assistances.get(PluginException.Preset.API_KEY),
data='An error occurred during plugin execution!\n\nInvalid API key provided. Verify your API key configured in your connection is correct. Response was: {"reply": {"err_code": 401, "err_msg": "Public API request unauthorized", "err_extra": null}}',
),
401,
],
[
"Forbidden",
STUB_STATE_ERROR,
Expand Down Expand Up @@ -179,6 +190,13 @@ def test_monitor_alerts_error_handling(
if error_code == 500:
mocked_response = mock_conditions(200, file_name="monitor_alerts_faulty_response")

elif error_code == 401:
mocked_response = MockResponse(
filename="monitor_alerts_faulty_response",
status_code=401,
text='{"reply": {"err_code": 401, "err_msg": "Public API request unauthorized", "err_extra": null}}',
)

# This else applies to every other usual exception
else:
mocked_response = mocked_response_type(error_code)
Expand Down

0 comments on commit 02fafbc

Please sign in to comment.