diff --git a/README.md b/README.md index 61d3383..9078174 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ HTTPS) on your Phantom host(s) in order to function. **Authentication is carried out in following priority order** 1. Basic Auth (username and password) -1. OAuth (oauth token url, client id and client secret) -1. Provided Auth token (auth_token_name, auth_token) +3. OAuth (oauth token url, client id and client secret) +4. Provided Auth token (auth_token_name, auth_token) ### Configuration variables @@ -31,6 +31,8 @@ VARIABLE | REQUIRED | TYPE | DESCRIPTION **auth_token** | optional | password | Value of authentication token | **username** | optional | string | Username (for HTTP basic auth) | **password** | optional | password | Password (for HTTP basic auth) | +**oauth_username** | optional | string | Username (for Oauth password grants) | +**oauth_password** | optional | password | Password (for Oauth password grants) | **oauth_token_url** | optional | string | URL to fetch oauth token from | **client_id** | optional | string | Client ID (for OAuth) | **client_secret** | optional | password | Client Secret (for OAuth) | diff --git a/http.json b/http.json index 7438ea0..293a40c 100644 --- a/http.json +++ b/http.json @@ -58,34 +58,44 @@ "order": 5, "description": "Password (for HTTP basic auth)" }, - "oauth_token_url": { + "oauth_username": { "data_type": "string", "order": 6, + "description": "Username (for OAuth password grants)" + }, + "oauth_password": { + "data_type": "password", + "order": 7, + "description": "Password (for OAuth password grants)" + }, + "oauth_token_url": { + "data_type": "string", + "order": 8, "description": "URL to fetch oauth token from" }, "placeholder": { "data_type": "ph", - "order": 7, + "order": 9, "description": "" }, "client_id": { "data_type": "string", - "order": 8, + "order": 10, "description": "Client ID (for OAuth)" }, "client_secret": { "data_type": "password", - "order": 9, + "order": 11, "description": "Client Secret (for OAuth)" }, "timeout": { "data_type": "numeric", - "order": 10, + "order": 12, "description": "Timeout for HTTP calls" }, "test_http_method": { "data_type": "string", - "order": 11, + "order": 13, "description": "HTTP Method for Test Connectivity", "default": "GET", "value_list": [ diff --git a/http_connector.py b/http_connector.py index a8a4ed2..9cc4745 100644 --- a/http_connector.py +++ b/http_connector.py @@ -64,6 +64,9 @@ def __init__(self): self._token = None self._username = None self._password = None + self._oauth_username = None + self._oauth_password = None + self._oauth_password_grant = False self._oauth_token_url = None self._client_id = None self._client_secret = None @@ -155,9 +158,23 @@ def initialize(self): self._password = config.get("password", "") self._test_http_method = config.get("test_http_method", "get").lower() + # if oauth password AND oauth username have been set we use the oauth password granttype + self._oauth_password = config.get("oauth_password") + self._oauth_username = config.get("oauth_username") + + # make sure both are set together + if bool(self._oauth_password) != bool(self._oauth_username): + return self.set_status( + phantom.APP_ERROR, + "Both oauth_username and oauth_password must be provided together" + ) + + self._oauth_password_grant = bool(self._oauth_username and self._oauth_password) + self._oauth_token_url = config.get("oauth_token_url") if self._oauth_token_url: self._oauth_token_url = self._oauth_token_url.strip("/") + self._client_id = config.get("client_id") self._client_secret = config.get("client_secret") self._access_token = self._state.get(HTTP_JSON_ACCESS_TOKEN) @@ -409,7 +426,7 @@ def _make_http_call( if access_token and r.status_code == 401 and self.access_token_retry: self.save_progress(f"Got error: {r.status_code}") self._access_token = None - self._state.pop("access_token") + self._state.pop(HTTP_JSON_ACCESS_TOKEN, None) self.access_token_retry = False # make it to false to avoid getting access token after one time (prevents recursive loop) return self._make_http_call( action_result, @@ -501,20 +518,39 @@ def _generate_api_token(self, action_result, new_token=False): self.save_progress("Using old token") return self._access_token - payload = {"grant_type": "client_credentials"} + if self._oauth_password_grant: + self.save_progress("Using password grant") + payload = { + "grant_type": "password", + "username": self._oauth_username, + "password": self._oauth_password, + } + else: + self.save_progress("Using client credentials") + payload = {"grant_type": "client_credentials"} self.save_progress("Fetching new token") + # Querying endpoint to generate token - response = requests.post( - self._oauth_token_url, - auth=HTTPBasicAuth(self._client_id, self._client_secret), # nosemgrep - data=payload, - timeout=DEFAULT_REQUEST_TIMEOUT, - ) + try: + response = requests.post( + self._oauth_token_url, + auth=HTTPBasicAuth(self._client_id, self._client_secret), # nosemgrep + data=payload, + timeout=DEFAULT_REQUEST_TIMEOUT, + ) + except Exception as e: + error_message = self._get_error_message_from_exception(e) + action_result.set_status( + phantom.APP_ERROR, + f"Error connecting to token endpoint {self._oauth_token_url}. Details: {error_message}", + ) + return None + if response.status_code not in [200, 201]: action_result.set_status( phantom.APP_ERROR, - f"Error fetching token from {self._oauth_token_url}. Server returned {response.status_code}", + f"Error fetching token from {self._oauth_token_url}. Server returned {response.status_code} with body {response.text}", ) return None diff --git a/manual_readme_content.md b/manual_readme_content.md index c70b8a2..b5d7b1c 100644 --- a/manual_readme_content.md +++ b/manual_readme_content.md @@ -6,5 +6,8 @@ HTTPS) on your Phantom host(s) in order to function. **Authentication is carried out in following priority order** 1. Basic Auth (username and password) +1. OAuth Password grants (username, password, oauth token url, client id and client secret) 1. OAuth (oauth token url, client id and client secret) 1. Provided Auth token (auth_token_name, auth_token) + +Basic auth is configured using `username`/`password` fields. For Oauth password grants both the `oauth_username` and `oauth_password` fields must be configured.