Details
| ID | DropboxEventsCollector |
|---|---|
| Provider | Dropbox |
| Category | Analytics & SIEM |
| From Version | 6.8.0 |
| Docker Image | demisto/py3-tools:1.0.0.10120494 |
| Supported Modules | Agentix XSIAM |
README
Collect events from Dropbox’s logs.
This integration was integrated and tested with version 2 of Dropbox API
Configure Dropbox Event Collector on Cortex XSIAM
- Navigate to Settings > Configurations > Data Collection > Automation and Feed Integrations.
- Search for Dropbox Event Collector.
-
Click Add instance to create and configure a new integration instance.
Parameter Description Required Server URL The endpoint from which to get the logs. True App Key The App key (created in the Dropbox app console). True App Secret The App secret (created in the Dropbox app console). True First fetch in timestamp format First fetch in timestamp format (<number> <time unit>, e.g., 12 hours, 7 days) False The maximum number of events per fetch False Trust any certificate (not secure) False Use system proxy settings False - Run the !dropbox-auth-start command to test the connection and the authorization process.
Commands
You can execute these commands from the Cortex XSIAM War Room, 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.
dropbox-auth-start
Run this command to start the authorization process and follow the instructions in the command results. This command generates a link. By clicking the link, you get a code for the dropbox-auth-complete command.
Base Command
dropbox-auth-start
Input
There are no input arguments for this command.
Context Output
There is no context output for this command.
dropbox-auth-complete
Run this command to complete the authorization process. Should be used after running the dropbox-auth-start command.
Base Command
dropbox-auth-complete
Input
| Argument Name | Description | Required |
|---|---|---|
| code | The code that returns from Dropbox. | Required |
Context Output
There is no context output for this command.
dropbox-auth-test
Run this command to test the connectivity to Dropbox.
Note: Use this command instead of the Test button in the UI.
Base Command
dropbox-auth-test
Input
There are no input arguments for this command.
Context Output
There is no context output for this command.
dropbox-auth-reset
Resets the authentication.
Base Command
dropbox-auth-reset
Input
There are no input arguments for this command.
Context Output
There is no context output for this command.
dropbox-get-events
Get events.
Base Command
dropbox-get-events
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The maximum events to fetch. Default is 500. | Optional |
| should_push_events | Set this argument to true to create events, otherwise the command will only display them. Possible values are: true, false. Default is false. | Required |
| from | Fetch events from this time (<number> <time unit>, e.g., 12 hours, 7 days). Default is 3 days. | Optional |
Context Output
There is no context output for this command.
Command example
!dropbox-get-events should_push_events='false' limit=3
Human Readable Output
Dropbox logs
Actor Context Details Event _ Category Event _ Type Involve Non Team _ Member Origin Timestamp .tag: admin
admin: {“.tag”: “team_member”, “account_id”: “123456”, “display_name”: “John Smith”, “email”: “JohnSmith@example.com”, “team_member_id”: “111111”}.tag: team_member
account_id: 123456
display_name: John Smith
email: JohnSmith@example.com
team_member_id: 111111.tag: member_change_status_details
previous_value: {“.tag”: “not_joined”}
new_value: {“.tag”: “active”}
action: {“.tag”: “team_join_details”, “linked_apps”: [], “linked_devices”: [], “linked_shared_folders”: [], “has_linked_apps”: false, “has_linked_devices”: true, “has_linked_shared_folders”: false}.tag: members .tag: member_change_status
description: Changed member status (invited, joined, suspended, etc.)false geo_location: {“city”: “Tel Aviv”, “region”: “Tel Aviv”, “country”: “IL”, “ip_address”: “1.1.1.1”}
access_method: {“.tag”: “end_user”, “end_user”: {“.tag”: “web”, “session_id”: “222222”}}2022-05-16T11:34:29Z .tag: admin
admin: {“.tag”: “team_member”, “account_id”: “123456”, “display_name”: “John Smith”, “email”: “JohnSmith@example.com”, “team_member_id”: “111111”}.tag: team_member
account_id: 123456
display_name: John Smith
email: JohnSmith@example.com
team_member_id: 111111.tag: member_change_admin_role_details
new_value: {“.tag”: “team_admin”}
previous_value: {“.tag”: “member_only”}.tag: members .tag: member_change_admin_role
description: Changed team member admin rolefalse geo_location: {“city”: “Tel Aviv”, “region”: “Tel Aviv”, “country”: “IL”, “ip_address”: “1.1.1.1”}
access_method: {“.tag”: “end_user”, “end_user”: {“.tag”: “web”, “session_id”: “222222”}}2022-05-16T11:34:29Z .tag: admin
admin: {“.tag”: “team_member”, “account_id”: “123456”, “display_name”: “John Smith”, “email”: “JohnSmith@example.com”, “team_member_id”: “111111”}.tag: team .tag: member_send_invite_policy_changed_details
new_value: {“.tag”: “everyone”}
previous_value: {“.tag”: “specific_members”}.tag: team_policies .tag: member_send_invite_policy_changed
description: Changed member send invite policy for teamfalse geo_location: {“city”: “Tel Aviv”, “region”: “Tel Aviv”, “country”: “IL”, “ip_address”: “1.1.1.1”}
access_method: {“.tag”: “end_user”, “end_user”: {“.tag”: “web”, “session_id”: “222222”}}2022-05-16T11:34:33Z
Configuration parameters
url— Server URL (required)credentials— App key (required)fetch_from— First fetch in timestamp format (<number> <time unit>, e.g., 12 hours, 7 days)limit— The maximum number of events per fetch.insecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (5)
-
dropbox-auth-completeCompletes the authentication.
-
dropbox-auth-resetResets the authentication.
-
dropbox-auth-startStarts the authentication.
-
dropbox-auth-testTests the authentication.
-
dropbox-get-eventsGet events.
# pylint: disable=no-name-in-module # pylint: disable=no-self-argument import json import urllib3 from pydantic import parse_obj_as from SiemApiModule import * # noqa: E402 urllib3.disable_warnings() DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ" VENDOR = "dropbox" PRODUCT = "dropbox" class DropboxEventsRequestConfig(IntegrationHTTPRequest): # Endpoint: https://api.dropbox.com/2/team_log/get_events url: AnyUrl = parse_obj_as(AnyUrl, "https://api.dropbox.com") method: Method = Method.POST headers: dict = {"Content-Type": "application/json"} data: str verify: bool = not demisto.params().get("insecure") class DropboxEventsClient(IntegrationEventsClient): request: DropboxEventsRequestConfig options: IntegrationOptions credentials: Credentials def __init__( self, request: DropboxEventsRequestConfig, options: IntegrationOptions, credentials: Credentials, session: Optional[requests.Session] = None, ) -> None: self.credentials = credentials self.refresh_token = demisto.getIntegrationContext().get("refresh_token") if session is None: session = requests.Session() super().__init__(request, options, session) def set_request_filter(self, cursor: str): if "continue" not in str(self.request.url): demisto.info("continue not in request url") self.request.url = parse_obj_as(AnyUrl, f'{str(self.request.url).removesuffix("/")}/continue') self.request.data = json.dumps({"cursor": cursor}) def get_access_token(self): request = IntegrationHTTPRequest( method=Method.POST, url=f'{str(self.request.url).removesuffix("/")}/oauth2/token', # type: ignore[arg-type] data={"grant_type": "refresh_token", "refresh_token": f"{self.refresh_token}"}, auth=HTTPBasicAuth(self.credentials.identifier, self.credentials.password), # type: ignore[arg-type] verify=self.request.verify, ) response = self.call(request) demisto.debug(f"Send request to obtain access_token get status code: {response.status_code}") # pragma: no cover self.request.headers["Authorization"] = f'Bearer {response.json()["access_token"]}' self.request.url = parse_obj_as(AnyUrl, f'{str(self.request.url).removesuffix("/")}/2/team_log/get_events') class DropboxEventsGetter(IntegrationGetEvents): client: DropboxEventsClient def get_last_run(self: Any, event: dict) -> dict: # type: ignore last_datetime = datetime.strptime(event.get("timestamp", ""), DATETIME_FORMAT) + timedelta(seconds=1) return {"start_time": datetime.strftime(last_datetime, DATETIME_FORMAT)} def _iter_events(self): self.client.get_access_token() # region First Call results = self.client.call(self.client.request).json() # endregion # region Yield Response while results.get("events"): # Run as long there are logs yield sorted(results.get("events", []), key=lambda d: d.get("timestamp")) if results.get("has_more"): self.client.set_request_filter(results.get("cursor")) demisto.debug( f'Setting the next request filter {results.get("cursor")}' # pragma: no cover ) results = self.client.call(self.client.request).json() else: break # ----------------------------------------- Authentication Functions ----------------------------------------- def start_auth_command(base_url: str, app_key: str) -> CommandResults: # pragma: no cover url = f"https://www.dropbox.com/oauth2/authorize?client_id={app_key}&token_access_type=offline&response_type=code" message = f"""### Authorization instructions 1. To sign in, use a web browser to open the page [{url}]({url}) 2. Run the **!dropbox-auth-complete** command with the code returned from Dropbox in the War Room.""" demisto.debug("start auth command") return CommandResults(readable_output=message) def complete_auth_command(code: str, credentials: Credentials, base_url: str, insecure: bool) -> CommandResults: data = { "grant_type": "authorization_code", "code": code, } auth = (credentials.identifier or "", credentials.password) redable_output = "" response = requests.post(f"{base_url}/oauth2/token", data=data, auth=auth, verify=insecure) if response.ok: demisto.setIntegrationContext({"refresh_token": response.json()["refresh_token"]}) readable_output = "✅ Authorization completed successfully." else: readable_output = f"❌ Authorization completed failed. {response.text}" demisto.debug(f"Complete auth command {readable_output=}") # pragma: no cover return CommandResults(readable_output=redable_output) def reset_auth_command() -> CommandResults: demisto.debug("resetting integration context to empty dict.") # pragma: no cover set_integration_context({}) message = "Authorization was reset successfully. Run **!dropbox-auth-start** to start the authentication process." return CommandResults(readable_output=message) def test_connection(events_client: DropboxEventsGetter) -> str: events_client.run() return "✅ Success." # ----------------------------------------- Main Functions ----------------------------------------- def main(command: str, demisto_params: dict): first_fetch = datetime.strftime( dateparser.parse(demisto_params.get("fetch_from", "")) or datetime.now() - timedelta(days=7), DATETIME_FORMAT ) start_time = demisto_params.get("start_time", first_fetch) request = DropboxEventsRequestConfig(data=json.dumps({"time": {"start_time": start_time}}), **demisto_params) credentials = Credentials(**demisto_params.get("credentials", {})) options = IntegrationOptions(**demisto_params) client = DropboxEventsClient(request, options, credentials) get_events = DropboxEventsGetter(client, options) try: base_url = str(demisto_params.get("url")).removesuffix("/") insecure = not demisto_params.get("insecure") if command == "test-module": raise DemistoException("Please run the !dropbox-auth-test command in order to test the connection") # ----- Authentication Commands ----- # elif command == "dropbox-auth-start": return_results(start_auth_command(base_url, str(credentials.identifier))) elif command == "dropbox-auth-complete": return_results(complete_auth_command(str(demisto_params.get("code")), credentials, base_url, insecure)) elif not demisto.getIntegrationContext().get("refresh_token"): demisto.debug("Integration getIntegrationContext.get(refresh_token) is empty run auth start.") # pragma: no cover return_results(CommandResults(readable_output="Please run the **!dropbox-auth-start** command first")) elif command == "dropbox-auth-reset": return_results(reset_auth_command()) elif command == "dropbox-auth-test": results = test_connection(get_events) return_results(CommandResults(readable_output=results)) # ----- Fetch/Get events command ----- # elif command in ("fetch-events", "dropbox-get-events"): events = get_events.run() if command == "fetch-events" or argToBoolean(demisto_params.get("should_push_events")): # Add _time field to each event before sending to XSIAM for event in events: event["_time"] = event.get("timestamp") send_events_to_xsiam(events, vendor=VENDOR, product=PRODUCT) if events: last_run = get_events.get_last_run(events[-1]) demisto.debug(f"Set last run to {last_run}") # pragma: no cover. demisto.setLastRun(last_run) if command == "dropbox-get-events": command_results = CommandResults( readable_output=tableToMarkdown("Dropbox logs", events, removeNull=True, headerTransform=pascalToSpace), raw_response=events, ) return_results(command_results) except Exception as e: return_error(f"An error was returned from dropbox event collector while executing {command} command. error: {e!s}") if __name__ in ("__main__", "__builtin__", "builtins"): # Args is always stronger. Get getLastRun even stronger demisto_params_ = demisto.params() | demisto.args() | demisto.getLastRun() main(demisto.command(), demisto_params_)