diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e995e36..d330dca 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,11 +1,11 @@ repos: - repo: https://github.com/phantomcyber/dev-cicd-tools - rev: v1.16 + rev: v1.24 hooks: - id: org-hook - id: package-app-dependencies - repo: https://github.com/Yelp/detect-secrets - rev: v1.4.0 + rev: v1.5.0 hooks: - id: detect-secrets args: ['--no-verify', '--exclude-files', '^awssts.json$'] diff --git a/README.md b/README.md index c7dbefc..4251f8f 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ # AWS Security Token Service Publisher: Splunk -Connector Version: 1.2.10 +Connector Version: 1.2.11 Product Vendor: AWS Product Name: Security Token Service Product Version Supported (regex): ".\*" -Minimum Product Version: 6.1.1 +Minimum Product Version: 6.3.0 This app integrates with AWS Security Token Service and allows a user to retrieve a temporary set of credentials for some specified account @@ -44,8 +44,8 @@ This is true whether the receiving action's asset is configured with the access or if the EC2 instance role credentials are used. -### Configuration Variables -The below configuration variables are required for this Connector to operate. These variables are specified when configuring a Security Token Service asset in SOAR. +### Configuration variables +This table lists the configuration variables required to operate AWS Security Token Service. These variables are specified when configuring a Security Token Service asset in Splunk SOAR. VARIABLE | REQUIRED | TYPE | DESCRIPTION -------- | -------- | ---- | ----------- diff --git a/awssts.json b/awssts.json index 642b206..bb4ad12 100644 --- a/awssts.json +++ b/awssts.json @@ -12,11 +12,11 @@ "product_version_regex": ".*", "publisher": "Splunk", "license": "Copyright (c) 2021-2024 Splunk Inc.", - "app_version": "1.2.10", - "utctime_updated": "2023-10-31T10:18:56.000000Z", + "app_version": "1.2.11", + "utctime_updated": "2024-12-17T14:42:37.000000Z", "package_name": "phantom_awssts", "main_module": "awssts_connector.py", - "min_phantom_version": "6.1.1", + "min_phantom_version": "6.3.0", "app_wizard_version": "1.0.0", "latest_tested_versions": [ "Cloud API, September 23, 2021" @@ -35,21 +35,9 @@ "module": "jmespath", "input_file": "wheels/shared/jmespath-0.10.0-py2.py3-none-any.whl" }, - { - "module": "python_dateutil", - "input_file": "wheels/shared/python_dateutil-2.8.2-py2.py3-none-any.whl" - }, { "module": "s3transfer", "input_file": "wheels/shared/s3transfer-0.3.7-py2.py3-none-any.whl" - }, - { - "module": "six", - "input_file": "wheels/shared/six-1.16.0-py2.py3-none-any.whl" - }, - { - "module": "urllib3", - "input_file": "wheels/shared/urllib3-1.26.17-py2.py3-none-any.whl" } ] }, @@ -375,4 +363,4 @@ "versions": "EQ(*)" } ] -} \ No newline at end of file +} diff --git a/awssts_connector.py b/awssts_connector.py index eb68bec..964b53b 100644 --- a/awssts_connector.py +++ b/awssts_connector.py @@ -52,19 +52,19 @@ def initialize(self): config = self.get_config() - self._region = STS_REGION_DICT.get(config['region']) + self._region = STS_REGION_DICT.get(config["region"]) if not self._region: return self.set_status(phantom.APP_ERROR, "Specified region is not valid") self._proxy = {} - env_vars = config.get('_reserve_environment_variables', {}) - if 'HTTP_PROXY' in env_vars: - self._proxy['http'] = env_vars['HTTP_PROXY']['value'] - if 'HTTPS_PROXY' in env_vars: - self._proxy['https'] = env_vars['HTTPS_PROXY']['value'] + env_vars = config.get("_reserve_environment_variables", {}) + if "HTTP_PROXY" in env_vars: + self._proxy["http"] = env_vars["HTTP_PROXY"]["value"] + if "HTTPS_PROXY" in env_vars: + self._proxy["https"] = env_vars["HTTPS_PROXY"]["value"] # Check for EC2 role creds, otherwise use the ones in the config - if config.get('use_role'): + if config.get("use_role"): credentials = self._handle_get_ec2_role() if not credentials: return self.set_status(phantom.APP_ERROR, ASSUME_ROLE_CREDENTIALS_FAILURE_MSG) @@ -87,7 +87,7 @@ def finalize(self): return phantom.APP_SUCCESS - def _create_client(self, action_result, service='sts', new_region=None): + def _create_client(self, action_result, service="sts", new_region=None): boto_config = None if self._proxy: @@ -106,17 +106,13 @@ def _create_client(self, action_result, service='sts', new_region=None): aws_access_key_id=self._access_key, aws_secret_access_key=self._secret_key, aws_session_token=self._token, - config=boto_config + config=boto_config, ) else: self.debug_print("Creating boto3 client without API keys") - self._client = client( - 'sts', - region_name=self._region, - config=boto_config - ) + self._client = client("sts", region_name=self._region, config=boto_config) except Exception as e: return action_result.set_status(phantom.APP_ERROR, "Could not create boto3 client: {0}".format(e)) @@ -163,7 +159,7 @@ def _handle_test_connectivity(self, param): if not self._create_client(action_result): return action_result.get_status() - ret_val, resp_json = self._make_boto_call(action_result, 'get_caller_identity') + ret_val, resp_json = self._make_boto_call(action_result, "get_caller_identity") if phantom.is_fail(ret_val): self.save_progress("Test Connectivity Failed.") @@ -178,13 +174,11 @@ def _handle_assume_role(self, param): action_result = self.add_action_result(ActionResult(dict(param))) - role_session_name = param.get('role_session_name', - DEFAULT_ROLE_SESSION_NAME) - external_id = param.get('external_id') - role_arn = param.get('role_arn') - role_session_duration = param.get('role_session_duration', - DEFAULT_ROLE_SESSION_DURATION) - region = param.get('region') + role_session_name = param.get("role_session_name", DEFAULT_ROLE_SESSION_NAME) + external_id = param.get("external_id") + role_arn = param.get("role_arn") + role_session_duration = param.get("role_session_duration", DEFAULT_ROLE_SESSION_DURATION) + region = param.get("region") if not region: region = self._region for region_name, region_value in STS_REGION_DICT.items(): @@ -192,21 +186,23 @@ def _handle_assume_role(self, param): region = region_name # create client - if phantom.is_fail(self._create_client(action_result, service='sts', new_region=region)): + if phantom.is_fail(self._create_client(action_result, service="sts", new_region=region)): return action_result.get_status() # make boto3 call if external_id: - ret_val, resp_json = self._make_boto_call(action_result, 'assume_role', - RoleSessionName=role_session_name, - RoleArn=role_arn, - ExternalId=external_id, - DurationSeconds=role_session_duration) + ret_val, resp_json = self._make_boto_call( + action_result, + "assume_role", + RoleSessionName=role_session_name, + RoleArn=role_arn, + ExternalId=external_id, + DurationSeconds=role_session_duration, + ) else: - ret_val, resp_json = self._make_boto_call(action_result, 'assume_role', - RoleSessionName=role_session_name, - RoleArn=role_arn, - DurationSeconds=role_session_duration) + ret_val, resp_json = self._make_boto_call( + action_result, "assume_role", RoleSessionName=role_session_name, RoleArn=role_arn, DurationSeconds=role_session_duration + ) if phantom.is_fail(ret_val): return action_result.get_status() @@ -224,10 +220,10 @@ def handle_action(self, param): self.debug_print("action_id", self.get_action_identifier()) - if action_id == 'test_connectivity': + if action_id == "test_connectivity": ret_val = self._handle_test_connectivity(param) - elif action_id == 'assume_role': + elif action_id == "assume_role": ret_val = self._handle_assume_role(param) return ret_val @@ -249,10 +245,10 @@ def main(): argparser = argparse.ArgumentParser() - argparser.add_argument('input_test_json', help='Input Test JSON file') - argparser.add_argument('-u', '--username', help='username', required=False) - argparser.add_argument('-p', '--password', help='password', required=False) - argparser.add_argument('-v', '--verify', action='store_true', help='verify', required=False, default=False) + argparser.add_argument("input_test_json", help="Input Test JSON file") + argparser.add_argument("-u", "--username", help="username", required=False) + argparser.add_argument("-p", "--password", help="password", required=False) + argparser.add_argument("-v", "--verify", action="store_true", help="verify", required=False, default=False) args = argparser.parse_args() session_id = None @@ -265,28 +261,29 @@ def main(): # User specified a username but not a password, so ask import getpass + password = getpass.getpass("Password: ") if username and password: try: - login_url = AwsSecureTokenServiceConnector._get_phantom_base_url() + '/login' + login_url = AwsSecureTokenServiceConnector._get_phantom_base_url() + "/login" print("Accessing the Login page") r = requests.get(login_url, verify=verify, timeout=DEFAULT_TIMEOUT) - csrftoken = r.cookies['csrftoken'] + csrftoken = r.cookies["csrftoken"] data = dict() - data['username'] = username - data['password'] = password - data['csrfmiddlewaretoken'] = csrftoken + data["username"] = username + data["password"] = password + data["csrfmiddlewaretoken"] = csrftoken headers = dict() - headers['Cookie'] = 'csrftoken=' + csrftoken - headers['Referer'] = login_url + headers["Cookie"] = "csrftoken=" + csrftoken + headers["Referer"] = login_url print("Logging into Platform to get the session id") r2 = requests.post(login_url, verify=verify, data=data, headers=headers, timeout=DEFAULT_TIMEOUT) - session_id = r2.cookies['sessionid'] + session_id = r2.cookies["sessionid"] except Exception as e: print("Unable to get session id from the platform. Error: " + str(e)) sys.exit(1) @@ -300,8 +297,8 @@ def main(): connector.print_progress_message = True if session_id is not None: - in_json['user_session_token'] = session_id - connector._set_csrf_info(csrftoken, headers['Referer']) + in_json["user_session_token"] = session_id + connector._set_csrf_info(csrftoken, headers["Referer"]) ret_val = connector._handle_action(json.dumps(in_json), None) print(json.dumps(json.loads(ret_val), indent=4)) @@ -309,5 +306,5 @@ def main(): sys.exit(0) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/awssts_consts.py b/awssts_consts.py index 27a3bb8..73e1591 100644 --- a/awssts_consts.py +++ b/awssts_consts.py @@ -13,31 +13,31 @@ # either express or implied. See the License for the specific language governing permissions # and limitations under the License. STS_JSON_ACCESS_KEY = "access_key" -STS_JSON_SECRET_KEY = "secret_key" +STS_JSON_SECRET_KEY = "secret_key" # pragma: allowlist secret STS_REGION_DICT = { - "US East (Ohio)": "us-east-1", - "US East (N. Virginia)": "us-east-2", - "US West (N. California)": "us-west-1", - "US West (Oregon)": "us-west-2", - "Canada (Central)": "ca-central-1", - "Asia Pacific (Mumbai)": "ap-south-1", - "Asia Pacific (Tokyo)": "ap-northeast-1", - "Asia Pacific (Seoul)": "ap-northeast-2", - "Asia Pacific (Singapore)": "ap-southeast-1", - "Asia Pacific (Sydney)": "ap-southeast-2", - "China (Ningxia)": "cn-northwest-1", - "EU (Frankfurt)": "eu-central-1", - "EU (Ireland)": "eu-west-1", - "EU (London)": "eu-west-2", - "South Americia (Sao Paulo)": "sa-east-1", - "US GovCloud East": "us-gov-east-1", - "US GovCloud West": "us-gov-west-1", - } + "US East (Ohio)": "us-east-1", + "US East (N. Virginia)": "us-east-2", + "US West (N. California)": "us-west-1", + "US West (Oregon)": "us-west-2", + "Canada (Central)": "ca-central-1", + "Asia Pacific (Mumbai)": "ap-south-1", + "Asia Pacific (Tokyo)": "ap-northeast-1", + "Asia Pacific (Seoul)": "ap-northeast-2", + "Asia Pacific (Singapore)": "ap-southeast-1", + "Asia Pacific (Sydney)": "ap-southeast-2", + "China (Ningxia)": "cn-northwest-1", + "EU (Frankfurt)": "eu-central-1", + "EU (Ireland)": "eu-west-1", + "EU (London)": "eu-west-2", + "South Americia (Sao Paulo)": "sa-east-1", + "US GovCloud East": "us-gov-east-1", + "US GovCloud West": "us-gov-west-1", +} DEFAULT_TIMEOUT = 30 DEFAULT_ROLE_SESSION_DURATION = 3600 -DEFAULT_ROLE_SESSION_NAME = 'Request_from_Phantom' -ASSUME_ROLE_SUCCESS_MSG = 'Successfully retrieved assume role credentials from region {}' -ASSUME_ROLE_CREDENTIALS_FAILURE_MSG = 'Failed to retrieve EC2 role credentials' -ASSUME_ROLE_BAD_ASSET_CONFIG_MSG = 'Please provide access keys or select assume role check box in asset configuration' +DEFAULT_ROLE_SESSION_NAME = "Request_from_Phantom" +ASSUME_ROLE_SUCCESS_MSG = "Successfully retrieved assume role credentials from region {}" +ASSUME_ROLE_CREDENTIALS_FAILURE_MSG = "Failed to retrieve EC2 role credentials" +ASSUME_ROLE_BAD_ASSET_CONFIG_MSG = "Please provide access keys or select assume role check box in asset configuration" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4c594fc --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,8 @@ +[tool.black] +line-length = 145 +target-version = ['py39'] +verbose = true + +[tool.isort] +line_length = 145 +profile = "black" diff --git a/release_notes/1.2.11.md b/release_notes/1.2.11.md new file mode 100644 index 0000000..e9e1e94 --- /dev/null +++ b/release_notes/1.2.11.md @@ -0,0 +1 @@ +* Updated dependencies to resolve security vulnerabilities [PSAAS-20398] \ No newline at end of file diff --git a/tox.ini b/tox.ini index c4644ad..720a141 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,4 @@ [flake8] max-line-length = 145 max-complexity = 28 -extend-ignore = F403,E128,E126,E111,E121,E127,E731,E201,E202,F405,E722,D,W292 - -[isort] -line_length = 145 +extend-ignore = F403,E128,E126,E121,E127,E731,E201,E202,E203,E701,F405,E722,D,W503 diff --git a/wheels/shared/python_dateutil-2.8.2-py2.py3-none-any.whl b/wheels/shared/python_dateutil-2.8.2-py2.py3-none-any.whl deleted file mode 100644 index 8ffb923..0000000 Binary files a/wheels/shared/python_dateutil-2.8.2-py2.py3-none-any.whl and /dev/null differ diff --git a/wheels/shared/six-1.16.0-py2.py3-none-any.whl b/wheels/shared/six-1.16.0-py2.py3-none-any.whl deleted file mode 100644 index fd94265..0000000 Binary files a/wheels/shared/six-1.16.0-py2.py3-none-any.whl and /dev/null differ diff --git a/wheels/shared/urllib3-1.26.17-py2.py3-none-any.whl b/wheels/shared/urllib3-1.26.17-py2.py3-none-any.whl deleted file mode 100644 index 4486a67..0000000 Binary files a/wheels/shared/urllib3-1.26.17-py2.py3-none-any.whl and /dev/null differ