Salesforce¶
Table of Contents¶
Release Notes¶
Version |
Date |
Notes |
---|---|---|
1.0.0 |
09/2023 |
Initial Release |
1.0.1 |
01/2024 |
Text Correction |
Overview¶
IBM SOAR app - bidirectional synchronization and functions for Salesforce
Bi-directional App for Salesforce. Query Salesforce for Cases based on user-defined query parameters and create and update cases in SOAR.
Key Features¶
Poll Salesforce cases and create and update the corresponding cases in SOAR
Set the Salesforce cases Status (and other case fields) from the corresponding case in SOAR
Create cases in SOAR based on user define Salesforce case field polling filters and case record type names
Create a case in Salesforce from a (non-Salesforce case) in SOAR
Create a case in Salesforce manually from SOAR with user specified case data
Synchronize case tasks between a Salesforce case and the corresponding SOAR case
Synchronize case attachments between Salesforce case and corresponding SOAR case
Synchronize case comments between Salesforce case and corresponding SOAR case
Requirements¶
This app supports the IBM Security QRadar SOAR Platform and the IBM Security QRadar SOAR for IBM Cloud Pak for Security.
SOAR platform¶
The SOAR platform supports two app deployment mechanisms, Edge Gateway (formerly App Host) and integration server.
If deploying to a SOAR platform with an Edge Gateway, the requirements are:
SOAR platform >=
46.0.8131
.The app is in a container-based format (available from the AppExchange as a
zip
file).
If deploying to a SOAR platform with an integration server, the requirements are:
SOAR platform >=
46.0.8131
.The app is in the older integration format (available from the AppExchange as a
zip
file which contains atar.gz
file).Integration server is running
resilient-circuits>=49.0.0
.If using an API key account, make sure the account provides the following minimum permissions:
Name
Permissions
Org Data
Read
Function
Read
Incidents
Read, Create
Edit Incidents
Fields, Status
Layouts
Read, Edit
The following SOAR platform guides provide additional information:
Edge Gateway Deployment Guide or App Host Deployment Guide: provides installation, configuration, and troubleshooting information, including proxy server settings.
Integration Server Guide: provides installation, configuration, and troubleshooting information, including proxy server settings.
System Administrator Guide: provides the procedure to install, configure and deploy apps.
The above guides are available on the IBM Documentation website at ibm.biz/soar-docs. On this web page, select your SOAR platform version. On the follow-on page, you can find the Edge Gateway Deployment Guide, App Host Deployment Guide, or Integration Server Guide by expanding Apps in the Table of Contents pane. The System Administrator Guide is available by expanding System Administrator.
Cloud Pak for Security¶
If you are deploying to IBM Cloud Pak for Security, the requirements are:
IBM Cloud Pak for Security >=
1.8
.Cloud Pak is configured with an Edge Gateway.
The app is in a container-based format (available from the AppExchange as a
zip
file).
The following Cloud Pak guides provide additional information:
Edge Gateway Deployment Guide or App Host Deployment Guide: provides installation, configuration, and troubleshooting information, including proxy server settings. From the Table of Contents, select Case Management and Orchestration & Automation > Orchestration and Automation Apps.
System Administrator Guide: provides information to install, configure, and deploy apps. From the IBM Cloud Pak for Security IBM Documentation table of contents, select Case Management and Orchestration & Automation > System administrator.
These guides are available on the IBM Documentation website at ibm.biz/cp4s-docs. From this web page, select your IBM Cloud Pak for Security version. From the version-specific IBM Documentation page, select Case Management and Orchestration & Automation.
Proxy Server¶
The app does support a proxy server.
Python Environment¶
Python 3.6 and Python 3.9 are supported. Additional package dependencies may exist for each of these packages:
resilient-circuits>=49.0.0
Salesforce Development Version¶
This app has been implemented using:
Product Name |
Product Version |
API URL |
API Version |
---|---|---|---|
Salesforce |
N/A |
58.0 |
Salesforce Configuration¶
Create a Connected App in Salesforce¶
To run the IBM QRadar SOAR app for Salesforce, first create a Connected App in Salesforce. Navigate to the App Manager
in Salesforce from the Service Setup
page and search for App Manager
:
Click on the New Connected App
button in the upper right hand corner:
Fill in the required Basic Information
with a Connected App Name that identifies that App as a Salesforce App for IBM QRadar SOAR.
Under API (Enable OAuth Settings)
check the Enable OAuth Settings
checkbox and fill in the information as shown below.
Callback URL: https://login.salesforce.com/services/oauth2/callback
In
Selected OAuth Scopes
section select:Access Connect REST API resources (chatter_api)
Manage user data via APIs (api)
Check checkboxes:
Required Secret for Web Server Flow
Require Secret for Refresh Token Flow
Enable Client Credential Flow
Enable Authorization Code and Credentials Flow
Hit the
Save
button at the bottom of the screen
Once the Connected App is created, you can View
the Connected App from the App Manager
page:
Get the Consumer Key
and Consumer Secret
by hitting the Manage Consumer Details
button:
Use the Consumer Key and Secret in the app.config settings consumer_key
and consumer_secret
.
Select an execution user for Client Credential Flow¶
Although there’s no user interaction in the client credentials flow, Salesforce still requires you to specify an execution user. By selecting an execution user, you allow Salesforce to return access tokens on behalf of this user.
From the connected app detail page, click
Manage
.Click
Edit Policies
.Under
Client Credentials Flow
, forRun As
, click Magnifying glass icon, and find the user that you want to assign the client credentials flow. For Enterprise Edition orgs, Salesforce recommends that you select an execution user who has the API Only User permission.Save your changes.
Installation¶
Install¶
To install or uninstall an App or Integration on the SOAR platform, see the documentation at ibm.biz/soar-docs.
To install or uninstall an App on IBM Cloud Pak for Security, see the documentation at ibm.biz/cp4s-docs and follow the instructions above to navigate to Orchestration and Automation.
App Configuration¶
The following table provides the settings you need to configure the app. These settings are made in the app.config file. See the documentation discussed in the Requirements section for the procedure.
Config |
Required |
Example |
Description |
---|---|---|---|
api_version |
Yes |
|
Salesforce REST API version |
case_fields_to_query |
No |
|
Case field names values to return from each polling interval query of Salesforce cases. Add Salesforce custom fields to the comma separated list if you want the values to map to SOAR cases |
consumer_key |
Yes |
|
Consumer Key of a Salesforce Connected App |
consumer_secret |
Yes |
|
Consumer Secret of a Salesforce Connected App |
my_domain_name |
Yes |
|
My Domain Name defined in My Domain Settings page in Salesforce Setup |
my_domain_url |
Yes |
|
My Domain URL defined in My Domain Settings page in Salesforce Setup |
polling_filters |
Yes |
|
Query filters: Comma separated tuples (“field”,”operator”,”value”) where “field” is a case field name |
polling_interval |
Yes |
|
Poller interval time in seconds. Value of zero to turn poller off. |
polling_lookback |
Yes |
|
Number of minutes to poller looks back for Salesforce cases. Value is only used on the first time polling when the app starts. |
polling_record_type_names |
No |
|
Case record type names the poller queries each polling interval. If not set all case record types are queried |
verify |
No |
|
Boolean indicating whether to verify the Salesforce client certificate. |
soar_create_case_template |
No |
|
Path to override template for automatic case creation. See Poller Considerations. |
soar_update_case_template |
No |
|
Path to override template for automatic case updating. See Poller Considerations. |
soar_close_case_template |
No |
|
Path to override template for automatic case closing. See Poller Considerations. |
Get the my_domain_name
and my_domain_url
from the My Domain Settings
page under Company Settings
:
Custom Layouts¶
The app automatically creates a custom Salesforce tab on first install:
The Salesforce platform is highly customizable. If custom fields are created and used in Salesforce cases, corresponding custom fields can be created in SOAR and you can drag them onto the Salesforce tab layout.
Poller Considerations¶
The poller is just one way to escalate Salesforce cases to SOAR cases. It’s also possible to send Salesforce information to a SIEM, such as IBM QRadar, which would then correlate cases into Offenses. With the QRadar Plugin for SOAR, offenses can then be escalated to SOAR cases. As long as the Salesforce Case ID is preserved in the custom case field salesforce_case_id
, then all the remaining details about the case synchronize to the SOAR case. In the case of the QRadar Plugin for SOAR, you would modify the escalation templates to reference this custom field with the Salesforce Case ID.
When using another source of Salesforce case escalation to IBM SOAR, disable the poller by changing the app.config setting to poller_interval=0
.
Poller Templates for SOAR Cases¶
It may be necessary to modify the templates used to create, update, or close SOAR cases based on your required custom fields in SOAR.
This is especially relevant if you have required custom close fields that need to be filled when closing a case in SOAR. If that is the case, be sure to implement a custom close_case_template
and reference those required close fields in the template.
When overriding the template in App Host, specify the file path for each file as /var/rescircuits
.
Below are the default templates used which can be copied, modified, and used with app_config’s
soar_create_case_template
, soar_update_case_template
, and soar_close_case_template
settings to override the default templates.
Case Fields Returned from Query and Case Update Limits¶
Salesforce case fields are mapped into a corresponding SOAR case as SOAR case fields, custom fields and artifacts using jinja templates. The app uses Salesforce Object Query Language (SOQL) to query for new or updated cases that need to be created or updated in SOAR.
By default, the app uses an SOQL SELECT FIELDS(ALL)
clause that allows for all fields of a case to be returned in a query and jinja templates can then be used to apply the mapping. However, use of this clause has a hard LIMIT of 200 cases that can be returned in a single REST API query to Salesforce. If the polling_interval
can be set to a reasonable value, where it is known that the results returned are 200 or less, then using this query method may be easiest and preferred.
A second method of querying cases is also provided. If the case fields are explicitly listed in the SOQL SELECT
clause query, then the Salesforce REST API query uses pagination to return all cases matching the search criteria. Define the case_fields_to_query
parameter in the app.config if you have large data sets returned from the polling interval query and you need them all processed. In the app.config file define case_fields_to_query
as a comma separate list of all case field names used in the jinja templates. The app.config file contains a default list of fields in the comments. Uncomment and add or remove from this list if you use other fields or custom fields in your custom jinja templates.
Case Filtering¶
The Salesforce app uses Salesforce Object Query Language (SOQL) to query for new or updated cases that need to be created or updated in SOAR. Additional query clauses can be added to the SQOL query statement to limit the Salesforce cases escalated to SOAR, by using the optional polling_filter
parameter in the app configuration file. Each filter is a tuple in the following format: (“field”,”operator”,”value”),
Where:
“field” is the Salesforce Case field to be queried
“operator” is a string operator performed in query
“value” is the value to be compared against in the query
If more than one filter is needed, separate each tuple with a comma. Enclose string values in quotes. Escaped single quotes are required in some SOQL query strings.
Here is a polling filter example that adds or updates cases that have a "Priority" equal to 'High':
polling_filters=("Priority","=","\'High\'")
This polling filter example adds or updates cases that are Closed and have a “CreatedDate” equal to “YESTERDAY”:
polling_filters=("IsClosed","=","true"),("CreatedDate","=","YESTERDAY")
This polling filter example adds or updates cases that have a case Status of ‘New’, ‘Working’ or ‘In Progress’:
polling_filters=("Status","IN",["\'New\'","\'Working\'","\'In Progress\'"])
The list of SOQL supported operators
:
Operator |
Name |
Description |
---|---|---|
= |
Equals |
Expression is true if the value in the fieldName equals the value in the expression. |
!= |
Not equals |
Expression is true if the value in the fieldName doesn’t equal the specified value. |
< |
Less than |
Expression is true if the value in the fieldName is less than the specified value. |
<= |
Less or equal |
Expression is true if the value in the fieldName is less than or equal to the specified value. |
> |
Greater than |
Expression is true if the value in the fieldName is greater than the specified value. |
>= |
Greater or equal |
Expression is true if the value in the fieldName is greater than or equal to the specified value. |
LIKE |
Like |
Expression is true if the value in the fieldName matches the characters of the text string in the specified value. The text string in the specified value must be enclosed in single quotes. |
IN |
IN |
If the value equals any one of the values in a WHERE clause. The string values for IN must be in parentheses and surrounded by single quotes. |
NOT IN |
NOT IN |
If the value doesn’t equal any of the values in a WHERE clause. The string values for NOT IN must be in parentheses and surrounded by single quotes. |
INCLUDES EXCLUDES |
Applies only to multi-select picklists. See Query Multi-Select Picklists in Salesforce documentation. |
Salesforce Case Record Types¶
Consider using Case Record Types for security cases that are escalated from Salesforce to SOAR. The case Record Type Names can be specified in the app.config file polling_record_type_names
parameter so that the poller queries only those record types in the platform. If this parameter is not specified, all case record types are searched each polling interval.
See the Salesforce documentation for information on creating Support Processes and Case Record Types.
Salesforce Case Type Picklist¶
It is recommended that Case Type
field picklist values be updated in Salesforce to include the QRadar SOAR case types which are:
Communication error (fax; email)
Customization Packages (internal)
Denial of Service
Improper disposal: digital assets
Improper disposal: documents / files / records
Lost documents / files / records
Lost PC / laptop / tablet
Lost storage device / media
Malware
Not an Issue
Other
Phishing
Stolen documents / files / records
Stolen PC / laptop / tablet
Stolen PDA / smartphone
Stolen storage device / media
System Intrusion
TBD / Unknown
Vendor / 3rd party error
Any custom incident types created in SOAR can be also be added to the Case Type Picklist values in Salesforce.
Function - Salesforce: Add Comment to Salesforce Case¶
Add a comment to a Salesforce case.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
Yes |
|
- |
|
|
Yes |
|
- |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": true,
"inputs": {
"salesforce_case_id": "500Hr00001X8WykIAF",
"salesforce_comment_text": "Created by IBM SOAR: Case 2357 created in IBM SOAR"
},
"metrics": {
"execution_time_ms": 1824,
"host": "MacBook-Pro.local",
"package": "fn-salesforce",
"package_version": "1.0.0",
"timestamp": "2023-07-18 15:29:53",
"version": "1.0"
},
"raw": null,
"reason": null,
"success": true,
"version": 2.0
}
Example Function Input Script:
inputs.salesforce_case_id = incident.properties.salesforce_case_id
results = playbook.functions.results.salesforce_case_results
inputs.salesforce_comment_text = "This Salesforce case created from SOAR case {0} URL: {1}".format(incident.id, playbook.functions.results.salesforce_case_results.content.salesforce_case.soar_case_url)
Example Function Post Process Script:
None
Function - Salesforce: Create Case in Salesforce¶
Create a Salesforce case in Salesforce using the specified JSON case data.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
No |
|
- |
|
|
Yes |
|
- |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": {
"salesforce_case": {
"errors": [],
"id": "500Hr00001X906jIAB",
"success": true
}
},
"inputs": {
"salesforce_case_data": "{\"Origin\": \"Web\", \"Status\": \"In Progress\", \"Description\": \"My Description\", \"Subject\": \"My Subject testing\", \"Reason\": \"Installation\"}"
},
"metrics": {
"execution_time_ms": 12850,
"host": "MacBook-Pro.local",
"package": "fn-salesforce",
"package_version": "1.0.0",
"timestamp": "2023-07-20 11:18:51",
"version": "1.0"
},
"raw": null,
"reason": null,
"success": true,
"version": 2.0
}
Example Function Input Script:
import json
case_json = {}
case_json['Origin'] = "Web"
if playbook.inputs.salesforce_case_status:
case_json['Status'] = playbook.inputs.salesforce_case_status
else:
case_json['Status'] = "New"
if playbook.inputs.salesforce_case_type:
case_json['Type'] = playbook.inputs.salesforce_case_type
if playbook.inputs.salesforce_case_description:
case_json['Description'] = playbook.inputs.salesforce_case_description
if playbook.inputs.salesforce_case_subject:
case_json['Subject'] = playbook.inputs.salesforce_case_subject
if playbook.inputs.salesforce_case_internal_comments:
case_json['Comments'] = playbook.inputs.salesforce_case_internal_comments
if incident.properties.salesforce_account_id and incident.properties.salesforce_account_id.lower() != "none":
case_json['AccountId'] = incident.properties.salesforce_account_id
if incident.properties.salesforce_owner_id and incident.properties.salesforce_owner_id.lower() != "none":
case_json['OwnerId'] = incident.properties.salesforce_owner_id
if incident.properties.salesforce_contact_id and incident.properties.salesforce_contact_id.lower() != "none":
case_json['ContactId'] = incident.properties.salesforce_contact_id
inputs.salesforce_case_payload = json.dumps(case_json)
inputs.incident_id = incident.id
Example Function Post Process Script:
results = playbook.functions.results.create_salesforce_case_results
content = results.get("content")
salesforce_case = content.get("salesforce_case")
if results.success:
note_text = "<b>Salesforce: Create Case in Salesforce</b> created Case with CaseId: {}".format(salesforce_case.get("id", None))
if salesforce_case.get("entity_url", None):
note_text = note_text + " <a target='_blank' href='{0}'>Link</a>".format(salesforce_case.get("entity_url"))
else:
note_text = "<b>Salesforce: Create Case in Salesforce</b> failed:<br>{}".format(salesforce_case.get("error", None))
incident.addNote(note_text)
Function - Salesforce: Create Task in Salesforce Case¶
Create a SOAR task in a Salesforce case.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
No |
|
- |
|
|
Yes |
|
- |
|
|
Yes |
|
task data in json format converted to a string |
|
|
No |
|
- |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": {
"salesforce_task": {
"errors": [],
"id": "00THr00008eYnBkMAK",
"success": true
}
},
"inputs": {
"incident_id": 2108,
"salesforce_case_id": "500Hr00001Wthb4IAB",
"salesforce_task_data": "{\"WhatId\": \"500Hr00001Wthb4IAB\", \"Description\": \"Task from IBM SOAR case\", \"Subject\": \"Investigate Exposure of Personal Information/Data\", \"Priority\": \"Normal\", \"Status\": \"In Progress\"}",
"task_id": 14
},
"metrics": {
"execution_time_ms": 7112,
"host": "MacBook-Pro.local",
"package": "fn-salesforce",
"package_version": "1.0.0",
"timestamp": "2023-08-02 17:17:32",
"version": "1.0"
},
"raw": null,
"reason": null,
"success": true,
"version": 2.0
}
Example Function Input Script:
import json
inputs.incident_id = incident.id
inputs.task_id = task.id
inputs.salesforce_case_id = incident.properties.salesforce_case_id
task_json = {}
task_json['WhatId'] = inputs.salesforce_case_id
description = "Task from IBM SOAR case {}".format(incident.id)
if task.instructions:
description = description + ": {}".format(task.instructions.content)
task_json['Description'] = description
if task.due_date:
task_json['ActivityDate'] = task.due_date
if task.name:
task_json['Subject'] = task.name
if playbook.inputs.task_priority:
task_json['Priority'] = playbook.inputs.task_priority
if playbook.inputs.task_status:
task_json['Status'] = playbook.inputs.task_status
inputs.salesforce_task_payload = json.dumps(task_json)
Example Function Post Process Script:
results = playbook.functions.results.create_task_results
content = results.get("content")
salesforce_task = content.get("salesforce_task")
if results.success:
note_text = "<b>Salesforce: Create Task in Salesforce</b> created with TaskId: {}".format(salesforce_task.get("id", None))
else:
note_text = "<b>Salesforce: Create Task in Salesforce</b> failed:<br>{}".format(salesforce_task.get("error", None))
incident.addNote(note_text)
Function - Salesforce: Get Account¶
Get the Salesforce account information for the specified Salesforce AccountId.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
Yes |
|
- |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": {
"salesforce_account": {
"AccountNumber": null,
"AccountSource": null,
"Active__c": null,
"AnnualRevenue": null,
"BillingAddress": null,
"BillingCity": null,
"BillingCountry": null,
"BillingGeocodeAccuracy": null,
"BillingLatitude": null,
"BillingLongitude": null,
"BillingPostalCode": null,
"BillingState": null,
"BillingStreet": null,
"CreatedById": "005Hr00000COneZIAT",
"CreatedDate": "2023-06-16T18:28:22.000+0000",
"CustomerPriority__c": null,
"DandbCompanyId": null,
"Description": null,
"DunsNumber": null,
"Fax": null,
"Id": "001Hr00001kFBihIAG",
"Industry": null,
"IsDeleted": false,
"Jigsaw": null,
"JigsawCompanyId": null,
"LastActivityDate": null,
"LastModifiedById": "005Hr00000COneZIAT",
"LastModifiedDate": "2023-06-16T18:28:22.000+0000",
"LastReferencedDate": "2023-07-17T19:04:52.000+0000",
"LastViewedDate": "2023-07-17T19:04:52.000+0000",
"MasterRecordId": null,
"NaicsCode": null,
"NaicsDesc": null,
"Name": "IBM SOAR",
"NumberOfEmployees": null,
"NumberofLocations__c": null,
"OwnerId": "005Hr00000COneZIAT",
"Ownership": null,
"ParentId": null,
"Phone": null,
"PhotoUrl": null,
"Rating": "Hot",
"SLAExpirationDate__c": null,
"SLASerialNumber__c": null,
"SLA__c": null,
"ShippingAddress": null,
"ShippingCity": null,
"ShippingCountry": null,
"ShippingGeocodeAccuracy": null,
"ShippingLatitude": null,
"ShippingLongitude": null,
"ShippingPostalCode": null,
"ShippingState": null,
"ShippingStreet": null,
"Sic": null,
"SicDesc": null,
"Site": null,
"SystemModstamp": "2023-06-16T18:28:22.000+0000",
"TickerSymbol": null,
"Tradestyle": null,
"Type": null,
"UpsellOpportunity__c": null,
"Website": null,
"YearStarted": null,
"attributes": {
"type": "Account",
"url": "/services/data/v58.0/sobjects/Account/001Hr00001kFBihIAG"
}
}
},
"inputs": {
"salesforce_account_id": "001Hr00001kFBihIAG"
},
"metrics": {
"execution_time_ms": 262,
"host": "MacBook-Pro.local",
"package": "fn-salesforce",
"package_version": "1.0.0",
"timestamp": "2023-07-17 15:08:09",
"version": "1.0"
},
"raw": null,
"reason": null,
"success": true,
"version": 2.0
}
Example Function Input Script:
inputs.salesforce_account_id = incident.properties.salesforce_account_id
Example Function Post Process Script:
results = playbook.functions.results.account_details
if results.success:
content = results.get("content", {})
if content:
account = content.get("salesforce_account", None)
if account:
incident.properties.salesforce_account_name = account.get("Name", None)
else:
incident.addNote("Salesforce: unable to get account details for Account Id ")
Function - Salesforce: Get Attachments from Salesforce¶
Get attachments associated with a Salesforce case and add the attachments in the corresponding SOAR case.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
No |
|
- |
|
|
Yes |
|
- |
|
|
No |
|
- |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": {
"salesforce_attachments": [
"test.txt"
]
},
"inputs": {
"incident_id": 2522,
"salesforce_case_id": "500Hr00001X98NnIAJ",
"task_id": null
},
"metrics": {
"execution_time_ms": 6912,
"host": "MacBook-Pro.local",
"package": "fn-salesforce",
"package_version": "1.0.0",
"timestamp": "2023-07-25 12:50:08",
"version": "1.0"
},
"raw": null,
"reason": null,
"success": true,
"version": 2.0
}
Example Function Input Script:
inputs.incident_id = incident.id
inputs.task_id = None
inputs.salesforce_case_id = incident.properties.salesforce_case_id
Example Function Post Process Script:
results = playbook.functions.results.get_attachments_results
if results.success:
salesforce_attachments = results.content.salesforce_attachments
note_text = "<b>Salesforce: Get Attachments:</b> added {} attachments to incident:<br>".format(len(salesforce_attachments))
for attachment_name in salesforce_attachments:
note_text = note_text + "<br>{}".format(attachment_name)
else:
note_text = "<b>Salesforce: Get Attachments</b> failed to get attachments from Salesforce."
incident.addNote(note_text)
Function - Salesforce: Get Case¶
Get Case information from a specified Salesforce CaseId.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
Yes |
|
- |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": {
"salesforce_case": {
"AccountId": "001Hr00001kFBihIAG",
"AssetId": null,
"CaseNumber": "00001064",
"ClosedDate": null,
"Comments": null,
"ContactEmail": null,
"ContactFax": null,
"ContactId": null,
"ContactMobile": null,
"ContactPhone": null,
"CreatedById": "005Hr00000COneZIAT",
"CreatedDate": "2023-07-07T21:40:12.000+0000",
"Description": "Testing SOAR poller for new cases",
"EngineeringReqNumber__c": null,
"Id": "500Hr00001VhyicIAB",
"IsClosed": false,
"IsDeleted": false,
"IsEscalated": false,
"LastModifiedById": "005Hr00000COneZIAT",
"LastModifiedDate": "2023-07-17T19:04:23.000+0000",
"LastReferencedDate": "2023-07-17T19:04:39.000+0000",
"LastViewedDate": "2023-07-17T19:04:39.000+0000",
"MasterRecordId": null,
"Origin": "Web",
"OwnerId": "005Hr00000COneZIAT",
"ParentId": null,
"PotentialLiability__c": null,
"Priority": "Medium",
"Product__c": null,
"Reason": "Equipment Complexity",
"SLAViolation__c": null,
"Status": "New",
"Subject": "SOAR Test Case",
"SuppliedCompany": null,
"SuppliedEmail": "user@qradar.dev",
"SuppliedName": null,
"SuppliedPhone": "444-444-4444",
"SystemModstamp": "2023-07-17T19:04:23.000+0000",
"Type": "Mechanical",
"attributes": {
"type": "Case",
"url": "/services/data/v58.0/sobjects/Case/500Hr00001VhyicIAB"
},
"entity_url": "https://dev-ed.develop.lightning.force.com/lightning/r/Case/500Hr00001VhyicIAB/view"
}
},
"inputs": {
"salesforce_case_id": "500Hr00001VhyicIAB"
},
"metrics": {
"execution_time_ms": 265,
"host": "MacBook-Pro.local",
"package": "fn-salesforce",
"package_version": "1.0.0",
"timestamp": "2023-07-17 15:07:07",
"version": "1.0"
},
"raw": null,
"reason": null,
"success": true,
"version": 2.0
}
Example Function Input Script:
inputs.salesforce_case_id = incident.properties.salesforce_case_id
Example Function Post Process Script:
results = playbook.functions.results.salesforce_case_results
TYPE_LOOKUP = {
'None': "TBD / Unknown",
'Communication error (fax; email)' : 'Communication error (fax; email)',
'Customization Packages (internal)': 'Customization Packages (internal)',
'Denial of Service': 'Denial of Service',
'Improper disposal: digital assets': 'Improper disposal: digital assets',
'Improper disposal: documents / files / records': 'Improper disposal: documents / files / records',
'Lost documents / files / records': 'Lost documents / files / records',
'Lost PC / laptop / tablet': 'Lost PC / laptop / tablet',
'Lost storage device / media': 'Lost storage device / media',
'Malware': 'Malware',
'Not an Issue': 'Not an Issue',
'Other': 'Other',
'Phishing': 'Phishing',
'Stolen documents / files / records':'Stolen documents / files / records',
'Stolen PC / laptop / tablet': 'Stolen PC / laptop / tablet',
'Stolen PDA / smartphone': 'Stolen PDA / smartphone',
'Stolen storage device / media': 'Stolen storage device / media',
'System Intrusion': 'System Intrusion',
'TBD / Unknown': 'TBD / Unknown',
'Vendor / 3rd party error': 'Vendor / 3rd party error'
}
if not results.success:
incident.addNote("Salesforce: Update custom fields: Unable to get case data to update custom fields.")
else:
content = results.get("content", {})
sf_case =content.get("salesforce_case")
incident.properties.salesforce_account_id = sf_case.get("AccountId")
incident.properties.salesforce_contact_id = sf_case.get("ContactId")
incident.properties.salesforce_owner_id = sf_case.get("OwnerId")
incident.properties.salesforce_case_number = sf_case.get("CaseNumber")
incident.properties.salesforce_case_type = TYPE_LOOKUP.get(sf_case.get("Type"), "None")
incident.properties.salesforce_contact_phone = sf_case.get("ContactPhone")
incident.properties.salesforce_contact_email = sf_case.get("ContactEmail")
incident.properties.salesforce_contact_fax = sf_case.get("ContactFax")
incident.properties.salesforce_supplied_name = sf_case.get("SuppliedName")
incident.properties.salesforce_supplied_phone = sf_case.get("SuppliedPhone")
incident.properties.salesforce_supplied_email = sf_case.get("SuppliedEmail")
incident.properties.salesforce_supplied_company = sf_case.get("SuppliedCompany")
incident.properties.salesforce_origin = sf_case.get("Origin")
incident.properties.salesforce_status = sf_case.get("Status")
entity_url = sf_case.get("entity_url", None)
if entity_url:
incident.properties.salesforce_case_link = "<a target='_blank' href='{0}'>{1}</a>".format(entity_url, sf_case.get("CaseNumber"))
# Add Salesforce case Comments as a note
sf_case_comments = sf_case.get("Comments", None)
if sf_case_comments:
incident.addNote(helper.createRichText("<b>Created by Salesforce:</b><br> {}".format(sf_case_comments)))
Function - Salesforce: Get Case Comments¶
Get the comments from the Salesforce case.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
No |
|
- |
|
|
Yes |
|
- |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": {
"count": 1
},
"inputs": {
"incident_id": 2312,
"salesforce_case_id": "500Hr00001VhyicIAB"
},
"metrics": {
"execution_time_ms": 4220,
"host": "MacBook-Pro.local",
"package": "fn-salesforce",
"package_version": "1.0.0",
"timestamp": "2023-07-17 15:09:28",
"version": "1.0"
},
"raw": null,
"reason": null,
"success": true,
"version": 2.0
}
Example Function Input Script:
inputs.incident_id = incident.id
inputs.salesforce_case_id = incident.properties.salesforce_case_id
Example Function Post Process Script:
results = playbook.functions.results.get_comment_results
if results.success:
incident.addNote("Salesforce: automatic playbook added {} notes from Salesforce".format(results.content.count))
else:
incident.addNote("Salesforce: ERROR in automatic playbook to get Salesforce case comments - function not successful.")
Function - Salesforce: Get Contact¶
Get the detailed information on the specified Salesforce Contact, give the ContactId.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
Yes |
|
- |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": {
"salesforce_contact": {
"AccountId": null,
"AssistantName": null,
"AssistantPhone": null,
"Birthdate": null,
"CreatedById": "005Hr00000COneZIAT",
"CreatedDate": "2023-06-16T18:29:41.000+0000",
"Department": null,
"Description": null,
"Email": null,
"EmailBouncedDate": null,
"EmailBouncedReason": null,
"Fax": null,
"FirstName": "John",
"HomePhone": null,
"Id": "003Hr00002REwc8IAD",
"IndividualId": null,
"IsDeleted": false,
"IsEmailBounced": false,
"Jigsaw": null,
"JigsawContactId": null,
"Languages__c": null,
"LastActivityDate": null,
"LastCURequestDate": null,
"LastCUUpdateDate": null,
"LastModifiedById": "005Hr00000COneZIAT",
"LastModifiedDate": "2023-06-16T18:29:41.000+0000",
"LastName": "Doe",
"LastReferencedDate": "2023-07-17T18:58:39.000+0000",
"LastViewedDate": "2023-07-17T18:58:39.000+0000",
"LeadSource": null,
"Level__c": null,
"MailingAddress": null,
"MailingCity": null,
"MailingCountry": null,
"MailingGeocodeAccuracy": null,
"MailingLatitude": null,
"MailingLongitude": null,
"MailingPostalCode": null,
"MailingState": null,
"MailingStreet": null,
"MasterRecordId": null,
"MobilePhone": null,
"Name": "John Doe",
"OtherAddress": null,
"OtherCity": null,
"OtherCountry": null,
"OtherGeocodeAccuracy": null,
"OtherLatitude": null,
"OtherLongitude": null,
"OtherPhone": null,
"OtherPostalCode": null,
"OtherState": null,
"OtherStreet": null,
"OwnerId": "005Hr00000COneZIAT",
"Phone": null,
"PhotoUrl": null,
"ReportsToId": null,
"Salutation": "Mr.",
"SystemModstamp": "2023-06-16T18:29:41.000+0000",
"Title": null,
"attributes": {
"type": "Contact",
"url": "/services/data/v58.0/sobjects/Contact/003Hr00002REwc8IAD"
}
}
},
"inputs": {
"salesforce_contact_id": "003Hr00002REwc8IAD"
},
"metrics": {
"execution_time_ms": 308,
"host": "MacBook-Pro.local",
"package": "fn-salesforce",
"package_version": "1.0.0",
"timestamp": "2023-07-17 15:04:52",
"version": "1.0"
},
"raw": null,
"reason": null,
"success": true,
"version": 2.0
}
Example Function Input Script:
inputs.salesforce_contact_id = incident.properties.salesforce_contact_id if incident.properties.salesforce_contact_id else helper.fail("Error: ContactId is None")
Example Function Post Process Script:
import json
results = playbook.functions.results.contact_results
if results.success:
content = results.get("content", {})
contact = content.get("salesforce_contact", {})
note_text = "Contact Details: <br>{0}".format(json.dumps(contact, indent=4))
incident.addNote(helper.createRichText(note_text))
else:
incident.addNote("Unable to get Contact details from Salesforce.")
Function - Salesforce: Get User¶
Get the detailed information of a Salesforce User, given the UserId.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
Yes |
|
- |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": {
"salesforce_user": {
"AboutMe": null,
"AccountId": null,
"Address": null,
"Alias": "anorc",
"BadgeText": "",
"BannerPhotoUrl": "/profilephoto/005/B",
"CallCenterId": null,
"City": null,
"CommunityNickname": "User1686331325735812",
"CompanyName": null,
"ContactId": null,
"Country": null,
"CreatedById": "005Hr00000COnUsIAL",
"CreatedDate": "2023-06-09T17:22:47.000+0000",
"DefaultGroupNotificationFrequency": "D",
"DelegatedApproverId": null,
"Department": null,
"DigestFrequency": "D",
"Division": null,
"Email": "user@example.com",
"EmailEncodingKey": "UTF-8",
"EmailPreferencesAutoBcc": true,
"EmailPreferencesAutoBccStayInTouch": false,
"EmailPreferencesStayInTouchReminder": true,
"EmployeeNumber": null,
"Extension": null,
"Fax": null,
"FederationIdentifier": null,
"FirstName": "Joe",
"ForecastEnabled": false,
"FullPhotoUrl": "https://ibmc4s-qradar-dev-dev-ed.develop.file.force.com/profilephoto/005/F",
"GeocodeAccuracy": null,
"Id": "005Hr00000COneZIAT",
"IndividualId": null,
"IsActive": true,
"IsExtIndicatorVisible": false,
"IsProfilePhotoActive": false,
"JigsawImportLimitOverride": 300,
"LanguageLocaleKey": "en_US",
"LastLoginDate": "2023-07-18T20:46:26.000+0000",
"LastModifiedById": "005Hr00000COneZIAT",
"LastModifiedDate": "2023-07-11T18:40:31.000+0000",
"LastName": "MyLastName",
"LastPasswordChangeDate": "2023-07-06T12:55:58.000+0000",
"LastReferencedDate": "2023-07-18T20:46:37.000+0000",
"LastViewedDate": "2023-07-18T20:46:37.000+0000",
"Latitude": null,
"LocaleSidKey": "en_US",
"Longitude": null,
"ManagerId": null,
"MediumBannerPhotoUrl": "/profilephoto/005/E",
"MediumPhotoUrl": "https://ibmc4s-qradar-dev-dev-ed.develop.file.force.com/profilephoto/005/M",
"MobilePhone": null,
"Name": "Joe MyLastName",
"NumberOfFailedLogins": 0,
"OfflinePdaTrialExpirationDate": null,
"OfflineTrialExpirationDate": null,
"OutOfOfficeMessage": "",
"Phone": null,
"PostalCode": null,
"ProfileId": "00eHr000001gfgwIAA",
"ReceivesAdminInfoEmails": true,
"ReceivesInfoEmails": true,
"SenderEmail": null,
"SenderName": null,
"Signature": null,
"SmallBannerPhotoUrl": "/profilephoto/005/D",
"SmallPhotoUrl": "https://ibmc4s-qradar-dev-dev-ed.develop.file.force.com/profilephoto/005/T",
"State": null,
"StayInTouchNote": null,
"StayInTouchSignature": null,
"StayInTouchSubject": null,
"Street": null,
"SystemModstamp": "2023-07-17T15:13:07.000+0000",
"TimeZoneSidKey": "America/Los_Angeles",
"Title": null,
"UserPermissionsCallCenterAutoLogin": false,
"UserPermissionsInteractionUser": false,
"UserPermissionsJigsawProspectingUser": false,
"UserPermissionsKnowledgeUser": false,
"UserPermissionsLiveAgentUser": false,
"UserPermissionsMarketingUser": false,
"UserPermissionsOfflineUser": false,
"UserPermissionsSFContentUser": true,
"UserPermissionsSiteforceContributorUser": false,
"UserPermissionsSiteforcePublisherUser": false,
"UserPermissionsSupportUser": false,
"UserPermissionsWorkDotComUserFeature": false,
"UserPreferencesActivityRemindersPopup": true,
"UserPreferencesApexPagesDeveloperMode": false,
"UserPreferencesCacheDiagnostics": false,
"UserPreferencesContentEmailAsAndWhen": false,
"UserPreferencesContentNoEmail": false,
"UserPreferencesCreateLEXAppsWTShown": false,
"UserPreferencesDisableAllFeedsEmail": false,
"UserPreferencesEventRemindersCheckboxDefault": true,
"UserPreferencesExcludeMailAppAttachments": false,
"UserPreferencesFavoritesShowTopFavorites": false,
"UserPreferencesFavoritesWTShown": false,
"UserPreferencesGlobalNavBarWTShown": false,
"UserPreferencesGlobalNavGridMenuWTShown": false,
"UserPreferencesHasCelebrationBadge": false,
"UserPreferencesHasSentWarningEmail": false,
"UserPreferencesHasSentWarningEmail238": false,
"UserPreferencesHasSentWarningEmail240": false,
"UserPreferencesHideBiggerPhotoCallout": false,
"UserPreferencesHideCSNDesktopTask": false,
"UserPreferencesHideCSNGetChatterMobileTask": false,
"UserPreferencesHideChatterOnboardingSplash": false,
"UserPreferencesHideEndUserOnboardingAssistantModal": false,
"UserPreferencesHideLightningMigrationModal": false,
"UserPreferencesHideS1BrowserUI": true,
"UserPreferencesHideSecondChatterOnboardingSplash": false,
"UserPreferencesHideSfxWelcomeMat": true,
"UserPreferencesJigsawListUser": false,
"UserPreferencesLightningExperiencePreferred": true,
"UserPreferencesNativeEmailClient": false,
"UserPreferencesNewLightningReportRunPageEnabled": false,
"UserPreferencesPathAssistantCollapsed": false,
"UserPreferencesPreviewCustomTheme": false,
"UserPreferencesPreviewLightning": false,
"UserPreferencesReceiveNoNotificationsAsApprover": false,
"UserPreferencesReceiveNotificationsAsDelegatedApprover": false,
"UserPreferencesRecordHomeReservedWTShown": false,
"UserPreferencesRecordHomeSectionCollapseWTShown": false,
"UserPreferencesReminderSoundOff": false,
"UserPreferencesReverseOpenActivitiesView": false,
"UserPreferencesSRHOverrideActivities": false,
"UserPreferencesShowCityToExternalUsers": false,
"UserPreferencesShowCityToGuestUsers": false,
"UserPreferencesShowCountryToExternalUsers": false,
"UserPreferencesShowCountryToGuestUsers": false,
"UserPreferencesShowEmailToExternalUsers": false,
"UserPreferencesShowEmailToGuestUsers": false,
"UserPreferencesShowFaxToExternalUsers": false,
"UserPreferencesShowFaxToGuestUsers": false,
"UserPreferencesShowForecastingChangeSignals": false,
"UserPreferencesShowManagerToExternalUsers": false,
"UserPreferencesShowManagerToGuestUsers": false,
"UserPreferencesShowMobilePhoneToExternalUsers": false,
"UserPreferencesShowMobilePhoneToGuestUsers": false,
"UserPreferencesShowPostalCodeToExternalUsers": false,
"UserPreferencesShowPostalCodeToGuestUsers": false,
"UserPreferencesShowProfilePicToGuestUsers": false,
"UserPreferencesShowStateToExternalUsers": false,
"UserPreferencesShowStateToGuestUsers": false,
"UserPreferencesShowStreetAddressToExternalUsers": false,
"UserPreferencesShowStreetAddressToGuestUsers": false,
"UserPreferencesShowTitleToExternalUsers": true,
"UserPreferencesShowTitleToGuestUsers": false,
"UserPreferencesShowWorkPhoneToExternalUsers": false,
"UserPreferencesShowWorkPhoneToGuestUsers": false,
"UserPreferencesSuppressEventSFXReminders": false,
"UserPreferencesSuppressTaskSFXReminders": false,
"UserPreferencesTaskRemindersCheckboxDefault": true,
"UserPreferencesUserDebugModePref": false,
"UserRoleId": "00EHr000002MWZLMA4",
"UserType": "Standard",
"Username": "user@qradar.dev",
"attributes": {
"type": "User",
"url": "/services/data/v58.0/sobjects/User/005Hr00000COneZIAT"
}
}
},
"inputs": {
"salesforce_user_id": "005Hr00000COneZIAT"
},
"metrics": {
"execution_time_ms": 225,
"host": "MacBook-Pro.local",
"package": "fn-salesforce",
"package_version": "1.0.0",
"timestamp": "2023-07-18 16:46:43",
"version": "1.0"
},
"raw": null,
"reason": null,
"success": true,
"version": 2.0
}
Example Function Input Script:
inputs.salesforce_user_id = incident.properties.salesforce_owner_id
Example Function Post Process Script:
results = playbook.functions.results.get_user_results
if results.success:
content = results.get("content", {})
user = content.get("salesforce_user")
if user:
incident.properties.salesforce_case_owner = user.get("Name", "")
else:
incident.addNote("Unable to get User information from OwnerId")
Function - Salesforce: Post Attachment to Salesforce Case¶
Post the SOAR attachment to the corresponding Case in Salesforce.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
No |
|
- |
|
|
No |
|
- |
|
|
No |
|
- |
|
|
Yes |
|
- |
|
|
No |
|
- |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": {
"content_document_link": {
"errors": [],
"id": "06AHr00000R0Rl0MAF",
"success": true
},
"salesforce_attachment": "temp.txt"
},
"inputs": {
"artifact_id": null,
"attachment_id": 50,
"incident_id": 2522,
"salesforce_case_id": "500Hr00001X98NnIAJ",
"task_id": null
},
"metrics": {
"execution_time_ms": 13321,
"host": "MacBook-Pro.local",
"package": "fn-salesforce",
"package_version": "1.0.0",
"timestamp": "2023-07-25 16:15:49",
"version": "1.0"
},
"raw": null,
"reason": null,
"success": true,
"version": 2.0
}
Example Function Input Script:
inputs.incident_id = incident.id
inputs.attachment_id = attachment.id
inputs.task_id = task.id if attachment.type == 'task' else None
inputs.artifact_id = None
inputs.salesforce_case_id = incident.properties.salesforce_case_id
Example Function Post Process Script:
results = playbook.functions.results.post_attachment_results
if results.success:
note_text = "<b>Salesforce: Post Attachment to Salesforce Case</b> post attachment to case:<br>{}".format(results.content.salesforce_attachment)
else:
note_text = "<b>Salesforce: Post Attachment to Salesforce Case</b> was NOT successful."
incident.addNote(note_text)
Function - Salesforce: Sync Tasks Between Cases¶
Synchronize tasks between Salesforce case and SOAR case. If the SOAR case name matches the Salesforce case Subject and the Description field contains the SOAR header text (indicating it was already sent from SOAR), then the task is not sent to Salesforce.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
No |
|
- |
|
|
Yes |
|
- |
|
|
No |
|
Direction to push tasks |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"version": 2.0,
"success": true,
"reason": null,
"content": {
"task_count_to_salesforce": 1,
"task_count_to_soar": 0
},
"raw": null,
"inputs": {
"task_sync_direction": "Salesforce",
"incident_id": 2199,
"salesforce_case_id": "500Hr00001Wu3EtIAJ"
},
"metrics": {
"version": "1.0",
"package": "fn-salesforce",
"package_version": "1.0.0",
"host": "MacBook-Pro.local",
"execution_time_ms": 914,
"timestamp": "2023-08-08 16:12:06"
}
}
Example Function Input Script:
inputs.incident_id = incident.id
inputs.salesforce_case_id = incident.properties.salesforce_case_id
inputs.task_sync_direction = "Salesforce"
Example Function Post Process Script:
results = playbook.functions.results.sync_task_results
if results.success:
note_text = "<b>Salesforce: Sync Tasks</b> added:<br> {0} tasks in Salesforce<br> {1} tasks in SOAR".format(results.content.task_count_to_salesforce, results.content.task_count_to_soar)
else:
note_text = "<b>Salesforce: Sync Tasks</b> FAILED and was unable to add tasks"
incident.addNote(note_text)
Function - Salesforce: Update Case Status¶
Update the Status field of a case in Salesforce.
Inputs:
Name |
Type |
Required |
Example |
Tooltip |
---|---|---|---|---|
|
|
No |
|
- |
|
|
Yes |
|
- |
|
|
Yes |
|
- |
Outputs:
NOTE: This example might be in JSON format, but
results
is a Python Dictionary on the SOAR platform.
results = {
"content": true,
"inputs": {
"salesforce_case_id": "500Hr00001X8WykIAF",
"salesforce_case_status": "Working"
},
"metrics": {
"execution_time_ms": 8467,
"host": "My-MBP",
"package": "fn-salesforce",
"package_version": "1.0.0",
"timestamp": "2023-07-14 12:43:49",
"version": "1.0"
},
"raw": null,
"reason": null,
"success": true,
"version": 2.0
}
Example Function Input Script:
inputs.salesforce_case_id = incident.properties.salesforce_case_id
inputs.salesforce_case_status = playbook.inputs.salesforce_case_status
inputs.salesforce_case_comment = playbook.inputs.salesforce_case_comment
Example Function Post Process Script:
update_status = playbook.functions.results.update_status
if not update_status.success:
incident.addNote("Salesforce: ERROR: Unable to Update Case Status to <b>{}</b>".format(update_status.inputs.salesforce_case_status))
else:
incident.properties.salesforce_status = update_status.inputs.salesforce_case_status
incident.addNote("Salesforce: Updated Case Status to <b>{}</b> in Salesforce".format(incident.properties.salesforce_status))
Custom Fields¶
Label |
API Access Name |
Type |
Prefix |
Placeholder |
Tooltip |
---|---|---|---|---|---|
Account Id |
|
|
|
- |
ID of the account associated with this case. |
Account Name |
|
|
|
- |
- |
Case Id |
|
|
|
- |
- |
Link to Case in Salesforce |
|
|
|
- |
- |
Case Number |
|
|
|
- |
- |
Case Owner |
|
|
|
- |
- |
Case Type |
|
|
|
- |
The type of case, such as Feature Request or Question. |
Contact Email |
|
|
|
- |
Email address for the contact. The Case.ContactEmail field displays the Email field on the contact that is referenced by Case.ContactId. Label is Contact Email. This field is available in API version 38.0 and later. |
Contact FAX |
|
|
|
- |
Fax number for the contact. Label is Contact Fax. This field is available in API version 38.0 and later. |
Contact Id |
|
|
|
- |
- |
Contact Name |
|
|
|
- |
- |
Contact Phone |
|
|
|
- |
Telephone number for the contact. Label is Contact Phone. This field is available in API version 38.0 and later. |
Case Origin |
|
|
|
- |
The source of the case, such as Email, Phone, or Web. Label is Case Origin. |
Owner Id |
|
|
|
- |
- |
Case Status |
|
|
|
- |
- |
Company |
|
|
|
- |
The company name that was entered when the case was created. Label is Company. |
|
|
|
- |
The email address that was entered when the case was created. Label is Email. If your organization has an active auto-response rule, SuppliedEmail is required when creating a case via the API. Auto-response rules use the email in the contact specified by ContactId. If no email address is in the contact record, the email specified here is used. |
|
Name |
|
|
|
- |
The name that was entered when the case was created. Label is Name. |
Phone |
|
|
|
- |
The phone number that was entered when the case was created. Label is Phone. |
Playbooks¶
Playbook Name |
Description |
Activation Type |
Object |
Status |
Condition |
---|---|---|---|---|---|
Salesforce: Add Comment to Salesforce Case |
Add the specified text as a comment to the specified case. |
Automatic |
incident |
|
|
Salesforce: Close Case |
Automatic playbook to close a case in Salesforce. |
Automatic |
incident |
|
|
Salesforce: Create Salesforce Case |
Create a case in Salesforce. Activation form input and custom field data are used in function input script to create the JSON format payload used to create the Salesforce case. |
Manual |
incident |
|
|
Salesforce: Create Salesforce Case from This SOAR Case |
Create a Salesforce case from the SOAR case which activated the playbook. This playbook is only available to SOAR cases that are not associated with a Salesforce case. |
Manual |
incident |
|
|
Salesforce: Write Account Details to Note |
Get information on the Salesforce account associated with a case and write to a SOAR note. |
Manual |
incident |
|
|
Salesforce: Get Attachments from Salesforce Case |
Get attachments from Salesforce case and add them to the SOAR case. |
Manual |
incident |
|
|
Salesforce: Write Contact Details to Note |
Manual playbook to get the Contact information associated with the Salesforce case. Write the details to a note in SOAR. |
Manual |
incident |
|
|
Salesforce: Post Artifact File to Salesforce Case |
Post a SOAR artifact file to a Salesforce cases as an attachment. |
Manual |
artifact |
|
|
Salesforce: Post Attachment to Salesforce Case |
Post the SOAR attachment to the corresponding case in Salesforce. |
Manual |
attachment |
|
|
Salesforce: Send Note to Salesforce Case |
Send the specified SOAR case note as a comment in the corresponding Salesforce case. |
Manual |
note |
|
|
Salesforce: Send Task to Salesforce Case |
Send the task to corresponding Salesforce case. |
Manual |
task |
|
|
Salesforce: Sync Tasks Between SOAR and Salesforce |
None |
Manual |
incident |
|
|
Salesforce: Update Account Details in SOAR |
None |
Automatic |
incident |
|
|
Salesforce: Update Case in SOAR |
Automatic playbook to update the SOAR case with information from Salesforce. |
Automatic |
incident |
|
|
Salesforce: Update Case Status in Salesforce |
Manual playbook to update the case Status field in Salesforce |
Manual |
incident |
|
|
Salesforce: Update Comments from Salesforce Case |
Get the comments from the specified Salesforce case and update the notes in corresponding SOAR case. |
Manual |
incident |
|
|
Salesforce: Update Contact Details in SOAR |
Automatic playbook to update the Contact details in SOAR when the ContactId has changed. |
Automatic |
incident |
|
|
Salesforce: Update Owner Details in SOAR |
Get the Case Owner details and update the Case Owner field in the SOAR case. |
Automatic |
incident |
|
|
Salesforce: Write Owner Details to Note |
Write the User details of the Case Owner in Salesforce to a SOAR incident Note. |
Manual |
incident |
|
|
Templates for SOAR Cases¶
It may necessary to modify the templates used to create or close SOAR cases based on a customer’s required custom fields. Below are the default templates used which can be copied, modified and used with app_config’s
soar_create_case_template
and soar_close_case_template
settings to override the default templates.
soar_create_case.jinja¶
When overriding the template in App Host, specify the file path as /var/rescircuits
.
{
{# JINJA template for creating a new SOAR incident from an endpoint #}
{# See https://ibmresilient.github.io/resilient-python-api/pages/resilient-lib/resilient-lib.html#module-resilient_lib.components.templates_common
for details on available jinja methods. Examples for `soar_substitute` and more are included below.
#}
{# modify to specify your specific **data** fields #}
"name": "Salesforce Case - {{ CaseNumber }} - {{ Subject }}",
"description": "{{ Description | replace('"', '\\"') }}",
{# start_date cannot be after discovered_date #}
"discovered_date": {{ CreatedDate | soar_datetimeformat(split_at='.') }},
"start_date": {{ CreatedDate | soar_datetimeformat(split_at='.') }},
"incident_type_ids": ["{{ Type }}"],
{# if alert users are different than SOAR users, consider using a mapping table using soar_substitute: #}
{# "owner_id": "{{ OwnerId }}", #}
{#"plan_status": "{{ Status|soar_substitute('{"Closed": "C", "New": "A", "Escalated": "A"}') }}",#}
"plan_status": "A",
"severity_code": "{{ Priority }}",
{# specify your custom fields for your endpoint solution #}
"properties": {
"salesforce_case_id": "{{ Id }}",
"salesforce_status": "{{ Status }}"
}
}
soar_create_case_with_artifacts.jinja¶
This example “create case” jinja template, in addition to creating a SOAR case, creates artifacts from Salesforce custom fields.
In this example, the custom fields are named similarly to SOAR artifact types.
Note: The appended “__c” denotes custom fields in Salesforce.
When overriding the template in App Host, specify the file path as /var/rescircuits
.
{
{%- set comma = joiner(",") -%}
{# JINJA template for creating a new SOAR incident from an endpoint #}
{# See https://ibmresilient.github.io/resilient-python-api/pages/resilient-lib/resilient-lib.html#module-resilient_lib.components.templates_common
for details on available jinja methods. Examples for `soar_substitute` and more are included below.
#}
{# modify to specify your specific **data** fields #}
"name": "Salesforce Case - {{ CaseNumber }} - {{ Subject }}",
"description": "{{ Description | replace('"', '\\"') }}",
{# start_date cannot be after discovered_date #}
"discovered_date": {{ CreatedDate | soar_datetimeformat(split_at='.') }},
"start_date": {{ CreatedDate | soar_datetimeformat(split_at='.') }},
"incident_type_ids": ["{{ Type }}"],soar_create_case_with_artifacts.jinja
{# if alert users are different than SOAR users, consider using a mapping table using soar_substitute: #}
{# "owner_id": "{{ OwnerId }}", #}
{#"plan_status": "{{ Status|soar_substitute('{"Closed": "C", "New": "A", "Escalated": "A"}') }}",#}
"plan_status": "A",
"severity_code": "{{ Priority }}",
{# specify your custom fields for your endpoint solution #}
"properties": {
"salesforce_case_id": "{{ Id }}",
"salesforce_status": "{{ Status }}"
},
"artifacts": [
{% if IP_Address__c is defined and IP_Address__c is not none %}
{{- comma() }}
{
"type": {
"name": "IP Address"
},
"value": "{{ IP_Address__c }}",
"description": {
"format": "text",
"content": "IP Address artifact from Salesforce"
}
}
{% endif %}
{% if Malware_SHA_256_Hash__c is defined and Malware_SHA_256_Hash__c is not none %}
{{- comma() }}
{
"type": {
"name": "Malware SHA-256 Hash"
},
"value": "{{ Malware_SHA_256_Hash__c }}",
"description": {
"format": "text",
"content": "Malware SHA-256 Hash from Salesforce case"
}
}
{% endif %}
{% if URL_artifact__c is defined and URL_artifact__c is not none %}
{{- comma() }}
{
"type": {
"name": "URL"
},
"value": "{{ URL_artifact__c }}",
"description": {
"format": "text",
"content": "URL artifact from Salesforce case"
}
}
{% endif %}
{% if Email_Recipient__c is defined and Email_Recipient__c is not none %}
{{- comma() }}
{
"type": {
"name": "Email Recipient"
},
"value": "{{ Email_Recipient__c }}",
"description": {
"format": "text",
"content": "Email Recipient artifact from Salesforce case"
}
}
{% endif %}
{% if Email_Sender__c is defined and Email_Sender__c is not none %}
{{- comma() }}
{
"type": {
"name": "Email Sender"
},
"value": "{{ Email_Sender__c }}",
"description": {
"format": "text",
"content": "Email Sender artifact from Salesforce case"
}
}
{% endif %}
]
}
soar_close_case.jinja¶
When overriding the template in App Host, specify the file path as /var/rescircuits
.
{
{# JINJA template for closing a SOAR incident using endpoint data #}
{# modify to specify your specific **data** fields #}
"plan_status": "C",
"resolution_id": "{{ "Resolved" }}",
"resolution_summary": "Closed by Salesforce, Status: {{ Status }}",
{# add additional fields based on your 'on close' field requirements #}
"properties": {
"salesforce_status": "{{ Status }}"
}
}
soar_update_case.jinja¶
When overriding the template in App Host, specify the file path as /var/rescircuits
.
{
{# JINJA template for updating a new SOAR incident from an endpoint #}
{# modify to specify your specific **data** fields #}
"severity_code": "{{ Priority }}",
{# specify your custom fields for your endpoint solution #}
"properties": {
"salesforce_case_id": "{{ Id }}",
"salesforce_case_number": "{{ CaseNumber }}",
"salesforce_case_type": "{{ Type }}",
"salesforce_case_link": "<a target='_blank' href='{{ entity_url }}'>{{ CaseNumber }}</a>",
"salesforce_origin": "{{ Origin }}",
"salesforce_account_id": {% if AccountId is none %} null {% else %} "{{ AccountId }}" {% endif %},
"salesforce_owner_id": {% if OwnerId is none %} null {% else %} "{{ OwnerId }}" {% endif %},
"salesforce_contact_id": {% if ContactId is none %} null {% else %} "{{ ContactId }}" {% endif %},
"salesforce_contact_phone": {% if ContactPhone is none %} null {% else %} "{{ ContactPhone }}" {% endif %},
"salesforce_contact_email": {% if ContactEmail is none %} null {% else %} "{{ ContactEmail }}" {% endif %},
"salesforce_contact_fax": {% if ContactFax is none %} null {% else %} "{{ ContactFax }}" {% endif %},
"salesforce_supplied_name": {% if SuppliedName is none %} null {% else %} "{{ SuppliedName }}" {% endif %},
"salesforce_supplied_email": {% if SuppliedEmail is none %} null {% else %} "{{ SuppliedEmail }}" {% endif %},
"salesforce_supplied_phone": {% if SuppliedPhone is none %} null {% else %} "{{ SuppliedPhone }}" {% endif %},
"salesforce_supplied_company": {% if SuppliedCompany is none %} null {% else %} "{{ SuppliedCompany }}" {% endif %},
"salesforce_status": "{{ Status }}"
}
}
Troubleshooting & Support¶
Refer to the documentation listed in the Requirements section for troubleshooting information.
For Support¶
This is an IBM supported app. Please search ibm.com/mysupport for assistance.