GoogleCalendar
Google Calendar is a time-management and scheduling calendar service developed by Google. This integration helps you to perform various tasks on the access control list (ACL).
IT Services · Google Calendar
Details
| ID | GoogleCalendar |
|---|---|
| Provider | |
| Category | IT Services |
| From Version | 5.0.0 |
| Docker Image | demisto/googleapi-python3:1.0.0.10182333 |
| Supported Modules | Agentix XSIAM |
README
Google Calendar is a time-management and scheduling calendar service developed by Google. This integration helps you to perform various tasks on the access control list (ACL). This integration was integrated and tested with G Suite Basic edition.
Configure Service Account for Google Calendar
-
Select or create a project:

-
Enable the Google Calendar API:
-
Under the main menu, select APIs & Services > Libary:

-
Enable Google Calendar API:

-
Select the project and click OPEN:

-
-
Create a service account with the correct restricted permissions:
-
Under the main menu, select IAM & Admin > Service Accounts:

-
In the top bar, select CREATE SERVICE ACCOUNT:

-
Under the main menu, select IAM & Admin > Service Accounts and open the account you just created.
-
Generate new credentials:
-
On the Service account details page, under Keys, click ADD KEY and select Create new key:

-
Under Key type, select JSON, and click CREATE. Save the credentials in a secure location. You will need the generated
credentials.jsonfile when you configure the instance in Cortex XSOAR:

-
-
Add Scopes in G Suite Admin
-
Go to https://admin.google.com
-
Click Menu and select Security > API Controls:

-
Under the Domain wide delegation tab, click MANAGE DOMAIN WIDE DELEGATION:

-
Click Add new and enter the Client ID from your credentials.json file and required scopes from the integration tips.

