Skip to content

Commit

Permalink
SOAR-18579-Better error handling for invalid dns (#3065)
Browse files Browse the repository at this point in the history
* SOAR-18579-Better error handling for invalid dns

* SOAR-18579-Better error handling for invalid dns

* adding unit tests

* bumping sdk to version 6.2.4
  • Loading branch information
rbowden-r7 authored Feb 4, 2025
1 parent d21db72 commit fcb65f5
Show file tree
Hide file tree
Showing 13 changed files with 121 additions and 30 deletions.
8 changes: 4 additions & 4 deletions plugins/salesforce/.CHECKSUM
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"spec": "63b7270d95683b98e315808e4df20354",
"manifest": "391ed2bce80fc53ee24774278259d26e",
"setup": "295d03a5efdf6658a6a10babe80a9a06",
"spec": "ca0461f1e8b0955a13e183d053e50eda",
"manifest": "e5d067d713f2381cc4875c19c200e489",
"setup": "bfad8c5af259dc2c0235de74e1b7d8dd",
"schemas": [
{
"identifier": "advanced_search/schema.py",
Expand Down Expand Up @@ -41,7 +41,7 @@
},
{
"identifier": "monitor_users/schema.py",
"hash": "87d5000d4862847cd58fec2364b9458a"
"hash": "a5369928b0fb356372ffad936aa59153"
}
]
}
4 changes: 2 additions & 2 deletions plugins/salesforce/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM --platform=linux/amd64 rapid7/insightconnect-python-3-plugin:6.2.0
FROM --platform=linux/amd64 rapid7/insightconnect-python-3-plugin:6.2.4

LABEL organization=rapid7
LABEL sdk=python
Expand All @@ -12,7 +12,7 @@ RUN if [ -f requirements.txt ]; then pip install -r requirements.txt; fi

ADD . /python/src

RUN python setup.py build && python setup.py install
RUN pip install .

# User to run plugin code. The two supported users are: root, nobody
USER nobody
Expand Down
2 changes: 1 addition & 1 deletion plugins/salesforce/bin/komand_salesforce
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ from sys import argv

Name = "Salesforce"
Vendor = "rapid7"
Version = "2.1.12"
Version = "2.1.13"
Description = "[Salesforce](https://www.salesforce.com) is a CRM solution that brings together all customer information in a single, integrated platform that enables building a customer-centered business from marketing right through to sales, customer service and business analysis. The Salesforce plugin allows you to search, update, and manage salesforce records. This plugin utilizes the [Salesforce API](https://developer.salesforce.com/docs/atlas.en-us.216.0.api_rest.meta/api_rest/intro_what_is_rest_api.htm)"


Expand Down
1 change: 1 addition & 0 deletions plugins/salesforce/help.md
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ Example output:

# Version History

* 2.1.13 - Task Monitor Users: improve error response to UI | Bump SDK to 6.2.4
* 2.1.12 - Task Monitor Users: ensure datetime includes microseconds | Bump SDK to 6.2.0
* 2.1.11 - Task Monitor Users: Return 500 for retry your request error | Bump SDK to 6.1.4
* 2.1.10 - Set Monitor Users task output length | Fix to remove whitespace from connection inputs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class MonitorUsersOutput(insightconnect_plugin_runtime.Output):
"type": "array",
"title": "Users",
"description": "Information about users, their login history and which users have been updated",
"items": {},
"required": [
"users"
],
Expand Down
34 changes: 23 additions & 11 deletions plugins/salesforce/komand_salesforce/util/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
SOBJECT_UPDATED_USERS,
)
from komand_salesforce.util.exceptions import ApiException
from requests.exceptions import ConnectionError as DNSError


