Zscaler
Zscaler is a cloud security solution built for performance and flexible scalability. This integration enables you to manage URL and IP address allow lists and block lists, manage and update categories, get Sandbox reports, create, manage, and update IP destination groups and manually log in, log out, and activate changes in a Zscaler session.
Network Security · Zscaler Internet Access
Details
| ID | Zscaler |
|---|---|
| Provider | Zscaler |
| Category | Network Security |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM EDR Cortex Cloud Cloud Runtime Security |
README
Zscaler is a cloud security solution built for performance and flexible scalability. This integration enables you to manage URL and IP address allow lists and block lists, manage and update categories, get Sandbox reports, create, manage, and update IP destination groups and manually log in, log out, and activate changes in a Zscaler session.
For the integration to work properly, the Zscaler user must have admin permissions.
Category ID is the same as the category name, except all letters are capitalized and each word is separated with an underscore instead of spaces. For example, if the category name is Other Education, then the Category ID is OTHER_EDUCATION.
A custom category ID has the format CUSTOM_01, which is not indicative of the category. Use the zscaler-get-categories command to get a custom category and its configured name.
Configure Zscaler Internet Access in Cortex
| Parameter | Description | Required |
|---|---|---|
| Cloud Name (i.e. https://zsapi.zscalertwo.net) | See https://help.zscaler.com/zia/getting-started-zia-api#RetrieveBaseURL on how to retrieve your cloud name. | True |
| Username | True | |
| Password | True | |
| API Key | True | |
| Source Reliability | Reliability of the source providing the intelligence data. | False |
| Auto Logout | If enabled, the integration will log out after executing each command. | False |
| Auto Activate Changes | If enabled, the integration will activate the command changes after each execution. If disabled, use the ‘zscaler-activate-changes’ command to activate Zscaler command changes. | False |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False | |
| Timeout (in seconds) for HTTP requests to Zscaler | False |
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.
zscaler-blacklist-url
Adds the specified URLs to the block list.
Base Command
zscaler-blacklist-url
Input
| Argument Name | Description | Required |
|---|---|---|
| url | A comma-separated list of URLs to add to block list. For example, snapchat.com,facebook.com. | Required |
Context Output
There is no context output for this command.
Command Example
!zscaler-blacklist-url url=phishing.com,malware.net
Human Readable Output
Added the following URLs to the block list successfully:
phishing.com
malware.net
url
Looks up the classification for the each of the specified URLs.
Base Command
url
Input
| Argument Name | Description | Required |
|---|---|---|
| url | A comma-separated list of URLs for which to look up the classification. For example, abc.com,xyz.com. The maximum number of URLs per call is 100. A URL cannot exceed 1024 characters. If there are multiple URLs, set the ‘multiple’ argument to ‘true’. | Required |
| multiple | Whether there are multiple URLs in the ‘url’ argument. If a URL contains commas, set this argument to ‘false’ and enter the single URL as the ‘url’ argument. Possible values are: true, false. Default is true. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| URL.Data | string | The URL that was searched. |
| URL.Address | string | The URL that was searched. |
| Zscaler.URL.urlClassifications | string | The classification of the URL. For example, MUSIC or WEB_SEARCH. |
| Zscaler.URL.urlClassificationsWithSecurityAlert | string | The classifications of the URLs that have security alerts. |
| URL.Malicious.Vendor | string | For malicious URLs, the vendor that tagged the URL as malicious. |
| URL.Malicious.Description | string | For malicious URLs, the reason the vendor tagged the URL as malicious. |
| DBotScore.Indicator | string | The indicator that was tested. |
| DBotScore.Type | string | The indicator type. |
| DBotScore.Vendor | string | The vendor used to calculate the score. |
| DBotScore.Score | number | The actual score. |
Command Example
!url url=facebook.com
Context Example
{
"DBotScore": [
{
"Indicator": "facebook.com",
"Score": 1,
"Type": "url",
"Vendor": "Zscaler"
}
],
"URL": {
"Address": "facebook.com",
"Data": "facebook.com",
"urlClassifications": "SOCIAL_NETWORKING"
}
}
Human Readable Output
Zscaler URL Lookup
url urlClassifications facebook.com SOCIAL_NETWORKING
ip
Looks up the classification for each of the specified IP addresses.
Base Command
ip
Input
| Argument Name | Description | Required |
|---|---|---|
| ip | A comma-separated list of IP address for which to look up the classification. For example, 8.8.8.8,1.2.3.4. The maximum number of URLs per call is 100. An IP address cannot exceed 1024 characters. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| IP.Address | string | The IP address that was searched. |
| Zscaler.IP.ipClassifications | string | The classification of the IP address. For example, MUSIC or WEB_SEARCH. |
| Zscaler.IP.iplClassificationsWithSecurityAlert | string | Classifications that have a security alert for the IP address. |
| IP.Malicious.Vendor | string | For malicious IP addresses, the vendor that tagged the IP address as malicious. |
| IP.Malicious.Description | string | For malicious IP addresses, the reason the vendor tagged the IP address as malicious. |
| DBotScore.Indicator | string | The indicator that was tested. |
| DBotScore.Type | string | The indicator type. |
| DBotScore.Vendor | string | The vendor used to calculate the score. |
| DBotScore.Score | number | The actual score. |
Command Example
!ip ip=8.8.8.8
Context Example
{
"DBotScore": [
{
"Indicator": "8.8.8.8",
"Score": 1,
"Type": "ip",
"Vendor": "Zscaler"
}
],
"IP": {
"Address": "8.8.8.8",
"ipClassifications": "WEB_SEARCH"
}
}
Human Readable Output
Zscaler IP Lookup
ip ipClassifications 8.8.8.8 WEB_SEARCH
domain
Looks up the classification for each of the specified domains.
Base Command
domain
Input
| Argument Name | Description | Required |
|---|---|---|
| domain | A comma-separated list of domains for which to look up the classification. For example, example.com,google.com. | Required |
| multiple | Whether there are multiple domains in the ‘domain’ argument. If a domain contains commas, set this argument to ‘false’ and enter the single domain as the ‘domain’ argument. Possible values are: true, false. Default is true. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Domain.Name | string | The domain that was searched. |
| Zscaler.Domain.domainClassifications | string | The classification of the domain. For example, MUSIC or WEB_SEARCH. |
| Zscaler.Domain.domainClassificationsWithSecurityAlert | string | The classifications of the domains that have security alerts. |
| Domain.Malicious.Vendor | string | For malicious domains, the vendor that tagged the domain as malicious. |
| Domain.Malicious.Description | string | For malicious domains, the reason the vendor tagged the domain as malicious. |
| DBotScore.Indicator | string | The indicator that was tested. |
| DBotScore.Type | string | The indicator type. |
| DBotScore.Vendor | string | The vendor used to calculate the score. |
| DBotScore.Score | number | The actual score. |
Command Example
!domain domain=example.com
Context Example
{
"DBotScore": [
{
"Indicator": "example.com",
"Score": 1,
"Type": "domain",
"Vendor": "Zscaler"
}
],
"Domain": {
"Name": "example.com"
},
"Zscaler": {
"Domain": {
"Name": "example.com",
"domainClassifications": "REFERENCE_SITES"
}
}
}
Human Readable Output
Zscaler Domain Lookup
domain domainClassifications example.com REFERENCE_SITES
Command Example with Multiple Domains
!domain domain=example.com,google.com multiple=true
Context Example
{
"DBotScore": [
{
"Indicator": "example.com",
"Score": 1,
"Type": "domain",
"Vendor": "Zscaler"
},
{
"Indicator": "google.com",
"Score": 1,
"Type": "domain",
"Vendor": "Zscaler"
}
],
"Domain": [
{
"Name": "example.com"
},
{
"Name": "google.com"
}
],
"Zscaler": {
"Domain": [
{
"Name": "example.com",
"domainClassifications": "REFERENCE_SITES"
},
{
"Name": "google.com",
"domainClassifications": "WEB_SEARCH"
}
]
}
}
Human Readable Output
Zscaler Domain Lookup
domain domainClassifications example.com REFERENCE_SITES google.com WEB_SEARCH
zscaler-undo-blacklist-url
Removes the specified URLs from the block list.
Base Command
zscaler-undo-blacklist-url
Input
| Argument Name | Description | Required |
|---|---|---|
| url | A comma-separated list of URLs to remove from the block list. For example, snapchat.com,facebook.com. | Required |
Context Output
There is no context output for this command.
zscaler-whitelist-url
Adds the specified URLs to the allow list.
Base Command
zscaler-whitelist-url
Input
| Argument Name | Description | Required |
|---|---|---|
| url | A comma-separated list of URLs to add to the allow list. For example, snapchat.com,facebook.com. | Required |
Context Output
There is no context output for this command.
Command Example
!zscaler-whitelist-url url=phising.com,malware.net
Human Readable Output
Added the following URLs to the allow list successfully:
phishing.com
malware.net
zscaler-undo-whitelist-url
Removes the specified URLs from the allow list.
Base Command
zscaler-undo-whitelist-url
Input
| Argument Name | Description | Required |
|---|---|---|
| url | A comma-separated list of URLs to remove from the allow list. For example, snapchat.com,facebook.com. | Required |
Context Output
There is no context output for this command.
Command Example
!zscaler-undo-whitelist-url url=phising.com,malware.net
Human Readable Output
Removed the following URLs from the allow list successfully:
phishing.com
malware.net
zscaler-undo-whitelist-ip
Removes the specified IP addresses from the allow list.
Base Command
zscaler-undo-whitelist-ip
Input
| Argument Name | Description | Required |
|---|---|---|
| ip | A comma-separated list of IP addresses to remove from the allow list. For example, 8.8.8.8,1.2.3.4. | Required |
Context Output
There is no context output for this command.
Command Example
!zscaler-undo-whitelist-ip ip=2.2.2.2,3.3.3.3
Human Readable Output
Removed the following IP addresses from the allow list successfully:
2.2.2.2
3.3.3.3
zscaler-whitelist-ip
Adds the specified IP address to the allow list.
Base Command
zscaler-whitelist-ip
Input
| Argument Name | Description | Required |
|---|---|---|
| ip | A comma-separated list of IP addresses to add to the allow list. For example, 8.8.8.8,1.2.3.4. | Required |
Context Output
There is no context output for this command.
Command Example
!zscaler-whitelist-ip ip=2.2.2.2,3.3.3.3
Human Readable Output
Added the following IP addresses to the allow list successfully:
2.2.2.2
3.3.3.3
zscaler-undo-blacklist-ip
Removes the specified IP addresses from the block list.
Base Command
zscaler-undo-blacklist-ip
Input
| Argument Name | Description | Required |
|---|---|---|
| ip | A comma-separated list of IP addresses to remove from the allow list. For example, 8.8.8.8,1.2.3.4. | Required |
Context Output
There is no context output for this command.
Command Example
!zscaler-undo-blacklist-ip ip=2.2.2.2,3.3.3.3
Human Readable Output
Removed the following IP addresses from the block list successfully:
2.2.2.2
3.3.3.3
zscaler-blacklist-ip
Adds the specified IP addresses to the block list.
Base Command
zscaler-blacklist-ip
Input
| Argument Name | Description | Required |
|---|---|---|
| ip | A comma-separated list of IP addresses to add to the block list. For example, 8.8.8.8,1.2.3.4. | Required |
Context Output
There is no context output for this command.
Command Example
!zscaler-blacklist-ip ip=2.2.2.2,3.3.3.3
Human Readable Output
Added the following IP addresses to the block list successfully:
2.2.2.2
3.3.3.3
zscaler-category-add-url
Adds URLs to the specified category.
Ensure that the URLs are properly formatted according to Zscaler’s guidelines. For more information on valid URL formats, refer to the Zscaler URL Format Guidelines.
Base Command
zscaler-category-add-url
Input
| Argument Name | Description | Required |
|---|---|---|
| category-id | The ID of the category to add the specified URLs to. For example, RADIO_STATIONS. You can retrieve the category IDs by running the ‘zscaler-get-categories’ command. | Required |
| url | A comma-separated list of URLs to add to the specified category. For example, pandora.com,spotify.com. Important: If any URL contains a comma ( ,), you must pass the url argument as a JSON list wrapped in backticks (`). Example (single URL with comma): url=`[“https://example.com/foo,bar”]` Example (multiple URLs with commas): url=`[“https://example.com/foo,bar”,”https://example2.com/foo,bar”]` |
Optional |
| retaining-parent-category-url | A comma-separated list of URLs to add to the retaining parent category section inside the specified category. For example, pandora.com,spotify.com. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Zscaler.Category.CustomCategory | boolean | True, if the category is a custom category. Otherwise, false. |
| Zscaler.Category.Description | string | The description of the category. |
| Zscaler.Category.ID | string | The ID of the category. |
| Zscaler.Category.URL | string | The URL of the category. |
Command Example
!zscaler-category-add-url category-id=MUSIC url=demisto.com,apple.com
Example with a URL containing a comma:
!zscaler-category-add-url category-id="CUSTOM_123" url=`["https://example.com/foo,bar"]`
Context example
{
"Zscaler": {
"Category": {
"CustomCategory": false,
"Description": "MUSIC_DESC",
"ID": "MUSIC",
"URL": [
"demisto.com",
"apple.com"
]
}
}
}
Human Readable Output
Added the following URL addresses to category MUSIC:
- demisto.com
- apple.com
zscaler-category-add-ip
Adds IP address to the specified category.
Base Command
zscaler-category-add-ip
Input
| Argument Name | Description | Required |
|---|---|---|
| category-id | The ID of the category to add the specified IP addresses to. For example, RADIO_STATIONS. You can retrieve the category IDs by running the ‘zscaler-get-categories’ command. | Required |
| ip | A comma-separated list of IP address to add to the specified category. For example, 1.2.3.4,8.8.8.8. | Optional |
| retaining-parent-category-ip | A comma-separated list of IP address to add to the retaining parent category section inside the specified category. For example, 1.2.3.4,8.8.8.8. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Zscaler.Category.CustomCategory | boolean | True, if the category is a custom category. Otherwise, false. |
| Zscaler.Category.Description | string | The description of the category. |
| Zscaler.Category.ID | string | The ID of the category. |
| Zscaler.Category.URL | string | The URL of the category |
Command Example
!zscaler-category-add-ip category-id=REFERENCE_SITES ip=1.2.3.4,8.8.8.8
Context Example
{
"Zscaler": {
"Category": {
"CustomCategory": false,
"Description": "REFERENCE_SITES_DESC",
"ID": "REFERENCE_SITES",
"URL": [
"1.2.3.4",
"8.8.8.8"
]
}
}
}
Human Readable Output
Added the following IP addresses to category REFERENCE_SITES:
- 1.2.3.4
- 8.8.8.8
zscaler-category-remove-url
Removes URLs from the specified category.
Base Command
zscaler-category-remove-url
Input
| Argument Name | Description | Required |
|---|---|---|
| category-id | The ID of the category to remove the specified URLs from. For example, RADIO_STATIONS. You can retrieve the category IDs by running the ‘zscaler-get-categories’ command. | Required |
| url | A comma-separated list of URLs to remove from the specified category. For example, pandora.com,spotify.com. | Optional |
| retaining-parent-category-url | A comma-separated list of URLs to remove from the retaining parent category section inside the specified category. For example, pandora.com,spotify.com. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Zscaler.Category.CustomCategory | boolean | True, if the category is a custom category. Otherwise, false. |
| Zscaler.Category.Description | string | The description of the category. |
| Zscaler.Category.ID | string | The ID of the category. |
| Zscaler.Category.URL | string | The URL of the category. |
Command Example
!zscaler-category-remove-url category-id=MUSIC url=apple.com
Context Example
{
"Zscaler": {
"Category": {
"CustomCategory": false,
"Description": "MUSIC_DESC",
"ID": "MUSIC",
"URL": [
"demisto.com"
]
}
}
}
Human Readable Output
Removed the following URL addresses to category MUSIC:
- apple.com
zscaler-category-remove-ip
Removes IP address from the specified category.
Base Command
zscaler-category-remove-ip
Input
| Argument Name | Description | Required |
|---|---|---|
| category-id | The ID of the category to remove the specified IP addresses from. For example, RADIO_STATIONS. You can retrieve the category IDs by running the ‘zscaler-get-categories’ command. | Required |
| ip | A comma-separated list of IP addresses to remove from the specified category. For example, 1.2.3.4,8.8.8.8. | Optional |
| retaining-parent-category-ip | A comma-separated list of IP address to remove from the retaining parent category section inside the specified category. For example, 1.2.3.4,8.8.8.8. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Zscaler.Category.CustomCategory | boolean | True, if the category is a custom category. Otherwise, false. |
| Zscaler.Category.Description | string | The description of the category. |
| Zscaler.Category.ID | string | The ID of the category. |
| Zscaler.Category.URL | string | The URL of the category. |
Command Example
!zscaler-category-remove-ip category-id=REFERENCE_SITES ip=1.2.3.4
Context Example
{
"Zscaler": {
"Category": {
"CustomCategory": false,
"Description": "REFERENCE_SITES_DESC",
"ID": "REFERENCE_SITES",
"URL": [
"8.8.8.8"
]
}
}
}
Human Readable Output
Removed the following IP addresses to category REFERENCE_SITES:
- 1.2.3.4
zscaler-get-categories
Retrieves a list of all categories.
Base Command
zscaler-get-categories
Input
| Argument Name | Description | Required |
|---|---|---|
| displayURL | Whether to display the URLs of each category in the War Room. URLs will always be returned to the Context Data. Possible values are: true, false. Default is false. | Optional |
| custom_categories_only | Whether to retrieve only custom categories to the War Room. Possible values are: true, false. Default is false. | Optional |
| get_ids_and_names_only | Whether to retrieve only a list containing URL category IDs and names. Even if displayURL is set to true, URLs will not be returned. Please note - the API does not support the combination of custom_only and get_ids_and_names_only. Possible values are: true, false. Default is false. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Zscaler.Category.ID | string | The ID of the category. |
| Zscaler.Category.CustomCategory | boolean | True, if the category is a custom category. Otherwise, false. |
| Zscaler.Category.URL | string | The URL of the category. |
| Zscaler.Category.RetainingParentCategoryURL | string | The URLs of the retaining parent category. |
| Zscaler.Category.Description | string | The description of the category. |
| Zscaler.Category.Name | string | The name of the category. |
Command Example
#### Context Example
```json
{
"Zscaler":{
"Category":{
"ID":"INTERNET_SERVICES",
"Description":"INTERNET_SERVICES_DESC",
"URL":[
"google.com",
"facebook.com"
],
"CustomCategory":"false"
},
"ID":"CUSTOM_01",
"Name":"CustomCategory",
"URL":[
"demisto.com",
"apple.com"
],
"RetainingParentCategoryURL":[
"pandora.com",
"spotify.com"
],
"CustomCategory":"true"
}
}
Human Readable Output
| CustomCategory | Description | ID | Name | URL | RetainingParentCategoryURL |
|---|---|---|---|---|---|
| false | INTERNET_SERVICES_DESC | INTERNET_SERVICES | google.com,facebook.com | ||
| true | CUSTOM_01 | CustomCategory | demisto.com,apple.com | pandora.com”,”spotify.com |
zscaler-get-blacklist
Retrieves the Zscaler default block list.
Base Command
zscaler-get-blacklist
Input
| Argument Name | Description | Required |
|---|---|---|
| filter | Filter results by URL or IP objects. Possible values are: url, ip. | Optional |
| query | Query (Python regular expression) to match against. For example, 8...8. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Zscaler.Blacklist | string | The Zscaler block list. |
Command Example
#### Context Example
```json
{
"Zscaler": {
"Blacklist": [
"malicious.com,
"bad.net"
]
}
}
Human Readable Output
Zscaler block list
- malicious.com
- bad.net
zscaler-get-whitelist
Retrieves the Zscaler default allow list.
Base Command
zscaler-get-whitelist
Input
There are no input arguments for this command.
Context Output
| Path | Type | Description |
|---|---|---|
| Zscaler.Whitelist | string | The Zscaler allow list. |
Command Example
#### Context Example
```json
{
"Zscaler": {
"Whitelist": [
"demisto.com,
"apple.com"
]
}
}
Human Readable Output
Zscaler whitelist
- demisto.com
- apple.net
zscaler-sandbox-report
Retrieves a full or summary report of the file that was analyzed by Sandbox. The file is represented by the specified MD5 hash.
Base Command
zscaler-sandbox-report
Input
| Argument Name | Description | Required |
|---|---|---|
| md5 | The MD5 hash of a file. | Required |
| details | The type of report. Possible values are ‘full’ or ‘summary’. Default is ‘full’. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| File.MD5 | string | The MD5 hash of the file. |
| File.Malicious.Vendor | string | For malicious files, the vendor that tagged the file as malicious. |
| File.Malicious.Description | string | For malicious files, the reason the vendor tagged the file as malicious. |
| File.DetectedMalware | string | The malware detected in the file. |
| File.FileType | string | The file type. |
| DBotScore.Indicator | string | The MD5 hash file that was tested. |
| DBotScore.Type | string | The MD5 hash file type. |
| DBotScore.Vendor | string | The vendor that calculated the DBot score. |
| DBotScore.Score | number | The actual DBot score. |
Command Example
!zscaler-sandbox-report md5=3FD0EA0AE759D58274310C022FB0CBBA details=summary
Context Example
{
"DBotScore": {
"Vendor": "Zscaler",
"Indicator": "3FD0EA0AE759D58274310C022FB0CBBA",
"Score": 3,
"Type": "file"
},
"File": {
"Zscaler": {
"FileType": null,
"DetectedMalware": ""
},
"Malicious": {
"Vendor": "Zscaler",
"Description": "Classified as Malicious, with threat score: 100"
},
"MD5": "3FD0EA0AE759D58274310C022FB0CBBA"
}
}
Human Readable Output
Full Sandbox Report
| Category | Indicator | Vendor | Score | Zscaler Score | Type |
|---|---|---|---|---|---|
| MALWARE_BOTNET | 3FD0EA0AE759D58274310C022FB0CBBA | Zscaler | 3 | 100 | file |
Additional Information
zscaler-login
Manually create a Zscaler login session. This command will also try to log out of the previous session.
Base Command
zscaler-login
Input
There are no input arguments for this command.
Context Output
There is no context output for this command.
Command Example
#### Human Readable Output
>Zscaler session created successfully.
### zscaler-logout
***
Logs out of the current Zscaler session.
#### Base Command
`zscaler-logout`
#### Input
There are no input arguments for this command.
#### Context Output
There is no context output for this command.
#### Command Example
```!zscaler-logout```
#### Human Readable Output
>API session logged out of Zscaler successfully.
### zscaler-activate-changes
***
Activates the changes executed by other Zscaler commands in this session.
#### Base Command
`zscaler-activate-changes`
#### Input
There are no input arguments for this command.
#### Context Output
There is no context output for this command.
#### Command Example
```!zscaler-activate-changes```
#### Human Readable Output
>Changes have been activated successfully.
### zscaler-url-quota
***
Gets information on the number of unique URLs that are currently provisioned for your organization as well as how many URLs you can add before reaching that number.
#### Base Command
`zscaler-url-quota`
#### Input
There are no input arguments for this command.
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| Zscaler.remainingUrlsQuota | Number | The number of URLs you can add before reaching the quota. |
| Zscaler.uniqueUrlsProvisioned | Number | The number of unique URLs that are currently provisioned for your organization. |
### zscaler-get-users
***
Get Zscaler users
#### Base Command
`zscaler-get-users`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| name | Filer by user name. | Optional |
| page | Specifies the page offset. | Optional |
| pageSize | Specifies the page size. Default is 100. | Optional |
#### Context Output
There is no context output for this command.
### zscaler-update-user
***
Updates the user information for the specified ID.
#### Base Command
`zscaler-update-user`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| id | The unique identifier for the user. | Required |
| user | New user information. Docs: <https://help.zscaler.com/zia/api#/User%20Management/updateUser>. | Required |
#### Context Output
There is no context output for this command.
### zscaler-get-departments
***
Get a list of departments. It can be searched by name.
#### Base Command
`zscaler-get-departments`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| name | Filter by department name. | Optional |
| page | Specifies the page offset. | Optional |
| pageSize | Specifies the page size. Default is 100. | Optional |
#### Context Output
There is no context output for this command.
### zscaler-get-usergroups
***
Gets a list of groups
#### Base Command
`zscaler-get-usergroups`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| name | Filter by group name or comment. | Optional |
| page | Specifies the page offset. | Optional |
| pageSize | Specifies the page size. Default is 100. | Optional |
#### Context Output
There is no context output for this command.
### zscaler-create-ip-destination-group
***
Adds a new IP destination group.
#### Base Command
`zscaler-create-ip-destination-group`
#### Input
| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| name | Destination IP group name. | Required |
| type | Destination IP group type (i.e., the group can contain destination IP addresses, countries, URL categories or FQDNs). Possible values are: DSTN_IP, DSTN_FQDN, DSTN_DOMAIN, DSTN_OTHER. | Required |
| addresses | Destination IP addresses, FQDNs, or wildcard FQDNs added to the group. | Optional |
| description | Additional information about the destination IP group. | Optional |
| ip_categories | Destination IP address URL categories. You can identify destinations based on the URL category of the domain. To retrieve a list of possible values, you can execute the zscaler-get-categories command. | Optional |
| countries | Destination IP address countries. You can identify destinations based on the location of a server. A list of possible values can be found here <https://help.zscaler.com/zia/firewall-policies#/ipDestinationGroups-post>. | Optional |
#### Context Output
| **Path** | **Type** | **Description** |
| --- | --- | --- |
| Zscaler.IPDestinationGroup.ID | number | Unique identifier for the destination IP group. |
| Zscaler.IPDestinationGroup.Name | string | Destination IP group name. |
| Zscaler.IPDestinationGroup.Type | string | Destination IP group type \(i.e., the group can contain destination IP addresses, countries, URL categories or FQDNs\). |
| Zscaler.IPDestinationGroup.Description | string | Destination IP group description. |
| Zscaler.IPDestinationGroup.Addresses | string | Destination IP addresses, FQDNs, or wildcard FQDNs added to the group. |
| Zscaler.IPDestinationGroup.IpCategories | string | Destination IP address URL categories. You can identify destinations based on the URL category of the domain. |
| Zscaler.IPDestinationGroup.Countries | string | Destination IP address countries. You can identify destinations based on the location of a server. |
| Zscaler.IPDestinationGroup.IsNonEditable | boolean | If set to true, the destination IP address group is non-editable. This field is applicable only to predefined IP address groups, which cannot be modified. |
#### Command Example
```!zscaler-create-ip-destination-group addresses="127.0.0.2,127.0.0.1" description=Localhost name=Test99 type=DSTN_IP```
#### Context example
```json
{
"Zscaler.IPDestinationGroup": {
"ID": 2000359,
"Name": "Test99",
"Type": "DSTN_IP",
"Addresses": [
"127.0.0.2",
"127.0.0.1"
],
"Description": "Localhost",
"IpCategories": [],
"Countries": [],
"IsNonEditable": false
}
}
Human Readable Output
IP Destination group created
| Addresses | Countries | Description | ID | IpCategories | IsNonEditable | Name | Type |
|---|---|---|---|---|---|---|---|
| 127.0.0.2, 127.0.0.1 |
Localhost | 2000359 | false | Test99 | DSTN_IP |
zscaler-edit-ip-destination-group
Updates the IP destination group information for the specified group ID.
Base Command
zscaler-edit-ip-destination-group
Input
| Argument Name | Description | Required |
|---|---|---|
| ip_group_id | The unique identifier for the IP destination group. | Required |
| name | Destination IP group name. | Optional |
| addresses | Destination IP addresses, FQDNs, or wildcard FQDNs added to the group. | Optional |
| description | Additional information about the destination IP group. | Optional |
| ip_categories | Destination IP address URL categories. You can identify destinations based on the URL category of the domain. To retrieve a list of possible values you can execute the zscaler-get-categories command. | Optional |
| countries | Destination IP address countries. You can identify destinations based on the location of a server. A list of possible values can be found here https://help.zscaler.com/zia/firewall-policies#/ipDestinationGroups/{ipGroupId}-put. | Optional |
| is_non_editable | If set to true, the destination IP address group is non-editable. This field is applicable only to predefined IP address groups, which cannot be modified. Possible values are: True, False. Default is False. | Optional |
| override | When set to true (default), the existing IP destination group configuration is replaced with the new values. When set to false, the existing configuration is preserved and new entries are appended. Possible values are: True, False. Default is True. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Zscaler.IPDestinationGroup.ID | number | Unique identifier for the destination IP group. |
| Zscaler.IPDestinationGroup.Name | string | Destination IP group name. |
| Zscaler.IPDestinationGroup.Type | string | Destination IP group type (i.e., the group can contain destination IP addresses, countries, URL categories or FQDNs). |
| Zscaler.IPDestinationGroup.Description | string | Destination IP group description. |
| Zscaler.IPDestinationGroup.Addresses | string | Destination IP addresses, FQDNs, or wildcard FQDNs added to the group. |
| Zscaler.IPDestinationGroup.IpCategories | string | Destination IP address URL categories. You can identify destinations based on the URL category of the domain. |
| Zscaler.IPDestinationGroup.Countries | string | Destination IP address countries. You can identify destinations based on the location of a server. |
Command Example
!zscaler-edit-ip-destination-group ip_group_id=2000359 addresses="127.0.0.2" description="Localhost v2" name=Test01
Context example
{
"Zscaler.IPDestinationGroup": {
"ID": 2000359,
"Name": "Test01",
"Type": "DSTN_IP",
"Description": "Localhost v2",
"Addresses": [
"127.0.0.2"
],
"IpCategories": [],
"Countries": []
}
}
Human Readable Output
IP Destination group updated
| Addresses | Countries | Description | ID | IpCategories | Name | Type |
|---|---|---|---|---|---|---|
| 127.0.0.2 | Localhost v2 | 2000359 | Test01 | DSTN_IP |
zscaler-list-ip-destination-groups
Gets a list of all IP destination groups or the IP destination group information for the specified group ID.
Base Command
zscaler-list-ip-destination-groups
Input
| Argument Name | Description | Required |
|---|---|---|
| ip_group_id | A comma-separated list of unique identifiers for the IP destination groups. | Optional |
| exclude_type | The IP group type to be excluded from the results. Possible values are: DSTN_IP, DSTN_FQDN, DSTN_DOMAIN, DSTN_OTHER. | Optional |
| category_type | The IP group type to be filtered from results. This argument is only supported when the ‘lite’ argument is set to True. Possible values are: DSTN_IP, DSTN_FQDN, DSTN_DOMAIN, DSTN_OTHER. | Optional |
| include_ipv6 | Retrieve IPv6 destination groups. Possible values are: True, False. Default is False. | Optional |
| limit | Limit of the results to be retrieved. Default is 50. | Optional |
| all_results | Whether to retrieve all results at once. Possible values are: True, False. Default is False. | Optional |
| lite | Whether to retrieve only limited information of IP destination groups. Includes ID, name and type of the IP destination groups. Possible values are: True, False. Default is False. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Zscaler.IPDestinationGroup.ID | string | Unique identifier for the destination IP group. |
| Zscaler.IPDestinationGroup.Name | string | Destination IP group name. |
| Zscaler.IPDestinationGroup.Type | string | Destination IP group type (i.e., the group can contain destination IP addresses, countries, URL categories or FQDNs). |
| Zscaler.IPDestinationGroup.Addresses | string | Destination IP addresses, FQDNs, or wildcard FQDNs added to the group. |
| Zscaler.IPDestinationGroup.Description | string | Additional information about the destination IP group |
| Zscaler.IPDestinationGroup.IpCategories | string | Destination IP address URL categories. You can identify destinations based on the URL category of the domain. |
| Zscaler.IPDestinationGroup.Countries | string | Destination IP address countries. You can identify destinations based on the location of a server. |
Command Example
!zscaler-list-ip-destination-groups exclude_type=DSTN_OTHER
Context example
{
"Zscaler.IPDestinationGroup": [
{
"ID": 1997898,
"Name": "Test99",
"Type": "DSTN_IP",
"Addresses": ["127.0.0.2"],
"Description": "Localhost v2",
"IpCategories": [],
"Countries": []
},
{
"ID": 2001335,
"Name": "Test01",
"Type": "DSTN_IP",
"Addresses": ["127.0.0.1"],
"Description": "Localhost v1",
"IpCategories": [],
"Countries": []
}
]
}
Human Readable Output
IPv4 Destination groups (2)
| Addresses | Countries | Description | ID | IpCategories | Name | Type |
|---|---|---|---|---|---|---|
| 127.0.0.2 | Localhost v2 | 1997898 | Test99 | DSTN_IP | ||
| 127.0.0.1 | Localhost v1 | 2001335 | Test01 | DSTN_IP |
!zscaler-list-ip-destination-groups lite=True
Context Example
[
{
"ID": 1964949,
"Name": "Russia-Region",
"Type": "DSTN_OTHER"
}
]
Human Readable Output
IPv4 Destination groups lite (1)
| ID | Name | Type | ||
|---|---|---|---|---|
| 1964949 | Russia-Region | DSTN_OTHER |
zscaler-delete-ip-destination-groups
Deletes the IP destination group associated with the specified group ID.
Base Command
zscaler-delete-ip-destination-groups
Input
| Argument Name | Description | Required |
|---|---|---|
| ip_group_ids | A comma-separated list of unique identifiers for the IP destination groups. | Optional |
Context Output
There is no context output for this command.
Command Example
!zscaler-delete-ip-destination-groups ip_group_id=2077311,2030563
Human Readable Output
IP Destination Group 2077311,2030563 deleted successfully
Configuration parameters
cloud— Cloud Name (i.e., <https://zsapi.zscalertwo.net>) (required)credentials— Username (required)creds_key—key— API Keyreliability— Source Reliabilityauto_logout— Auto Logoutauto_activate— Auto Activate Changesinsecure— Trust any certificate (not secure)proxy— Use system proxy settingsrequestTimeout— Timeout (in seconds) for HTTP requests to Zscaler
Commands (31)
-
domainLooks up the classification for each of the specified Domains.
-
ipLooks up the classification for each of the specified IP addresses.
-
urlLooks up the classification for the each of the specified URLs.
-
zscaler-activate-changesActivates the changes executed by other Zscaler commands in this session.
-
zscaler-blacklist-ipAdds the specified IP addresses to the block list.
-
zscaler-blacklist-urlAdds the specified URLs to the block list.
-
zscaler-category-add-ipAdds IP address to the specified category.
-
zscaler-category-add-urlAdds URLs to the specified category.
-
zscaler-category-remove-ipRemoves IP address from the specified category.
-
zscaler-category-remove-urlRemoves URLs from the specified category.
-
zscaler-create-ip-destination-groupAdds a new IP destination group.
-
zscaler-delete-ip-destination-groupsDeletes the IP destination group associated with the specified group ID.
-
zscaler-edit-ip-destination-groupUpdates the IP destination group information for the specified group ID.
-
zscaler-get-blacklistRetrieves the Zscaler default block list.
-
zscaler-get-categoriesRetrieves a list of all categories.
-
zscaler-get-departmentsGet a list of departments. It can be searched by name.
-
zscaler-get-usergroupsGets a list of groups.
-
zscaler-get-usersGet Zscaler users.
-
zscaler-get-whitelistRetrieves the Zscaler default allow list.
-
zscaler-list-ip-destination-groupsGets a list of all IP destination groups or the IP destination group information for the specified group ID.
-
zscaler-loginManually create a Zscaler login session. This command will also try to log out of the previous session.
-
zscaler-logoutLogs out of the current Zscaler session.
-
zscaler-sandbox-reportRetrieves a full or summary report of the file that was analyzed by Sandbox. The file is represented by the specified MD5 hash.
-
zscaler-undo-blacklist-ipRemoves the specified IP addresses from the block list.
-
zscaler-undo-blacklist-urlRemoves the specified URLs from the block list.
-
zscaler-undo-whitelist-ipRemoves the specified IP addresses from the allow list.
-
zscaler-undo-whitelist-urlRemoves the specified URLs from the allow list.
-
zscaler-update-userUpdates the user information for the specified ID.
-
zscaler-url-quotaGets information on the number of unique URLs that are currently provisioned for your organization as well as how many URLs you can add before reaching that number.
-
zscaler-whitelist-ipAdds the specified IP address to the allow list.
-
zscaler-whitelist-urlAdds the specified URLs to the allow list.
import demistomock as demisto import CommonServerPython from CommonServerPython import urljoin import pytest import json import requests_mock class ResponseMock: def __init__(self, response): self._json = response self.content = json.dumps(response) self.status_code = 200 def json(self): return self._json class ObjectMocker(dict): __getattr__ = dict.__getitem__ __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__ def run_command_test(command_func, args, response_path, expected_result_path, mocker, result_validator=None, resp_type="json"): with open(response_path) as response_f: response = ResponseMock(json.load(response_f)) match resp_type: case "json": response = response.json() case "content": response = response.content mocker.patch("Zscaler.http_request", return_value=response) if command_func.__name__ in [ "url_lookup", "get_users_command", "set_user_command", "get_departments_command", "get_usergroups_command", "list_ip_destination_groups", "create_ip_destination_group", "edit_ip_destination_group", "delete_ip_destination_groups", ]: res = command_func(args) else: res = command_func(**args) if result_validator: assert result_validator(res) else: with open(expected_result_path) as ex_f: expected_result = json.load(ex_f) if isinstance(res, CommonServerPython.CommandResults): assert expected_result == res.to_context() else: assert expected_result == res @pytest.fixture(autouse=True) def init_tests(mocker): params = {"cloud": "http://cloud", "credentials": {"identifier": "security", "password": "ninja"}, "key": "api"} mocker.patch.object(demisto, "params", return_value=params) def test_validate_urls_invalid(mocker): return_error_mock = mocker.patch.object(CommonServerPython, "return_error") import Zscaler invalid_urls = ["http://not_very_valid", "https://maybe_valid.", "www.valid_url.com"] Zscaler.validate_urls(invalid_urls) assert return_error_mock.call_count == 2 def test_url_command(mocker): """url""" import Zscaler def validator(res): assert res assert len(res) == 2 for command_res in res: assert command_res.indicator.url assert command_res.indicator.dbot_score assert command_res.outputs["urlClassifications"] assert command_res.outputs_prefix == "Zscaler.URL" return True run_command_test( command_func=Zscaler.url_lookup, args={"url": "https://www.demisto-news.com,https://www.demisto-search.com"}, response_path="test_data/responses/url.json", expected_result_path="test_data/results/url.json", mocker=mocker, result_validator=validator, resp_type="content", ) def test_url_fails_unknown_error_code(mocker, requests_mock): """url""" import Zscaler Zscaler.BASE_URL = "http://cloud/api/v1" requests_mock.post(urljoin(Zscaler.BASE_URL, "urlLookup"), status_code=501) args = {"url": "https://www.demisto-news.com,https://www.demisto-search.com"} try: Zscaler.url_lookup(args) except Exception as ex: assert "following error: 501" in str(ex) def test_url_command_with_urlClassificationsWithSecurityAlert(mocker): """url""" import Zscaler def validator(res): assert res assert len(res) == 1 assert res[0].outputs["urlClassifications"] == "MISCELLANEOUS_OR_UNKNOWN" assert res[0].outputs["urlClassificationsWithSecurityAlert"] == "MALWARE_SITE" return True run_command_test( command_func=Zscaler.url_lookup, args={"url": "www.demisto22.com"}, response_path="test_data/responses/url_with_urlClassificationsWithSecurityAlert.json", expected_result_path="test_data/results/url_with_urlClassificationsWithSecurityAlert.json", mocker=mocker, result_validator=validator, resp_type="content", ) def test_ip_command(mocker): """ip""" import Zscaler def validator(res): assert res assert len(res) == 2 for command_res in res: assert command_res.indicator.ip assert command_res.indicator.dbot_score assert command_res.outputs["ipClassifications"] assert not command_res.outputs.get("urlClassifications") assert command_res.outputs_prefix == "Zscaler.IP" return True run_command_test( command_func=Zscaler.ip_lookup, args={"ip": "1.22.33.4"}, response_path="test_data/responses/ip.json", expected_result_path="test_data/results/ip.json", mocker=mocker, result_validator=validator, resp_type="content", ) def test_domain_lookup_single(mocker): """ Given: - A single domain to lookup When: - domain_lookup is called Then: - Verify the function returns a CommandResults object - Verify outputs_prefix is 'Zscaler.Domain' - Verify Domain.Name context path is set correctly - Verify DBotScore is created with correct type (DOMAIN) - Verify domainClassifications is properly set """ import Zscaler from unittest.mock import patch mock_response = json.dumps( [ { "url": "example.com", "urlClassifications": ["BUSINESS"], "urlClassificationsWithSecurityAlert": [], } ] ) with patch.object(Zscaler, "lookup_request", return_value=mock_response): results = Zscaler.domain_lookup({"domain": "https://example.com"}) assert results assert len(results) == 1 assert isinstance(results[0], CommonServerPython.CommandResults) # Verify outputs_prefix assert results[0].outputs_prefix == "Zscaler.Domain" # Verify domain assert results[0].indicator.domain == "example.com" # Verify context outputs assert results[0].outputs["Name"] == "example.com" assert results[0].outputs["domainClassifications"] == "BUSINESS" # Verify DBotScore assert results[0].indicator.dbot_score.indicator == "example.com" assert results[0].indicator.dbot_score.indicator_type == CommonServerPython.DBotScoreType.DOMAIN assert results[0].indicator.dbot_score.score == CommonServerPython.Common.DBotScore.GOOD def test_domain_lookup_multiple(mocker): """ Given: - Multiple domains to lookup (comma-separated) When: - domain_lookup is called Then: - Verify the function returns multiple CommandResults objects - Verify each domain is processed correctly """ import Zscaler from unittest.mock import patch mock_response = json.dumps( [ { "url": "example.com", "urlClassifications": ["BUSINESS"], "urlClassificationsWithSecurityAlert": [], }, {"url": "test.com", "urlClassifications": ["TECHNOLOGY"], "urlClassificationsWithSecurityAlert": []}, ] ) with patch.object(Zscaler, "lookup_request", return_value=mock_response): results = Zscaler.domain_lookup({"domain": "example.com,test.com"}) assert results assert len(results) == 2 # Verify first domain assert results[0].indicator.domain == "example.com" assert results[0].outputs["domainClassifications"] == "BUSINESS" # Verify second domain assert results[1].indicator.domain == "test.com" assert results[1].outputs["domainClassifications"] == "TECHNOLOGY" def test_domain_lookup_with_security_alert(mocker): """ Given: - A domain with security alert classifications When: - domain_lookup is called Then: - Verify domainClassificationsWithSecurityAlert is properly set - Verify DBotScore is BAD for malicious domains - Verify DBotScore is SUSPICIOUS for suspicious categories """ import Zscaler from unittest.mock import patch # Test with malicious domain mock_response_malicious = json.dumps( [ { "url": "malicious.com", "urlClassifications": ["MISCELLANEOUS_OR_UNKNOWN"], "urlClassificationsWithSecurityAlert": ["MALWARE_SITE"], } ] ) with patch.object(Zscaler, "lookup_request", return_value=mock_response_malicious): results = Zscaler.domain_lookup({"domain": "malicious.com"}) assert results assert len(results) == 1 assert results[0].outputs["domainClassificationsWithSecurityAlert"] == "MALWARE_SITE" assert results[0].indicator.dbot_score.score == CommonServerPython.Common.DBotScore.BAD assert results[0].indicator.dbot_score.malicious_description == "MALWARE_SITE" # Test with suspicious domain mock_response_suspicious = json.dumps( [ { "url": "suspicious.com", "urlClassifications": [], "urlClassificationsWithSecurityAlert": ["SUSPICIOUS_DESTINATION"], } ] ) with patch.object(Zscaler, "lookup_request", return_value=mock_response_suspicious): results = Zscaler.domain_lookup({"domain": "suspicious.com"}) assert results assert len(results) == 1 assert results[0].outputs["domainClassificationsWithSecurityAlert"] == "SUSPICIOUS_DESTINATION" assert results[0].indicator.dbot_score.score == CommonServerPython.Common.DBotScore.SUSPICIOUS def test_domain_lookup_miscellaneous_classification(mocker): """ Given: - A domain with MISCELLANEOUS_OR_UNKNOWN classification and no security alerts When: - domain_lookup is called Then: - Verify DBotScore is NONE for miscellaneous domains without security alerts """ import Zscaler from unittest.mock import patch mock_response = json.dumps( [ { "url": "unknown.com", "urlClassifications": ["MISCELLANEOUS_OR_UNKNOWN"], "urlClassificationsWithSecurityAlert": [], } ] ) with patch.object(Zscaler, "lookup_request", return_value=mock_response): results = Zscaler.domain_lookup({"domain": "unknown.com"}) assert results assert len(results) == 1 assert results[0].outputs["domainClassifications"] == "MISCELLANEOUS_OR_UNKNOWN" assert results[0].indicator.dbot_score.score == CommonServerPython.Common.DBotScore.NONE def test_domain_lookup_pipe_extraction(mocker): """ Given: - API response with domain When: - domain_lookup is called Then: - Verify the domain is used in all context outputs """ import Zscaler from unittest.mock import patch mock_response = json.dumps( [ { "url": "google.com", "urlClassifications": ["SEARCH_ENGINES"], "urlClassificationsWithSecurityAlert": [], } ] ) with patch.object(Zscaler, "lookup_request", return_value=mock_response): results = Zscaler.domain_lookup({"domain": "google.com"}) assert results assert len(results) == 1 # Verify domain assert results[0].indicator.domain == "google.com" assert results[0].outputs["Name"] == "google.com" # Verify the raw response has the domain field (not url) assert "domain" in results[0].raw_response assert results[0].raw_response["domain"] == "google.com" def test_domain_lookup_empty_classifications(mocker): """ Given: - A domain with empty classifications arrays When: - domain_lookup is called Then: - Verify DBotScore is GOOD for domains with no classifications """ import Zscaler from unittest.mock import patch mock_response = json.dumps([{"url": "clean.com", "urlClassifications": [], "urlClassificationsWithSecurityAlert": []}]) with patch.object(Zscaler, "lookup_request", return_value=mock_response): results = Zscaler.domain_lookup({"domain": "clean.com"}) assert results assert len(results) == 1 assert results[0].indicator.dbot_score.score == CommonServerPython.Common.DBotScore.GOOD def test_undo_blacklist_url_command(mocker): """zscaler-undo-blacklist-url""" import Zscaler run_command_test( command_func=Zscaler.unblacklist_url, args={"url": "www.demisto22.com, www.demisto33.com"}, response_path="test_data/responses/blacklist_urls.json", expected_result_path="test_data/results/undo_blacklist_urls.txt", mocker=mocker, resp_type="content", ) def test_blacklist_url_command(mocker): """zscaler-blacklist-url""" import Zscaler run_command_test( command_func=Zscaler.blacklist_url, args={"url": "www.demisto22.com, www.demisto33.com"}, response_path="test_data/responses/blacklist_urls.json", expected_result_path="test_data/results/blacklist_urls.txt", mocker=mocker, ) def test_category_remove_url(mocker): """zscaler-category-remove-url""" import Zscaler run_command_test( command_func=Zscaler.category_remove, args={ "data": "demisto.com, dbot.com,www.demisto22.com", "category_id": "CUSTOM_1", "retaining_parent_category_data": None, "data_type": "url", }, response_path="test_data/responses/categories.json", expected_result_path="test_data/results/remove_url.json", mocker=mocker, ) def test_category_remove_ip(mocker): """zscaler-category-remove-ip""" import Zscaler run_command_test( command_func=Zscaler.category_remove, args={"data": "1.2.3.4,8.8.8.8", "category_id": "CUSTOM_1", "retaining_parent_category_data": None, "data_type": "ip"}, response_path="test_data/responses/categories2.json", expected_result_path="test_data/results/remove_ip.json", mocker=mocker, ) def test_get_categories(mocker): # zscaler-get-categories import Zscaler run_command_test( command_func=Zscaler.get_categories_command, args={"args": {"displayURL": "true"}}, response_path="test_data/responses/categories2.json", expected_result_path="test_data/results/get_categories.json", mocker=mocker, ) def test_get_categories_custom_only(mocker): # zscaler-get-categories import Zscaler run_command_test( command_func=Zscaler.get_categories_command, args={"args": {"displayURL": "true", "custom_only": True}}, response_path="test_data/responses/categories2.json", expected_result_path="test_data/results/get_categories.json", mocker=mocker, ) @pytest.mark.parametrize("display_url, get_ids_and_names_only", [(False, True), (True, True)]) def test_get_categories_ids_and_names_only(mocker, display_url, get_ids_and_names_only): # zscaler-get-categories retrieve only categories IDs and names (without urls) import Zscaler run_command_test( command_func=Zscaler.get_categories_command, args={"args": {"displayURL": display_url, "get_ids_and_names_only": get_ids_and_names_only}}, response_path="test_data/responses/categories2_no_urls.json", expected_result_path="test_data/results/get_categories_no_urls.json", mocker=mocker, ) def test_url_quota_command(mocker): # zscaler-url-quota import Zscaler run_command_test( command_func=Zscaler.url_quota_command, args={}, response_path="test_data/responses/url_quota.json", expected_result_path="test_data/results/url_quota.json", mocker=mocker, ) def test_get_blacklist(mocker): # zscaler-get-blacklist import Zscaler run_command_test( command_func=Zscaler.get_blacklist, args={}, response_path="test_data/responses/blacklist_urls.json", expected_result_path="test_data/results/blacklist.json", mocker=mocker, resp_type="content", ) def test_get_blacklist_filter(requests_mock): """ Given: - The `filter` arg set to `url` - API response with a URL and IP When: - Running the get-blacklist command Then: - Ensure only the URL is returned """ import Zscaler api_res = { "blacklistUrls": [ "demisto.com", "8.8.8.8", ], } requests_mock.get( "http://cloud/api/v1/security/advanced", json=api_res, ) args = { "filter": "url", } cmd_res = Zscaler.get_blacklist_command(args) assert cmd_res["Contents"] == [api_res["blacklistUrls"][0]] def test_get_blacklist_query(requests_mock): """ Given: - The `query` arg set to `demisto` - API response with a URL and IP When: - Running the get-blacklist command Then: - Ensure only the URL (which contains `demisto`) is returned """ import Zscaler api_res = { "blacklistUrls": [ "demisto.com", "8.8.8.8", ], } requests_mock.get( "http://cloud/api/v1/security/advanced", json=api_res, ) args = { "query": "demisto", } cmd_res = Zscaler.get_blacklist_command(args) assert cmd_res["Contents"] == [api_res["blacklistUrls"][0]] def test_get_blacklist_query_and_filter(requests_mock): """ Given: - The `filter` arg set to `ip` - The `query` arg set to `8.8.*.8` - API response with a URL and IP When: - Running the get-blacklist command Then: - Ensure only the IP is returned """ import Zscaler api_res = { "blacklistUrls": [ "demisto.com", "8.8.8.8", ], } requests_mock.get( "http://cloud/api/v1/security/advanced", json=api_res, ) args = { "filter": "ip", "query": "8.8.*.8", } cmd_res = Zscaler.get_blacklist_command(args) assert cmd_res["Contents"] == [api_res["blacklistUrls"][1]] def test_get_whitelist(mocker): # zscaler-get-whitelist import Zscaler run_command_test( command_func=Zscaler.get_whitelist, args={}, response_path="test_data/responses/whitelist_url.json", expected_result_path="test_data/results/whitelist.json", mocker=mocker, resp_type="content", ) # disable-secrets-detection-start test_data = [ ("https://madeup.fake.com/css?family=blah:1,2,3", "true", ["madeup.fake.com/css?family=blah:1", "2", "3"]), ("https://madeup.fake.com/css?family=blah:1,2,3", "false", ["madeup.fake.com/css?family=blah:1,2,3"]), ] # disable-secrets-detection-end @pytest.mark.parametrize("url,multiple,expected_data", test_data) def test_url_multiple_arg(url, multiple, expected_data): """Scenario: Submit a URL with commas in it Given - A URL with commas in it When - case A: 'multiple' argument is set to "true" (the default) - case B: 'multiple' argument is set to "false" Then - case A: Ensure the URL is interpreted as multiple values to be sent in the subsequent API call - case B: Ensure the URL is interpreted as a single value to be sent in the subsequent API call Args: url (str): The URL to submit. multiple (str): "true" or "false" - whether to interpret the 'url' argument as multiple comma separated values. expected_data (list): The data expected to be sent in the API call. """ import Zscaler with requests_mock.mock() as m: # 'fake_resp_content' doesn't really matter here since we are checking the data being sent in the call, # not what it is that we expect to get in response fake_resp_content = b'[{"url": "blah", "urlClassifications": [], "urlClassificationsWithSecurityAlert": []}]' m.post(Zscaler.BASE_URL + "/urlLookup", content=fake_resp_content) args = {"url": url, "multiple": multiple} Zscaler.url_lookup(args) assert m.called assert m.call_count == 1 request_data = m.last_request.json() assert len(request_data) == len(expected_data) assert request_data == expected_data def test_login__active_session(mocker): """ Scenario: test login with an active session Given: - User has authorization to login - There is an active session When: - login is called Then: - No login request is done - Result is as expected """ import Zscaler mock_id = "mock_id" mocker.patch.object(demisto, "debug") mocker.patch.object(Zscaler, "get_integration_context", return_value={Zscaler.SESSION_ID_KEY: mock_id}) mocker.patch.object(Zscaler, "test_module") Zscaler.login() assert Zscaler.DEFAULT_HEADERS["cookie"] == mock_id def test_login__no_active_session(mocker): """ Scenario: test login when there is no active session Given: - User has authorization to login - There is an active session When: - User wishes to login using login command Then: - Result is as expected """ import Zscaler mock_header = "JSESSIONID=MOCK_ID; Path=/; Secure; HttpOnly" Zscaler.API_KEY = "Lcb38EvjtZVc" mocker.patch.object(demisto, "debug") mocker.patch.object(Zscaler, "get_integration_context", return_value={}) mocker.patch.object(Zscaler, "test_module") mocker.patch.object(Zscaler, "http_request", return_value=ObjectMocker({"headers": {"Set-Cookie": mock_header}})) Zscaler.login() assert Zscaler.DEFAULT_HEADERS["cookie"] == "JSESSIONID=MOCK_ID" def test_login_command(mocker): """ Scenario: test successful login command Given: - User provided valid credentials - Integration context is empty When: - zscaler-login command is called Then: - Ensure logout is not called - Ensure login is called - Ensure readable output is as expected """ import Zscaler mocker.patch.object(demisto, "debug") mocker.patch.object(Zscaler, "get_integration_context", return_value={}) logout_mock = mocker.patch.object(Zscaler, "logout") login_mock = mocker.patch.object(Zscaler, "login") raw_res = Zscaler.login_command() assert not logout_mock.called assert login_mock.called assert raw_res.readable_output == "Zscaler session created successfully." def test_login_command__load_from_context(mocker): """ Scenario: test successful login command attempt with load from the context Given: - User has provided valid credentials - Integration context has a previous session When: - zscaler-login command is called Then: - Ensure logout is called - Ensure login is called - Ensure readable output is as expected """ import Zscaler mocker.patch.object(demisto, "debug") mocker.patch.object(Zscaler, "get_integration_context", return_value={Zscaler.SESSION_ID_KEY: "test_key"}) logout_mock = mocker.patch.object(Zscaler, "logout") login_mock = mocker.patch.object(Zscaler, "login") raw_res = Zscaler.login_command() assert logout_mock.called assert login_mock.called assert raw_res.readable_output == "Zscaler session created successfully." def test_logout_command__no_context(mocker): """ Scenario: logout when there's no active session Given: - There is no active session When: - logout command is performed Then: - Return readable output detailing no action was performed """ import Zscaler mocker.patch.object(Zscaler, "get_integration_context", return_value={}) raw_res = Zscaler.logout_command() assert raw_res.readable_output == "No API session was found. No action was performed." def test_logout_command__happy_context(mocker): """ Scenario: logout when there's an active session Given: - There is an active session When: - logout command is performed Then: - Return readable output detailing logout was performed """ import Zscaler mocker.patch.object(Zscaler, "get_integration_context", return_value={Zscaler.SESSION_ID_KEY: "test_key"}) mocker.patch.object(Zscaler, "logout", return_value=ResponseMock({})) raw_res = Zscaler.logout_command() assert raw_res.readable_output == "API session logged out of Zscaler successfully." def test_logout_command__context_expired(mocker): """ Scenario: fail to logout with AuthorizationError when there's an active session Given: - There is an active session When: - logout command is performed - logout action fails with AuthorizationError Then: - Return readable output detailing no logout was done """ import Zscaler mocker.patch.object(Zscaler, "get_integration_context", return_value={Zscaler.SESSION_ID_KEY: "test_key"}) mocker.patch.object(Zscaler, "logout", side_effect=Zscaler.AuthorizationError("")) raw_res = Zscaler.logout_command() assert raw_res.readable_output == "API session is not authenticated. No action was performed." def test_get_users_command(mocker): """zscaler-get-users""" import Zscaler run_command_test( command_func=Zscaler.get_users_command, args={"pageSize": "100"}, response_path="test_data/responses/get_users.json", expected_result_path="test_data/results/get_users.json", mocker=mocker, ) def test_set_user_command(mocker): """zscaler-update-user""" import Zscaler user_json = """{ "department": {"id": "12","name": "user test"}, "email": "user@test.com", "groups": [{"id": 13,"name": "name_test"}], "id": 11, "name": "name.test.com" }""" run_command_test( command_func=Zscaler.set_user_command, args={"id": "11", "user": user_json}, response_path="test_data/responses/set_user.json", expected_result_path="test_data/results/set_user.json", mocker=mocker, resp_type="response", ) def test_get_departments_command(mocker): """zscaler-get-departments""" import Zscaler run_command_test( command_func=Zscaler.get_departments_command, args={"pageSize": "1"}, response_path="test_data/responses/get_departments.json", expected_result_path="test_data/results/get_departments.json", mocker=mocker, ) def test_get_usergroups_command(mocker): """zscaler-get-usergroups""" import Zscaler run_command_test( command_func=Zscaler.get_usergroups_command, args={"pageSize": "100"}, response_path="test_data/responses/get_usergroups.json", expected_result_path="test_data/results/get_usergroups.json", mocker=mocker, ) def test_list_ip_destination_groups__command_no_argument(mocker): """zscaler-list-ip-destination-groups""" import Zscaler run_command_test( command_func=Zscaler.list_ip_destination_groups, args={}, response_path="test_data/responses/" + "list_ip_destination_groups.json", expected_result_path="test_data/results/" + "list_ip_destination_groups.json", mocker=mocker, ) def test_list_ip_destination_groups__command_with_id_argument(mocker): """zscaler-list-ip-destination-groups""" import Zscaler run_command_test( command_func=Zscaler.list_ip_destination_groups, args={"ip_group_id": "1964949"}, response_path="test_data/responses/" + "list_ip_destination_groups_with_id.json", expected_result_path="test_data/results/" + "list_ip_destination_groups_with" + "_id.json", mocker=mocker, ) def test_list_ip_destination_groups__command_with_exclude_argument(mocker): """zscaler-list-ip-destination-groups""" import Zscaler run_command_test( command_func=Zscaler.list_ip_destination_groups, args={"exclude_type": "DSTN_OTHER"}, response_path="test_data/responses/" + "list_ip_destination_groups_with_exclude" + ".json", expected_result_path="test_data/results/" + "list_ip_destination_groups_with" + "_exclude.json", mocker=mocker, ) def test_list_ip_destination_groups_command_with_lite_argument(mocker): """zscaler-list-ip-destination-groups-lite""" import Zscaler run_command_test( command_func=Zscaler.list_ip_destination_groups, args={"lite": "True"}, response_path="test_data/responses/list_ip_destination_groups_lite.json", expected_result_path="test_data/results/list_ip_destination_groups_lite.json", mocker=mocker, ) def test_create_ip_destination_group(mocker): """zscaler-create-ip-destination-group""" import Zscaler run_command_test( command_func=Zscaler.create_ip_destination_group, args={"name": "Test99", "type": "DSTN_IP", "addresses": ["127.0.0.2", "127.0.0.1"], "description": "Localhost"}, response_path="test_data/responses/" + "create_ip_destination_group.json", expected_result_path="test_data/results/" + "create_ip_destination_group.json", mocker=mocker, ) def test_edit_ip_destination_group(mocker): """zscaler-edit-ip-destination-group""" import Zscaler run_command_test( command_func=Zscaler.edit_ip_destination_group, args={"ip_group_id": "2000359", "name": "Test01", "addresses": ["127.0.0.2"], "description": "Localhost v2"}, response_path="test_data/responses/" + "edit_ip_destination_group.json", expected_result_path="test_data/results/" + "edit_ip_destination_group.json", mocker=mocker, ) def test_delete_ip_destination_groups(mocker): """zscaler-delete-ip-destination-group""" import Zscaler run_command_test( command_func=Zscaler.delete_ip_destination_groups, args={"ip_group_id": "1964949"}, response_path="test_data/responses/delete_ip_destination_group.json", expected_result_path="test_data/results/delete_ip_destination_group.json", mocker=mocker, ) def test_category_add_url(mocker): """ Given: - A category ID, URL, and retaining parent category URL When: - category_add_url is called Then: - The URL should be added to the category """ from Zscaler import category_add mocker.patch("Zscaler.get_category_by_id", return_value={"urls": []}) mocker.patch("Zscaler.argToList", side_effect=[["test1.com"], ["test2.com"]]) mocker.patch("Zscaler.add_or_remove_urls_from_category", return_value=None) result = category_add("1", "test1.com", "test2.com", "url") assert result["HumanReadable"].startswith("Added the following URL, retaining-parent-category-url addresses to category 1") def test_category_add_url_with_category_name(mocker): """ Given: - A category ID, URL, retaining parent category URL, and category name When: - category_add_url is called with category_name argument Then: - The URL should be added to the category with the category name passed through """ from Zscaler import category_add mocker.patch("Zscaler.get_category_by_id", return_value={"urls": [], "customCategory": True}) mocker.patch("Zscaler.argToList", side_effect=[["test1.com"], ["test2.com"]]) mock_add_or_remove = mocker.patch("Zscaler.add_or_remove_urls_from_category", return_value=None) result = category_add("CUSTOM_01", "test1.com", "test2.com", "url", "My-Custom-Category") assert result["HumanReadable"].startswith( "Added the following URL, retaining-parent-category-url addresses to category CUSTOM_01" ) # Verify category_name was passed to add_or_remove_urls_from_category mock_add_or_remove.assert_called_once() call_args = mock_add_or_remove.call_args assert call_args[0][4] == "My-Custom-Category" # category_name is the 5th positional argument def test_category_add_ip(mocker): """ Given: - A category ID, IP address, and retaining parent category IP When: - category_add_ip is called Then: - The IP address should be added to the category """ from Zscaler import category_add mocker.patch("Zscaler.get_categories", return_value=[{"id": 1, "urls": [], "customCategory": "true"}]) mocker.patch("Zscaler.add_or_remove_urls_from_category", return_value={}) result = category_add(1, "1.1.1.1", "1.1.1.1", "ip") assert result["HumanReadable"].startswith("Added the following IP, retaining-parent-category-ip addresses to category 1") def test_add_or_remove_urls_from_category_with_configured_name(mocker, requests_mock): """ Given: - A custom category with configuredName and superCategory in category_data When: - add_or_remove_urls_from_category is called Then: - Both configuredName and superCategory should be included in the request body """ import Zscaler Zscaler.BASE_URL = "http://cloud/api/v1" category_data = { "id": "CUSTOM_01", "customCategory": True, "urls": [], "configuredName": "My-Custom-Category", "superCategory": "USER_DEFINED", } requests_mock.put("http://cloud/api/v1/urlCategories/CUSTOM_01?action=ADD_TO_LIST", json={}) Zscaler.add_or_remove_urls_from_category(Zscaler.ADD, ["test.com"], category_data) assert requests_mock.called request_body = requests_mock.last_request.json() assert request_body.get("configuredName") == "My-Custom-Category" assert request_body.get("superCategory") == "USER_DEFINED" def test_add_or_remove_urls_from_category_with_category_name_override(mocker, requests_mock): """ Given: - A custom category with configuredName and superCategory in category_data - A category_name argument provided When: - add_or_remove_urls_from_category is called Then: - The provided category_name should override the one from category_data - The superCategory should still be included """ import Zscaler Zscaler.BASE_URL = "http://cloud/api/v1" category_data = { "id": "CUSTOM_01", "customCategory": True, "urls": [], "configuredName": "Old-Name", "superCategory": "NEWS_AND_MEDIA", } requests_mock.put("http://cloud/api/v1/urlCategories/CUSTOM_01?action=ADD_TO_LIST", json={}) Zscaler.add_or_remove_urls_from_category(Zscaler.ADD, ["test.com"], category_data, category_name="New-Name") assert requests_mock.called request_body = requests_mock.last_request.json() assert request_body.get("configuredName") == "New-Name" assert request_body.get("superCategory") == "NEWS_AND_MEDIA" def test_add_or_remove_urls_from_category_custom_without_name_raises_error(mocker): """ Given: - A custom category without configuredName in category_data - No category_name argument provided When: - add_or_remove_urls_from_category is called Then: - A DemistoException should be raised """ import Zscaler from CommonServerPython import DemistoException category_data = {"id": "CUSTOM_01", "customCategory": True, "urls": []} with pytest.raises(DemistoException) as exc_info: Zscaler.add_or_remove_urls_from_category(Zscaler.ADD, ["test.com"], category_data) assert "configuredName" in str(exc_info.value) assert "category-name" in str(exc_info.value) def test_get_category_by_id_injects_category_name(mocker): """ Given: - A category without configuredName - A category_name argument provided When: - get_category_by_id is called Then: - The category_name should be injected into the returned category data """ import Zscaler mocker.patch("Zscaler.get_categories", return_value=[{"id": "CUSTOM_01", "customCategory": True, "urls": []}]) result = Zscaler.get_category_by_id("CUSTOM_01", "My-Custom-Category") assert result is not None assert result.get("configuredName") == "My-Custom-Category" def test_edit_ip_destination_group_override_false(mocker): """ Given: - An existing IP destination group ID and override='False' When: - edit_ip_destination_group is called Then: - The PUT request URL contains 'override=false' """ import Zscaler http_mock = mocker.patch( "Zscaler.http_request", return_value={ "id": "2000359", "name": "Test01", "type": "DSTN_IP", "addresses": ["127.0.0.2"], "description": "Localhost v2", "ipCategories": [], "countries": [], }, ) Zscaler.edit_ip_destination_group( { "ip_group_id": "2000359", "name": "Test01", "addresses": ["127.0.0.2"], "description": "Localhost v2", "override": "False", } ) # First call is the GET to fetch existing group, second is the PUT with override param put_call = http_mock.call_args_list[1] assert "override=false" in put_call.args[1] def test_edit_ip_destination_group_override_true_default(mocker): """ Given: - An existing IP destination group ID with no override argument provided When: - edit_ip_destination_group is called Then: - The PUT request URL does not contains 'override' (the default) """ import Zscaler http_mock = mocker.patch( "Zscaler.http_request", return_value={ "id": "2000359", "name": "Test01", "type": "DSTN_IP", "addresses": ["127.0.0.2"], "description": "Localhost v2", "ipCategories": [], "countries": [], }, ) Zscaler.edit_ip_destination_group( {"ip_group_id": "2000359", "name": "Test01", "addresses": ["127.0.0.2"], "description": "Localhost v2"} ) put_call = http_mock.call_args_list[1] assert "override" not in put_call.args[1] def test_return_error_is_called_on_error(mocker, requests_mock): """ Given: - Any command run When: - Calling login() which fails on 429 Then: - Ensure an error entry is returned """ import sys import importlib import Zscaler as original_zscaler Zscaler = importlib.reload(original_zscaler) mock_id = "mock_id" mocker.patch.object(Zscaler, "get_integration_context", return_value={Zscaler.SESSION_ID_KEY: mock_id}) requests_mock.get("http://cloud/api/v1/status", status_code=429) mocker.patch.object(demisto, "results") mocker.patch.object(sys, "exit") Zscaler.main() error_results = demisto.results.call_args_list[0][0] assert "Exceeded the rate limit or quota" in error_results[0].get("Contents")

