Symantec Data Loss Prevention v2
Symantec Data Loss Prevention version 15.7 enables you to discover, monitor and protect your sensitive corporate information.
Network Security · Symantec Data Loss Prevention
Details
| ID | Symantec Data Loss Prevention v2 |
|---|---|
| Provider | Broadcom |
| Category | Network Security |
| From Version | 6.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
Symantec Data Loss Prevention enables you to discover, monitor and protect your sensitive corporate information.
This integration was integrated and tested with Symantec Data Loss Prevention version 15.7 RESTful API.
Check Symantec DLP 15.7 API docs
Some changes have been made that might affect your existing content.
If you are upgrading from a previous of this integration, see Breaking Changes.
Configure Symantec Data Loss Prevention v2 in Cortex
| Parameter | Description | Required |
|---|---|---|
| Enforce Server (e.g. https://192.168.0.1) | True | |
| Username | True | |
| Password | True | |
| First fetch timestamp (<number> <time unit>, e.g., 12 hours, 7 days) | False | |
| Fetch limit | Max fetch limit is 50 | False |
| Fetch incidents from type | If not selected, fetches all incident types. | False |
| Incident Status ID | The status ID of the incidents. To get the status IDs, run the `symantec-dlp-list-incident-status` command. | False |
| Incident Severity | If not selected, fetches high and medium incidents. | False |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False | |
| Fetch incidents | False | |
| Incident type | False |
Fetch Incidents
The integration fetches incidents in the order they were created.
Note that incident IDs may not be fetched in order, due to creation time differences.
Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
symantec-dlp-list-incidents
Returns a list of incidents.
Base Command
symantec-dlp-list-incidents
Input
| Argument Name | Description | Required |
|---|---|---|
| creation_date | The earliest time from which to get incidents. Supports ISO (e.g 2021-12-28T00:00:00Z) and free text (e.g. ‘2 days’). | Optional |
| status_id | The status ID of the incidents. To get status IDs, run the symantec-dlp-list-incident-status command. |
Optional |
| severity | The severity of the incidents. Possible values are: Info, Low, Medium, High. | Optional |
| incident_type | The incident type. Possible values are: Network, Discover, Endpoint. | Optional |
| limit | The limit for number of incidents listed per page. Default is 50. | Optional |
| page | The page number you would like to view. Each page contains page_size values. Must be used along with page_size. Default is 1. |
Optional |
| page_size | The number of results per page to display. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SymantecDLP.Incident.ID | Number | The ID of the Incident. |
| SymantecDLP.Incident.messageType | String | Indicates the Symantec DLP product component that generated the incident. |
| SymantecDLP.Incident.messageSource | String | The localized label that corresponds to the Symantec DLP product that generated the incident. |
| SymantecDLP.Incident.detectionServerId | Number | The ID of the detection server that created the incident. |
| SymantecDLP.Incident.policyVersion | Number | The version of the policy. |
| SymantecDLP.Incident.matchCount | Number | Indicates the number of detection rule matches in the incident. |
| SymantecDLP.Incident.policyId | Number | The ID of the policy. |
| SymantecDLP.Incident.creationDate | Date | The creation date of the incident. |
| SymantecDLP.Incident.detectionDate | Date | The detection date of the incident. |
| SymantecDLP.Incident.severity | String | The severity of the incident. |
| SymantecDLP.Incident.messageTypeId | Number | The ID of the message type. |
| SymantecDLP.Incident.incidentStatusId | Number | The status ID of the incident. |
Command example
!symantec-dlp-list-incidents limit=2 severity=High incident_type=Network creation_date="4 days"
Context Example
{
"SymantecDLP": {
"Incident": [
{
"ID": 4044,
"creationDate": "2022-03-27T03:23:52.315",
"detectionDate": "2022-03-27T03:23:44.773",
"detectionServerId": 1,
"incidentStatusId": 1,
"matchCount": 3,
"messageSource": "NETWORK",
"messageType": "HTTP",
"messageTypeId": 3,
"policyId": 2,
"policyVersion": 4,
"severity": "High"
},
{
"ID": 4043,
"creationDate": "2022-03-27T03:23:52.299",
"detectionDate": "2022-03-27T03:23:44.773",
"detectionServerId": 1,
"incidentStatusId": 1,
"matchCount": 2,
"messageSource": "NETWORK",
"messageType": "HTTP",
"messageTypeId": 3,
"policyId": 41,
"policyVersion": 4,
"severity": "High"
}
]
}
}
Human Readable Output
Symantec DLP incidents results
ID Severity Status Creation Date Incident Type Message Type Policy ID Match Count 4044 High 1 2022-03-27T03:23:52.315 NETWORK HTTP 2 3 4043 High 1 2022-03-27T03:23:52.299 NETWORK HTTP 41 2
symantec-dlp-get-incident-details
Returns details of the specified incident.
Base Command
symantec-dlp-get-incident-details
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | Incident ID for which to retrieve details. | Required |
| custom_attributes | This argument can get the following values: all - All custom attributes are needed none - None of the custom attributes are needed specific attributes - A comma-separated list of custom attribute names. For example: ca1,ca2,ca3 custom attribute group name - A comma-separated list of custom attribute group names. For example: cag1, cag2, cag3. This value retrieves all custom attributes in the mentioned group. The value “none” is default. Possible values are: all, none, specific attributes, custom attribute group name. Default is none. |
Optional |
| custom_data | A comma-separated list of custom attribute names or custom attribute group names. For example: item1,item2,item3. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SymantecDLP.Incident.ID | Number | The ID of the incident. |
| SymantecDLP.Incident.policyVersion | Number | The version of the policy. |
| SymantecDLP.Incident.attachmentInfo.componentType | Number | The ID of the type of the message component that generated the incident. |
| SymantecDLP.Incident.attachmentInfo.messageComponentName | String | The name of the file or attachment that generated the incident. |
| SymantecDLP.Incident.attachmentInfo.messageComponentId | Number | The ID of the message component that generated the incident. |
| SymantecDLP.Incident.attachmentInfo.wasCracked | Boolean | Indicates if the message component that generated the incident was cracked. |
| SymantecDLP.Incident.attachmentInfo.documentFormat | String | The file format of the message component that generated the incident. |
| SymantecDLP.Incident.attachmentInfo.mimeType | String | The standard mime type of the message component that generated the incident. |
| SymantecDLP.Incident.attachmentInfo.originalSize | Number | The size, in bytes, of the file or attachment that generated the incident. |
| SymantecDLP.Incident.messageSubject | String | The subject of the message that caused the incident. |
| SymantecDLP.Incident.policyName | String | The name of the policy. |
| SymantecDLP.Incident.policyGroupName | String | The name of the policy group. |
| SymantecDLP.Incident.policyGroupId | Number | The ID of the policy group of the policy that was violated. |
| SymantecDLP.Incident.messageSource | String | The localized label that corresponds to the Symantec DLP product that generated the incident. |
| SymantecDLP.Incident.messageId | Number | The ID of the message that caused the incident. |
| SymantecDLP.Incident.messageOriginatorID | Number | The ID of the sender or originator of the message that caused the incident. |
| SymantecDLP.Incident.matchCount | Number | The total number of policy violation matches produced by policies for this incident. |
| SymantecDLP.Incident.creationDate | Date | The creation date of the incident. |
| SymantecDLP.Incident.isBlockedStatusSuperseded | Boolean | Specifies whether the incident response was superseded by another response. |
| SymantecDLP.Incident.detectionServerName | String | The name of the detection server that created the incident. |
| SymantecDLP.Incident.networkSenderPort | Number | The port number on the host from which network traffic originated. |
| SymantecDLP.Incident.messageType | String | Indicates the Symantec DLP product component that generated the incident. |
| SymantecDLP.Incident.policyId | Number | The ID of the policy. |
| SymantecDLP.Incident.detectionDate | Date | The detection date of the incident. |
| SymantecDLP.Incident.messageTypeId | Number | The ID of the message type. |
| SymantecDLP.Incident.detectionServerId | Number | The ID of the detection server or cloud detector that created the incident. |
| SymantecDLP.Incident.messageDate | Date | The date and time that the network message that caused the incident originated. |
| SymantecDLP.Incident.senderIPAddress | String | The IP address of the sender. |
| SymantecDLP.Incident.endpointMachineIpAddress | String | The IP address of the endpoint machine. |
| SymantecDLP.Incident.recipientInfo.recipientType | Number | The type of the recipient. |
| SymantecDLP.Incident.recipientInfo.recipientPort | Number | The port of the recipient. |
| SymantecDLP.Incident.recipientInfo.recipientDomain | String | The domain of the recipient. |
| SymantecDLP.Incident.recipientInfo.recipientIdentifier | String | The identifier of the recipient. |
| SymantecDLP.Incident.recipientInfo.recipientIPAddress | String | The IP address of the recipient. |
| SymantecDLP.Incident.recipientInfo.recipientUrl | String | The URL address of the recipient. |
| SymantecDLP.Incident.networkSenderIdentifier | String | The name and/or IP address of the user who caused the incident. |
| SymantecDLP.Incident.isHidingNotAllowed | Boolean | Indicates if incident hiding is not allowed for the incident. |
| SymantecDLP.Incident.incidentStatusName | String | The status of the incident. |
| SymantecDLP.Incident.dataOwnerEmail | String | The email of the data owner. |
| SymantecDLP.Incident.dataOwnerName | String | The name of the data owner. |
| SymantecDLP.Incident.severity | Number | The severity of the incident. |
| SymantecDLP.Incident.incidentStatusId | Number | The status ID of the incident. |
| SymantecDLP.Incident.isHidden | Boolean | The hidden state of the incident. |
| SymantecDLP.Incident.preventOrProtectStatusId | Number | The remediation status ID. |
| SymantecDLP.Incident.CustomAttribute.Name | String | The name of the custom attribute. |
| SymantecDLP.Incident.CustomAttribute.Value | String | The value of the custom attribute. |
| SymantecDLP.Incident.CustomAttribute.Index | Number | The index of the custom attribute. |
| SymantecDLP.Incident.fileCreateDate | Date | The date and time the file was created. |
| SymantecDLP.Incident.discoverServer | String | The name of the file share, server, or SQL database that was scanned. |
| SymantecDLP.Incident.fileAccessDate | Date | The date and time the file was last accessed. |
| SymantecDLP.Incident.discoverTargetName | String | The name of the Discover scan target. |
| SymantecDLP.Incident.discoverRepositoryLocation | String | The location, file location, or other path to the resource which generated the incident. |
| SymantecDLP.Incident.discoverScanId | Number | The ID of the Discover scan. |
| SymantecDLP.Incident.discoverContentRootPath | String | The full path on the file share, server, or SQL database that was scanned. |
| SymantecDLP.Incident.discoverMillisSinceFirstSeen | Number | The time from the first incident generated, by the same policy on the same file, or resource using Discover detection, up to the detection time of the current incident. |
| SymantecDLP.Incident.isBlockedStatusSuperseded | Boolean | Specifies whether the incident response was superseded by another response. |
| SymantecDLP.Incident.messageAclEntries.principal | String | The principal of the entry. |
| SymantecDLP.Incident.messageAclEntries.aclType | String | The type of resource the access control list applies to. |
| SymantecDLP.Incident.messageAclEntries.permission | String | The permission of the entry. |
| SymantecDLP.Incident.messageAclEntries.grantDeny | String | Whether access is allowed or not. |
| SymantecDLP.Incident.discoverTargetId | Number | The ID of the Discover scan target. |
| SymantecDLP.Incident.discoverScanStartDate | Date | The date and time that the Discover scan started. |
| SymantecDLP.Incident.discoverName | String | The name of the file or resource that caused the incident. |
| SymantecDLP.Incident.fileOwner | String | The owner of the file at the time the incident was created. |
| SymantecDLP.Incident.discoverUrl | String | The URL of the resource scanned. |
| SymantecDLP.Incident.endpointFilePath | String | The file system path of the file that violated the policy. |
| SymantecDLP.Incident.endpointApplicationPath | String | The path to the application that caused the incident. |
| SymantecDLP.Incident.endpointVolumeName | String | The name of the local drive where the incident occurred. |
| SymantecDLP.Incident.domainUserName | String | The domain and user name associated with the incident. |
| SymantecDLP.Incident.fileCreatedBy | String | The name of the user who created the file. |
| SymantecDLP.Incident.fileModifiedBy | String | The name of the user who last modified the file. |
| SymantecDLP.Incident.endpointDeviceInstanceId | String | The ID to specifically identify an endpoint computer. |
| SymantecDLP.Incident.endpointFileName | String | The name of the file that violated the policy. |
| SymantecDLP.Incident.endpointConnectionStatus | String | The location of the endpoint computer, on or off the corporate network. |
| SymantecDLP.Incident.endpointMachineIpAddress | String | The IP address of the computer on which the incident occurred, if the computer is in the corporate network. |
| SymantecDLP.Incident.endpointMachineName | String | The name of the computer on which the incident occurred. |
| SymantecDLP.Incident.endpointApplicationName | String | The name of the application that caused the incident. |
Command example
!symantec-dlp-get-incident-details incident_id=1 custom_attributes="custom attribute group name" custom_data="att group2"
Context Example
{
"SymantecDLP": {
"Incident": {
"ID": 1,
"attachmentInfo": [
{
"componentType": 3,
"documentFormat": "unknown",
"messageComponentId": 5,
"messageComponentName": "token",
"mimeType": "application/octet-stream",
"originalSize": 0,
"wasCracked": false
}
],
"creationDate": "2021-12-20T13:25:46.103",
"customAttributeGroup": [
{
"customAttribute": [
{
"index": 4,
"name": "kjv",
"value": "test"
}
],
"name": "att group2"
}
],
"dataOwnerEmail": "testing@gmail.com",
"dataOwnerName": "test123",
"detectionDate": "2021-12-20T13:25:27.56",
"detectionServerId": 1,
"detectionServerName": "Detection - Network monitor",
"endpointMachineIpAddress": "1.31.25.150",
"incidentStatusId": 1,
"incidentStatusName": "incident.status.New",
"isBlockedStatusSuperseded": false,
"isHidden": false,
"isHidingNotAllowed": false,
"matchCount": 1,
"messageDate": "2021-12-20T13:25:27.623",
"messageId": 2,
"messageOriginatorID": 2,
"messageSource": "NETWORK",
"messageSubject": "HTTP incident",
"messageType": "HTTP",
"messageTypeId": 3,
"networkSenderIdentifier": "1.31.25.150",
"networkSenderPort": 51108,
"policyGroupId": 1,
"policyGroupName": "policy_group.default.name",
"policyId": 2,
"policyName": "Network Test policy",
"policyVersion": 1,
"preventOrProtectStatusId": 0,
"recipientInfo": [
{
"recipientDomain": "1.254.1.254",
"recipientIPAddress": "1.254.1.254",
"recipientIdentifier": "http://1.254.1.254/latest/api/token",
"recipientPort": 80,
"recipientType": 1,
"recipientUrl": "http://1.254.1.254/latest/api/token"
}
],
"senderIPAddress": "1.31.25.150",
"severity": "Medium"
}
}
}
Human Readable Output
Symantec DLP incident 1 details
Status Creation Date Detection Date Incident Type Policy Name Policy Group Name Detection Server Name Message Type Message Source Data Owner Name Data Owner Email Custom Attributes 1 2021-12-20T13:25:46.103 2021-12-20T13:25:27.56 NETWORK Network Test policy policy_group.default.name Detection - Network monitor HTTP NETWORK test123 testing@gmail.com - name: att group2
customAttribute:
- name: kjv
value: test
symantec-dlp-update-incident
Updates the details of a specific incident.
Base Command
symantec-dlp-update-incident
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_ids | The incident IDs to update. | Required |
| data_owner_email | The data owner email. | Optional |
| data_owner_name | The data owner name. | Optional |
| note | The note to be added. | Optional |
| incident_status_id | The status ID to update. Run the symantec-dlp-list-incident-status command to get the status ID. |
Optional |
| remediation_status_name | The remediation status name of an incident. | Optional |
| remediation_location | The remediation location of the incident. Values can be user-defined. | Optional |
| severity | The severity level of the incident. Possible values are: Info, Low, Medium, High. | Optional |
| custom_attributes | The custom attributes to update. To get the custom attribute details, run the symantec-dlp-get-incident-details command with the custom_attributes=all command.Format: {columnIndex}:{newValue} For example, 1:update, 4:att. |
Optional |
Context Output
There is no context output for this command.
Command example
!symantec-dlp-update-incident incident_ids=1,2 severity=Medium data_owner_email=testing@gmail.com custom_attributes=4:test
Human Readable Output
Symantec DLP incidents: [‘1’, ‘2’] were updated
symantec-dlp-list-incident-status
Returns a list of the custom status values defined in the Symantec DLP deployment.
Base Command
symantec-dlp-list-incident-status
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| SymantecDLP.IncidentStatus.id | Number | The ID of the status. |
| SymantecDLP.IncidentStatus.name | String | The name of the status. |
Command example
#### Context Example
```json
{
"SymantecDLP": {
"IncidentStatus": [
{
"id": 1,
"name": "incident.status.New"
},
{
"id": 42,
"name": "Escalated"
},
{
"id": 21,
"name": "In Process"
},
{
"id": 43,
"name": "False Positive"
},
{
"id": 44,
"name": "Configuration Error"
},
{
"id": 45,
"name": "Resolved"
},
{
"id": 61,
"name": "Custom status"
}
]
}
}
Human Readable Output
Symantec DLP incidents status
Id Name 1 incident.status.New 42 Escalated 21 In Process 43 False Positive 44 Configuration Error 45 Resolved 61 Custom status
symantec-dlp-get-incident-history
Returns the history of the specified incident.
Base Command
symantec-dlp-get-incident-history
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | The incident ID. | Required |
| limit | The limit of the incident history list per page. Default is 50. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SymantecDLP.IncidentHistory.incidentHistoryDate | String | The date of the incident history. |
| SymantecDLP.IncidentHistory.dlpUserName | String | The name of the user. |
| SymantecDLP.IncidentHistory.incidentHistoryAction | String | The action of the incident history. |
| SymantecDLP.IncidentHistory.incidentHistoryDetail | String | The incident history detail. |
| SymantecDLP.IncidentHistory.policyGroupId | Number | The ID of the policy group. |
| SymantecDLP.IncidentHistory.detectionServerName | String | The name of the detection server that created the incident. |
| SymantecDLP.IncidentHistory.incidentHistoryId | Number | The ID of the incident history. |
| SymantecDLP.IncidentHistory.messageSource | String | The localized label that corresponds to the Symantec DLP product that generated the incident. |
| SymantecDLP.IncidentHistory.messageDate | String | The date of the message. |
| SymantecDLP.IncidentHistory.ID | Number | The ID of the incident. |
Command example
!symantec-dlp-get-incident-history limit=6 incident_id=2
Context Example
{
"SymantecDLP": {
"IncidentHistory": {
"ID": 2,
"incidentHistory": [
{
"detectionServerName": "Detection - Network monitor",
"dlpUserName": "Administrator",
"incidentHistoryAction": "SET_STATUS",
"incidentHistoryDate": "2021-12-20T13:25:46.197",
"incidentHistoryDetail": "incident.status.New",
"messageDate": "2021-12-20T13:25:27.623",
"messageSource": "NETWORK",
"policyGroupId": 1
},
{
"detectionServerName": "Detection - Network monitor",
"dlpUserName": "Administrator",
"incidentHistoryAction": "MESSAGE_NOT_RETAINED",
"incidentHistoryDate": "2021-12-20T13:25:27.576",
"messageDate": "2021-12-20T13:25:27.623",
"messageSource": "NETWORK",
"policyGroupId": 1
},
{
"detectionServerName": "Detection - Network monitor",
"dlpUserName": "Administrator",
"incidentHistoryAction": "SET_SEVERITY",
"incidentHistoryDate": "2021-12-20T13:25:27.576",
"incidentHistoryDetail": "incident.severity.High",
"messageDate": "2021-12-20T13:25:27.623",
"messageSource": "NETWORK",
"policyGroupId": 1
},
{
"detectionServerName": "Detection - Network monitor",
"dlpUserName": "Administrator",
"incidentHistoryAction": "DETECTED",
"incidentHistoryDate": "2021-12-20T13:25:27.576",
"messageDate": "2021-12-20T13:25:27.623",
"messageSource": "NETWORK",
"policyGroupId": 1
}
]
}
}
}
Human Readable Output
Symantec DLP Incident 2 history results
DLP User Name History Date Incident History Action Administrator 2021-12-20T13:25:46.197 SET_STATUS Administrator 2021-12-20T13:25:27.576 MESSAGE_NOT_RETAINED Administrator 2021-12-20T13:25:27.576 SET_SEVERITY Administrator 2021-12-20T13:25:27.576 DETECTED
symantec-dlp-list-remediation-status
Returns a list of the remediation status values defined in the Symantec DLP deployment.
Base Command
symantec-dlp-list-remediation-status
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| SymantecDLP.IncidentRemediationStatus.id | Number | The ID of the remediation status. |
| SymantecDLP.IncidentRemediationStatus.name | String | The name of the remediation status. |
Command example
#### Context Example
```json
{
"SymantecDLP": {
"IncidentRemediationStatus": [
{
"id": 0,
"name": "PASSED"
},
{
"id": 1,
"name": "BLOCKED"
},
{
"id": 2,
"name": "MESSAGE_MODIFIED"
},
{
"id": 3,
"name": "PROTECT_FILE_COPIED"
},
{
"id": 4,
"name": "PROTECT_FILE_QUARANTINED"
},
{
"id": 5,
"name": "PROTECT_FILE_DELETED"
},
{
"id": 6,
"name": "PROTECT_REMEDIATION_ERROR"
},
{
"id": 8,
"name": "CONTENT_REMOVED"
},
{
"id": 9,
"name": "ENDPOINT_BLOCK"
},
{
"id": 10,
"name": "ENDPOINT_NOTIFY"
},
{
"id": 11,
"name": "FLEX_RESPONSE_EXECUTED"
},
{
"id": 12,
"name": "FLEX_RESPONSE_ERROR"
},
{
"id": 13,
"name": "FLEX_RESPONSE_REQUESTED"
},
{
"id": 14,
"name": "ENDPOINT_NOTIFY_CANCEL_ALLOW"
},
{
"id": 15,
"name": "ENDPOINT_NOTIFY_CANCEL_BLOCK"
},
{
"id": 16,
"name": "ENDPOINT_NOTIFY_CANCEL_TIMEOUT_ALLOW"
},
{
"id": 17,
"name": "ENDPOINT_NOTIFY_CANCEL_TIMEOUT_BLOCK"
},
{
"id": 18,
"name": "ENDPOINT_FILE_QUARANTINE_FAILED"
},
{
"id": 19,
"name": "ENDPOINT_FILE_QUARANTINED"
},
{
"id": 20,
"name": "UNKNOWN"
},
{
"id": 21,
"name": "EMAIL_QUARANTINED"
},
{
"id": 22,
"name": "EMAIL_APPROVED"
},
{
"id": 23,
"name": "EMAIL_BLOCKED"
},
{
"id": 24,
"name": "CUSTOM_ACTION_ON_EMAIL"
},
{
"id": 25,
"name": "EMAIL_MESSAGE_EXPUNGED"
},
{
"id": 26,
"name": "TRANSPORT_HEADERS_ADDED"
},
{
"id": 27,
"name": "VISUAL_TAG_ADDED"
},
{
"id": 28,
"name": "VISUAL_TAG_ADDITION_FAILED"
},
{
"id": 29,
"name": "QUARANTINE_FAILED"
},
{
"id": 30,
"name": "REST_ENCRYPTED"
},
{
"id": 31,
"name": "REST_PERFORMED_DRM"
},
{
"id": 32,
"name": "REST_PERFORMED_BREAK_LINKS"
},
{
"id": 33,
"name": "REST_PERFORMED_CUSTOM_ACTION"
},
{
"id": 34,
"name": "ENCRYPTED"
},
{
"id": 35,
"name": "ENCRYPT_FAILED"
},
{
"id": 36,
"name": "ENDPOINT_USER_ENCRYPT_CANCEL_ENCRYPT"
},
{
"id": 37,
"name": "ENDPOINT_USER_ENCRYPT_CANCEL_PREVENT"
},
{
"id": 38,
"name": "ENDPOINT_USER_ENCRYPT_CANCEL_TIMEOUT_ENCRYPT"
},
{
"id": 39,
"name": "ENDPOINT_USER_ENCRYPT_CANCEL_TIMEOUT_PREVENT"
},
{
"id": 40,
"name": "PROTECT_FILE_ENCRYPTED"
},
{
"id": 41,
"name": "REST_ACTION_REQUESTED"
},
{
"id": 42,
"name": "REST_ACTION_SUCCESS"
},
{
"id": 43,
"name": "REST_ACTION_FAILURE"
},
{
"id": 44,
"name": "REST_ACTION_WARNING"
},
{
"id": 45,
"name": "REST_USER_REMEDIATED"
},
{
"id": 46,
"name": "MANUAL_ACTION_REQUESTED"
},
{
"id": 47,
"name": "REST_RESTRICTED_FILE_AUTHORIZATION"
},
{
"id": 48,
"name": "REST_PREVENTED_PHYSICAL_ACCESS"
},
{
"id": 49,
"name": "REST_ADDITIONAL_ACCESS_PROTECTION"
},
{
"id": 50,
"name": "ENDPOINT_ENCRYPT"
},
{
"id": 51,
"name": "ENDPOINT_ENCRYPT_PREVENT_ENFORCED"
},
{
"id": 52,
"name": "ENDPOINT_ICT_TAGGING_SUCCESS"
},
{
"id": 53,
"name": "ENDPOINT_ICT_TAGGING_FAILURE"
},
{
"id": 54,
"name": "ENDPOINT_ICT_TAGGING_NOT_SUPPORTED"
},
{
"id": 55,
"name": "ENDPOINT_ICD_SUCCESS"
},
{
"id": 56,
"name": "ENDPOINT_ICD_FAILURE"
},
{
"id": 57,
"name": "PROTECT_FILE_TAGGED"
},
{
"id": 58,
"name": "PROTECT_FILE_TAGGING_FAILED"
},
{
"id": 59,
"name": "PROTECT_FILE_TAGGING_NOT_SUPPORTED"
},
{
"id": 60,
"name": "PROTECT_REMEDIATION_FAILED_CORRUPTION"
},
{
"id": 61,
"name": "REMEDIATION_PENDING"
},
{
"id": 62,
"name": "REMEDIATION_OVERRIDEN"
}
]
}
}
Human Readable Output
Incidents remediation status results
Id Name 0 PASSED 1 BLOCKED 2 MESSAGE_MODIFIED 3 PROTECT_FILE_COPIED 4 PROTECT_FILE_QUARANTINED 5 PROTECT_FILE_DELETED 6 PROTECT_REMEDIATION_ERROR 8 CONTENT_REMOVED 9 ENDPOINT_BLOCK 10 ENDPOINT_NOTIFY 11 FLEX_RESPONSE_EXECUTED 12 FLEX_RESPONSE_ERROR 13 FLEX_RESPONSE_REQUESTED 14 ENDPOINT_NOTIFY_CANCEL_ALLOW 15 ENDPOINT_NOTIFY_CANCEL_BLOCK 16 ENDPOINT_NOTIFY_CANCEL_TIMEOUT_ALLOW 17 ENDPOINT_NOTIFY_CANCEL_TIMEOUT_BLOCK 18 ENDPOINT_FILE_QUARANTINE_FAILED 19 ENDPOINT_FILE_QUARANTINED 20 UNKNOWN 21 EMAIL_QUARANTINED 22 EMAIL_APPROVED 23 EMAIL_BLOCKED 24 CUSTOM_ACTION_ON_EMAIL 25 EMAIL_MESSAGE_EXPUNGED 26 TRANSPORT_HEADERS_ADDED 27 VISUAL_TAG_ADDED 28 VISUAL_TAG_ADDITION_FAILED 29 QUARANTINE_FAILED 30 REST_ENCRYPTED 31 REST_PERFORMED_DRM 32 REST_PERFORMED_BREAK_LINKS 33 REST_PERFORMED_CUSTOM_ACTION 34 ENCRYPTED 35 ENCRYPT_FAILED 36 ENDPOINT_USER_ENCRYPT_CANCEL_ENCRYPT 37 ENDPOINT_USER_ENCRYPT_CANCEL_PREVENT 38 ENDPOINT_USER_ENCRYPT_CANCEL_TIMEOUT_ENCRYPT 39 ENDPOINT_USER_ENCRYPT_CANCEL_TIMEOUT_PREVENT 40 PROTECT_FILE_ENCRYPTED 41 REST_ACTION_REQUESTED 42 REST_ACTION_SUCCESS 43 REST_ACTION_FAILURE 44 REST_ACTION_WARNING 45 REST_USER_REMEDIATED 46 MANUAL_ACTION_REQUESTED 47 REST_RESTRICTED_FILE_AUTHORIZATION 48 REST_PREVENTED_PHYSICAL_ACCESS 49 REST_ADDITIONAL_ACCESS_PROTECTION 50 ENDPOINT_ENCRYPT 51 ENDPOINT_ENCRYPT_PREVENT_ENFORCED 52 ENDPOINT_ICT_TAGGING_SUCCESS 53 ENDPOINT_ICT_TAGGING_FAILURE 54 ENDPOINT_ICT_TAGGING_NOT_SUPPORTED 55 ENDPOINT_ICD_SUCCESS 56 ENDPOINT_ICD_FAILURE 57 PROTECT_FILE_TAGGED 58 PROTECT_FILE_TAGGING_FAILED 59 PROTECT_FILE_TAGGING_NOT_SUPPORTED 60 PROTECT_REMEDIATION_FAILED_CORRUPTION 61 REMEDIATION_PENDING 62 REMEDIATION_OVERRIDEN
symantec-dlp-get-incident-original-message
Fetches the original message from an incident. Requires SDLP 15.8.
Base Command
symantec-dlp-get-incident-original-message
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | The incident ID. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| InfoFile.EntryID | String | The EntryID of the original message file. |
| InfoFile.Extension | String | The extension of the original message file. |
| InfoFile.Name | String | The name of the original message file. |
| InfoFile.Info | String | The info of the original message file. |
| InfoFile.Size | Number | The size of the original message file. |
| InfoFile.Type | String | The type of the original message file. |
Command example
!symantec-dlp-get-incident-original-message incident_id=1
Context Example
{
"File": {
"EntryID": "2442@1a367091-9d9f-4851-8e71-bfbbb66563a6",
"Info": "text/plain",
"MD5": "cb79735bc7c9de30eb3a63110c6febd9",
"Name": "unknown",
"SHA1": "30dcc9ed8a7b1f44de4c4cdcde055708f96487d5",
"SHA256": "d085bf376b122a38064ef32ede13b0ff64b7dc085079e1cfd57ae664bf76d78b",
"SHA512": "3db852235a9d84dccacc04e805c5a3d843d0cd90c71833e2b8c68c17f77f04aadd88f8f72216a9f23417336e689c342a25588390002edd51605067a78bfabfa4",
"SSDeep": "3:ZwRRrPD+sGMw2Bu:+7Dy324",
"Size": 37,
"Type": "ASCII text, with no line terminators"
}
}
Human Readable Output
symantec-dlp-get-report-filters
Retrieves the filter criteria for a saved search in the Enforce console by report ID. Requires SDLP 16.0.
Base Command
symantec-dlp-get-report-filters
Input
| Argument Name | Description | Required |
|---|---|---|
| report_id | Report ID for which to retrieve filters. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SymantecDLP.ReportFilter | Unknown | The filter criteria for a saved search in the Enforce console. |
Command example
!symantec-dlp-get-report-filters report_id=1
Context Example
{
"SymantecDLP": {
"ReportFilter": {
"filter": {
"booleanOperator": "AND",
"filterType": "booleanLogic",
"filters": [
{
"filterType": "string",
"operandOne": {
"name": "messageSource"
},
"operandTwoValues": [
"NETWORK"
],
"operator": "EQ"
},
{
"booleanOperator": "AND",
"filterType": "booleanLogic",
"filters": [
{
"filterType": "localDateTime",
"operandOne": {
"name": "messageDate"
},
"operandTwoValues": [
"2022-01-01T00:00:00"
],
"operator": "GTE"
},
{
"filterType": "localDateTime",
"operandOne": {
"name": "messageDate"
},
"operandTwoValues": [
"2022-12-31T23:59:59"
],
"operator": "LTE"
},
{
"filterType": "string",
"operandOne": {
"function": "UPPER",
"name": "networkSenderIdentifier"
},
"operandTwoValues": [
"example_email@demisto.com"
],
"operator": "IN"
}
]
}
]
},
"filterString": "{\"select\": [{\"id\": 173, \"name\": \"messageDate\"}, {\"id\": 174, \"name\": \"incidentId\"}, {\"id\": 175, \"name\": \"networkSenderIdentifier\"}, {\"id\": 176, \"name\": \"messageSubject\"}, {\"id\": 177, \"name\": \"recipientIdentifier\"}, {\"id\": 178, \"name\": \"policyName\"}, {\"id\": 179, \"name\": \"matchCount\"}, {\"id\": 180, \"name\": \"incidentStatusName\"}], \"filter\": {\"filterType\": \"booleanLogic\", \"booleanOperator\": \"AND\", \"filters\": [{\"filterType\": \"string\", \"operandOne\": {\"name\": \"messageSource\"}, \"operator\": \"EQ\", \"operandTwoValues\": [\"NETWORK\"]}, {\"filterType\": \"booleanLogic\", \"booleanOperator\": \"AND\", \"filters\": [{\"filterType\": \"localDateTime\", \"operandOne\": {\"name\": \"messageDate\"}, \"operator\": \"GTE\", \"operandTwoValues\": [\"2022-01-01T00:00:00\"]}, {\"filterType\": \"localDateTime\", \"operandOne\": {\"name\": \"messageDate\"}, \"operator\": \"LTE\", \"operandTwoValues\": [\"2022-12-31T23:59:59\"]}, {\"filterType\": \"string\", \"operandOne\": {\"name\": \"networkSenderIdentifier\", \"function\": \"UPPER\"}, \"operator\": \"IN\", \"operandTwoValues\": [\"example_email@demisto.com\"]}]}]}, \"orderBy\": [{\"field\": {\"name\": \"messageDate\"}, \"order\": \"DESC\"}]}",
"orderBy": [
{
"field": {
"name": "messageDate"
},
"order": "DESC"
}
],
"select": [
{
"id": 173,
"name": "messageDate"
},
{
"id": 174,
"name": "incidentId"
},
{
"id": 175,
"name": "networkSenderIdentifier"
},
{
"id": 176,
"name": "messageSubject"
},
{
"id": 177,
"name": "recipientIdentifier"
},
{
"id": 178,
"name": "policyName"
},
{
"id": 179,
"name": "matchCount"
},
{
"id": 180,
"name": "incidentStatusName"
}
]
}
}
}
Human Readable Output
Returned results for report id 1
symantec-dlp-list-users
Returns details for all SDLP users from the Enforce console. Requires SDLP 16.0.
Base Command
symantec-dlp-list-users
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| SymantecDLP.Users | Unknown | List of SDLP users and details. |
Command example
#### Context Example
```json
{
"SymantecDLP": {
"Users": {
"accountDisabled": "no",
"emailAddress": "test@gmail.com",
"roles": [
"API Web"
],
"userId": 1,
"userName": "User1"
}
}
}
Human Readable Output
Symantec DLP Users
Accountdisabled Emailaddress Roles Userid Username no test@gmail.com API Web 1 User1
symantec-dlp-get-sender-recipient-pattern
Returns a sender/recipient pattern. Requires SDLP 16.0.
Base Command
symantec-dlp-get-sender-recipient-pattern
Input
| Argument Name | Description | Required |
|---|---|---|
| pattern_id | Pattern ID for which to retrieve pattern details. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SymantecDLP.SenderRecipientPattern | Unknown | Sender/recipient pattern returned from the Enforce console. |
Command example
!symantec-dlp-get-sender-recipient-pattern pattern_id=1
Context Example
{
"SymantecDLP": {
"SenderRecipientPattern": {
"description": "demo",
"id": 1,
"ipAddresses": [
"1.1.1.1",
"2.2.2.2"
],
"modifiedBy": {
"id": 343,
"name": "AdminUsername "
},
"modifiedDate": "05/16/23 12:20 PM",
"name": "XSOAR Sender Block Example",
"ruleType": 4,
"userPatterns": [
"domain-jsmith",
"domain-jdoe"
]
}
}
}
Human Readable Output
XSOAR Sender Block Example
description id ipAddresses modifiedBy modifiedDate name ruleType userPatterns demo 1 1.1.1.1,
2.2.2.2id: 343
name: AdminUsername05/16/23 12:20 PM XSOAR Sender Block Example 4 domain-jsmith,
domain-jdoe
symantec-dlp-list-sender-recipient-patterns
Returns a list of all sender/recipient patterns from the Enforce console. Requires SDLP 16.0.
Base Command
symantec-dlp-list-sender-recipient-patterns
Input
| Argument Name | Description | Required |
| — | — | — |
Context Output
| Path | Type | Description |
|---|---|---|
| SymantecDLP.Patterns | Unknown | The list of all sender/recipient patterns returned from the Enforce console. |
Command example
#### Context Example
```json
{
"SymantecDLP": {
"Patterns": {
"description": "demo",
"id": 1,
"ipAddresses": [
"1.1.1.1",
"2.2.2.2"
],
"modifiedBy": {
"id": 343,
"name": "AdminUsername "
},
"modifiedDate": "05/16/23 12:20 PM",
"name": "XSOAR Sender Block Example",
"ruleType": 4,
"userPatterns": [
"domain-jsmith",
"domain-jdoe"
]
}
}
}
Human Readable Output
Sender/Recipient Patterns
description id ipAddresses modifiedBy modifiedDate name ruleType userPatterns demo 1 1.1.1.1,
2.2.2.2id: 343
name: AdminUsername05/16/23 12:20 PM XSOAR Sender Block Example 4 domain-jsmith,
domain-jdoe
symantec-dlp-update-sender-pattern
Updates a sender pattern in the Enforce console. Requires SDLP 16.0.
Base Command
symantec-dlp-update-sender-pattern
Input
| Argument Name | Description | Required |
|---|---|---|
| pattern_id | ID number of the pattern to update. | Required |
| ips | Comma-separated list of IP addresses for the pattern. Note: These IP values will replace the existing values in the pattern. | Optional |
| users | Comma-separated list of emails, Windows names, or screen names for the pattern. Note: These user values will replace the existing values in the pattern. | Optional |
| name | Name of the sender pattern. Note: This value will change the name of the pattern if different from the existing name. | Required |
| description | Description of the sender pattern. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SymantecDLP.SenderUpdate | Unknown | Results of updating the sender pattern from the Enforce Console. |
Command example
!symantec-dlp-update-sender-pattern pattern_id=1 name="XSOAR Sender Block Example" description="demo"
Context Example
{
"SymantecDLP": {
"SenderUpdate": {
"description": "demo",
"id": 1,
"ipAddresses": [
"1.1.1.1",
"2.2.2.2"
],
"modifiedBy": {
"id": 343,
"name": "AdminUsername "
},
"modifiedDate": "05/16/23 12:20 PM",
"name": "XSOAR Sender Block Example",
"ruleType": 4,
"userPatterns": [
"domain-jsmith",
"domain-jdoe"
]
}
}
}
Human Readable Output
Sender Pattern Update Results
description id ipAddresses modifiedBy modifiedDate name ruleType userPatterns demo 1 1.1.1.1,
2.2.2.2id: 343
name: AdminUsername05/16/23 12:20 PM XSOAR Sender Block Example 4 domain-jsmith,
domain-jdoe
symantec-dlp-update-recipient-pattern
Updates a recipient pattern in the Enforce console. Requires SDLP 16.0.
Base Command
symantec-dlp-update-recipient-pattern
Input
| Argument Name | Description | Required |
|---|---|---|
| pattern_id | ID number of the pattern to update. | Required |
| ips | Comma-separated list of IP addresses for the pattern. Note: These IP values will replace the existing values in the pattern. | Optional |
| emails | Comma-separated list of emails for the pattern. Note: These email values will replace the existing values in the pattern. | Optional |
| domains | Comma-separated list of domains for the pattern. Note: These domain values will replace the existing values in the pattern. | Optional |
| name | Name of the sender pattern. Note: This value will change the name of the pattern if different from the existing name. | Required |
| description | Description of the sender pattern. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| SymantecDLP.RecipientUpdate | Unknown | Results of updating the recipient pattern from the Enforce Console. |
Command example
!symantec-dlp-update-recipient-pattern pattern_id=1 name="XSOAR Recipient Edit Test" description="updated from XSOAR for demo"
Context Example
{
"SymantecDLP": {
"RecipientUpdate": {
"description": "updated from XSOAR for demo",
"emailAddresses": [
"test1@gmail.com",
"test2@gmail.com"
],
"id": 1,
"ipAddresses": [
"1.1.1.1",
"2.2.2.2"
],
"modifiedBy": {
"id": 343,
"name": "AdminUsername"
},
"modifiedDate": "05/16/23 12:18 PM",
"name": "XSOAR Recipient Edit Test",
"ruleType": 2,
"urlDomains": [
"example.com",
"external.com"
]
}
}
}
Human Readable Output
Sender Pattern Update Results
description emailAddresses id ipAddresses modifiedBy modifiedDate name ruleType urlDomains updated from XSOAR for demo test1@gmail.com,
test2@gmail.com1 1.1.1.1,
2.2.2.2id: 343
name: AdminUsername05/16/23 12:18 PM XSOAR Recipient Edit Test 2 example.com,
external.com
symantec-dlp-get-message-body
Returns the message body from the Enforce console by incident ID. Requires SDLP 16.0.
Base Command
symantec-dlp-get-message-body
Input
| Argument Name | Description | Required |
|---|---|---|
| incident_id | The incident ID. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| SymantecDLP.MessageBody | Unknown | Message body for the incident returned by the Enforce console. |
Command example
!symantec-dlp-get-message-body incident_id=1
Context Example
{
"SymantecDLP": {
"MessageBody": {
"IncidentID": "1",
"MessageBody": "message body for incident 1"
}
}
}
Human Readable Output
Message body for incident 1 written to context data
Breaking changes from the previous version of this integration - Symantec Data Loss Prevention v2
Commands
The following commands were removed in this version
- symantec-dlp-incident-binaries
- symantec-dlp-incident-violations
- symantec-dlp-list-custom-attributes
Arguments
The following arguments were removed in this version
In the symantec-dlp-update-incident command:
- incident_id - this argument was replaced by incident_ids.
- note_time
- status
- custom_attribute_name - this argument was replaced by custom_attributes.
- custom_attribute_value - this argument was replaced by custom_attributes.
- remediation_status - this argument was replaced by remediation_status_name.
The behavior of the following arguments was changed
In the symantec-dlp-update-incident command:
custom_attribute_name and custom_attribute_value are now used in custom_attributes.
incident_id argument are now called incident_ids and can get a list of incident IDs to update.
Outputs
The following outputs were removed in this version
In the symantec-dlp-get-incident-details command:
- SymantecDLP.Incident.LongID
- SymantecDLP.Incident.StatusCode - this output was replaced by SymantecDLP.Incident.incidentStatusId.
- SymantecDLP.Incident.CreationDate - this output was replaced by SymantecDLP.Incident.creationDate.
- SymantecDLP.Incident.DetectionDate - this output was replaced by SymantecDLP.Incident.detectionDate.
- SymantecDLP.Incident.Severity - this output was replaced by SymantecDLP.Incident.severity.
- SymantecDLP.Incident.MessageSource - this output was replaced by SymantecDLP.Incident.messageSource.
- SymantecDLP.Incident.MessageSourceType - this output was replaced by SymantecDLP.Incident.messageType.
- SymantecDLP.Incident.MessageType - this output was replaced by SymantecDLP.Incident.messageType.
- SymantecDLP.Incident.MessageTypeID - this output was replaced by *SymantecDLP.Incident.messageTypeId.*
- SymantecDLP.Incident.Policy.Name - this output was replaced by SymantecDLP.Incident.policyName.
- SymantecDLP.Incident.Policy.Version - this output was replaced by SymantecDLP.Incident.policyVersion.
- SymantecDLP.Incident.Policy.Label
- SymantecDLP.Incident.Policy.ID - this output was replaced by SymantecDLP.Incident.policyId.
- SymantecDLP.Incident.BlockedStatus
- SymantecDLP.Incident.MatchCount - this output was replaced by SymantecDLP.Incident.matchCount.
- SymantecDLP.Incident.RuleViolationCount
- SymantecDLP.Incident.DetectionServer - this output was replaced by SymantecDLP.Incident.detectionServerName.
- SymantecDLP.Incident.DataOwner.Name - this output was replaced by SymantecDLP.Incident.dataOwnerName.
- SymantecDLP.Incident.DataOwner.Email - this output was replaced by SymantecDLP.Incident.dataOwnerEmail.
- SymantecDLP.Incident.EventDate
- SymantecDLP.Incident.ViolatedPolicyRule.Name
- SymantecDLP.Incident.ViolatedPolicyRule.ID
- SymantecDLP.Incident.OtherViolatedPolicy.Name
- SymantecDLP.Incident.OtherViolatedPolicy.Version
- SymantecDLP.Incident.OtherViolatedPolicy.Label
- SymantecDLP.Incident.OtherViolatedPolicy.ID
Additional Considerations for this version
There is an issue with DLP API where some incidents get a 401 error.
For these incidents, the missing data is returned. From the Network incident layout, in the description field, you can see information about this issue.
Configuration parameters
server— Enforce Server (e.g. https://192.168.0.1) (required)credentials— Username (required)first_fetch— First fetch timestamp (<number> <time unit>, e.g., 12 hours, 7 days)max_fetch— Fetch limitfetchIncidentType— Fetch incidents from typeincidentStatusId— Incident Status IDincidentSeverity— Incident Severityinsecure— Trust any certificate (not secure)proxy— Use system proxy settingsisFetch— Fetch incidentsincidentType— Incident typeincidentFetchInterval— Incidents Fetch Intervalincidents_time_zone— Incidents Time Zone
Commands (14)
-
symantec-dlp-get-incident-detailsReturns details of the specified incident.
-
symantec-dlp-get-incident-historyReturns the history of the specified incident.
-
symantec-dlp-get-incident-original-messageFetches the original message from an incident. Requires SDLP 15.8.
-
symantec-dlp-get-message-bodyReturns the message body from the Enforce console by incident ID. Requires SDLP 16.0.
-
symantec-dlp-get-report-filtersRetrieve the filter criteria for a saved search in the Enforce console by report ID. Requires SDLP 16.0.
-
symantec-dlp-get-sender-recipient-patternReturns a sender/recipient pattern. Requires SDLP 16.0.
-
symantec-dlp-list-incident-statusReturns a list of the custom status values defined in the Symantec DLP deployment.
-
symantec-dlp-list-incidentsReturns a list of incidents.
-
symantec-dlp-list-remediation-statusReturns a list of the remediation status values defined in the Symantec DLP deployment.
-
symantec-dlp-list-sender-recipient-patternsReturns a list of all sender/recipient patterns from the Enforce console. Requires SDLP 16.0.
-
symantec-dlp-list-usersReturns details for all SDLP users from the Enforce console. Requires SDLP 16.0.
-
symantec-dlp-update-incidentUpdates the details of a specific incident.
-
symantec-dlp-update-recipient-patternUpdates a recipient pattern in the Enforce console. Requires SDLP 16.0.
-
symantec-dlp-update-sender-patternUpdates a sender pattern in the Enforce console. Requires SDLP 16.0.
from typing import Any import dateparser import demistomock as demisto # noqa: F401 import requests import pytz # Disable insecure warnings import urllib3 from CommonServerPython import * # noqa: F401 urllib3.disable_warnings() """ CONSTANTS """ DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ" # ISO8601 format with UTC, default in XSOAR TIME_ZONE = "UTC" MAX_PAGE_SIZE = 50 INCIDENT_TYPE_MAPPING = {"Network": "NETWORK", "Discover": "DISCOVER", "Endpoint": "ENDPOINT"} INCIDENT_SEVERITY_MAPPING = {"Info": 4, "Low": 3, "Medium": 2, "High": 1} UPDATE_INCIDENT_SEVERITY_MAPPING = {"Info": "INFO", "Low": "LOW", "Medium": "MEDIUM", "High": "HIGH"} INCIDENT_UPDATE_MAPPING = { "incident_id": "incidentIds", "data_owner_email": "dataOwnerEmail", "data_owner_name": "dataOwnerName", "note": "incidentNotes", "incident_status_id": "incidentStatusId", "remediation_status_name": "preventOrProtectStatus", "remediation_location": "remediationLocation", "severity": "severity", "custom_attributes": "incidentCustomAttributes", } INCIDENTS_LIST_BODY = [ {"name": "incidentId"}, {"name": "incidentStatusId"}, {"name": "creationDate"}, {"name": "detectionDate"}, {"name": "severityId"}, {"name": "messageSource"}, {"name": "messageTypeId"}, {"name": "policyVersion"}, {"name": "policyId"}, {"name": "matchCount"}, {"name": "detectionServerId"}, ] """ CLIENT CLASS """ class Client(BaseClient): def __init__(self, base_url, verify, proxy, headers, auth): super().__init__(base_url=base_url, verify=verify, proxy=proxy, headers=headers, auth=auth) def get_incidents_request( self, creation_date: str = None, status_id: List[str] = None, severity: List[int] = None, incident_type: List[str] = None, limit: int = MAX_PAGE_SIZE, order_by: bool = None, raw_filter: str = None, ): """Returns incidents list in the input (dummy). :param creation_date: The creation date to filter. (greater than the creation date) :param status_id: The status IDs to filter. :param severity: The severities to filter. :param incident_type: The incident types to filter. :param limit: The limit of the incidents. :param order_by: If order by according the creation date or not :param raw_filter: Full filter that is used for the body of the request, bypasses all other filters criteria. """ if raw_filter: try: data = json.loads(raw_filter) data["limit"] = limit except ValueError as e: raise ValueError( f"The provided filter must be in JSON format as detailed" f" at https://apidocs.securitycloud.symantec.com/#/: " f"\nError: {e}" ) else: data = {"limit": limit, "select": INCIDENTS_LIST_BODY} if order_by: data["orderBy"] = [{"order": "ASC", "field": {"name": "creationDate"}}] if creation_date or status_id or severity or incident_type: data["filter"] = {"booleanOperator": "AND", "filterType": "booleanLogic", "filters": []} if creation_date: data["filter"]["filters"].append( # type: ignore create_filter_dict( filter_type="localDateTime", filter_by="creationDate", filter_value=[creation_date], operator="GT" ) ) if status_id: data["filter"]["filters"].append( # type: ignore create_filter_dict( filter_type="long", filter_by="incidentStatusId", filter_value=status_id, operator="IN" ) ) if severity: data["filter"]["filters"].append( # type: ignore create_filter_dict(filter_type="long", filter_by="severityId", filter_value=severity, operator="IN") ) if incident_type: data["filter"]["filters"].append( # type: ignore create_filter_dict( filter_type="string", filter_by="messageSource", filter_value=incident_type, operator="IN" ) ) headers = self._headers response = self._http_request( method="POST", url_suffix="/ProtectManager/webservices/v2/incidents", json_data=data, headers=headers ) return response def update_incident_request(self, update_body: dict[str, Any]) -> dict[str, str]: """Update incident :param update_body: The details to update in the incident. """ headers = self._headers response = self._http_request( method="PATCH", url_suffix="/ProtectManager/webservices/v2/incidents", headers=headers, json_data=update_body ) return response def get_incident_static_attributes_request(self, incident_id: str) -> dict[str, str]: """Returns incident static attributes. :param incident_id: The incident ID. """ headers = self._headers response = self._http_request( method="GET", url_suffix=f"/ProtectManager/webservices/v2/incidents/{incident_id}/staticAttributes", headers=headers, ) return response def get_incident_editable_attributes_request(self, incident_id: str) -> dict[str, str]: """Returns incident editable attributes. :param incident_id: The incident ID. """ headers = self._headers response = self._http_request( method="GET", url_suffix=f"/ProtectManager/webservices/v2/incidents/{incident_id}/editableAttributes", headers=headers, ) return response def get_incidents_status_request(self) -> List[dict]: """Returns incidents status""" headers = self._headers response = self._http_request( method="GET", url_suffix="/ProtectManager/webservices/v2/incidents/statuses", headers=headers ) return response def get_incident_history_request(self, incident_id: Optional[int]) -> List[dict]: """Returns incident history :param incident_id: The incident ID. """ headers = self._headers response = self._http_request( method="GET", url_suffix=f"/ProtectManager/webservices/v2/incidents/{incident_id}/history", headers=headers ) return response def get_list_remediation_status_request(self) -> List[dict]: """Returns incidents remediation status""" headers = self._headers response = self._http_request( method="GET", url_suffix="/ProtectManager/webservices/v2/incidents/protectOrPreventStatuses", headers=headers ) return response def get_incident_original_message_request(self, incident_id: str) -> requests.Response: """Returns incident original message. :param incident_id: The incident ID. """ headers = self._headers response = self._http_request( method="GET", url_suffix=f"/ProtectManager/webservices/v2/incidents/{incident_id}/originalMessage", headers=headers, resp_type="bytes", ) return response def get_report_filters_request(self, report_id: str) -> dict[str, str]: """Returns incident static attributes. :param report_id: The report id ID. """ headers = self._headers response = self._http_request( method="GET", url_suffix=f"/ProtectManager/webservices/v2/savedReport/{report_id}", headers=headers ) return response def get_sdlp_users_request(self) -> List[dict]: """Returns list of SDLP users""" headers = self._headers response = self._http_request(method="GET", url_suffix="/ProtectManager/webservices/v2/users", headers=headers) return response def get_sender_recipient_pattern_request(self, pattern_id: str) -> dict[str, str]: """Returns incident static attributes. :param incident_id: The incident ID. """ headers = self._headers response = self._http_request( method="GET", url_suffix=f"/ProtectManager/webservices/v2/senderRecipientPattern/{pattern_id}", headers=headers ) return response def list_sender_recipient_patterns_request(self) -> List[dict]: """Returns list of sender/recipient patterns""" headers = self._headers response = self._http_request( method="GET", url_suffix="/ProtectManager/webservices/v2/senderRecipientPattern/list", headers=headers ) return response def update_sender_pattern_request( self, pattern_id: str, pattern_name: str | None, pattern_description: str | None, new_ips: List[str] = None, new_users: List[str] = None, ) -> dict[str, str]: """ Updates the sender pattern :param pattern_id: The pattern ID to update :param pattern_name: The new name for the sender pattern :param pattern_description: The new description for the sender pattern :param new_ips: List of new IP address values :param new_users: List of new """ headers = self._headers data = { "name": pattern_name, "description": pattern_description, "ruleType": 4, # ruleType 4 = Sender pattern } if new_ips: data["ipAddresses"] = new_ips # type: ignore[assignment] if new_users: data["userPatterns"] = new_users # type: ignore[assignment] response = self._http_request( method="PUT", url_suffix=f"/ProtectManager/webservices/v2/senderRecipientPattern/{pattern_id}", headers=headers, json_data=data, ) return response def update_recipient_pattern_request( self, pattern_id: str, pattern_name: str | None, pattern_description: str | None, new_ips: List[str] = None, new_emails: List[str] = None, new_domains: List[str] = None, ) -> dict[str, str]: """ Updates the sender pattern :param pattern_id: The pattern ID to update :param pattern_name: The new name for the sender pattern :param pattern_description: The new description for the sender pattern :param new_ips: List of new IP address values :param new_emails: List of new email address values :param new_domains: List of new domain values """ headers = self._headers data = { "name": pattern_name, "description": pattern_description, "ruleType": 2, # ruleType 2 = Recipient pattern } if new_ips: data["ipAddresses"] = new_ips # type: ignore[assignment] if new_emails: data["emailAddresses"] = new_emails # type: ignore[assignment] if new_domains: data["urlDomains"] = new_domains # type: ignore[assignment] response = self._http_request( method="PUT", url_suffix=f"/ProtectManager/webservices/v2/senderRecipientPattern/{pattern_id}", headers=headers, json_data=data, ) return response def get_message_body_request(self, incident_id: str) -> dict[str, str]: """Returns incident message body. :param incident_id: The incident ID. """ headers = self._headers response = self._http_request( method="GET", url_suffix=f"/ProtectManager/webservices/v2/incidents/{incident_id}/messageBody", headers=headers ) return response """ HELPER FUNCTIONS """ def check_status_ids_type(status_ids_list: list): if not all(status_id.isdigit() for status_id in status_ids_list): raise ValueError("Status IDs must be integers.") return status_ids_list def create_filter_dict(filter_type: str, filter_by: str, filter_value: List[Any], operator: str) -> dict[str, Any]: """Creates a dictionary with the filter for the list-incidents request. :param filter_type: The filter type. :param filter_by: The field name to filter by. :param filter_value: The filter value. :param operator: The operator to use for the filter. """ return {"filterType": filter_type, "operandOne": {"name": filter_by}, "operandTwoValues": filter_value, "operator": operator} def get_severity_name_by_id(severity: Optional[int]): """Returns the name of the severity according to the given severity ID :param severity: The severity ID. """ for severity_name, severity_num in INCIDENT_SEVERITY_MAPPING.items(): # noqa: RET503 if severity_num == severity: return severity_name def parse_creation_date(creation_date: str): if creation_date: creation_date = dateparser.parse( creation_date, settings={"TIMEZONE": TIME_ZONE, "RETURN_AS_TIMEZONE_AWARE": True, "TO_TIMEZONE": "UTC"} ).strftime(DATE_FORMAT) # type: ignore[union-attr] return creation_date def set_time_zone(timezone_str: str): global TIME_ZONE if timezone_str in pytz.all_timezones: TIME_ZONE = timezone_str def get_readable_output_incidents_list(incidents_list: List[dict]): readable_output = [] for incident in incidents_list: readable_output.append( assign_params( **{ "ID": incident.get("incidentId"), "Severity": get_severity_name_by_id(arg_to_number(incident.get("severityId"))), "Status": incident.get("incidentStatusId"), "Incident Type": incident.get("messageSource"), "Creation Date": incident.get("creationDate"), "Message Type": incident.get("messageType"), "Policy ID": incident.get("policyId"), "Match Count": incident.get("matchCount"), } ) ) return readable_output def get_context_incidents_list(incidents_list: List[dict]): for incident in incidents_list: incident_id = {"ID": incident.get("incidentId")} incident_severity = {"severity": get_severity_name_by_id(arg_to_number(incident.get("severityId")))} incident.pop("severityId") incident.pop("incidentId") incident.update(incident_id) incident.update(incident_severity) return incidents_list def get_readable_output_incident_details(incidents_list: List[dict]): readable_output = [] for incident in incidents_list: readable_output.append( assign_params( **{ "ID": incident.get("incidentId"), "Severity": get_severity_name_by_id(incident.get("severityId")), "Incident Type": incident.get("messageSource"), "Creation Date": incident.get("creationDate"), "Detection Date": incident.get("detectionDate"), "Message Type": incident.get("messageType"), "Message Source": incident.get("messageSource"), "Detection Server Name": incident.get("detectionServerName"), "Data Owner Name": incident.get("dataOwnerName"), "Data Owner Email": incident.get("dataOwnerEmail"), "Status": incident.get("incidentStatusId"), "Policy Name": incident.get("policyName"), "Policy Group Name": incident.get("policyGroupName"), "Custom Attributes": incident.get("customAttributeGroup"), } ) ) return readable_output def get_incidents_of_current_page(limit, page, page_size, incidents_list): """ :param limit: The limit of the incidents. :param page: The page number :param page_size: Maximum number of objects to retrieve per page. :param incidents_list: The incidents list :return: List of objects from the response according to the limit, page and page_size. """ if page is not None and page_size is not None: if page <= 0: raise Exception("Chosen page number must be greater than 0") start = (page - 1) * page_size end = page * page_size return incidents_list[start:end] limit = limit if limit else MAX_PAGE_SIZE return incidents_list[0:limit] def parse_custom_attribute(custom_attribute_group_list: list, args: dict) -> list: """ Returns a list of all custom attributes chosen by the user. There are four options to choose from: all, none, specific attributes, custom attributes group name. The choosing flag is given in demisto.args value in the field custom_attributes. If the user has chosen "all" then the function will return all custom attributes possible (from all groups). If the user has chosen "none" then the function won't return any custom attributes. If the user has chosen "specific attributes" then he must also provide a list of all custom attribute names in the demisto.args dict under the field "custom_data". If not provided, an error msg will be shown. If provided, the function will return only the custom attributes mentioned in the custom_data list. If the user has chosen "custom attributes group name" the handling of this option is similar to the "custom" option. :param custom_attribute_group_list: the raw list of custom attributes group (as returned from the request) :param args: demisto.args :return: the parsed custom attributes list """ custom_attributes_flag = args.get("custom_attributes") custom_attributes_list: list = [] # all case if custom_attributes_flag == "all": for group in custom_attribute_group_list: custom_attributes_list.append(get_all_group_custom_attributes(group)) # custom attributes group name case elif custom_attributes_flag == "custom attribute group name": custom_data = args.get("custom_data") if not custom_data: raise DemistoException( "When choosing the group value for custom_attributes argument - the custom_data" " list must be filled with group names. For example: custom_value=g1,g2,g3" ) group_name_list: list = argToList(custom_data, ",") for group in custom_attribute_group_list: if group.get("name") in group_name_list: custom_attributes_list.append(get_all_group_custom_attributes(group)) # specific attributes case elif custom_attributes_flag == "specific attributes": custom_data = args.get("custom_data") if not custom_data: raise DemistoException( "When choosing the custom value for custom_attributes argument - the custom_data" " list must be filled with custom attribute names." " For example: custom_value=ca1,ca2,ca3" ) custom_attribute_name_list: list = argToList(custom_data, ",") for group in custom_attribute_group_list: for raw_custom_attribute in group.get("customAttributes", []): custom_attribute_name: str = raw_custom_attribute.get("name") if custom_attribute_name in custom_attribute_name_list: custom_attribute: dict = {"name": custom_attribute_name} custom_attribute_value = raw_custom_attribute.get("value") if custom_attribute_value: custom_attribute["value"] = custom_attribute_value custom_attribute["index"] = raw_custom_attribute.get("index") custom_attributes_list.append({"name": group.get("name"), "customAttribute": custom_attribute}) # none case - If custom_attributes_flag == 'none' than we return empty list return custom_attributes_list def get_all_group_custom_attributes(group: dict) -> dict: """ Returns a list of all the custom attributes in the group :param group: the group :return: the list of all custom attributes """ custom_attributes_dict: dict = {"name": group.get("name"), "customAttribute": []} for raw_custom_attribute in group.get("customAttributes", []): custom_attribute: dict = {"name": raw_custom_attribute.get("name"), "index": raw_custom_attribute.get("index")} custom_attribute_value = raw_custom_attribute.get("value") if custom_attribute_value: custom_attribute["value"] = custom_attribute_value custom_attributes_dict["customAttribute"].append(custom_attribute) return custom_attributes_dict def get_common_incident_details(static_attributes: dict, editable_attributes: dict, args) -> dict: """ Parses the needed incident details into context paths :param static_attributes: The static attributes of the incident :param editable_attributes: The editable attributes of the incident :param args: demisto.args :return: the parsed dict """ incident_info_map_editable = editable_attributes.get("infoMap", {}) incident_info_map_static = static_attributes.get("infoMap", {}) incident_custom_attribute_groups = editable_attributes.get("customAttributeGroups", []) incident_details: dict = assign_params( ID=static_attributes.get("incidentId"), severity=get_severity_name_by_id(arg_to_number(incident_info_map_editable.get("severityId"))), customAttributeGroup=parse_custom_attribute(incident_custom_attribute_groups, args), ) static_attributes.pop("incidentId") editable_attributes.pop("incidentId") incident_info_map_editable.pop("severityId") editable_attributes.pop("customAttributeGroups", []) incident_details.update(incident_info_map_static) incident_details.update(incident_info_map_editable) return assign_params(**incident_details) def get_details_unauthorized_incident(incident_data): incident_details: dict = assign_params( ID=incident_data.get("incidentId"), creationDate=incident_data.get("creationDate"), policyId=incident_data.get("policyId"), severity=get_severity_name_by_id(arg_to_number(incident_data.get("severityId"))), incidentStatusId=incident_data.get("incidentStatusId"), detectionDate=incident_data.get("detectionDate"), policyVersion=incident_data.get("policyVersion"), messageSource=incident_data.get("messageSource"), messageType=incident_data.get("messageType"), matchCount=incident_data.get("matchCount"), errorMessage="Notice: Incident contains partial data only", ) return {key: val for key, val in incident_details.items() if val} def get_hr_context_incidents_status(status_list: List[dict]): status_readable_output = [] for status in status_list: status_readable_output.append(assign_params(id=status.get("id"), name=status.get("name"))) return status_readable_output def get_readable_output_incident_history(incident_history_list: List[dict]): history_readable_output = [] for incident_history in incident_history_list: history_readable_output.append( assign_params( **{ "History Date": incident_history.get("incidentHistoryDate"), "Incident History Action": incident_history.get("incidentHistoryAction"), "DLP User Name": incident_history.get("dlpUserName"), } ) ) return history_readable_output def get_context_incident_history(incident_history_list: List[dict]): history_context = [] incident_id = arg_to_number(incident_history_list[0].get("incidentId")) for incident_history in incident_history_list: incident_history.pop("incidentId") incident_history.pop("incidentHistoryActionI18nKey") incident_history.pop("internationalized") history_context.append({"ID": incident_id, "incidentHistory": incident_history_list}) return history_context def create_update_body( incident_ids: list, data_owner_email: str = None, data_owner_name: str = None, note: str = None, incident_status_id: str = None, remediation_status_name: str = None, remediation_location: str = None, severity: str = None, custom_attributes: List[str] = None, ): data: dict[str, Any] = assign_params( incidentIds=incident_ids, dataOwnerEmail=data_owner_email, dataOwnerName=data_owner_name, incidentStatusId=incident_status_id, preventOrProtectStatus=remediation_status_name, remediationLocation=remediation_location, severity=severity, ) custom_attributes_list = build_custom_attributes_update(custom_attributes) # type: ignore if custom_attributes_list: data["incidentCustomAttributes"] = custom_attributes_list if note: data["incidentNotes"] = [{"note": note}] return data def build_custom_attributes_update(custom_attributes: List[str]): """ Builds the custom_attributes_list that the user wants to update. The input should be {columnIndex}:{newValue}. :param custom_attributes: The custom attributes the user wants to update :return: A list of custom attributes """ custom_attributes_list = [] for attribute in custom_attributes: splitted_att = attribute.split(":") if len(splitted_att) != 2: raise DemistoException("Error: custom_attributes argument format is {columnIndex}:{newValue}. E.g: 1:test") attribute_index = splitted_att[0] if not attribute_index.isdigit(): raise DemistoException("Error: The attribute index must be an integer.") attribute_value = splitted_att[1] custom_attributes_list.append({"columnIndex": int(attribute_index), "value": attribute_value}) return custom_attributes_list def get_incident_details_fetch(client, incident): """ Create incident details dict for each incident pulled from the fetch In case of getting 401 error we will return missing data on the incident. """ incident_details = {} try: incident_id = incident.get("incidentId") static_attributes = client.get_incident_static_attributes_request(incident_id) editable_attributes = client.get_incident_editable_attributes_request(incident_id) incident_details = get_common_incident_details(static_attributes, editable_attributes, args={"custom_attributes": "all"}) # In case of getting 401 (Unauthorized incident) - will get missing data except DemistoException as e: if "401" in str(e): incident_details = get_details_unauthorized_incident(incident) else: raise e return incident_details """ COMMAND FUNCTIONS """ def test_module(client: Client, params, fetch_time, fetch_limit, incident_type, incident_status_id, incident_severity) -> str: message: str = "" try: if params.get("isFetch"): fetch_incidents( client, fetch_time=fetch_time, fetch_limit=fetch_limit, last_run={}, incident_types=incident_type, incident_status_id=incident_status_id, incident_severities=incident_severity, is_test=True, ) else: client.get_incidents_request() message = "ok" except DemistoException as e: if "Forbidden" in str(e) or "Unauthorized" in str(e): message = "Authorization Error: make sure username and password are correctly set" else: raise e return message def list_incidents_command(client: Client, args: dict[str, Any]) -> CommandResults: creation_date = parse_creation_date(args.get("creation_date", "")) status_ids = argToList(args.get("status_id", "")) severities = argToList(args.get("severity", "")) severities_dlp = [INCIDENT_SEVERITY_MAPPING[severity] for severity in severities] incident_types = argToList(args.get("incident_type", "")) incident_types_dlp = [INCIDENT_TYPE_MAPPING[incident_type] for incident_type in incident_types] limit = arg_to_number(args.get("limit", 50)) page = arg_to_number(args.get("page", 1)) page_size = arg_to_number(args.get("page_size")) raw_filter = args.get("raw_filter") try: incidents_result = client.get_incidents_request( creation_date, status_ids, severities_dlp, incident_types_dlp, limit * page, # type: ignore[operator] raw_filter=raw_filter, ) except DemistoException as error: if raw_filter: raise DemistoException(f"Please make sure the {raw_filter=} is correct, {error=}") raise incidents_result = get_incidents_of_current_page(limit, page, page_size, incidents_list=incidents_result.get("incidents", [])) if raw_filter: list_incidents_hr = incidents_result context_incidents_list = incidents_result if incidents_result: output_headers = list(incidents_result[0].keys()) else: output_headers = None else: list_incidents_hr = get_readable_output_incidents_list(incidents_result) context_incidents_list = get_context_incidents_list(incidents_result) output_headers = [ "ID", "Severity", "Status", "Creation Date", "Incident Type", "Message Type", "Policy ID", "Match Count", ] return CommandResults( readable_output=tableToMarkdown( "Symantec DLP incidents results", list_incidents_hr, removeNull=True, headers=output_headers ), outputs_prefix="SymantecDLP.Incident", outputs_key_field="ID", outputs=context_incidents_list, ) def update_incident_command(client: Client, args: dict[str, Any]) -> CommandResults: incident_ids = argToList(args.get("incident_ids")) if not all(incident_id.isdigit() for incident_id in incident_ids): raise ValueError("Incident IDs must be integers.") data_owner_email = args.get("data_owner_email", "") data_owner_name = args.get("data_owner_name", "") note = args.get("note", "") incident_status_id = args.get("incident_status_id", "") remediation_status_name = args.get("remediation_status_name", "") remediation_location = args.get("remediation_location", "") severity = args.get("severity", "") if severity: severity = UPDATE_INCIDENT_SEVERITY_MAPPING[severity] custom_attributes = argToList(args.get("custom_attributes", "")) update_body = create_update_body( incident_ids=incident_ids, data_owner_email=data_owner_email, data_owner_name=data_owner_name, note=note, incident_status_id=incident_status_id, remediation_status_name=remediation_status_name, remediation_location=remediation_location, severity=severity, custom_attributes=custom_attributes, ) client.update_incident_request(update_body) return CommandResults(readable_output=f"Symantec DLP incidents: {incident_ids} were updated") def get_incident_details_command(client: Client, args: dict[str, Any]): """ static attributes API docs - https://techdocs.broadcom.com/us/en/symantec-security-software/information-security/ data-loss-prevention/15-8/DLP-Enforce-REST-APIs-overview/definitions/staticincidentinfomap.html editable attributes API docs - https://techdocs.broadcom.com/us/en/symantec-security-software/information-security/ data-loss-prevention/15-8/DLP-Enforce-REST-APIs-overview/definitions/editableincidentinfomap.html """ try: incident_id = args.get("incident_id", "") custom_attributes = args.get("custom_attributes", "") custom_data = args.get("custom_data", "") if custom_attributes in ["specific_attributes", "custom_attribute_group_name"] and not custom_data: raise DemistoException( "Error: custom_data argument must be provided if you chose specific_attributes or custom_attribute_group_name." ) static_attributes = client.get_incident_static_attributes_request(incident_id) editable_attributes = client.get_incident_editable_attributes_request(incident_id) incident_details = get_common_incident_details(static_attributes, editable_attributes, args=args) incident_details_hr = get_readable_output_incident_details([incident_details]) return CommandResults( readable_output=tableToMarkdown( f"Symantec DLP incident {incident_id} details", incident_details_hr, removeNull=True, json_transform_mapping={ "Custom Attributes": JsonTransformer(keys=("GroupName", "name", "value"), is_nested=True) }, headers=[ "ID", "Severity", "Status", "Creation Date", "Detection Date", "Incident Type", "Policy Name", "Policy Group Name", "Detection Server Name", "Message Type", "Message Source", "Data Owner Name", "Data Owner Email", "Custom Attributes", ], ), outputs_prefix="SymantecDLP.Incident", outputs_key_field="ID", outputs=incident_details, ) except DemistoException as e: if "401" in str(e): raise DemistoException(f"Error 401: Incident access not authorized or the incident does not exist. {e.res}") else: raise DemistoException(f"Error {e.res}") def list_incident_status_command(client: Client) -> CommandResults: incidents_status_result = client.get_incidents_status_request() return CommandResults( readable_output=tableToMarkdown( "Symantec DLP incidents status", camelize(incidents_status_result), removeNull=True, ), outputs_prefix="SymantecDLP.IncidentStatus", outputs_key_field="id", outputs=incidents_status_result, ) def get_incident_history_command(client: Client, args: dict[str, Any]) -> CommandResults: incident_id = arg_to_number(args.get("incident_id")) limit = arg_to_number(args.get("limit", 50)) incident_history_result = client.get_incident_history_request(incident_id) incident_history_result = incident_history_result[:limit] incidents_history_hr = get_readable_output_incident_history(incident_history_result) incidents_history_context = get_context_incident_history(incident_history_result) return CommandResults( readable_output=tableToMarkdown( f"Symantec DLP Incident {incident_id} history results", incidents_history_hr, removeNull=True ), outputs_prefix="SymantecDLP.IncidentHistory", outputs_key_field="incidentId", outputs=remove_empty_elements(incidents_history_context), ) def get_list_remediation_status(client: Client) -> CommandResults: remediation_status_result = client.get_list_remediation_status_request() remediation_status_output = get_hr_context_incidents_status(remediation_status_result) return CommandResults( readable_output=tableToMarkdown( "Incidents remediation status results", camelize(remediation_status_output), removeNull=True ), outputs_prefix="SymantecDLP.IncidentRemediationStatus", outputs_key_field="id", outputs=remediation_status_output, ) def get_incident_original_message_command(client: Client, args: dict[str, Any]): """ Fetch the original message """ try: incident_id = args.get("incident_id", "") results = client.get_incident_original_message_request(incident_id) original_message_file = results.content try: original_filename = results.headers.get("Content-Disposition").split("=")[1] # type: ignore[union-attr] except (TypeError, IndexError, AttributeError): original_filename = "unknown" return fileResult(original_filename, original_message_file) except DemistoException as e: if "401" in str(e): raise DemistoException(f"Error 401: Incident access not authorized or the incident does not exist. {e.res}") else: raise DemistoException(f"Error {e.res}") def get_report_filters_command(client: Client, args: dict[str, Any]): """ Get report filters """ try: report_id = args.get("report_id", "") report_results = client.get_report_filters_request(report_id) report_results["filterString"] = json.dumps(report_results) return CommandResults( readable_output=f"Returned results for report id {report_id}", outputs_prefix="SymantecDLP.ReportFilter", outputs=report_results, outputs_key_field="id", ) except DemistoException as e: if "401" in str(e): raise DemistoException(f"Error 401: Report access not authorized or the report does not exist. {e.res}") else: raise DemistoException(f"Error {e.res}") def list_users_command(client: Client) -> CommandResults: users_results = client.get_sdlp_users_request() return CommandResults( readable_output=tableToMarkdown( "Symantec DLP Users", camelize(users_results), removeNull=True, ), outputs_prefix="SymantecDLP.Users", outputs_key_field="id", outputs=users_results, ) def get_sender_recipient_pattern_command(client: Client, args: dict[str, Any]): """ Fetch the original message """ pattern_id = args.get("pattern_id", "") pattern_results = client.get_sender_recipient_pattern_request(pattern_id) return CommandResults( readable_output=tableToMarkdown( name=pattern_results.get("name") or f"Pattern Results for Pattern ID {pattern_id}", t=pattern_results, ), outputs_prefix="SymantecDLP.SenderRecipientPattern", outputs=pattern_results, outputs_key_field="id", ) def list_sender_recipient_patterns_command(client: Client) -> CommandResults: patterns_results = client.list_sender_recipient_patterns_request() return CommandResults( readable_output=tableToMarkdown("Sender/Recipient Patterns", patterns_results), outputs_prefix="SymantecDLP.Patterns", outputs=patterns_results, outputs_key_field="id", ) def update_sender_pattern_command(client: Client, args: dict[str, Any]): """ Update the sender pattern """ pattern_id = args.get("pattern_id", "") pattern_name = args.get("name") pattern_description = args.get("description") new_ips = argToList(args.get("ips", [])) new_users = argToList(args.get("users", [])) update_results = client.update_sender_pattern_request(pattern_id, pattern_name, pattern_description, new_ips, new_users) return CommandResults( readable_output=tableToMarkdown("Sender Pattern Update Results", update_results), outputs_prefix="SymantecDLP.SenderUpdate", outputs=update_results, outputs_key_field="id", ) def update_recipient_pattern_command(client: Client, args: dict[str, Any]): """ Update the sender pattern """ pattern_id = args.get("pattern_id", "") pattern_name = args.get("name") pattern_description = args.get("description") new_ips = argToList(args.get("ips", [])) new_emails = argToList(args.get("emails", [])) new_domains = argToList(args.get("domains", [])) update_results = client.update_recipient_pattern_request( pattern_id, pattern_name, pattern_description, new_ips, new_emails, new_domains ) return CommandResults( readable_output=tableToMarkdown("Sender Pattern Update Results", update_results), outputs_prefix="SymantecDLP.RecipientUpdate", outputs=update_results, outputs_key_field="id", ) def get_message_body_command(client: Client, args: dict[str, Any]): """ Fetch the message body """ try: incident_id = args.get("incident_id", "") body_results = client.get_message_body_request(incident_id) results = {"IncidentID": incident_id, "MessageBody": body_results} return CommandResults( readable_output=f"Message body for incident {incident_id} written to context data", outputs_prefix="SymantecDLP.MessageBody", outputs=results, outputs_key_field="id", ) except DemistoException as e: if "401" in str(e): raise DemistoException(f"Error 401: Incident access not authorized or the incident does not exist. {e.res}") else: raise DemistoException(f"Error {e.res}") def is_incident_already_fetched_in_previous_fetch(last_update_time, incident_creation_date): """ Checks if the incident was already fetched :param last_update_time: last_update_time from last_run :param incident_creation_date: The current incident creation date """ return last_update_time and last_update_time >= incident_creation_date def fetch_incidents( client: Client, fetch_time: str, fetch_limit: int, last_run: dict, incident_types: List[str] = None, incident_status_id: List[str] = None, incident_severities: List[str] = None, is_test=False, ): """ Performs the fetch incidents functionality, which means that every minute if fetches incidents from Symantec DLP and uploads them to Cortex XSOAR server. There are multiple incidents created at the same time, that is why we check the lasst update time and incident ID to make sure we will not fetch an incident that we already fetched. :param client: Cortex XSOAR Client :param fetch_time: For the first time the integration is enabled with the fetch incidents functionality, the fetch time indicates from what time to start fetching existing incidents in Symantec DLP system. :param fetch_limit: Indicates how many incidents to fetch every minute :param last_run: Cortex XSOAR last run object :param incident_types: The incident type to filter. :param incident_status_id: The incident status ID to filter. :param incident_severities: The incident severities to filter. :param is_test: If we test the fetch for the test module :return: A list of Cortex XSOAR incidents """ incidents = [] if incident_severities: incident_severities = [INCIDENT_SEVERITY_MAPPING[severity] for severity in incident_severities] # type: ignore if incident_types: incident_types = [INCIDENT_TYPE_MAPPING[incident_type] for incident_type in incident_types] if last_run: last_update_time = last_run.get("last_incident_creation_time") else: # In first run last_update_time = parse_creation_date(fetch_time) incidents_data_res = client.get_incidents_request( status_id=incident_status_id, severity=incident_severities, # type: ignore incident_type=incident_types, limit=fetch_limit, creation_date=last_update_time, order_by=True, ) incidents_data_list = incidents_data_res.get("incidents", []) for incident_data in incidents_data_list: incident_id = incident_data.get("incidentId") incident_creation_time = incident_data.get("creationDate") if is_incident_already_fetched_in_previous_fetch(last_update_time, incident_creation_time): # Skipping last incident from last cycle if fetched again continue incident_details = get_incident_details_fetch(client, incident_data) incident: dict = { "rawJSON": json.dumps(incident_details), "name": f"Symantec DLP Incident ID {incident_id}", "occurred": parse_creation_date(incident_creation_time), } incidents.append(incident) if incident_creation_time == incidents_data_list[-1].get("creationDate"): last_update_time = incident_creation_time if is_test: return None demisto.setLastRun({"last_incident_creation_time": last_update_time}) # Sort the incidents list because the incident's ID and creation date are not synchronize sorted_incidents = sorted(incidents, key=lambda d: d["name"]) return sorted_incidents """ MAIN FUNCTION """ def main() -> None: """main function, parses params and runs command functions :return: :rtype: """ try: params = demisto.params() server = params.get("server", "") credentials = params.get("credentials", {}) username = credentials.get("identifier", "") password = credentials.get("password", "") incident_type = argToList(params.get("fetchIncidentType"), "Network,Discover,Endpoint") incident_status_id = check_status_ids_type(argToList(params.get("incidentStatusId", ""))) incident_severity = argToList(params.get("incidentSeverity"), "Medium,High") verify_certificate = not params.get("insecure", False) proxy = params.get("proxy", False) set_time_zone(params.get("incidents_time_zone")) fetch_time = params.get("first_fetch", "3 days").strip() try: fetch_limit: int = int(params.get("max_fetch", 10)) fetch_limit = min(fetch_limit, MAX_PAGE_SIZE) except ValueError: raise DemistoException("Value for fetch limit must be an integer.") client = Client( base_url=server, verify=verify_certificate, headers={"Content-type": "application/json"}, proxy=proxy, auth=(username, password), ) args = demisto.args() demisto.debug(f"Command being called is {demisto.command()}") if demisto.command() == "test-module": result = test_module(client, params, fetch_time, fetch_limit, incident_type, incident_status_id, incident_severity) return_results(result) elif demisto.command() == "fetch-incidents": last_run = demisto.getLastRun() incidents = fetch_incidents( client, fetch_time, fetch_limit, last_run, incident_type, incident_status_id, incident_severity ) demisto.incidents(incidents) elif demisto.command() == "symantec-dlp-list-incidents": return_results(list_incidents_command(client, args)) elif demisto.command() == "symantec-dlp-get-incident-details": return_results(get_incident_details_command(client, args)) elif demisto.command() == "symantec-dlp-update-incident": return_results(update_incident_command(client, args)) elif demisto.command() == "symantec-dlp-list-incident-status": return_results(list_incident_status_command(client)) elif demisto.command() == "symantec-dlp-get-incident-history": return_results(get_incident_history_command(client, args)) elif demisto.command() == "symantec-dlp-list-remediation-status": return_results(get_list_remediation_status(client)) elif demisto.command() == "symantec-dlp-get-incident-original-message": return_results(get_incident_original_message_command(client, args)) elif demisto.command() == "symantec-dlp-get-report-filters": return_results(get_report_filters_command(client, args)) elif demisto.command() == "symantec-dlp-list-users": return_results(list_users_command(client)) elif demisto.command() == "symantec-dlp-get-sender-recipient-pattern": return_results(get_sender_recipient_pattern_command(client, args)) elif demisto.command() == "symantec-dlp-list-sender-recipient-patterns": return_results(list_sender_recipient_patterns_command(client)) elif demisto.command() == "symantec-dlp-update-sender-pattern": return_results(update_sender_pattern_command(client, args)) elif demisto.command() == "symantec-dlp-update-recipient-pattern": return_results(update_recipient_pattern_command(client, args)) elif demisto.command() == "symantec-dlp-get-message-body": return_results(get_message_body_command(client, args)) # Log exceptions and return errors except Exception as e: return_error(f"Failed to execute {demisto.command()} command.\nError:\n{e!s}") """ ENTRY POINT """ if __name__ in ("__main__", "__builtin__", "builtins"): main()