def rate_limiting(max_tries: int):
Expand Down Expand Up @@ -190,17 +191,27 @@ def _get_token(
client_url = f"https://{salesforce_url}/services/oauth2/token"

self.logger.info(f"SalesforceAPI: Getting API token from {client_url}... ")
response = requests.request(
method="POST",
url=client_url,
data={
"grant_type": "password",
"client_id": client_id,
"client_secret": client_secret,
"username": username,
"password": password + security_token,
},
)

try:
response = requests.request(
method="POST",
url=client_url,
data={
"grant_type": "password",
"client_id": client_id,
"client_secret": client_secret,
"username": username,
"password": password + security_token,
},
)
except DNSError as error_message:
self.logger.info(f"Network error or DNS resolution failed: {error_message}")
raise ApiException(
cause="Network error or DNS resolution failed. Please check the domain entered",
assistance="Network error or DNS resolution failed. Please check the domain entered",
status_code=400,
data="Network error or DNS resolution failed. Please check the domain entered",
)

if 400 <= response.status_code <= 504:
decoded_response = response.content.decode()
Expand Down Expand Up @@ -357,6 +368,7 @@ def get_error(self, response: str) -> Tuple[str, str, int]:
"invalid_grant": "Invalid password or security token supplied.",
"invalid_client_id": "Invalid client ID supplied.",
"invalid_client": "Invalid client secret supplied.",
"unsupported_grant_type": "Grant type not supported, Please ensure correct login URL is provided",
}

try:
Expand Down
5 changes: 3 additions & 2 deletions plugins/salesforce/plugin.spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ products: [insightconnect]
name: salesforce
title: Salesforce
description: "[Salesforce](https://www.salesforce.com) is a CRM solution that brings together all customer information in a single, integrated platform that enables building a customer-centered business from marketing right through to sales, customer service and business analysis. The Salesforce plugin allows you to search, update, and manage salesforce records. This plugin utilizes the [Salesforce API](https://developer.salesforce.com/docs/atlas.en-us.216.0.api_rest.meta/api_rest/intro_what_is_rest_api.htm)"
version: 2.1.12
version: 2.1.13
connection_version: 2
vendor: rapid7
support: community
Expand All @@ -13,7 +13,7 @@ status: []
supported_versions: ["Salesforce API v58 2023-06-30"]
sdk:
type: full
version: 6.2.0
version: 6.2.4
user: nobody
resources:
source_url: https://github.com/rapid7/insightconnect-plugins/tree/master/plugins/salesforce
Expand All @@ -37,6 +37,7 @@ references:
- "[Connecting your app to the API](https://developer.salesforce.com/docs/atlas.en-us.216.0.api_rest.meta/api_rest/quickstart.htm)"
- "[SOQL](https://developer.salesforce.com/docs/atlas.en-us.216.0.soql_sosl.meta/soql_sosl/sforce_api_calls_soql.htm)"
version_history:
- "2.1.13 - Task Monitor Users: improve error response to UI | Bump SDK to 6.2.4"
- "2.1.12 - Task Monitor Users: ensure datetime includes microseconds | Bump SDK to 6.2.0"
- "2.1.11 - Task Monitor Users: Return 500 for retry your request error | Bump SDK to 6.1.4"
- "2.1.10 - Set Monitor Users task output length | Fix to remove whitespace from connection inputs"
Expand Down
21 changes: 11 additions & 10 deletions plugins/salesforce/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
from setuptools import setup, find_packages


