diff --git a/.github/workflows/generate-doc.yml b/.github/workflows/generate-doc.yml new file mode 100644 index 0000000..9284f9d --- /dev/null +++ b/.github/workflows/generate-doc.yml @@ -0,0 +1,20 @@ +name: Generate Readme Doc +on: + workflow_dispatch: + push: + paths: + - '*.json' + - 'readme.html' + - 'manual_readme_content.md' + tags-ignore: + - '**' + branches-ignore: + - next + - main +jobs: + generate-doc: + runs-on: ubuntu-latest + steps: + - uses: 'phantomcyber/dev-cicd-tools/github-actions/generate-doc@main' + with: + GITHUB_TOKEN: ${{ secrets.SOAR_APPS_TOKEN }} diff --git a/.github/workflows/review-release.yml b/.github/workflows/review-release.yml new file mode 100644 index 0000000..6f3bf31 --- /dev/null +++ b/.github/workflows/review-release.yml @@ -0,0 +1,22 @@ +name: Review Release +concurrency: + group: app-release + cancel-in-progress: true +permissions: + contents: read + id-token: write + statuses: write +on: + workflow_dispatch: + inputs: + task_token: + description: 'StepFunction task token' + required: true + +jobs: + review: + uses: 'phantomcyber/dev-cicd-tools/.github/workflows/review-release.yml@main' + with: + task_token: ${{ inputs.task_token }} + secrets: + resume_release_role_arn: ${{ secrets.RESUME_RELEASE_ROLE_ARN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c45d531..bc7e0a5 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.13 + rev: v1.16 hooks: - id: org-hook - id: package-app-dependencies - repo: https://github.com/Yelp/detect-secrets - rev: v1.2.0 + rev: v1.4.0 hooks: - id: detect-secrets args: ['--no-verify', '--exclude-files', '^microsoftteams.json$'] diff --git a/LICENSE b/LICENSE index f9b71ef..94b040f 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright (c) 2019-2022 Splunk Inc. + Copyright (c) 2019-2023 Splunk Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/NOTICE b/NOTICE index d82862f..960418f 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ Splunk SOAR Microsoft Teams -Copyright (c) 2019-2022 Splunk Inc. +Copyright (c) 2019-2023 Splunk Inc. Third-party Software Attributions: diff --git a/README.md b/README.md index 8832e33..eb82ee5 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,17 @@ # Microsoft Teams Publisher: Splunk -Connector Version: 2\.4\.0 +Connector Version: 2.5.0 Product Vendor: Microsoft Product Name: Teams -Product Version Supported (regex): "\.\*" -Minimum Product Version: 5\.2\.0 +Product Version Supported (regex): ".\*" +Minimum Product Version: 6.0.2 This app integrates with Microsoft Teams to support various generic and investigative actions [comment]: # " File: README.md" -[comment]: # " Copyright (c) 2019-2022 Splunk Inc." + +[comment]: # " Copyright (c) 2019-2023 Splunk Inc." [comment]: # "" [comment]: # "Licensed under the Apache License, Version 2.0 (the 'License');" [comment]: # "you may not use this file except in compliance with the License." @@ -46,24 +47,48 @@ This app requires creating an app in the Azure Active Directory. - Once the app is created, the below steps needs to be performed on the next page: - - - Under **Certificates & secrets** , select **New client secret** . Note this key somewhere secure, as it cannot be retrieved after closing the window. - Under **Authentication** , select **Add a platform** . In the **Add a platform** window, select **Web** . The **Redirect URLs** should be filled right here. We will get **Redirect - URLs** from the Phantom asset that we will create below in the section titled "Configure the - Microsoft Teams Phantom app asset". - - Under **API Permissions** , the following **Delegated Permissions** from **Microsoft Graph** + + URLs** from the Splunk SOAR asset that we will create below in the section titled "Configure the + Microsoft Teams Splunk SOAR app asset". + - Under **API Permissions** , the following minimum **Delegated Permissions** from **Microsoft Graph** needs to be added: - - Group.ReadWrite.All (https://graph.microsoft.com/Group.ReadWrite.All) - - offline_access (https://graph.microsoft.com/offline_access) - - User.ReadWrite.All (https://graph.microsoft.com/User.ReadWrite.All) - - Calendars.ReadWrite (https://graph.microsoft.com/Calendars.ReadWrite) - - OnlineMeetings.ReadWrite (https://graph.microsoft.com/OnlineMeetings.ReadWrite) + + + | Permission | Action | Description | Admin Consent Required + | :--------------- | :-------- | :------------ | :------------------- | + | offline_access | test connectivity | Allows the app to read and update user data, even when they are not currently using the app. This permission is required to generate the refresh_token, if offline_access is not provided then Test connectivity action will fail and no other action will work. | No + | User.ReadBasic.All | list users, get admin consent and test connectivity | Allows the app to read a basic set of profile properties of other users in your organization on behalf of the signed-in user. This includes display name, first and last name, email address, open extensions and photo. Also allows the app to read the full profile of the signed-in user | No + | OnlineMeetings.ReadWrite | create meeting | Allows an app to create, read online meetings on behalf of the signed-in user. | No + | Calendars.ReadWrite | create meeting (while add_calendar_event parameter is set to True) | Allows the app to create, read, update, and delete events in user calendars. | No + | Channel.ReadBasic.All | list channels | Read channel names and channel descriptions, on behalf of the signed-in user. | No + | ChannelMessage.Send | send message | Allows an app to send channel messages in Microsoft Teams, on behalf of the signed-in user. | No + | GroupMember.Read.All | list groups, list teams | Allows the app to list groups, read basic group properties and read membership of all groups the signed-in user has access to. | Yes + After making these changes, click **Add permissions** at the bottom of the screen, then - click **Grant admin consent for Phantom** . + click **Grant admin consent for ** . +## Method to revoke permission +- For revoking the permissions, please refer [this](https://learn.microsoft.com/en-gb/azure/active-directory/manage-apps/manage-application-permissions?pivots=ms-graph) documentation. + +- After removing the permissions from the Azure app, it might still be visible in the state file as those permissions aren’t fully revoked. + +- To verify the permissions are revoked or not, follow the below steps: + - Navigate to the https://portal.azure.com in a browser and log in with a Microsoft account + - Select **Azure Active Directory** from the left side menu + - From the left panel, select **Enterprise applications** + - Select the application used in the asset + - From the left hand side select **Permissions** + - In the **Permissions** page go to **user consent** + + - If any extra permissions are present in the user consent, then it should be removed. + - To remove the permissions visible in the **user consent** please refer [this](https://learn.microsoft.com/en-gb/azure/active-directory/manage-apps/manage-application-permissions?pivots=ms-graph) documentation. + + Note: Following the given steps will remove consent for all the permissions + ## State file permissions @@ -71,8 +96,8 @@ Please check the permissions for the state file as mentioned below. #### State file path -- For Non-NRI instance: /opt/phantom/local_data/app_states/\/\\_state.json -- For NRI instance: + +- For unprivileged instance: /\/local_data/app_states/\/\\_state.json #### State file permissions @@ -81,13 +106,19 @@ Please check the permissions for the state file as mentioned below. file) - File owner: Appropriate phantom user -## Configure the Microsoft Teams Phantom app asset + +## Configure the Microsoft Teams Splunk SOAR app asset + When creating an asset for the **Microsoft Teams** app, place the **Application Id** of the app in the **Client ID** field and place the password generated during the app creation process in the **Client Secret** field. Then, after filling out the **Tenant ID** field, click **SAVE** . Both the Application/Client ID and the Tenant ID can be found in the **Overview** tab on your app's Azure page. + + +The **Scope** configuration parameter's default value is the minimum required scopes. You can add/delete scopes as needed. The scopes added in this parameter should be consistent with those used to create the application on the Azure portal + After saving, a new field will appear in the **Asset Settings** tab. Take the URL found in the **POST incoming for Microsoft Teams to this location** field and place it in the **Redirect URLs** @@ -95,43 +126,52 @@ field mentioned in a previous step. To this URL, add **/result** . After doing s look something like: -https://\/rest/handler/microsoftteams_6ba1906f-5899-44df-bb65-1bee4df8ca3c/\/result + +https://\/rest/handler/microsoftteams_6ba1906f-5899-44df-bb65-1bee4df8ca3c/\/result Once again, click Save at the bottom of the screen. -Additionally, updating the Base URL in the Phantom Company Settings is also required. Navigate to -**Administration \> Company Settings \> Info** to configure the Base URL For Phantom Appliance. + +Additionally, updating the Base URL in the Company Settings is also required. Navigate to +**Administration \> Company Settings \> Info** to configure the Base URL For Splunk SOAR Appliance. Then, select **Save Changes.** ## Method to run get admin consent -Run **get_admin_consent** action. It will display an URL. Navigate to this URL in a separate browser +Run **get_admin_consent** action. It will display an URL in spawn.logs file. Navigate to this URL in a separate browser tab. This new tab will redirect to a Microsoft login page. Log in to a Microsoft account with administrator privileges. After logging in, review the requested permissions listed, then click **Accept** . Finally, close that tab. Action should show a success message. -**Note:** If the URL is not displayed while running the **get_admin_consent** action, the user can -get the URL from the following ways: - -- User can find the URL in 'spawn.log' file. +**Note:** To user can get the URL while running the **get_admin_consent** action via following ways: -- User needs to manually navigate to the URL in a separate browser tab. The URL format is: - **https://\/rest/handler/microsoftteams_6ba1906f-5899-44df-bb65-1bee4df8ca3c/\/admin_consent?asset_id=\** +1. User can find the URL in 'spawn.log' file. Search for the line starting with "Please hit the mentioned URL in another tab of browser to authorize the user and provide the admin consent". It should contain the URL. +2. If not via spawn.log, user can also manually generate the URL and navigate to the URL in a separate browser tab. The URL format is: + **https://\/rest/handler/microsoftteams_6ba1906f-5899-44df-bb65-1bee4df8ca3c/\/admin_consent?asset_id=\** + + User needs to replace splunk_soar_host, asset_name and asset_id with it's corrosponding values in the above mentioned URL. - - **Steps to fetch asset id** + **Steps to fetch splunk_soar_host, asset_id and asset_name** - Open the asset on which the action is executed. - URL for the asset will be in the following format: - + **https://\/apps/\/asset/\/** + + - For example, the splunk_soar_host, app_id and asset_id as highlighted below. + + - After replacing splunk_soar_host, asset_id and asset_name with it's corresponding values the redirect URL would be, + + **https://splunk_soar_test/rest/handler/microsoftteams_6ba1906f-5899-44df-bb65-1bee4df8ca3c/microsoft_teams/admin_consent?asset_id=6** + + + - **https//\/apps/\/asset/\/** + [![](img/microsoftteams_asset.png)](img/microsoftteams_asset.png) - - Take the asset id from the URL. ## Method to run test connectivity @@ -168,14 +208,15 @@ The below configuration variables are required for this Connector to operate. T VARIABLE | REQUIRED | TYPE | DESCRIPTION -------- | -------- | ---- | ----------- -**client\_id** | required | string | Client ID -**client\_secret** | required | password | Client Secret -**tenant\_id** | required | string | Tenant ID +**client_id** | required | string | Client ID +**client_secret** | required | password | Client Secret +**tenant_id** | required | string | Tenant ID **timezone** | optional | timezone | Microsoft Teams' timezone +**scope** | required | string | Scopes to access (space-separated) ### Supported Actions [test connectivity](#action-test-connectivity) - Validate the asset configuration for connectivity using supplied configuration -[get admin consent](#action-get-admin-consent) - Get the admin consent for a non\-admin user +[get admin consent](#action-get-admin-consent) - Get the admin consent for a non-admin user [list users](#action-list-users) - List all users [send message](#action-send-message) - Send a message to a channel of a group [list channels](#action-list-channels) - Lists all channels of a group @@ -189,7 +230,7 @@ Validate the asset configuration for connectivity using supplied configuration Type: **test** Read only: **True** -You first need admin consent if you're a non\-admin user\. +You first need admin consent if you're a non-admin user. #### Action Parameters No parameters are required for this action @@ -198,25 +239,25 @@ No parameters are required for this action No Output ## action: 'get admin consent' -Get the admin consent for a non\-admin user +Get the admin consent for a non-admin user Type: **generic** Read only: **False** -Action 'get admin consent' has to be run by an admin user to provide consent to a non\-admin user\. +Action 'get admin consent' has to be run by an admin user to provide consent to a non-admin user. #### Action Parameters No parameters are required for this action #### Action Output -DATA PATH | TYPE | CONTAINS ---------- | ---- | -------- -action\_result\.status | string | -action\_result\.data | string | -action\_result\.summary | string | -action\_result\.message | string | -summary\.total\_objects | numeric | -summary\.total\_objects\_successful | numeric | +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | success failed +action_result.data | string | | +action_result.summary | string | | +action_result.message | string | | Admin consent Received +summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 ## action: 'list users' List all users @@ -228,64 +269,64 @@ Read only: **True** No parameters are required for this action #### Action Output -DATA PATH | TYPE | CONTAINS ---------- | ---- | -------- -action\_result\.status | string | -action\_result\.data\.\*\.accountEnabled | boolean | -action\_result\.data\.\*\.assignedLicenses\.\*\.disabledPlans | string | -action\_result\.data\.\*\.assignedLicenses\.\*\.skuId | string | -action\_result\.data\.\*\.assignedPlans\.\*\.assignedDateTime | string | -action\_result\.data\.\*\.assignedPlans\.\*\.capabilityStatus | string | -action\_result\.data\.\*\.assignedPlans\.\*\.service | string | -action\_result\.data\.\*\.assignedPlans\.\*\.servicePlanId | string | -action\_result\.data\.\*\.businessPhones | string | -action\_result\.data\.\*\.city | string | -action\_result\.data\.\*\.companyName | string | -action\_result\.data\.\*\.country | string | -action\_result\.data\.\*\.deletedDateTime | string | -action\_result\.data\.\*\.department | string | -action\_result\.data\.\*\.deviceKeys | string | -action\_result\.data\.\*\.displayName | string | `user name` -action\_result\.data\.\*\.employeeId | string | -action\_result\.data\.\*\.givenName | string | `user name` -action\_result\.data\.\*\.id | string | -action\_result\.data\.\*\.imAddresses | string | `email` -action\_result\.data\.\*\.jobTitle | string | -action\_result\.data\.\*\.legalAgeGroupClassification | string | -action\_result\.data\.\*\.mail | string | `email` -action\_result\.data\.\*\.mailNickname | string | `user name` -action\_result\.data\.\*\.mobilePhone | string | -action\_result\.data\.\*\.officeLocation | string | -action\_result\.data\.\*\.onPremisesDomainName | string | `domain` -action\_result\.data\.\*\.onPremisesExtensionAttributes | string | -action\_result\.data\.\*\.onPremisesImmutableId | string | -action\_result\.data\.\*\.onPremisesLastSyncDateTime | string | -action\_result\.data\.\*\.onPremisesProvisioningErrors | string | -action\_result\.data\.\*\.onPremisesSamAccountName | string | -action\_result\.data\.\*\.onPremisesSecurityIdentifier | string | -action\_result\.data\.\*\.onPremisesSyncEnabled | string | -action\_result\.data\.\*\.onPremisesUserPrincipalName | string | -action\_result\.data\.\*\.passwordPolicies | string | -action\_result\.data\.\*\.passwordProfile | string | -action\_result\.data\.\*\.postalCode | string | -action\_result\.data\.\*\.preferredDataLocation | string | -action\_result\.data\.\*\.preferredLanguage | string | -action\_result\.data\.\*\.provisionedPlans\.\*\.capabilityStatus | string | -action\_result\.data\.\*\.provisionedPlans\.\*\.provisioningStatus | string | -action\_result\.data\.\*\.provisionedPlans\.\*\.service | string | -action\_result\.data\.\*\.proxyAddresses | string | -action\_result\.data\.\*\.refreshTokensValidFromDateTime | string | -action\_result\.data\.\*\.showInAddressList | string | -action\_result\.data\.\*\.state | string | -action\_result\.data\.\*\.streetAddress | string | -action\_result\.data\.\*\.surname | string | -action\_result\.data\.\*\.usageLocation | string | -action\_result\.data\.\*\.userPrincipalName | string | `email` -action\_result\.data\.\*\.userType | string | -action\_result\.summary\.total\_users | numeric | -action\_result\.message | string | -summary\.total\_objects | numeric | -summary\.total\_objects\_successful | numeric | +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | success failed +action_result.data.\*.accountEnabled | boolean | | True False +action_result.data.\*.assignedLicenses.\*.disabledPlans | string | | +action_result.data.\*.assignedLicenses.\*.skuId | string | | 6fd2c87f-b296-42f0-b197-1e91e994b900 +action_result.data.\*.assignedPlans.\*.assignedDateTime | string | | 2018-01-24T11:17:21Z +action_result.data.\*.assignedPlans.\*.capabilityStatus | string | | Enabled +action_result.data.\*.assignedPlans.\*.service | string | | exchange +action_result.data.\*.assignedPlans.\*.servicePlanId | string | | efb87545-963c-4e0d-99df-69c6916d9eb0 +action_result.data.\*.businessPhones | string | | 22211156 +action_result.data.\*.city | string | | +action_result.data.\*.companyName | string | | +action_result.data.\*.country | string | | US +action_result.data.\*.deletedDateTime | string | | 2018-01-24T11:16:50Z +action_result.data.\*.department | string | | +action_result.data.\*.deviceKeys | string | | +action_result.data.\*.displayName | string | `user name` | Test User +action_result.data.\*.employeeId | string | | +action_result.data.\*.givenName | string | `user name` | User +action_result.data.\*.id | string | | a1a6d0a2-b0f6-46c1-b49e-98a9ddabac09 +action_result.data.\*.imAddresses | string | `email` | test@abc.com +action_result.data.\*.jobTitle | string | | +action_result.data.\*.legalAgeGroupClassification | string | | +action_result.data.\*.mail | string | `email` | test.user@abc.com +action_result.data.\*.mailNickname | string | `user name` | User +action_result.data.\*.mobilePhone | string | | +action_result.data.\*.officeLocation | string | | +action_result.data.\*.onPremisesDomainName | string | `domain` | +action_result.data.\*.onPremisesExtensionAttributes | string | | +action_result.data.\*.onPremisesImmutableId | string | | +action_result.data.\*.onPremisesLastSyncDateTime | string | | 2018-01-24T11:16:50Z +action_result.data.\*.onPremisesProvisioningErrors | string | | +action_result.data.\*.onPremisesSamAccountName | string | | +action_result.data.\*.onPremisesSecurityIdentifier | string | | +action_result.data.\*.onPremisesSyncEnabled | string | | +action_result.data.\*.onPremisesUserPrincipalName | string | | +action_result.data.\*.passwordPolicies | string | | +action_result.data.\*.passwordProfile | string | | +action_result.data.\*.postalCode | string | | +action_result.data.\*.preferredDataLocation | string | | +action_result.data.\*.preferredLanguage | string | | en +action_result.data.\*.provisionedPlans.\*.capabilityStatus | string | | Enabled +action_result.data.\*.provisionedPlans.\*.provisioningStatus | string | | Success +action_result.data.\*.provisionedPlans.\*.service | string | | exchange +action_result.data.\*.proxyAddresses | string | | SMTP:test@abc.com +action_result.data.\*.refreshTokensValidFromDateTime | string | | 2018-01-24T11:16:50Z +action_result.data.\*.showInAddressList | string | | +action_result.data.\*.state | string | | +action_result.data.\*.streetAddress | string | | +action_result.data.\*.surname | string | | User +action_result.data.\*.usageLocation | string | | US +action_result.data.\*.userPrincipalName | string | `email` | test.user@abc.com +action_result.data.\*.userType | string | | Member +action_result.summary.total_users | numeric | | 5 +action_result.message | string | | Total users: 5 +summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 ## action: 'send message' Send a message to a channel of a group @@ -296,44 +337,44 @@ Read only: **False** #### Action Parameters PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS --------- | -------- | ----------- | ---- | -------- -**group\_id** | required | ID of group | string | `ms teams group id` -**channel\_id** | required | ID of channel | string | `ms teams channel id` -**message** | required | Message to send \(HTML is supported\) | string | +**group_id** | required | ID of group | string | `ms teams group id` +**channel_id** | required | ID of channel | string | `ms teams channel id` +**message** | required | Message to send (HTML is supported) | string | #### Action Output -DATA PATH | TYPE | CONTAINS ---------- | ---- | -------- -action\_result\.status | string | -action\_result\.parameter\.channel\_id | string | `ms teams channel id` -action\_result\.parameter\.group\_id | string | `ms teams group id` -action\_result\.parameter\.message | string | -action\_result\.data\.\*\.\@odata\.context | string | `url` -action\_result\.data\.\*\.body\.content | string | -action\_result\.data\.\*\.body\.contentType | string | -action\_result\.data\.\*\.createdDateTime | string | -action\_result\.data\.\*\.deletedDateTime | string | -action\_result\.data\.\*\.etag | string | -action\_result\.data\.\*\.from\.application | string | -action\_result\.data\.\*\.from\.conversation | string | -action\_result\.data\.\*\.from\.device | string | -action\_result\.data\.\*\.from\.user\.displayName | string | -action\_result\.data\.\*\.from\.user\.id | string | -action\_result\.data\.\*\.from\.user\.userIdentityType | string | -action\_result\.data\.\*\.id | string | -action\_result\.data\.\*\.importance | string | -action\_result\.data\.\*\.lastEditedDateTime | string | -action\_result\.data\.\*\.lastModifiedDateTime | string | -action\_result\.data\.\*\.locale | string | -action\_result\.data\.\*\.messageType | string | -action\_result\.data\.\*\.policyViolation | string | -action\_result\.data\.\*\.replyToId | string | -action\_result\.data\.\*\.subject | string | -action\_result\.data\.\*\.summary | string | -action\_result\.data\.\*\.webUrl | string | -action\_result\.summary | string | -action\_result\.message | string | -summary\.total\_objects | numeric | -summary\.total\_objects\_successful | numeric | +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | success failed +action_result.parameter.channel_id | string | `ms teams channel id` | cd6f5efb-39f8-492e-80cd-c228c211cf17 +action_result.parameter.group_id | string | `ms teams group id` | 594101ba-1fde-482d-8e24-3bbab23a3ca8 +action_result.parameter.message | string | | This is a test message Test link +action_result.data.\*.@odata.context | string | `url` | https://test.link.com/beta/$metadata#chatThreads/$entity +action_result.data.\*.body.content | string | | test message +action_result.data.\*.body.contentType | string | | text +action_result.data.\*.createdDateTime | string | | 2021-03-12T06:02:01.352Z +action_result.data.\*.deletedDateTime | string | | +action_result.data.\*.etag | string | | 1615528921352 +action_result.data.\*.from.application | string | | +action_result.data.\*.from.conversation | string | | +action_result.data.\*.from.device | string | | +action_result.data.\*.from.user.displayName | string | | Test User +action_result.data.\*.from.user.id | string | | eeb3645f-df19-47a1-8e8c-fcd234cb5f6f +action_result.data.\*.from.user.userIdentityType | string | | aadUser +action_result.data.\*.id | string | | 1517826451101 +action_result.data.\*.importance | string | | normal +action_result.data.\*.lastEditedDateTime | string | | +action_result.data.\*.lastModifiedDateTime | string | | 2021-03-12T06:02:01.352Z +action_result.data.\*.locale | string | | +action_result.data.\*.messageType | string | | message +action_result.data.\*.policyViolation | string | | +action_result.data.\*.replyToId | string | | +action_result.data.\*.subject | string | | +action_result.data.\*.summary | string | | +action_result.data.\*.webUrl | string | | +action_result.summary | string | | +action_result.message | string | | Message sent +summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 ## action: 'list channels' Lists all channels of a group @@ -344,24 +385,24 @@ Read only: **True** #### Action Parameters PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS --------- | -------- | ----------- | ---- | -------- -**group\_id** | required | ID of group | string | `ms teams group id` +**group_id** | required | ID of group | string | `ms teams group id` #### Action Output -DATA PATH | TYPE | CONTAINS ---------- | ---- | -------- -action\_result\.status | string | -action\_result\.parameter\.group\_id | string | `ms teams group id` -action\_result\.data\.\*\.description | string | -action\_result\.data\.\*\.displayName | string | -action\_result\.data\.\*\.email | string | -action\_result\.data\.\*\.id | string | `ms teams channel id` -action\_result\.data\.\*\.isFavoriteByDefault | string | -action\_result\.data\.\*\.membershipType | string | -action\_result\.data\.\*\.webUrl | string | -action\_result\.summary\.total\_channels | numeric | -action\_result\.message | string | -summary\.total\_objects | numeric | -summary\.total\_objects\_successful | numeric | +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | success failed +action_result.parameter.group_id | string | `ms teams group id` | caf444a0-0e0e-426b-98ea-db67ff6b0b25 +action_result.data.\*.description | string | | Test team +action_result.data.\*.displayName | string | | General +action_result.data.\*.email | string | | +action_result.data.\*.id | string | `ms teams channel id` | 78f4a378-e7d3-49c8-a8a7-645b886752d9 +action_result.data.\*.isFavoriteByDefault | string | | +action_result.data.\*.membershipType | string | | standard +action_result.data.\*.webUrl | string | | +action_result.summary.total_channels | numeric | | 1 +action_result.message | string | | Total channels: 3 +summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 ## action: 'list groups' List all Azure Groups @@ -373,44 +414,44 @@ Read only: **True** No parameters are required for this action #### Action Output -DATA PATH | TYPE | CONTAINS ---------- | ---- | -------- -action\_result\.status | string | -action\_result\.data\.\*\.classification | string | -action\_result\.data\.\*\.createdDateTime | string | -action\_result\.data\.\*\.deletedDateTime | string | -action\_result\.data\.\*\.description | string | -action\_result\.data\.\*\.displayName | string | -action\_result\.data\.\*\.expirationDateTime | string | -action\_result\.data\.\*\.groupTypes | string | -action\_result\.data\.\*\.id | string | `ms teams group id` -action\_result\.data\.\*\.isAssignableToRole | string | -action\_result\.data\.\*\.mail | string | `email` -action\_result\.data\.\*\.mailEnabled | boolean | -action\_result\.data\.\*\.mailNickname | string | -action\_result\.data\.\*\.membershipRule | string | -action\_result\.data\.\*\.membershipRuleProcessingState | string | -action\_result\.data\.\*\.onPremisesDomainName | string | -action\_result\.data\.\*\.onPremisesLastSyncDateTime | string | -action\_result\.data\.\*\.onPremisesNetBiosName | string | -action\_result\.data\.\*\.onPremisesProvisioningErrors | string | -action\_result\.data\.\*\.onPremisesSamAccountName | string | -action\_result\.data\.\*\.onPremisesSecurityIdentifier | string | -action\_result\.data\.\*\.onPremisesSyncEnabled | string | -action\_result\.data\.\*\.preferredDataLocation | string | -action\_result\.data\.\*\.preferredLanguage | string | -action\_result\.data\.\*\.proxyAddresses | string | -action\_result\.data\.\*\.renewedDateTime | string | -action\_result\.data\.\*\.resourceBehaviorOptions | string | -action\_result\.data\.\*\.resourceProvisioningOptions | string | -action\_result\.data\.\*\.securityEnabled | boolean | -action\_result\.data\.\*\.securityIdentifier | string | -action\_result\.data\.\*\.theme | string | -action\_result\.data\.\*\.visibility | string | -action\_result\.summary\.total\_groups | numeric | -action\_result\.message | string | -summary\.total\_objects | numeric | -summary\.total\_objects\_successful | numeric | +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | success failed +action_result.data.\*.classification | string | | classification +action_result.data.\*.createdDateTime | string | | 2018-01-30T09:43:13Z +action_result.data.\*.deletedDateTime | string | | 2018-01-30T09:43:13Z +action_result.data.\*.description | string | | team2 +action_result.data.\*.displayName | string | | team2 +action_result.data.\*.expirationDateTime | string | | +action_result.data.\*.groupTypes | string | | DynamicMembership +action_result.data.\*.id | string | `ms teams group id` | 594101ba-1fde-482d-8e24-3bbab23a3ca8 +action_result.data.\*.isAssignableToRole | string | | +action_result.data.\*.mail | string | `email` | team2@test.com +action_result.data.\*.mailEnabled | boolean | | True False +action_result.data.\*.mailNickname | string | | team2 +action_result.data.\*.membershipRule | string | | user.department -eq "Marketing" +action_result.data.\*.membershipRuleProcessingState | string | | on +action_result.data.\*.onPremisesDomainName | string | | +action_result.data.\*.onPremisesLastSyncDateTime | string | | 2018-01-30T09:43:13Z +action_result.data.\*.onPremisesNetBiosName | string | | +action_result.data.\*.onPremisesProvisioningErrors | string | | +action_result.data.\*.onPremisesSamAccountName | string | | +action_result.data.\*.onPremisesSecurityIdentifier | string | | +action_result.data.\*.onPremisesSyncEnabled | string | | +action_result.data.\*.preferredDataLocation | string | | +action_result.data.\*.preferredLanguage | string | | +action_result.data.\*.proxyAddresses | string | | SMTP : team2@test.com +action_result.data.\*.renewedDateTime | string | | 2018-01-30T09:43:13Z +action_result.data.\*.resourceBehaviorOptions | string | | +action_result.data.\*.resourceProvisioningOptions | string | | +action_result.data.\*.securityEnabled | boolean | | True False +action_result.data.\*.securityIdentifier | string | | S-2-22-2-123456789-1234567890-123456789-1234567890 +action_result.data.\*.theme | string | | +action_result.data.\*.visibility | string | | Private +action_result.summary.total_groups | numeric | | 4 +action_result.message | string | | Total groups: 3 +summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 ## action: 'list teams' List all Microsoft Teams @@ -422,47 +463,47 @@ Read only: **True** No parameters are required for this action #### Action Output -DATA PATH | TYPE | CONTAINS ---------- | ---- | -------- -action\_result\.status | string | -action\_result\.data\.\*\.classification | string | -action\_result\.data\.\*\.createdByAppId | string | -action\_result\.data\.\*\.createdDateTime | string | -action\_result\.data\.\*\.deletedDateTime | string | -action\_result\.data\.\*\.description | string | -action\_result\.data\.\*\.displayName | string | -action\_result\.data\.\*\.expirationDateTime | string | -action\_result\.data\.\*\.groupTypes\.\*\. | string | -action\_result\.data\.\*\.id | string | `ms teams group id` -action\_result\.data\.\*\.isAssignableToRole | string | -action\_result\.data\.\*\.isManagementRestricted | string | -action\_result\.data\.\*\.mail | string | `email` -action\_result\.data\.\*\.mailEnabled | boolean | -action\_result\.data\.\*\.mailNickname | string | -action\_result\.data\.\*\.membershipRule | string | -action\_result\.data\.\*\.membershipRuleProcessingState | string | -action\_result\.data\.\*\.onPremisesDomainName | string | `domain` -action\_result\.data\.\*\.onPremisesLastSyncDateTime | string | -action\_result\.data\.\*\.onPremisesNetBiosName | string | -action\_result\.data\.\*\.onPremisesSamAccountName | string | -action\_result\.data\.\*\.onPremisesSecurityIdentifier | string | -action\_result\.data\.\*\.onPremisesSyncEnabled | string | -action\_result\.data\.\*\.preferredDataLocation | string | -action\_result\.data\.\*\.preferredLanguage | string | -action\_result\.data\.\*\.proxyAddresses | string | -action\_result\.data\.\*\.proxyAddresses\.\*\. | string | -action\_result\.data\.\*\.renewedDateTime | string | -action\_result\.data\.\*\.resourceProvisioningOptions\.\*\. | string | -action\_result\.data\.\*\.securityEnabled | boolean | -action\_result\.data\.\*\.securityIdentifier | string | -action\_result\.data\.\*\.theme | string | -action\_result\.data\.\*\.visibility | string | -action\_result\.data\.\*\.writebackConfiguration\.isEnabled | string | -action\_result\.data\.\*\.writebackConfiguration\.onPremisesGroupType | string | -action\_result\.summary\.total\_teams | numeric | -action\_result\.message | string | -summary\.total\_objects | numeric | -summary\.total\_objects\_successful | numeric | +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | success failed +action_result.data.\*.classification | string | | +action_result.data.\*.createdByAppId | string | | +action_result.data.\*.createdDateTime | string | | 2018-02-05T21:42:33Z +action_result.data.\*.deletedDateTime | string | | +action_result.data.\*.description | string | | TeamOne +action_result.data.\*.displayName | string | | TeamOne +action_result.data.\*.expirationDateTime | string | | +action_result.data.\*.groupTypes.\*. | string | | Unified +action_result.data.\*.id | string | `ms teams group id` | a84b973e-ad51-4248-9a3e-df054415f026 +action_result.data.\*.isAssignableToRole | string | | +action_result.data.\*.isManagementRestricted | string | | +action_result.data.\*.mail | string | `email` | test@test.com +action_result.data.\*.mailEnabled | boolean | | True False +action_result.data.\*.mailNickname | string | | TeamOne +action_result.data.\*.membershipRule | string | | +action_result.data.\*.membershipRuleProcessingState | string | | +action_result.data.\*.onPremisesDomainName | string | `domain` | +action_result.data.\*.onPremisesLastSyncDateTime | string | | +action_result.data.\*.onPremisesNetBiosName | string | | +action_result.data.\*.onPremisesSamAccountName | string | | +action_result.data.\*.onPremisesSecurityIdentifier | string | | +action_result.data.\*.onPremisesSyncEnabled | string | | +action_result.data.\*.preferredDataLocation | string | | +action_result.data.\*.preferredLanguage | string | | +action_result.data.\*.proxyAddresses | string | | SMTP:test@test.com +action_result.data.\*.proxyAddresses.\*. | string | | SPO:SPO_2e56f4be-737f-418d-8dee-7d01911b91df@SPO_a417c578-c7ee-480d-a225-d48057e74df5 +action_result.data.\*.renewedDateTime | string | | 2018-02-05T21:42:33Z +action_result.data.\*.resourceProvisioningOptions.\*. | string | | Team +action_result.data.\*.securityEnabled | boolean | | True False +action_result.data.\*.securityIdentifier | string | | S-1-12-1-2823526206-1112059217-98516634-653268292 +action_result.data.\*.theme | string | | +action_result.data.\*.visibility | string | | Public +action_result.data.\*.writebackConfiguration.isEnabled | string | | +action_result.data.\*.writebackConfiguration.onPremisesGroupType | string | | +action_result.summary.total_teams | numeric | | 1 +action_result.message | string | | Total teams: 1 +summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 ## action: 'create meeting' Create a microsoft teams meeting @@ -470,128 +511,128 @@ Create a microsoft teams meeting Type: **generic** Read only: **False** -The add\_calendar\_event parameter can be used for creating a calender event for the given time and send the meeting invitation to all the attendees\. If the value of that parameter is false, then apart from subject, rest of the parameters will be ignored and no event will be created in the calendar\. +The add_calendar_event parameter can be used for creating a calender event for the given time and send the meeting invitation to all the attendees. If the value of that parameter is false, then apart from subject, rest of the parameters will be ignored and no event will be created in the calendar. #### Action Parameters PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS --------- | -------- | ----------- | ---- | -------- -**add\_calendar\_event** | optional | Create a calendar event for the meeting or not | boolean | +**add_calendar_event** | optional | Create a calendar event for the meeting or not | boolean | **subject** | optional | Subject of the meeting | string | **description** | optional | Description of the meeting | string | -**start\_time** | optional | Date and Time to start the meeting | string | -**end\_time** | optional | Date and Time to end the meeting | string | -**attendees** | optional | Email\-id of the users to send the meeting invitation | string | `email` +**start_time** | optional | Date and Time to start the meeting | string | +**end_time** | optional | Date and Time to end the meeting | string | +**attendees** | optional | Email-id of the users to send the meeting invitation | string | `email` #### Action Output -DATA PATH | TYPE | CONTAINS ---------- | ---- | -------- -action\_result\.status | string | -action\_result\.parameter\.add\_calendar\_event | boolean | -action\_result\.parameter\.attendees | string | `email` -action\_result\.parameter\.description | string | -action\_result\.parameter\.end\_time | string | -action\_result\.parameter\.start\_time | string | -action\_result\.parameter\.subject | string | -action\_result\.data\.\*\.\@odata\.context | string | `url` -action\_result\.data\.\*\.\@odata\.etag | string | -action\_result\.data\.\*\.allowNewTimeProposals | boolean | -action\_result\.data\.\*\.attendees\.\*\.emailAddress\.address | string | `email` -action\_result\.data\.\*\.attendees\.\*\.emailAddress\.name | string | `email` -action\_result\.data\.\*\.attendees\.\*\.status\.response | string | -action\_result\.data\.\*\.attendees\.\*\.status\.time | string | -action\_result\.data\.\*\.attendees\.\*\.type | string | -action\_result\.data\.\*\.body\.content | string | -action\_result\.data\.\*\.body\.contentType | string | -action\_result\.data\.\*\.bodyPreview | string | -action\_result\.data\.\*\.changeKey | string | -action\_result\.data\.\*\.createdDateTime | string | -action\_result\.data\.\*\.end\.dateTime | string | -action\_result\.data\.\*\.end\.timeZone | string | -action\_result\.data\.\*\.hasAttachments | boolean | -action\_result\.data\.\*\.hideAttendees | numeric | -action\_result\.data\.\*\.iCalUId | string | -action\_result\.data\.\*\.id | string | -action\_result\.data\.\*\.importance | string | -action\_result\.data\.\*\.isAllDay | boolean | -action\_result\.data\.\*\.isCancelled | boolean | -action\_result\.data\.\*\.isDraft | boolean | -action\_result\.data\.\*\.isOnlineMeeting | boolean | -action\_result\.data\.\*\.isOrganizer | boolean | -action\_result\.data\.\*\.isReminderOn | boolean | -action\_result\.data\.\*\.lastModifiedDateTime | string | -action\_result\.data\.\*\.location\.displayName | string | -action\_result\.data\.\*\.location\.locationType | string | -action\_result\.data\.\*\.location\.uniqueIdType | string | -action\_result\.data\.\*\.occurrenceId | string | -action\_result\.data\.\*\.onlineMeeting\.joinUrl | string | `url` -action\_result\.data\.\*\.onlineMeetingProvider | string | -action\_result\.data\.\*\.onlineMeetingUrl | string | -action\_result\.data\.\*\.organizer\.emailAddress\.address | string | `email` -action\_result\.data\.\*\.organizer\.emailAddress\.name | string | -action\_result\.data\.\*\.originalEndTimeZone | string | -action\_result\.data\.\*\.originalStartTimeZone | string | -action\_result\.data\.\*\.recurrence | string | -action\_result\.data\.\*\.reminderMinutesBeforeStart | numeric | -action\_result\.data\.\*\.responseRequested | boolean | -action\_result\.data\.\*\.responseStatus\.response | string | -action\_result\.data\.\*\.responseStatus\.time | string | -action\_result\.data\.\*\.sensitivity | string | -action\_result\.data\.\*\.seriesMasterId | string | -action\_result\.data\.\*\.showAs | string | -action\_result\.data\.\*\.start\.dateTime | string | -action\_result\.data\.\*\.start\.timeZone | string | -action\_result\.data\.\*\.subject | string | -action\_result\.data\.\*\.transactionId | string | -action\_result\.data\.\*\.type | string | -action\_result\.data\.\*\.webLink | string | `url` -action\_result\.data\.\*\.joinUrl | string | `url` -action\_result\.data\.\*\.chatInfo\.threadId | string | -action\_result\.data\.\*\.chatInfo\.messageId | string | -action\_result\.data\.\*\.chatInfo\.replyChainMessageId | string | -action\_result\.data\.\*\.externalId | string | -action\_result\.data\.\*\.joinWebUrl | string | `url` -action\_result\.data\.\*\.endDateTime | string | -action\_result\.data\.\*\.isBroadcast | numeric | -action\_result\.data\.\*\.meetingCode | string | -action\_result\.data\.\*\.meetingInfo | string | -action\_result\.data\.\*\.participants\.organizer\.upn | string | `email` -action\_result\.data\.\*\.participants\.organizer\.role | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.user\.id | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.user\.tenantId | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.user\.displayName | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.user\.registrantId | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.user\.identityProvider | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.guest | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.phone | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.device | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.acsUser | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.encrypted | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.spoolUser | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.onPremises | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.application | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.applicationInstance | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.acsApplicationInstance | string | -action\_result\.data\.\*\.participants\.organizer\.identity\.spoolApplicationInstance | string | -action\_result\.data\.\*\.startDateTime | string | -action\_result\.data\.\*\.joinInformation\.content | string | -action\_result\.data\.\*\.joinInformation\.contentType | string | -action\_result\.data\.\*\.allowMeetingChat | string | -action\_result\.data\.\*\.creationDateTime | string | -action\_result\.data\.\*\.allowedPresenters | string | -action\_result\.data\.\*\.audioConferencing | string | -action\_result\.data\.\*\.autoAdmittedUsers | string | -action\_result\.data\.\*\.broadcastSettings | string | -action\_result\.data\.\*\.lobbyBypassSettings\.scope | boolean | -action\_result\.data\.\*\.lobbyBypassSettings\.isDialInBypassEnabled | boolean | -action\_result\.data\.\*\.recordAutomatically | boolean | -action\_result\.data\.\*\.isEntryExitAnnounced | boolean | -action\_result\.data\.\*\.joinMeetingIdSettings | string | -action\_result\.data\.\*\.videoTeleconferenceId | string | -action\_result\.data\.\*\.allowTeamworkReactions | boolean | -action\_result\.data\.\*\.allowAttendeeToEnableMic | boolean | -action\_result\.data\.\*\.allowAttendeeToEnableCamera | boolean | -action\_result\.data\.\*\.outerMeetingAutoAdmittedUsers | string | -action\_result\.summary | string | -action\_result\.message | string | -summary\.total\_objects | numeric | -summary\.total\_objects\_successful | numeric | \ No newline at end of file +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | success failed +action_result.parameter.add_calendar_event | boolean | | False True +action_result.parameter.attendees | string | `email` | test@abc.com, testuser@abc.com +action_result.parameter.description | string | | Test +action_result.parameter.end_time | string | | 2017-04-15T12:30:00 24 April, 2022 4:30 am +action_result.parameter.start_time | string | | 2017-04-15T12:00:00 24 April, 2022 4 am +action_result.parameter.subject | string | | Let's go for lunch +action_result.data.\*.@odata.context | string | `url` | https://graph.microsoft.com/v1.0/$metadata#users('eeb3645f-df19-47a1-8e8c-fcd234cb5f6f')/calendar/events/$entity https://graph.microsoft.com/v1.0/$metadata#users('eeb3645f-df19-47a1-8e8c-fcd234cb5f6f')/onlineMeetings/$entity +action_result.data.\*.@odata.etag | string | | W/"07XhOkNngkCkqoNfY+k/jQAFHNmDaQ==" +action_result.data.\*.allowNewTimeProposals | boolean | | True False +action_result.data.\*.attendees.\*.emailAddress.address | string | `email` | test@abc.com +action_result.data.\*.attendees.\*.emailAddress.name | string | `email` | test@abc.com +action_result.data.\*.attendees.\*.status.response | string | | none +action_result.data.\*.attendees.\*.status.time | string | | 0001-01-01T00:00:00Z +action_result.data.\*.attendees.\*.type | string | | required +action_result.data.\*.body.content | string | | +action_result.data.\*.body.contentType | string | | html +action_result.data.\*.bodyPreview | string | | .........................................................................................................................................\\r\\nJoin Teams Meeting\\r\\nen-US\\r\\nhttps://teams.microsoft.com/l/meetup-join/19%3ameeting_ZDljMDhjMDAtNWI2Yy00MGUxLWExYjUtYT +action_result.data.\*.changeKey | string | | 07XhOkNngkCkqoNfY+k/jQAFHNmDaQ== +action_result.data.\*.createdDateTime | string | | 2022-04-22T10:51:54.9092527Z +action_result.data.\*.end.dateTime | string | | 2022-04-23T12:40:00.0000000 +action_result.data.\*.end.timeZone | string | | Pacific Standard Time +action_result.data.\*.hasAttachments | boolean | | True False +action_result.data.\*.hideAttendees | numeric | | False +action_result.data.\*.iCalUId | string | | 040000008200E00074C5B7101A82E00800000000A3FE23FB3656D80100000000000000001000000045D024D0A24F814DA4CBB362A95DD153 +action_result.data.\*.id | string | | AQMkAGYxNGJmOWQyLTlhMjctNGRiOS1iODU0LTA1ZWE3ZmQ3NDU3MQBGAAADeDDJKaEf4EihMWU6SZgKbAcA07XhOkNngkCkqoNfY_k-jQAAAgENAAAA07XhOkNngkCkqoNfY_k-jQAFHbOt_AAAAA== +action_result.data.\*.importance | string | | normal +action_result.data.\*.isAllDay | boolean | | True False +action_result.data.\*.isCancelled | boolean | | True False +action_result.data.\*.isDraft | boolean | | True False +action_result.data.\*.isOnlineMeeting | boolean | | True False +action_result.data.\*.isOrganizer | boolean | | True False +action_result.data.\*.isReminderOn | boolean | | True False +action_result.data.\*.lastModifiedDateTime | string | | 2022-04-22T10:51:56.5665393Z +action_result.data.\*.location.displayName | string | | Meeting Room1 +action_result.data.\*.location.locationType | string | | default +action_result.data.\*.location.uniqueIdType | string | | unknown +action_result.data.\*.occurrenceId | string | | +action_result.data.\*.onlineMeeting.joinUrl | string | `url` | https://teams.microsoft.com/l/meetup-join/19%3ameeting_ZDljMDhjMDAtNWI2Yy00MGUxLWExYjUtYThjNzMwNDc4NzZj%40thread.v2/0?context=%7b%22Tid%22%3a%22140fe46d-819d-4b6d-b7ef-1c0a8270f4f0%22%2c%22Oid%22%3a%22eeb3645f-df19-47a1-8e8c-fcd234cb5f6f%22%7d +action_result.data.\*.onlineMeetingProvider | string | | teamsForBusiness +action_result.data.\*.onlineMeetingUrl | string | | +action_result.data.\*.organizer.emailAddress.address | string | `email` | test@abc.com +action_result.data.\*.organizer.emailAddress.name | string | | Test User +action_result.data.\*.originalEndTimeZone | string | | Pacific Standard Time +action_result.data.\*.originalStartTimeZone | string | | Pacific Standard Time +action_result.data.\*.recurrence | string | | +action_result.data.\*.reminderMinutesBeforeStart | numeric | | 15 +action_result.data.\*.responseRequested | boolean | | True False +action_result.data.\*.responseStatus.response | string | | organizer +action_result.data.\*.responseStatus.time | string | | 0001-01-01T00:00:00Z +action_result.data.\*.sensitivity | string | | normal +action_result.data.\*.seriesMasterId | string | | +action_result.data.\*.showAs | string | | busy +action_result.data.\*.start.dateTime | string | | 2022-04-23T12:30:00.0000000 +action_result.data.\*.start.timeZone | string | | Pacific Standard Time +action_result.data.\*.subject | string | | My Code Review +action_result.data.\*.transactionId | string | | +action_result.data.\*.type | string | | singleInstance +action_result.data.\*.webLink | string | `url` | https://outlook.office365.com/owa/?itemid=AQMkAGYxNGJmOWQyLTlhMjctNGRiOS1iODU0LTA1ZWE3ZmQ3NDU3MQBGAAADeDDJKaEf4EihMWU6SZgKbAcA07XhOkNngkCkqoNfY%2Bk%2FjQAAAgENAAAA07XhOkNngkCkqoNfY%2Bk%2FjQAFHbOt%2BAAAAA%3D%3D&exvsurl=1&path=/calendar/item +action_result.data.\*.joinUrl | string | `url` | https://teams.microsoft.com/l/meetup-join/19%3ameeting_MjViZWE2ODItM2UyNi00YjdhLWJhOGUtN2FmYWQwM2NkOTJm%40thread.v2/0?context=%7b%22Tid%22%3a%22140fe46d-819d-4b6d-b7ef-1c0a8270f4f0%22%2c%22Oid%22%3a%22eeb3645f-df19-47a1-8e8c-fcd234cb5f6f%22%7d +action_result.data.\*.chatInfo.threadId | string | | 19:meeting_MjViZWE2ODItM2UyNi00YjdhLWJhOGUtN2FmYWQwM2NkOTJm@thread.v2 +action_result.data.\*.chatInfo.messageId | string | | 0 +action_result.data.\*.chatInfo.replyChainMessageId | string | | +action_result.data.\*.externalId | string | | +action_result.data.\*.joinWebUrl | string | `url` | https://teams.microsoft.com/l/meetup-join/19%3ameeting_MjViZWE2ODItM2UyNi00YjdhLWJhOGUtN2FmYWQwM2NkOTJm%40thread.v2/0?context=%7b%22Tid%22%3a%22140fe46d-819d-4b6d-b7ef-1c0a8270f4f0%22%2c%22Oid%22%3a%22eeb3645f-df19-47a1-8e8c-fcd234cb5f6f%22%7d +action_result.data.\*.endDateTime | string | | 2022-04-28T13:11:55.0940461Z +action_result.data.\*.isBroadcast | numeric | | False +action_result.data.\*.meetingCode | string | | 230408462435 +action_result.data.\*.meetingInfo | string | | +action_result.data.\*.participants.organizer.upn | string | `email` | test@abc.com +action_result.data.\*.participants.organizer.role | string | | presenter +action_result.data.\*.participants.organizer.identity.user.id | string | | eeb3645f-df19-47a1-8e8c-fcd234cb5f6f +action_result.data.\*.participants.organizer.identity.user.tenantId | string | | 140fe46d-819d-4b6d-b7ef-1c0a8270f4f0 +action_result.data.\*.participants.organizer.identity.user.displayName | string | | +action_result.data.\*.participants.organizer.identity.user.registrantId | string | | +action_result.data.\*.participants.organizer.identity.user.identityProvider | string | | AAD +action_result.data.\*.participants.organizer.identity.guest | string | | +action_result.data.\*.participants.organizer.identity.phone | string | | +action_result.data.\*.participants.organizer.identity.device | string | | +action_result.data.\*.participants.organizer.identity.acsUser | string | | +action_result.data.\*.participants.organizer.identity.encrypted | string | | +action_result.data.\*.participants.organizer.identity.spoolUser | string | | +action_result.data.\*.participants.organizer.identity.onPremises | string | | +action_result.data.\*.participants.organizer.identity.application | string | | +action_result.data.\*.participants.organizer.identity.applicationInstance | string | | +action_result.data.\*.participants.organizer.identity.acsApplicationInstance | string | | +action_result.data.\*.participants.organizer.identity.spoolApplicationInstance | string | | +action_result.data.\*.startDateTime | string | | 2022-04-28T12:11:55.0940461Z +action_result.data.\*.joinInformation.content | string | | +action_result.data.\*.joinInformation.contentType | string | | html +action_result.data.\*.allowMeetingChat | string | | enabled +action_result.data.\*.creationDateTime | string | | 2022-04-28T12:11:55.7803555Z +action_result.data.\*.allowedPresenters | string | | everyone +action_result.data.\*.audioConferencing | string | | +action_result.data.\*.autoAdmittedUsers | string | | everyoneInCompany +action_result.data.\*.broadcastSettings | string | | +action_result.data.\*.lobbyBypassSettings.scope | boolean | | True False +action_result.data.\*.lobbyBypassSettings.isDialInBypassEnabled | boolean | | True False +action_result.data.\*.recordAutomatically | boolean | | True False +action_result.data.\*.isEntryExitAnnounced | boolean | | True False +action_result.data.\*.joinMeetingIdSettings | string | | +action_result.data.\*.videoTeleconferenceId | string | | +action_result.data.\*.allowTeamworkReactions | boolean | | True False +action_result.data.\*.allowAttendeeToEnableMic | boolean | | True False +action_result.data.\*.allowAttendeeToEnableCamera | boolean | | True False +action_result.data.\*.outerMeetingAutoAdmittedUsers | string | | +action_result.summary | string | | +action_result.message | string | | Meeting Created Successfully +summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 \ No newline at end of file diff --git a/__init__.py b/__init__.py index f7ee2da..44bae34 100644 --- a/__init__.py +++ b/__init__.py @@ -1,6 +1,6 @@ # File: __init__.py # -# Copyright (c) 2019-2022 Splunk Inc. +# Copyright (c) 2019-2023 Splunk Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/exclude_files.txt b/exclude_files.txt deleted file mode 100644 index 412082c..0000000 --- a/exclude_files.txt +++ /dev/null @@ -1,6 +0,0 @@ -docker-compose.yml -.gitlab-ci.yml -Makefile -.git* -whitesource-results -*.postman_collection.json diff --git a/img/microsoftteams_asset.png b/img/microsoftteams_asset.png new file mode 100644 index 0000000..fd5b19f Binary files /dev/null and b/img/microsoftteams_asset.png differ diff --git a/manual_readme_content.md b/manual_readme_content.md new file mode 100644 index 0000000..93ef24d --- /dev/null +++ b/manual_readme_content.md @@ -0,0 +1,191 @@ +[comment]: # " File: README.md" + +[comment]: # " Copyright (c) 2019-2023 Splunk Inc." +[comment]: # "" +[comment]: # "Licensed under the Apache License, Version 2.0 (the 'License');" +[comment]: # "you may not use this file except in compliance with the License." +[comment]: # "You may obtain a copy of the License at" +[comment]: # "" +[comment]: # " http://www.apache.org/licenses/LICENSE-2.0" +[comment]: # "" +[comment]: # "Unless required by applicable law or agreed to in writing, software distributed under" +[comment]: # "the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND," +[comment]: # "either express or implied. See the License for the specific language governing permissions" +[comment]: # "and limitations under the License." +[comment]: # "" +## Note + +- For an admin user, you can run the test connectivity directly. +- For a non-admin user, you need to get the admin consent first. This can be done by running the + action **get_admin_consent** by an admin user. + +## Authentication + +This app requires creating an app in the Azure Active Directory. + +- Navigate to the in a browser and log in with a Microsoft account + +- Select **Azure Active Directory** from the left side menu + +- From the left panel, select **App Registrations** + +- At the top of the middle section, select **New registration** + +- On the next page, give a name to your application and click **Register** + +- Once the app is created, the below steps needs to be performed on the next page: + + - Under **Certificates & secrets** , select **New client secret** . Note this key somewhere + secure, as it cannot be retrieved after closing the window. + - Under **Authentication** , select **Add a platform** . In the **Add a platform** window, + select **Web** . The **Redirect URLs** should be filled right here. We will get **Redirect + + URLs** from the Splunk SOAR asset that we will create below in the section titled "Configure the + Microsoft Teams Splunk SOAR app asset". + - Under **API Permissions** , the following minimum **Delegated Permissions** from **Microsoft Graph** + needs to be added: + + + | Permission | Action | Description | Admin Consent Required + | :--------------- | :-------- | :------------ | :------------------- | + | offline_access | test connectivity | Allows the app to read and update user data, even when they are not currently using the app. This permission is required to generate the refresh_token, if offline_access is not provided then Test connectivity action will fail and no other action will work. | No + | User.ReadBasic.All | list users, get admin consent and test connectivity | Allows the app to read a basic set of profile properties of other users in your organization on behalf of the signed-in user. This includes display name, first and last name, email address, open extensions and photo. Also allows the app to read the full profile of the signed-in user | No + | OnlineMeetings.ReadWrite | create meeting | Allows an app to create, read online meetings on behalf of the signed-in user. | No + | Calendars.ReadWrite | create meeting (while add_calendar_event parameter is set to True) | Allows the app to create, read, update, and delete events in user calendars. | No + | Channel.ReadBasic.All | list channels | Read channel names and channel descriptions, on behalf of the signed-in user. | No + | ChannelMessage.Send | send message | Allows an app to send channel messages in Microsoft Teams, on behalf of the signed-in user. | No + | GroupMember.Read.All | list groups, list teams | Allows the app to list groups, read basic group properties and read membership of all groups the signed-in user has access to. | Yes + + + After making these changes, click **Add permissions** at the bottom of the screen, then + click **Grant admin consent for ** . +## Method to revoke permission +- For revoking the permissions, please refer [this](https://learn.microsoft.com/en-gb/azure/active-directory/manage-apps/manage-application-permissions?pivots=ms-graph) documentation. + +- After removing the permissions from the Azure app, it might still be visible in the state file as those permissions aren’t fully revoked. + +- To verify the permissions are revoked or not, follow the below steps: + - Navigate to the https://portal.azure.com in a browser and log in with a Microsoft account + - Select **Azure Active Directory** from the left side menu + - From the left panel, select **Enterprise applications** + - Select the application used in the asset + - From the left hand side select **Permissions** + - In the **Permissions** page go to **user consent** + + - If any extra permissions are present in the user consent, then it should be removed. + - To remove the permissions visible in the **user consent** please refer [this](https://learn.microsoft.com/en-gb/azure/active-directory/manage-apps/manage-application-permissions?pivots=ms-graph) documentation. + + Note: Following the given steps will remove consent for all the permissions + + +## State file permissions + +Please check the permissions for the state file as mentioned below. + +#### State file path + + +- For unprivileged instance: + /\/local_data/app_states/\/\\_state.json + +#### State file permissions + +- File rights: rw-rw-r-- (664) (The phantom user should have read and write access for the state + file) +- File owner: Appropriate phantom user + + +## Configure the Microsoft Teams Splunk SOAR app asset + + +When creating an asset for the **Microsoft Teams** app, place the **Application Id** of the app in +the **Client ID** field and place the password generated during the app creation process in the +**Client Secret** field. Then, after filling out the **Tenant ID** field, click **SAVE** . Both the +Application/Client ID and the Tenant ID can be found in the **Overview** tab on your app's Azure +page. + + +The **Scope** configuration parameter's default value is the minimum required scopes. You can add/delete scopes as needed. The scopes added in this parameter should be consistent with those used to create the application on the Azure portal + + +After saving, a new field will appear in the **Asset Settings** tab. Take the URL found in the +**POST incoming for Microsoft Teams to this location** field and place it in the **Redirect URLs** +field mentioned in a previous step. To this URL, add **/result** . After doing so the URL should +look something like: + + + +https://\/rest/handler/microsoftteams_6ba1906f-5899-44df-bb65-1bee4df8ca3c/\/result + + +Once again, click Save at the bottom of the screen. + + +Additionally, updating the Base URL in the Company Settings is also required. Navigate to +**Administration \> Company Settings \> Info** to configure the Base URL For Splunk SOAR Appliance. +Then, select **Save Changes.** + +## Method to run get admin consent + +Run **get_admin_consent** action. It will display an URL in spawn.logs file. Navigate to this URL in a separate browser +tab. This new tab will redirect to a Microsoft login page. Log in to a Microsoft account with +administrator privileges. After logging in, review the requested permissions listed, then click +**Accept** . Finally, close that tab. Action should show a success message. + +**Note:** To user can get the URL while running the **get_admin_consent** action via following ways: + +1. User can find the URL in 'spawn.log' file. Search for the line starting with "Please hit the mentioned URL in another tab of browser to authorize the user and provide the admin consent". It should contain the URL. + +2. If not via spawn.log, user can also manually generate the URL and navigate to the URL in a separate browser tab. The URL format is: + **https://\/rest/handler/microsoftteams_6ba1906f-5899-44df-bb65-1bee4df8ca3c/\/admin_consent?asset_id=\** + + User needs to replace splunk_soar_host, asset_name and asset_id with it's corrosponding values in the above mentioned URL. + + **Steps to fetch splunk_soar_host, asset_id and asset_name** + + - Open the asset on which the action is executed. + + - URL for the asset will be in the following format: + + **https://\/apps/\/asset/\/** + + - For example, the splunk_soar_host, app_id and asset_id as highlighted below. + + - After replacing splunk_soar_host, asset_id and asset_name with it's corresponding values the redirect URL would be, + + **https://splunk_soar_test/rest/handler/microsoftteams_6ba1906f-5899-44df-bb65-1bee4df8ca3c/microsoft_teams/admin_consent?asset_id=6** + + + + + [![](img/microsoftteams_asset.png)](img/microsoftteams_asset.png) + + +## Method to run test connectivity + +After setting up the asset and user, click the **TEST CONNECTIVITY** button. A window should pop up +and display a URL. Navigate to this URL in a separate browser tab. This new tab will redirect to a +Microsoft login page. Log in to a Microsoft account. After logging in, review the requested +permissions listed, then click **Accept** . Finally, close that tab. The test connectivity window +should show a success message. + +The app should now be ready to be used. + +## Important points to be considered for 'Create Meeting' action + +- The **timezone** configuration parameter will only be used for **Create Meeting** action, when + the user wants to provide **start_time** and **end_time** of the meeting. +- The **timezone** parameter can be configured using the timezone of the microsoft teams calender. + If not provided, by default the **UTC** timezone will be considered for scheduling the meetings. +- In case of add_calendar_event = true, if the user wants to provide schedule time for the + meeting, **start_time** and **end_time** both the parameters are required. + +## Port Information + +The app uses HTTP/HTTPS protocol for communicating with the Microsoft Teams Server. Below are the +default ports used by Splunk SOAR. + +| Service Name | Transport Protocol | Port | +|--------------|--------------------|------| +| http | tcp | 80 | +| https | tcp | 443 | diff --git a/microsoftteams.json b/microsoftteams.json index 65bf5fd..add88da 100644 --- a/microsoftteams.json +++ b/microsoftteams.json @@ -9,18 +9,18 @@ "product_name": "Teams", "product_version_regex": ".*", "publisher": "Splunk", - "license": "Copyright (c) 2019-2022 Splunk Inc.", - "app_version": "2.4.0", + "license": "Copyright (c) 2019-2023 Splunk Inc.", + "app_version": "2.5.0", "utctime_updated": "2022-01-14T23:54:39.000000Z", "package_name": "phantom_microsoftteams", "main_module": "microsoftteams_connector.py", - "min_phantom_version": "5.2.0", + "min_phantom_version": "6.0.2", "app_wizard_version": "1.0.0", "rest_handler": "microsoftteams_connector._handle_rest_request", "python_version": "3", "fips_compliant": true, "latest_tested_versions": [ - "Cloud 2022-05-23" + "Cloud, Aug 17 2023" ], "configuration": { "client_id": { @@ -46,6 +46,13 @@ "description": "Microsoft Teams' timezone", "default": "UTC", "order": 3 + }, + "scope": { + "description": "Scopes to access (space-separated)", + "data_type": "string", + "required": true, + "default": "offline_access calendars.readwrite onlinemeetings.readwrite channelmessage.send user.readbasic.all channel.readbasic.all groupmember.read.all", + "order": 4 } }, "actions": [ @@ -897,7 +904,6 @@ "data_path": "action_result.data.*.groupTypes", "data_type": "string", "example_values": [ - "Unified", "DynamicMembership" ] }, @@ -953,8 +959,7 @@ "data_path": "action_result.data.*.membershipRuleProcessingState", "data_type": "string", "example_values": [ - "on", - "off" + "on" ] }, { @@ -1043,8 +1048,7 @@ "column_name": "Visibility", "column_order": 3, "example_values": [ - "Private", - "Public" + "Private" ] }, { @@ -1430,8 +1434,7 @@ "data_path": "action_result.parameter.subject", "data_type": "string", "example_values": [ - "Let's go for lunch", - "Test" + "Let's go for lunch" ] }, { @@ -1516,7 +1519,7 @@ "data_path": "action_result.data.*.bodyPreview", "data_type": "string", "example_values": [ - ".........................................................................................................................................\r\nJoin Teams Meeting\r\nen-US\r\nhttps://teams.microsoft.com/l/meetup-join/19%3ameeting_ZDljMDhjMDAtNWI2Yy00MGUxLWExYjUtYT" + ".........................................................................................................................................\\r\\nJoin Teams Meeting\\r\\nen-US\\r\\nhttps://teams.microsoft.com/l/meetup-join/19%3ameeting_ZDljMDhjMDAtNWI2Yy00MGUxLWExYjUtYT" ] }, { @@ -1573,8 +1576,7 @@ "data_path": "action_result.data.*.id", "data_type": "string", "example_values": [ - "AQMkAGYxNGJmOWQyLTlhMjctNGRiOS1iODU0LTA1ZWE3ZmQ3NDU3MQBGAAADeDDJKaEf4EihMWU6SZgKbAcA07XhOkNngkCkqoNfY_k-jQAAAgENAAAA07XhOkNngkCkqoNfY_k-jQAFHbOt_AAAAA==", - "MSplZWIzNjQ1Zi1kZjE5LTQ3YTEtOGU4Yy1mY2QyMzRjYjVmNmYqMCoqMTk6bWVldGluZ19NalZpWldFMk9ESXRNMlV5TmkwMFlqZGhMV0poT0dVdE4yRm1ZV1F3TTJOa09USm1AdGhyZWFkLnYy" + "AQMkAGYxNGJmOWQyLTlhMjctNGRiOS1iODU0LTA1ZWE3ZmQ3NDU3MQBGAAADeDDJKaEf4EihMWU6SZgKbAcA07XhOkNngkCkqoNfY_k-jQAAAgENAAAA07XhOkNngkCkqoNfY_k-jQAFHbOt_AAAAA==" ] }, { @@ -1785,8 +1787,7 @@ "data_path": "action_result.data.*.subject", "data_type": "string", "example_values": [ - "My Code Review", - "Test" + "My Code Review" ] }, { @@ -2124,101 +2125,25 @@ ], "pip_dependencies": { "wheel": [ - { - "module": "Django", - "input_file": "wheels/py3/Django-3.2.5-py3-none-any.whl" - }, - { - "module": "asgiref", - "input_file": "wheels/py3/asgiref-3.4.1-py3-none-any.whl" - }, { "module": "beautifulsoup4", "input_file": "wheels/py3/beautifulsoup4-4.9.1-py3-none-any.whl" }, - { - "module": "certifi", - "input_file": "wheels/shared/certifi-2021.10.8-py2.py3-none-any.whl" - }, - { - "module": "chardet", - "input_file": "wheels/shared/chardet-3.0.4-py2.py3-none-any.whl" - }, - { - "module": "idna", - "input_file": "wheels/shared/idna-2.10-py2.py3-none-any.whl" - }, - { - "module": "pytz", - "input_file": "wheels/shared/pytz-2022.1-py2.py3-none-any.whl" - }, - { - "module": "requests", - "input_file": "wheels/shared/requests-2.25.0-py2.py3-none-any.whl" - }, { "module": "soupsieve", "input_file": "wheels/py3/soupsieve-2.3.2.post1-py3-none-any.whl" - }, - { - "module": "sqlparse", - "input_file": "wheels/py3/sqlparse-0.4.2-py3-none-any.whl" - }, - { - "module": "typing_extensions", - "input_file": "wheels/py3/typing_extensions-4.1.1-py3-none-any.whl" - }, - { - "module": "urllib3", - "input_file": "wheels/shared/urllib3-1.26.9-py2.py3-none-any.whl" } ] }, "pip39_dependencies": { "wheel": [ - { - "module": "Django", - "input_file": "wheels/py3/Django-3.2.5-py3-none-any.whl" - }, - { - "module": "asgiref", - "input_file": "wheels/py3/asgiref-3.5.0-py3-none-any.whl" - }, { "module": "beautifulsoup4", "input_file": "wheels/py3/beautifulsoup4-4.9.1-py3-none-any.whl" }, - { - "module": "certifi", - "input_file": "wheels/shared/certifi-2021.10.8-py2.py3-none-any.whl" - }, - { - "module": "chardet", - "input_file": "wheels/shared/chardet-3.0.4-py2.py3-none-any.whl" - }, - { - "module": "idna", - "input_file": "wheels/shared/idna-2.10-py2.py3-none-any.whl" - }, - { - "module": "pytz", - "input_file": "wheels/shared/pytz-2022.1-py2.py3-none-any.whl" - }, - { - "module": "requests", - "input_file": "wheels/shared/requests-2.25.0-py2.py3-none-any.whl" - }, { "module": "soupsieve", - "input_file": "wheels/py3/soupsieve-2.3.2.post1-py3-none-any.whl" - }, - { - "module": "sqlparse", - "input_file": "wheels/py3/sqlparse-0.4.2-py3-none-any.whl" - }, - { - "module": "urllib3", - "input_file": "wheels/shared/urllib3-1.26.9-py2.py3-none-any.whl" + "input_file": "wheels/py3/soupsieve-2.4.1-py3-none-any.whl" } ] } diff --git a/microsoftteams_connector.py b/microsoftteams_connector.py index f51b1c7..866d5fc 100644 --- a/microsoftteams_connector.py +++ b/microsoftteams_connector.py @@ -1,6 +1,6 @@ # File: microsoftteams_connector.py # -# Copyright (c) 2019-2022 Splunk Inc. +# Copyright (c) 2019-2023 Splunk Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ import encryption_helper import phantom.app as phantom import requests -from bs4 import BeautifulSoup, UnicodeDammit +from bs4 import BeautifulSoup from django.http import HttpResponse from phantom.action_result import ActionResult from phantom.base_connector import BaseConnector @@ -60,57 +60,34 @@ def _handle_login_redirect(request, key): return response -def _handle_py_ver_compat_for_input_str(python_version, input_str, app_connector=None): +def _get_error_message_from_exception(self, e): """ - This method returns the encoded|original string based on the Python version. - :param python_version: Python major version - :param input_str: Input string to be processed - :param app_connector: Object of app_connector class - :return: input_str (Processed input string based on following logic 'input_str - Python 3; encoded input_str - Python 2') + Get appropriate error message from the exception. + :param e: Exception object + :return: error message """ - try: - if input_str and python_version == 2: - input_str = UnicodeDammit(input_str).unicode_markup.encode('utf-8') - except Exception: - if app_connector: - app_connector.debug_print("Error occurred while handling python 2to3 compatibility for the input string") - return input_str + error_code = None + error_msg = ERROR_MSG_UNAVAILABLE + self.error_print("Error occurred.", e) -def _get_error_message_from_exception(python_version, e, app_connector=None): - """ This function is used to get appropriate error message from the exception. - :param python_version: Python major version - :param e: Exception object - :param app_connector: Object of app_connector class - :return: error code and message - """ - error_msg = "Unknown error occurred. Please check the asset configuration and|or action parameters." - error_code = "Error code unavailable" try: - if e.args: + if hasattr(e, "args"): if len(e.args) > 1: error_code = e.args[0] error_msg = e.args[1] elif len(e.args) == 1: - error_code = "Error code unavailable" error_msg = e.args[0] - else: - error_code = "Error code unavailable" - error_msg = "Unknown error occurred. Please check the asset configuration and|or action parameters." - except: - error_code = "Error code unavailable" - error_msg = "Unknown error occurred. Please check the asset configuration and|or action parameters." + except Exception as e: + self.error_print("Error occurred while fetching exception information. Details: {}".format(str(e))) - try: - error_msg = _handle_py_ver_compat_for_input_str(python_version, error_msg, app_connector) - except TypeError: - error_msg = "Error occurred while connecting to the Microsoft Teams server. " - error_msg += "Please check the asset configuration and|or the action parameters." - except: - error_msg = "Unknown error occurred. Please check the asset configuration and|or action parameters." + if not error_code: + error_text = "Error Message: {}".format(error_msg) + else: + error_text = "Error Code: {}. Error Message: {}".format(error_code, error_msg) - return error_code, error_msg + return error_text def _load_app_state(asset_id, app_connector=None): @@ -142,15 +119,8 @@ def _load_app_state(asset_id, app_connector=None): state = json.loads(state_file_data) except Exception as e: if app_connector: - # Fetching the Python major version - try: - python_version = int(sys.version_info[0]) - except Exception: - app_connector.debug_print("Error occurred while getting the Phantom server's Python major version.") - return state - - error_code, error_msg = _get_error_message_from_exception(python_version, e, app_connector) - app_connector.debug_print('In _load_app_state: Error Code: {0}. Error Message: {1}'.format(error_code, error_msg)) + error_text = _get_error_message_from_exception(e, app_connector) + app_connector.debug_print('In _load_app_state: {}'.format(error_text)) if app_connector: app_connector.debug_print('Loaded state: ', state) @@ -189,18 +159,10 @@ def _save_app_state(state, asset_id, app_connector=None): with open(real_state_file_path, 'w+') as state_file_obj: state_file_obj.write(json.dumps(state)) except Exception as e: - # Fetching the Python major version - try: - python_version = int(sys.version_info[0]) - except Exception: - if app_connector: - app_connector.debug_print("Error occurred while getting the Phantom server's Python major version.") - return phantom.APP_ERROR - - error_code, error_msg = _get_error_message_from_exception(python_version, e, app_connector) + error_text = _get_error_message_from_exception(e, app_connector) if app_connector: - app_connector.debug_print('Unable to save state file: Error Code: {0}. Error Message: {1}'.format(error_code, error_msg)) - print('Unable to save state file: Error Code: {0}. Error Message: {1}'.format(error_code, error_msg)) + app_connector.debug_print('Unable to save state file: {}'.format(error_text)) + print('Unable to save state file: {}'.format(error_text)) return phantom.APP_ERROR return phantom.APP_SUCCESS @@ -258,7 +220,7 @@ def _handle_login_response(request): state['code'] = MicrosoftTeamConnector().encrypt_state(code, "code") state[MSTEAMS_STATE_IS_ENCRYPTED] = True except Exception as e: - return HttpResponse("{}: {}".format(MSTEAMS_ENCRYPTION_ERR, str(e)), content_type="text/plain", status=400) + return HttpResponse("{}: {}".format(MSTEAMS_ENCRYPTION_ERROR, str(e)), content_type="text/plain", status=400) _save_app_state(state, asset_id, None) return HttpResponse('Code received. Please close this window, the action will continue to get new token.', content_type="text/plain") @@ -342,6 +304,7 @@ def __init__(self): self._access_token = None self._refresh_token = None self.asset_id = self.get_asset_id() + self._scope = None def encrypt_state(self, encrypt_var, token_name): """ Handle encryption of token. @@ -397,7 +360,6 @@ def _process_html_response(self, response, action_result): except Exception: error_text = "Cannot parse error details" - error_text = _handle_py_ver_compat_for_input_str(self._python_version, error_text, self) message = "Status Code: {0}. Data from server:\n{1}\n".format(status_code, error_text) @@ -417,20 +379,19 @@ def _process_json_response(self, response, action_result): try: resp_json = response.json() except Exception as e: - error_code, error_msg = _get_error_message_from_exception(self._python_version, e, self) - return RetVal(action_result.set_status(phantom.APP_ERROR, "Unable to parse JSON response. Error Code: {0}. " - "Error Message: {1}".format(error_code, error_msg)), None) + error_text = _get_error_message_from_exception(e, self) + return RetVal(action_result.set_status(phantom.APP_ERROR, "Unable to parse JSON response. {}".format(error_text)), None) # Please specify the status codes here if 200 <= response.status_code < 399: return RetVal(phantom.APP_SUCCESS, resp_json) - error_message = _handle_py_ver_compat_for_input_str(self._python_version, response.text.replace('{', '{{').replace('}', '}}'), self) + error_message = response.text.replace('{', '{{').replace('}', '}}') message = "Error from server. Status Code: {0} Data from server: {1}".format(response.status_code, error_message) # Show only error message if available if isinstance(resp_json.get('error', {}), dict) and resp_json.get('error', {}).get('message'): - error_message = _handle_py_ver_compat_for_input_str(self._python_version, resp_json['error']['message'], self) + error_message = resp_json['error']['message'] message = "Error from server. Status Code: {0} Data from server: {1}".format(response.status_code, error_message) return RetVal(action_result.set_status(phantom.APP_ERROR, message), None) @@ -470,7 +431,7 @@ def _process_response(self, response, action_result): return self._process_empty_response(response, action_result) # everything else is actually an error at this point - error_message = _handle_py_ver_compat_for_input_str(self._python_version, response.text.replace('{', '{{').replace('}', '}}'), self) + error_message = response.text.replace('{', '{{').replace('}', '}}') message = "Can't process response from server. Status Code: {0} Data from server: {1}".format( response.status_code, error_message) @@ -503,7 +464,7 @@ def _update_request(self, action_result, endpoint, headers=None, params=None, da self._tenant = urllib.quote(self._tenant) token_data = { 'client_id': self._client_id, - 'scope': MSTEAMS_REST_REQUEST_SCOPE, + 'scope': self._scope, 'client_secret': self._client_secret, 'grant_type': MSTEAMS_REFRESH_TOKEN_STRING, 'refresh_token': self._refresh_token @@ -527,8 +488,10 @@ def _update_request(self, action_result, endpoint, headers=None, params=None, da ret_val, resp_json = self._make_rest_call(action_result=action_result, endpoint=endpoint, headers=headers, params=params, data=data, method=method) + message = action_result.get_message().lower() + # If token is expired, generate new token - if MSTEAMS_TOKEN_EXPIRED in action_result.get_message(): + if "token" in message and "expired" in message: status = self._generate_new_access_token(action_result=action_result, data=token_data) if phantom.is_fail(status): @@ -567,9 +530,8 @@ def _make_rest_call(self, endpoint, action_result, headers=None, params=None, da try: r = request_func(endpoint, data=data, headers=headers, verify=verify, params=params, timeout=MSTEAMS_DEFAULT_TIMEOUT) except Exception as e: - error_code, error_msg = _get_error_message_from_exception(self._python_version, e, self) - return RetVal(action_result.set_status(phantom.APP_ERROR, "Error connecting to server. Error Code: {0}. " - "Error Message: {1}".format(error_code, error_msg)), resp_json) + error_text = _get_error_message_from_exception(e, self) + return RetVal(action_result.set_status(phantom.APP_ERROR, "Error connecting to server. {}".format(error_text)), resp_json) return self._process_response(r, action_result) @@ -660,14 +622,14 @@ def _generate_new_access_token(self, action_result, data): try: encrypted_access_token = self.encrypt_state(resp_json[MSTEAMS_ACCESS_TOKEN_STRING], "access") except Exception as e: - self.debug_print("{}: {}".format(MSTEAMS_ENCRYPTION_ERR, _get_error_message_from_exception(self._python_version, e, self))) - return action_result.set_status(phantom.APP_ERROR, MSTEAMS_ENCRYPTION_ERR) + self.debug_print("{}: {}".format(MSTEAMS_ENCRYPTION_ERROR, _get_error_message_from_exception(e, self))) + return action_result.set_status(phantom.APP_ERROR, MSTEAMS_ENCRYPTION_ERROR) try: encrypted_refresh_token = self.encrypt_state(resp_json[MSTEAMS_REFRESH_TOKEN_STRING], "refresh") except Exception as e: - self.debug_print("{}: {}".format(MSTEAMS_ENCRYPTION_ERR, _get_error_message_from_exception(self._python_version, e, self))) - return action_result.set_status(phantom.APP_ERROR, MSTEAMS_ENCRYPTION_ERR) + self.debug_print("{}: {}".format(MSTEAMS_ENCRYPTION_ERROR, _get_error_message_from_exception(e, self))) + return action_result.set_status(phantom.APP_ERROR, MSTEAMS_ENCRYPTION_ERROR) resp_json[MSTEAMS_ACCESS_TOKEN_STRING] = encrypted_access_token resp_json[MSTEAMS_REFRESH_TOKEN_STRING] = encrypted_refresh_token @@ -696,8 +658,8 @@ def _generate_new_access_token(self, action_result, data): message += "ownership for the corresponding state file (refer to readme file for more information)." return action_result.set_status(phantom.APP_ERROR, message) except Exception as e: - self.debug_print("{}: {}".format(MSTEAMS_DECRYPTION_ERR, _get_error_message_from_exception(self._python_version, e, self))) - return action_result.set_status(phantom.APP_ERROR, MSTEAMS_DECRYPTION_ERR) + self.debug_print("{}: {}".format(MSTEAMS_DECRYPTION_ERROR, _get_error_message_from_exception(e, self))) + return action_result.set_status(phantom.APP_ERROR, MSTEAMS_DECRYPTION_ERROR) return phantom.APP_SUCCESS @@ -730,7 +692,7 @@ def _handle_test_connectivity(self, param): authorization_url = MSTEAMS_AUTHORIZE_URL.format(tenant_id=self._tenant, client_id=self._client_id, redirect_uri=redirect_uri, state=self.get_asset_id(), response_type='code', - scope=MSTEAMS_REST_REQUEST_SCOPE) + scope=self._scope) authorization_url = '{}{}'.format(MSTEAMS_LOGIN_BASE_URL, authorization_url) app_state['authorization_url'] = authorization_url @@ -766,15 +728,15 @@ def _handle_test_connectivity(self, param): try: current_code = self.decrypt_state(self._state['code'], "code") except Exception as e: - self.debug_print("{}: {}".format(MSTEAMS_DECRYPTION_ERR, _get_error_message_from_exception(self._python_version, e, self))) - return action_result.set_status(phantom.APP_ERROR, MSTEAMS_DECRYPTION_ERR) + self.debug_print("{}: {}".format(MSTEAMS_DECRYPTION_ERROR, _get_error_message_from_exception(e, self))) + return action_result.set_status(phantom.APP_ERROR, MSTEAMS_DECRYPTION_ERROR) self.save_state(self._state) _save_app_state(self._state, self.get_asset_id(), self) self.save_progress(MSTEAMS_GENERATING_ACCESS_TOKEN_MSG) data = { 'client_id': self._client_id, - 'scope': MSTEAMS_REST_REQUEST_SCOPE, + 'scope': self._scope, 'client_secret': self._client_secret, 'grant_type': 'authorization_code', 'redirect_uri': redirect_uri, @@ -951,9 +913,9 @@ def _handle_send_message(self, param): self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) - group_id = _handle_py_ver_compat_for_input_str(self._python_version, param[MSTEAMS_JSON_GROUP_ID], self) - channel_id = _handle_py_ver_compat_for_input_str(self._python_version, param[MSTEAMS_JSON_CHANNEL_ID], self) - message = param[MSTEAMS_JSON_MESSAGE] + group_id = param[MSTEAMS_JSON_GROUP_ID] + channel_id = param[MSTEAMS_JSON_CHANNEL_ID] + message = param[MSTEAMS_JSON_MSG] status = self._verify_parameters(group_id=group_id, channel_id=channel_id, action_result=action_result) @@ -963,7 +925,7 @@ def _handle_send_message(self, param): error_message = error_message.replace('teamId', "'group_id'") return action_result.set_status(phantom.APP_ERROR, error_message) - endpoint = MSTEAMS_MSGRAPH_SEND_MESSAGE_ENDPOINT.format(group_id=group_id, channel_id=channel_id) + endpoint = MSTEAMS_MSGRAPH_SEND_MSG_ENDPOINT.format(group_id=group_id, channel_id=channel_id) data = { "body": { @@ -996,7 +958,7 @@ def _handle_list_channels(self, param): self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) - group_id = _handle_py_ver_compat_for_input_str(self._python_version, param[MSTEAMS_JSON_GROUP_ID], self) + group_id = param[MSTEAMS_JSON_GROUP_ID] endpoint = MSTEAMS_MSGRAPH_LIST_CHANNELS_ENDPOINT.format(group_id=group_id) @@ -1200,7 +1162,7 @@ def initialize(self): if not isinstance(self._state, dict): self.debug_print("Resetting the state file with the default format") self._state = {"app_version": self.get_app_json().get("app_version")} - return self.set_status(phantom.APP_ERROR, MSTEAMS_STATE_FILE_CORRUPT_ERR) + return self.set_status(phantom.APP_ERROR, MSTEAMS_STATE_FILE_CORRUPT_ERROR) # Fetching the Python major version try: @@ -1211,25 +1173,26 @@ def initialize(self): # get the asset config config = self.get_config() - self._tenant = _handle_py_ver_compat_for_input_str(self._python_version, config[MSTEAMS_CONFIG_TENANT_ID], self) - self._client_id = _handle_py_ver_compat_for_input_str(self._python_version, config[MSTEAMS_CONFIG_CLIENT_ID], self) + self._tenant = config[MSTEAMS_CONFIG_TENANT_ID] + self._client_id = config[MSTEAMS_CONFIG_CLIENT_ID] self._client_secret = config[MSTEAMS_CONFIG_CLIENT_SECRET] self._access_token = self._state.get(MSTEAMS_TOKEN_STRING, {}).get(MSTEAMS_ACCESS_TOKEN_STRING) self._refresh_token = self._state.get(MSTEAMS_TOKEN_STRING, {}).get(MSTEAMS_REFRESH_TOKEN_STRING) + self._scope = config[MSTEAMS_CONFIG_SCOPE] if self._state.get(MSTEAMS_STATE_IS_ENCRYPTED): try: if self._access_token: self._access_token = self.decrypt_state(self._access_token, "access") except Exception as e: - self.debug_print("{}: {}".format(MSTEAMS_DECRYPTION_ERR, _get_error_message_from_exception(self._python_version, e, self))) - return self.set_status(phantom.APP_ERROR, MSTEAMS_DECRYPTION_ERR) + self.debug_print("{}: {}".format(MSTEAMS_DECRYPTION_ERROR, _get_error_message_from_exception(e, self))) + return self.set_status(phantom.APP_ERROR, MSTEAMS_DECRYPTION_ERROR) try: if self._refresh_token: self._refresh_token = self.decrypt_state(self._refresh_token, "refresh") except Exception as e: - self.debug_print("{}: {}".format(MSTEAMS_DECRYPTION_ERR, _get_error_message_from_exception(self._python_version, e, self))) - return self.set_status(phantom.APP_ERROR, MSTEAMS_DECRYPTION_ERR) + self.debug_print("{}: {}".format(MSTEAMS_DECRYPTION_ERROR, _get_error_message_from_exception(e, self))) + return self.set_status(phantom.APP_ERROR, MSTEAMS_DECRYPTION_ERROR) self._timezone = config.get(MSTEAMS_CONFIG_TIMEZONE) return phantom.APP_SUCCESS @@ -1245,15 +1208,15 @@ def finalize(self): if self._state.get(MSTEAMS_TOKEN_STRING, {}).get(MSTEAMS_ACCESS_TOKEN_STRING): self._state[MSTEAMS_TOKEN_STRING][MSTEAMS_ACCESS_TOKEN_STRING] = self.encrypt_state(self._access_token, "access") except Exception as e: - self.debug_print("{}: {}".format(MSTEAMS_ENCRYPTION_ERR, self._get_error_message_from_exception(e))) - return self.set_status(phantom.APP_ERROR, MSTEAMS_ENCRYPTION_ERR) + self.debug_print("{}: {}".format(MSTEAMS_ENCRYPTION_ERROR, self._get_error_message_from_exception(e))) + return self.set_status(phantom.APP_ERROR, MSTEAMS_ENCRYPTION_ERROR) try: if self._state.get(MSTEAMS_TOKEN_STRING, {}).get(MSTEAMS_REFRESH_TOKEN_STRING): self._state[MSTEAMS_TOKEN_STRING][MSTEAMS_REFRESH_TOKEN_STRING] = self.encrypt_state(self._refresh_token, "refresh") except Exception as e: - self.debug_print("{}: {}".format(MSTEAMS_ENCRYPTION_ERR, self._get_error_message_from_exception(e))) - return self.set_status(phantom.APP_ERROR, MSTEAMS_ENCRYPTION_ERR) + self.debug_print("{}: {}".format(MSTEAMS_ENCRYPTION_ERROR, self._get_error_message_from_exception(e))) + return self.set_status(phantom.APP_ERROR, MSTEAMS_ENCRYPTION_ERROR) self._state[MSTEAMS_STATE_IS_ENCRYPTED] = True # Save the state, this data is saved across actions and app upgrades self.save_state(self._state) diff --git a/microsoftteams_consts.py b/microsoftteams_consts.py index d054b6b..a5f1531 100644 --- a/microsoftteams_consts.py +++ b/microsoftteams_consts.py @@ -1,6 +1,6 @@ # File: microsoftteams_consts.py # -# Copyright (c) 2019-2022 Splunk Inc. +# Copyright (c) 2019-2023 Splunk Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -26,14 +26,12 @@ MSTEAMS_MSGRAPH_TEAMS_ENDPOINT = '/groups?$filter=resourceProvisioningOptions/Any(x:x eq \'Team\')' MSTEAMS_MSGRAPH_LIST_USERS_ENDPOINT = '/users' MSTEAMS_MSGRAPH_LIST_CHANNELS_ENDPOINT = '/teams/{group_id}/channels' -MSTEAMS_MSGRAPH_SEND_MESSAGE_ENDPOINT = '/teams/{group_id}/channels/{channel_id}/messages' +MSTEAMS_MSGRAPH_SEND_MSG_ENDPOINT = '/teams/{group_id}/channels/{channel_id}/messages' MSTEAMS_MSGRAPH_CALENDER_EVENT_ENDPOINT = '/me/calendar/events' MSTEAMS_MSGRAPH_ONLINE_MEETING_ENDPOINT = '/me/onlineMeetings' MSTEAMS_TC_FILE = 'oauth_task.out' MSTEAMS_TC_STATUS_SLEEP = 3 MSTEAMS_AUTHORIZE_WAIT_TIME = 15 -MSTEAMS_REST_REQUEST_SCOPE = 'offline_access group.readwrite.all user.readwrite.all' -MSTEAMS_TOKEN_EXPIRED = 'Access token has expired' MSTEAMS_TOKEN_NOT_AVAILABLE_MSG = 'Token not available. Please run test connectivity first.' MSTEAMS_BASE_URL_NOT_FOUND_MSG = 'Phantom Base URL not found in System Settings. ' \ 'Please specify this value in System Settings.' @@ -44,9 +42,9 @@ MSTEAMS_ADMIN_CONSENT_PASSED_MSG = 'Admin consent Received' MSTEAMS_AUTHORIZE_USER_MSG = 'Please authorize user in a separate tab using URL' MSTEAMS_AUTHORIZE_WAIT_MSG = 'Waiting for authorization to complete' -MSTEAMS_AUTHORIZE_TROUBLESHOOT_MSG = 'If authorization URL fails to communicate with your Phantom instance, check whether you have: '\ +MSTEAMS_AUTHORIZE_TROUBLESHOOT_MSG = 'If authorization URL fails to communicate with your SOAR instance, check whether you have: '\ ' 1. Specified the Web Redirect URL of your App -- The Redirect URL should be /result . '\ - ' 2. Configured the base URL of your Phantom Instance at Administration -> Company Settings -> Info' + ' 2. Configured the base URL of your SOAR Instance at Administration -> Company Settings -> Info' MSTEAMS_CODE_RECEIVED_MSG = 'Code Received' MSTEAMS_MAKING_CONNECTION_MSG = 'Making Connection...' MSTEAMS_REST_URL_NOT_AVAILABLE_MSG = 'Rest URL not available. Error: {error}' @@ -55,11 +53,11 @@ MSTEAMS_CURRENT_USER_INFO_MSG = 'Getting info about the current user to verify token' MSTEAMS_GOT_CURRENT_USER_INFO_MSG = 'Got current user info' MSTEAMS_INVALID_CHANNEL_MSG = 'Channel {channel_id} does not belongs to group {group_id}' -MSTEAMS_STATE_FILE_CORRUPT_ERR = "Error occurred while loading the state file due to it's unexpected format. " \ +MSTEAMS_STATE_FILE_CORRUPT_ERROR = "Error occurred while loading the state file due to it's unexpected format. " \ "Resetting the state file with the default format. Please test the connectivity." MSTEAMS_JSON_GROUP_ID = 'group_id' MSTEAMS_JSON_CHANNEL_ID = 'channel_id' -MSTEAMS_JSON_MESSAGE = 'message' +MSTEAMS_JSON_MSG = 'message' MSTEAMS_JSON_SUBJECT = 'subject' MSTEAMS_JSON_CALENDAR = 'add_calendar_event' MSTEAMS_JSON_DESCRIPTION = 'description' @@ -74,11 +72,15 @@ MSTEAMS_REFRESH_TOKEN_STRING = 'refresh_token' MSTEAMS_CONFIG_CLIENT_SECRET = 'client_secret' # pragma: allowlist secret MSTEAMS_CONFIG_TIMEZONE = 'timezone' +MSTEAMS_CONFIG_SCOPE = 'scope' MSTEAMS_NEXT_LINK_STRING = '@odata.nextLink' MSTEAMS_DEFAULT_TIMEOUT = 30 # For encryption and decryption MSTEAMS_ENCRYPT_TOKEN = "Encrypting the {} token" MSTEAMS_DECRYPT_TOKEN = "Decrypting the {} token" -MSTEAMS_ENCRYPTION_ERR = "Error occurred while encrypting the state file" -MSTEAMS_DECRYPTION_ERR = "Error occurred while decrypting the state file" +MSTEAMS_ENCRYPTION_ERROR = "Error occurred while encrypting the state file" +MSTEAMS_DECRYPTION_ERROR = "Error occurred while decrypting the state file" + +# Constants relating to '_get_error_message_from_exception' +ERROR_MSG_UNAVAILABLE = "Error message unavailable. Please check the asset configuration and|or action parameters" diff --git a/microsoftteams_display_channels.html b/microsoftteams_display_channels.html index b404354..40173ff 100644 --- a/microsoftteams_display_channels.html +++ b/microsoftteams_display_channels.html @@ -10,7 +10,7 @@ {% block widget_content %} - - - - -

Note

-
    -
  • For an admin user, you can run the test connectivity directly. -
  • For a non-admin user, you need to get the admin consent first. This can be done by running the action get_admin_consent by an admin user. -
-

Authentication

-This app requires creating an app in the Azure Active Directory. -
    -
  • Navigate to the https://portal.azure.com in a browser and log in with a Microsoft account
  • -
  • Select Azure Active Directory from the left side menu
  • -
  • From the left panel, select App Registrations
  • -
  • At the top of the middle section, select New registration
  • -
  • On the next page, give a name to your application and click Register
  • -
  • Once the app is created, the below steps needs to be performed on the next page:
  • -
      -
    • Under Certificates & secrets, select New client secret. Note this key somewhere secure, as it cannot be retrieved after closing the window.
    • -
    • Under Authentication, select Add a platform. In the Add a platform window, select Web. The Redirect - URLs should be filled right here. We will get Redirect URLs from the Phantom asset that we will create below in the section titled "Configure the Microsoft Teams Phantom app asset".
    • -
    • Under API Permissions, the following Delegated Permissions from Microsoft Graph needs to be added: -
        -
      • Group.ReadWrite.All (https://graph.microsoft.com/Group.ReadWrite.All)
      • -
      • offline_access (https://graph.microsoft.com/offline_access)
      • -
      • User.ReadWrite.All (https://graph.microsoft.com/User.ReadWrite.All)
      • -
      • Calendars.ReadWrite (https://graph.microsoft.com/Calendars.ReadWrite)
      • -
      • OnlineMeetings.ReadWrite (https://graph.microsoft.com/OnlineMeetings.ReadWrite)
      • -
      - After making these changes, click Add permissions at the bottom of the screen, then click Grant admin consent for Phantom. -
    -
- -

State file permissions

-

- Please check the permissions for the state file as mentioned below. -

State file path

-
    -
  • For Non-NRI instance: /opt/phantom/local_data/app_states/<appid>/<asset_id>_state.json
  • -
  • For NRI instance: /<PHANTOM_HOME_DIRECTORY>/local_data/app_states/<appid>/<asset_id>_state.json
  • -
-

State file permissions

-
    -
  • File rights: rw-rw-r-- (664) (The phantom user should have read and write access for the state file)
  • -
  • File owner: Appropriate phantom user
  • -
-

- -

Configure the Microsoft Teams Phantom app asset

-When creating an asset for the Microsoft Teams app, place the Application Id of the app in the Client ID field and place the password generated during the app creation process in the Client Secret field. Then, after filling out the Tenant ID field, click SAVE. Both the Application/Client ID and the Tenant ID can be found in the Overview tab on your app's Azure page. -

-After saving, a new field will appear in the Asset Settings tab. Take the URL found in the POST incoming for Microsoft Teams to this location field and place it in the Redirect URLs field mentioned in a previous step. To this URL, add /result. After doing so the URL should look something like: -

-

-https://<phantom_host>/rest/handler/microsoftteams_6ba1906f-5899-44df-bb65-1bee4df8ca3c/<asset_name>/result -

-
-Once again, click Save at the bottom of the screen. -

-Additionally, updating the Base URL in the Phantom Company Settings is also required. Navigate to Administration > Company Settings > Info to configure the Base URL For Phantom Appliance. Then, select Save Changes. -
-

Method to run get admin consent

-Run get_admin_consent action. It will display an URL. Navigate to this URL in a separate browser tab. This new tab will redirect to a Microsoft login page. Log in to a Microsoft account with administrator privileges. After logging in, review the requested permissions listed, then click Accept. Finally, close that tab. Action should show a success message. -

- Note: If the URL is not displayed while running the get_admin_consent action, the user can get the URL from the following ways: -

    -
  • User can find the URL in 'spawn.log' file.
  • -
  • User needs to manually navigate to the URL in a separate browser tab. The URL format is: - https://<phantom_host>/rest/handler/microsoftteams_6ba1906f-5899-44df-bb65-1bee4df8ca3c/<asset_name>/admin_consent?asset_id=<asset_id>
  • -

    Steps to fetch asset id

    -
      -
    • Open the asset on which the action is executed.
    • -
    • URL for the asset will be in the following format:
    • -

      https//<phantom_host>/apps/<app_id>/asset/<asset_id>/

      -
    • Take the asset id from the URL.
    • -
    -
-

- -

Method to run test connectivity

-After setting up the asset and user, click the TEST CONNECTIVITY button. A window should pop up and display a URL. Navigate to this URL in a separate browser tab. This new tab will redirect to a Microsoft login page. Log in to a Microsoft account. After logging in, review the requested permissions listed, then click Accept. Finally, close that tab. The test connectivity window should show a success message. -

-The app should now be ready to be used. - -

Important points to be considered for 'Create Meeting' action

-
    -
  • The timezone configuration parameter will only be used for Create Meeting action, when the user wants to provide start_time and end_time of the meeting.
  • -
  • The timezone parameter can be configured using the timezone of the microsoft teams calender. If not provided, by default the UTC timezone will be considered for scheduling the meetings.
  • -
  • In case of add_calendar_event = true, if the user wants to provide schedule time for the meeting, start_time and end_time both the parameters are required.
  • -
- -

Port Information

-

- The app uses HTTP/HTTPS protocol for communicating with the Microsoft Teams Server. Below are the default ports used by Splunk SOAR. - - - - - - - - - - - - - - - - -
Service NameTransport ProtocolPort
httptcp80
httpstcp443
-

- - diff --git a/release_notes/2.5.0.md b/release_notes/2.5.0.md new file mode 100644 index 0000000..d8bf3ab --- /dev/null +++ b/release_notes/2.5.0.md @@ -0,0 +1,4 @@ +* Added scope as asset configuration parameter +* Updated documentation with minimum required permissions for individual actions +* Removed django and requests in order to use platform packages instead [PAPP-31087, PAPP-31082, PAPP-30822] +* Fixed access_token regeneration issue [PAPP-31959] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 896a5ba..e861161 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1 @@ beautifulsoup4==4.9.1 -Django==3.2.5 -requests==2.25.0 diff --git a/wheels/py3/Django-3.2.5-py3-none-any.whl b/wheels/py3/Django-3.2.5-py3-none-any.whl deleted file mode 100644 index 406b006..0000000 Binary files a/wheels/py3/Django-3.2.5-py3-none-any.whl and /dev/null differ diff --git a/wheels/py3/asgiref-3.4.1-py3-none-any.whl b/wheels/py3/asgiref-3.4.1-py3-none-any.whl deleted file mode 100644 index 238f1dc..0000000 Binary files a/wheels/py3/asgiref-3.4.1-py3-none-any.whl and /dev/null differ diff --git a/wheels/py3/asgiref-3.5.0-py3-none-any.whl b/wheels/py3/asgiref-3.5.0-py3-none-any.whl deleted file mode 100644 index 8157bc2..0000000 Binary files a/wheels/py3/asgiref-3.5.0-py3-none-any.whl and /dev/null differ diff --git a/wheels/py3/soupsieve-2.4.1-py3-none-any.whl b/wheels/py3/soupsieve-2.4.1-py3-none-any.whl new file mode 100644 index 0000000..26a486c Binary files /dev/null and b/wheels/py3/soupsieve-2.4.1-py3-none-any.whl differ diff --git a/wheels/py3/sqlparse-0.4.2-py3-none-any.whl b/wheels/py3/sqlparse-0.4.2-py3-none-any.whl deleted file mode 100644 index 8639d83..0000000 Binary files a/wheels/py3/sqlparse-0.4.2-py3-none-any.whl and /dev/null differ diff --git a/wheels/py3/typing_extensions-4.1.1-py3-none-any.whl b/wheels/py3/typing_extensions-4.1.1-py3-none-any.whl deleted file mode 100644 index 73c3dce..0000000 Binary files a/wheels/py3/typing_extensions-4.1.1-py3-none-any.whl and /dev/null differ diff --git a/wheels/shared/certifi-2021.10.8-py2.py3-none-any.whl b/wheels/shared/certifi-2021.10.8-py2.py3-none-any.whl deleted file mode 100644 index fbcb86b..0000000 Binary files a/wheels/shared/certifi-2021.10.8-py2.py3-none-any.whl and /dev/null differ diff --git a/wheels/shared/chardet-3.0.4-py2.py3-none-any.whl b/wheels/shared/chardet-3.0.4-py2.py3-none-any.whl deleted file mode 100644 index d276977..0000000 Binary files a/wheels/shared/chardet-3.0.4-py2.py3-none-any.whl and /dev/null differ diff --git a/wheels/shared/idna-2.10-py2.py3-none-any.whl b/wheels/shared/idna-2.10-py2.py3-none-any.whl deleted file mode 100644 index 41225cb..0000000 Binary files a/wheels/shared/idna-2.10-py2.py3-none-any.whl and /dev/null differ diff --git a/wheels/shared/pytz-2022.1-py2.py3-none-any.whl b/wheels/shared/pytz-2022.1-py2.py3-none-any.whl deleted file mode 100644 index a0f6378..0000000 Binary files a/wheels/shared/pytz-2022.1-py2.py3-none-any.whl and /dev/null differ diff --git a/wheels/shared/requests-2.25.0-py2.py3-none-any.whl b/wheels/shared/requests-2.25.0-py2.py3-none-any.whl deleted file mode 100644 index c3f28e5..0000000 Binary files a/wheels/shared/requests-2.25.0-py2.py3-none-any.whl and /dev/null differ diff --git a/wheels/shared/urllib3-1.26.9-py2.py3-none-any.whl b/wheels/shared/urllib3-1.26.9-py2.py3-none-any.whl deleted file mode 100644 index 5019453..0000000 Binary files a/wheels/shared/urllib3-1.26.9-py2.py3-none-any.whl and /dev/null differ