-
Click AUTHORIZE.
Configure Google Calendar in Cortex
| Parameter | Description | Required |
|---|---|---|
| user_service_account_json | User’s Service Account JSON | True |
| insecure | Trust any certificate (not secure) | False |
| proxy | Use system proxy settings | False |
google-calendar-acl-add
Creates an access control rule.
Base Command
google-calendar-acl-add
Input
| Argument Name | Description | Required |
|---|---|---|
| calendar_id | Identifier of the calendar. If you want to access the primary calendar of the currently logged in user, use the “primary” keyword. | Required |
| user_id | The user’s primary email address. | Optional |
| role | The role assigned to the scope. Available Options: “none” - Provides no access. “freeBusyReader” - Provides read access to free/busy information. “reader” - Provides read access to the calendar. Private events will appear to users with reader access, but event details will be hidden. “writer” - Provides read and write access to the calendar. Private events will appear to users with writer access, and event details will be visible. “owner” - Provides ownership of the calendar. This role has all of the permissions of the writer role with the additional ability to see and manipulate ACLs. |
Required |
| scope_type | The type of the scope. Available Options: “default” - The public scope. This is the default value. “user” - Limits the scope to a single user. “group” - Limits the scope to a group. “domain” - Limits the scope to a domain. Note: The permissions granted to the “default”, or public scope, apply to any user, authenticated or not. |
Required |
| scope_value | The email address of a user or group, or the name of a domain, depending on the scope type. Omitted for type “default”. | Optional |
| send_notifications | Whether to send notifications about the calendar sharing change. Default is “true”. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GoogleCalendar.Acl.calendarId | String | Calendar identifier. |
| GoogleCalendar.Acl.userId | String | User’s email address. |
| GoogleCalendar.Acl.id | String | Identifier of the ACL rule. |
| GoogleCalendar.Acl.kind | String | Type of the resource. |
| GoogleCalendar.Acl.etag | String | ETag of the resource. |
| GoogleCalendar.Acl.scopeType | String | The type of the scope. |
| GoogleCalendar.Acl.scopeValue | String | The email address of a user or group, or the name of a domain, depending on the scope type. |
| GoogleCalendar.Acl.role | String | The role assigned to the scope. |
Command Example
!google-calendar-acl-add calendar_id=calenderId role=freeBusyReader scope_type=user scope_value=useracl@domain.com user_id=user1@domain.com
Context Example
{
"GoogleCalendar": {
"Acl": {
"calendarId": "calenderId",
"userId": "user1@domain.com"
"etag": "\"00001600760672577000\"",
"id": "user:useracl@domain.com",
"kind": "calendar#aclRule",
"role": "freeBusyReader",
"scopeType": "user",
"scopeValue": "useracl@domain.com"
}
}
}
Human Readable Output
Giving an access control rule for calendar id “calenderId”
Id Role Scope Type Scope Value user:useracl@domain.com freeBusyReader user useracl@domain.com
google-calendar-acl-list
Returns the rules in the access control list for the calendar.
Base Command
google-calendar-acl-list
Input
| Argument Name | Description | Required |
|---|---|---|
| calendar_id | Calendar identifier. If you want to access the primary calendar of the currently logged in user, use the “primary” keyword. | Required |
| user_id | The user’s primary email address. | Optional |
| max_results | Maximum number of entries returned on a result page. Default is 100. The page size cannot be greater than 250 entries. | Optional |
| page_token | Token specifying which result page to return. | Optional |
| show_deleted | Whether to include deleted ACLs in the result. Deleted ACLs are represented by role “none”. Deleted ACLs will always be included if syncToken is provided. Default is “false”. | Optional |
| sync_token | Token obtained from the nextSyncToken field returned on the last page of results from the previous list request. The result of this list request contains only entries that have changed since then. All entries deleted since the previous list request will always be in the result set and it is not allowed to set showDeleted to false. If the syncToken expires, the server will respond with a 410 GONE response code and the client should clear its storage and perform a full synchronization without any syncToken. |
Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| GoogleCalendar.Acl.calendarId | String | Calendar identifier. |
| GoogleCalendar.Acl.userId | String | User’s email address. |
| GoogleCalendar.Acl.id | String | Identifier of the ACL rule. |
| GoogleCalendar.Acl.kind | String | Type of the resource. |
| GoogleCalendar.Acl.etag | String | ETag of the resource. |
| GoogleCalendar.Acl.scopeType | String | The type of the scope. |
| GoogleCalendar.Acl.scopeValue | String | The email address of a user or group, or the name of a domain, depending on the scope type. |
| GoogleCalendar.Acl.role | String | The role assigned to the scope. |
| GoogleCalendar.PageToken.Acl.calendarId | String | Calendar identifier. |
| GoogleCalendar.PageToken.Acl.userId | String | User’s email address. |
| GoogleCalendar.PageToken.Acl.nextPageToken | String | Token used to access the next page of this result. |
| GoogleCalendar.PageToken.Acl.nextSyncToken | String | Token used at a later point in time to retrieve only the entries that have changed since this result was returned. |
Command Example
!google-calendar-acl-list calendar_id=calenderID user_id=user1@domain.com max_results=2
Context Example
{
"GoogleCalendar": {
"Acl": [
{
"calendarId": "calenderID",
"userId": "user1@domain.com",
"etag": "\"00000000000000000000\"",
"id": "user:user1@domain.com",
"kind": "calendar#aclRule",
"role": "owner",
"scopeType": "user",
"scopeValue": "user1@domain.com"
},
{
"calendarId": "calenderID",
"userId": "user1@domain.com",
"etag": "\"00001598621012848000\"",
"id": "user:user2@domain.com",
"kind": "calendar#aclRule",
"role": "reader",
"scopeType": "user",
"scopeValue": "user2@domain.com"
}
],
"PageToken": {
"Acl": {
"calendarId": "calenderID",
"userId": "user1@domain.com"
"nextPageToken": "EKiDnZGM_OsCGAAgADIkCgwI1Iqk-gUQgOitlAMSFCoSeHh4eEBuaW1ibGVkYXRhLmlv"
}
}
}
}
Human Readable Output
Next Page Token: EKiDnZGM_OsCGAAgADIkCgwI1Iqk-gUQgOitlAMSFCoSeHh4eEBuaW1ibGVkYXRhLmlv
Total Retrieved ACL: 2
Id Role Scope Type Scope Value user:user1@domain.com owner user user1@domain.com user:user2@domain.com reader user user2@domain.com
Configuration parameters
user_service_account_json— User's Service Account JSONuser_service_account_json_creds—insecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (2)
-
google-calendar-acl-addCreates an access control rule.
-
google-calendar-acl-listReturns the rules in the access control list for the calendar.
from CommonServerPython import * """ IMPORTS """ import urllib.parse from collections.abc import Callable from typing import Any import urllib3 # Disable insecure warnings urllib3.disable_warnings() """ CONSTANTS """ MESSAGES: dict[str, str] = { "TEST_FAILED_ERROR": "Test connectivity failed. Check the configuration parameters provided.", "BOOLEAN_ERROR": "The argument {} must be either true or false.", } HR_MESSAGES: dict[str, str] = { "ACL_ADD_SUCCESS": 'Giving an access control rule for calendar id "{}".', "LIST_COMMAND_SUCCESS": "Total Retrieved {}: {}", } URL_SUFFIX: dict[str, str] = {"TEST_MODULE": "calendar/v3/users/me/calendarList", "CALENDAR_ACL": "calendar/v3/calendars/{}/acl"} SCOPES: dict[str, list[str]] = { "TEST_MODULE": ["https://www.googleapis.com/auth/userinfo.email"], "CALENDAR": ["https://www.googleapis.com/auth/calendar"], } OUTPUT_PREFIX: dict[str, str] = { "ADD_ACL": "GoogleCalendar.Acl", "LIST_ACL": "GoogleCalendar.Acl(val.id == obj.id && val.calendarId == obj.calendarId && val.userId == obj.userId)", "LIST_ACL_PAGE_TOKEN": "GoogleCalendar.PageToken.Acl(val.calendarId == obj.calendarId && val.userId == obj.userId)", } NEXT_PAGE_TOKEN: str = "### Next Page Token: {}\n" def prepare_acl_list_output( acl_records: dict[str, Any], calendar_id: str, user_id: str ) -> tuple[dict[str, list[dict[str, str | Any]] | dict[str, str | Any]], list[dict]]: """ Prepares context output and human readable for gsuite-acl-list command. :param acl_records: Dict containing acl records. :param calendar_id: Calendar id. :param user_id: User id. :return: Tuple of prepared context output list and human readable. """ acl_context = [ { "calendarId": calendar_id, "userId": user_id, "kind": record.get("kind", ""), "etag": record.get("etag", ""), "id": record.get("id", ""), "scopeType": record.get("scope", {}).get("type", ""), "scopeValue": record.get("scope", {}).get("value", ""), "role": record.get("role", ""), } for record in acl_records.get("items", []) ] page_context = { "calendarId": calendar_id, "userId": user_id, "nextPageToken": acl_records.get("nextPageToken", ""), "nextSyncToken": acl_records.get("nextSyncToken", ""), } outputs = {OUTPUT_PREFIX["LIST_ACL"]: acl_context, OUTPUT_PREFIX["LIST_ACL_PAGE_TOKEN"]: page_context} outputs = GSuiteClient.remove_empty_entities(outputs) acl_hr = acl_context acl_hr_list = [ {acl_key: acl_value for acl_key, acl_value in acl.items() if acl_key not in ["kind", "etag", "calendarId", "userId"]} for acl in acl_hr ] acl_hr_list = GSuiteClient.remove_empty_entities(acl_hr_list) return outputs, acl_hr_list def prepare_output_acl_add( acl_records: dict[str, Any], calendar_id: str, user_id: str ) -> tuple[dict[str, Any], list[dict[str, Any]]]: """ Prepares context output and human readable for gsuite-user-to-acl-add command. :param acl_records: List containing dictionaries of ACL records. :param calendar_id: Calendar id. :param user_id: User id. :return: prepared context output list. """ acl_id = acl_records.get("id", "") acl_scope_type = acl_records.get("scope", {}).get("type", "") acl_scope_value = acl_records.get("scope", {}).get("value", "") acl_role = acl_records.get("role", "") acl_add_output = { "calendarId": calendar_id, "userId": user_id, "kind": acl_records.get("kind", ""), "etag": acl_records.get("etag", ""), "id": acl_id, "scopeType": acl_scope_type, "scopeValue": acl_scope_value, "role": acl_role, } acl_add_output = GSuiteClient.remove_empty_entities(acl_add_output) acl_add_hr = {"id": acl_id, "scopeType": acl_scope_type, "scopeValue": acl_scope_value, "role": acl_role} acl_add_hr = GSuiteClient.remove_empty_entities(acl_add_hr) return acl_add_hr, acl_add_output def prepare_body_gsuite_acl_add(args: dict[str, str]) -> dict[str, Any]: """ To prepare params for acl_add_command. :param args: Command arguments. :return: Dict of body. """ return GSuiteClient.remove_empty_entities( {"role": args.get("role"), "scope": {"type": args.get("scope_type"), "value": args.get("scope_value")}} ) def prepare_params_for_acl_list(args: dict[str, str]) -> dict[str, str | int]: """ To prepare params for gsuite_acl_list. :param args: Command arguments. :return: Dict of arguments. """ max_result = args.get("max_results", 100) GSuiteClient.validate_set_boolean_arg( args, "show_deleted", ) return GSuiteClient.remove_empty_entities( { "maxResults": max_result, "pageToken": args.get("page_token", ""), "showDeleted": args.get("show_deleted", "false"), "syncToken": args.get("sync_token", ""), } ) """ COMMAND FUNCTIONS """ @logger def test_module(gsuite_client) -> str: """ Performs test connectivity by valid http response :param gsuite_client: client object which is used to get response from api. :return: raise ValueError if any error occurred during connection :raises DemistoException: If there is any other issues while making the http call. """ with GSuiteClient.http_exception_handler(): gsuite_client.set_authorized_http(scopes=SCOPES["CALENDAR"]) gsuite_client.http_request(url_suffix=URL_SUFFIX["TEST_MODULE"], method="GET") return "ok" @logger def acl_add_command(client, args: dict[str, Any]) -> CommandResults: """ Creates an access control rule. :param client: client object which is used to get response from api :param args: command arguments. :return: CommandResults object with context and human-readable. """ calendar_id = args.get("calendar_id", "") calendar_id = urllib.parse.quote(calendar_id) # type: ignore user_id = args.get("user_id", "") body = prepare_body_gsuite_acl_add(args) send_notifications = args.get("send_notifications", "true").lower() if send_notifications not in ["true", "false"]: raise ValueError(MESSAGES["BOOLEAN_ERROR"].format("send_notifications")) client.set_authorized_http(scopes=SCOPES["CALENDAR"], subject=user_id) response = client.http_request( url_suffix=URL_SUFFIX["CALENDAR_ACL"].format(calendar_id), body=body, method="POST", params={"sendNotifications": send_notifications}, ) acl_add_hr, acl_add_output = prepare_output_acl_add(response, args.get("calendar_id", ""), user_id) readable_output = tableToMarkdown( HR_MESSAGES["ACL_ADD_SUCCESS"].format(args.get("calendar_id"), acl_add_hr.get("scopeValue", "")), acl_add_hr, headerTransform=pascalToSpace, removeNull=True, ) return CommandResults( outputs_prefix=OUTPUT_PREFIX["ADD_ACL"], outputs_key_field=["calendarId", "id", "userId"], outputs=acl_add_output, readable_output=readable_output, raw_response=response, ) @logger def acl_list_command(client, args: dict[str, Any]) -> CommandResults: """ Shows the access control lists for the given calendar id. The ACL list will show who has access to the calendar and what level of access they have. :param client: client object which is used to get response from api :param args: command arguments. :return: CommandResults object with context and human-readable. """ user_id = args.get("user_id", "") calendar_id = urllib.parse.quote(args.get("calendar_id", "")) # type: ignore params = prepare_params_for_acl_list(args) client.set_authorized_http(scopes=SCOPES["CALENDAR"], subject=user_id) response = client.http_request(url_suffix=URL_SUFFIX["CALENDAR_ACL"].format(calendar_id), method="GET", params=params) outputs, acl_hr_list = prepare_acl_list_output(response, args.get("calendar_id", ""), user_id) readable_hr = "" if response.get("nextPageToken"): readable_hr += NEXT_PAGE_TOKEN.format(response.get("nextPageToken")) if response.get("nextSyncToken"): readable_hr += "### Next Sync Token: {}\n".format(response.get("nextSyncToken")) readable_hr += tableToMarkdown( HR_MESSAGES["LIST_COMMAND_SUCCESS"].format("ACL", len(acl_hr_list)), acl_hr_list, headerTransform=pascalToSpace, removeNull=True, ) return CommandResults(outputs=outputs, readable_output=readable_hr, raw_response=response) def main() -> None: """ PARSE AND VALIDATE INTEGRATION PARAMS """ # Commands dictionary commands: dict[str, Callable] = { "google-calendar-acl-add": acl_add_command, "google-calendar-acl-list": acl_list_command, } command = demisto.command() demisto.info(f"Command being called is {command}") try: params = demisto.params() service_account_dict = GSuiteClient.safe_load_non_strict_json( params.get("user_service_account_json_creds", {}).get("password") or params.get("user_service_account_json") ) verify_certificate = not params.get("insecure", False) proxy = params.get("proxy", False) headers = {"Content-Type": "application/json"} # prepare client class object gsuite_client = GSuiteClient( service_account_dict, base_url="https://www.googleapis.com/", verify=verify_certificate, proxy=proxy, headers=headers ) # Trim the arguments args = GSuiteClient.strip_dict(demisto.args()) # This is the call made when pressing the integration Test button. if demisto.command() == "test-module": result = test_module(gsuite_client) demisto.results(result) elif command in commands: return_results(commands[command](gsuite_client, args)) # Log exceptions except Exception as e: return_error(f"Error: {e!s}") from GSuiteApiModule import * # noqa: E402 if __name__ in ("__main__", "__builtin__", "builtins"): main()