setup(name="salesforce-rapid7-plugin",
version="2.1.12",
description="[Salesforce](https://www.salesforce.com) is a CRM solution that brings together all customer information in a single, integrated platform that enables building a customer-centered business from marketing right through to sales, customer service and business analysis. The Salesforce plugin allows you to search, update, and manage salesforce records. This plugin utilizes the [Salesforce API](https://developer.salesforce.com/docs/atlas.en-us.216.0.api_rest.meta/api_rest/intro_what_is_rest_api.htm)",
author="rapid7",
author_email="",
url="",
packages=find_packages(),
install_requires=['insightconnect-plugin-runtime'], # Add third-party dependencies to requirements.txt, not here!
scripts=['bin/komand_salesforce']
)
setup(
name="salesforce-rapid7-plugin",
version="2.1.13",
description="[Salesforce](https://www.salesforce.com) is a CRM solution that brings together all customer information in a single, integrated platform that enables building a customer-centered business from marketing right through to sales, customer service and business analysis. The Salesforce plugin allows you to search, update, and manage salesforce records. This plugin utilizes the [Salesforce API](https://developer.salesforce.com/docs/atlas.en-us.216.0.api_rest.meta/api_rest/intro_what_is_rest_api.htm)",
author="rapid7",
author_email="",
url="",
packages=find_packages(),
install_requires=["insightconnect-plugin-runtime"], # Add third-party dependencies to requirements.txt, not here!
scripts=["bin/komand_salesforce"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"clientId": "unsupported-grant-type",
"clientSecret": {
"secretKey": "example-secret-key"
},
"salesforceAccountUsernameAndPassword": {
"username": "example-username",
"password": "example-password"
},
"securityToken": {
"secretKey": "example-secret-key"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"error": "unsupported_grant_type",
"error_description": "unsupported_grant_type"
}
6 changes: 6 additions & 0 deletions plugins/salesforce/unit_test/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ def test_connection(
"Salesforce error: 'retry your request'",
PluginException.assistances[PluginException.Preset.UNKNOWN],
],
[
"unsupported_grant",
Util.read_file_to_dict("inputs/connection_unsupported_grant.json.inp"),
"Salesforce error: 'Grant type not supported, Please ensure correct login URL is provided'",
PluginException.assistances[PluginException.Preset.INVALID_CREDENTIALS],
],
]
)
def test_connection_raise_exception(
Expand Down
45 changes: 45 additions & 0 deletions plugins/salesforce/unit_test/test_monitor_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from jsonschema import validate
from komand_salesforce.tasks.monitor_users.schema import MonitorUsersOutput
from komand_salesforce.tasks.monitor_users.task import MonitorUsers
from komand_salesforce.connection.schema import Input
from parameterized import parameterized

from util import Util
Expand Down Expand Up @@ -179,3 +180,47 @@ def test_default_cut_off_values_of_7_days(self, mock_unset, mocked_logger, _mock
self.assertEqual(user_login_cutoff, mocked_logger.call_args_list[3][0][0])

mock_unset.assert_called()

@parameterized.expand(
[
[
"without_state",
{
"last_user_update_collection_timestamp": "2025-07-21 15:21:15.340262+00:00",
"next_user_collection_timestamp": "2023-07-21 15:21:15.340262+00:00",
"next_user_login_collection_timestamp": "2023-07-20 15:21:15.340262+00:00",
"last_user_login_collection_timestamp": "2023-07-20 14:21:15.340262+00:00",
},
{},
],
]
)
def test_bad_domain_provided(
self,
mocked_unset: MagicMock,
mocked_logger: MagicMock,
_mock_request: MagicMock,
_mock_get_time: MagicMock,
test_name: str,
current_state: Dict[str, Any],
expected: Dict[str, Any],
) -> None:

params = {
Input.CLIENTID: "example-client-id",
Input.CLIENTSECRET: {"secretKey": "example-secret-key"},
Input.SALESFORCEACCOUNTUSERNAMEANDPASSWORD: {
"username": "example-username",
"password": "example-password",
},
Input.SECURITYTOKEN: {"secretKey": "example-secret-key"},
Input.LOGINURL: "bad_domain",
}

self.action = Util.default_connector(MonitorUsers(), params=params)
actual, _actual_state, _has_more_pages, status_code, error = self.action.run(state=current_state)

self.assertEqual(error.cause, "Network error or DNS resolution failed. Please check the domain entered")
self.assertEqual(status_code, 400)

validate(actual, MonitorUsersOutput.schema)
7 changes: 7 additions & 0 deletions plugins/salesforce/unit_test/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ def json(self):
url = kwargs.get("url", "")
method = kwargs.get("method", "")

if url == "https://bad_domain/services/oauth2/token":
from requests.exceptions import ConnectionError as DNSError

raise DNSError()

if url == "https://login.salesforce.com/services/oauth2/token":
if data.get("client_id") == "invalid-client-id":
return MockResponse(400, "invalid_grant") # returns 400 when failing to get a token.
Expand All @@ -73,6 +78,8 @@ def json(self):
return MockResponse(400, "invalid_client_id")
if data.get("client_id") == "retry-request":
return MockResponse(400, "retry_request")
if data.get("client_id") == "unsupported-grant-type":
return MockResponse(400, "unsupported_grant_type")
return MockResponse(200, "get_token")
if url == "https://example.com/services/data/":
return MockResponse(200, "get_version")
Expand Down

0 comments on commit fcb65f5

Please sign in to comment.