From ce2fd3fa06b581a7ad9781f39ef822d368d2940a Mon Sep 17 00:00:00 2001 From: Tapish Jain Date: Mon, 5 Aug 2024 15:53:46 -0700 Subject: [PATCH 01/16] PAPP-34459: Update user action working --- zscaler.json | 189 +++++++++++++++++++++++++++++++++++++++++++ zscaler_connector.py | 27 +++++++ 2 files changed, 216 insertions(+) diff --git a/zscaler.json b/zscaler.json index 5ed9741..0fcd677 100644 --- a/zscaler.json +++ b/zscaler.json @@ -3000,6 +3000,195 @@ "type": "table" }, "versions": "EQ(*)" + }, + { + "action": "update user", + "identifier": "update_user", + "description": "Update user with given id", + "type": "correct", + "read_only": false, + "parameters": { + "user_id": { + "description": "ZScaler User Id", + "data_type": "numeric", + "required": true, + "primary": true, + "contains": [ + "zscaler user id" + ], + "example_values": [ + 889814 + ], + "order": 0 + }, + "user": { + "description": "JSON object containing the user details (see https://help.zscaler.com/zia/user-management#/users/{userId}-put)", + "data_type": "string", + "primary": true, + "order": 1 + } + }, + "output": [ + { + "data_path": "action_result.status", + "data_type": "string", + "column_name": "Status", + "column_order": 2, + "example_values": [ + "test success", + "test failed" + ] + }, + { + "data_path": "action_result.parameter.user", + "data_type": "string", + "column_name": "User", + "column_order": 1 + }, + { + "data_path": "action_result.parameter.user_id", + "data_type": "numeric", + "contains": [ + "zscaler user id" + ], + "column_name": "User ID", + "column_order": 0, + "example_values": [ + 889814 + ] + }, + { + "data_path": "action_result.data.*.adminUser", + "data_type": "boolean", + "example_values": [ + true, + false + ] + }, + { + "data_path": "action_result.data.*.comments", + "data_type": "string", + "example_values": [ + "test This is test user" + ] + }, + { + "data_path": "action_result.data.*.deleted", + "data_type": "boolean", + "example_values": [ + true, + false + ] + }, + { + "data_path": "action_result.data.*.department.id", + "data_type": "numeric", + "example_values": [ + 81896690 + ] + }, + { + "data_path": "action_result.data.*.department.name", + "data_type": "string", + "example_values": [ + "test IT" + ] + }, + { + "data_path": "action_result.data.*.email", + "data_type": "string", + "contains": [ + "email" + ], + "example_values": [ + "test first.last@domain.com" + ], + "column_name": "User Email", + "column_order": 2 + }, + { + "data_path": "action_result.data.*.groups.*.id", + "data_type": "numeric", + "contains": [ + "zscaler group id" + ], + "example_values": [ + 8894813 + ], + "column_name": "Group ID", + "column_order": 3 + }, + { + "data_path": "action_result.data.*.groups.*.name", + "data_type": "string", + "example_values": [ + "test Super Admin" + ], + "column_name": "Group Name", + "column_order": 4 + }, + { + "data_path": "action_result.data.*.id", + "data_type": "numeric", + "contains": [ + "zscaler user id" + ], + "example_values": [ + 889814 + ], + "column_name": "User ID", + "column_order": 0 + }, + { + "data_path": "action_result.data.*.name", + "data_type": "string", + "example_values": [ + "test First Last" + ], + "column_name": "User Name", + "column_order": 1 + }, + { + "data_path": "action_result.summary", + "data_type": "string" + }, + { + "data_path": "action_result.summary.message", + "data_type": "string", + "example_values": [ + "test User removed from group" + ] + }, + { + "data_path": "action_result.message", + "data_type": "string", + "example_values": [ + "test User removed from group" + ] + }, + { + "data_path": "summary.message", + "data_type": "string" + }, + { + "data_path": "summary.total_objects", + "data_type": "numeric", + "example_values": [ + 1 + ] + }, + { + "data_path": "summary.total_objects_successful", + "data_type": "numeric", + "example_values": [ + 1 + ] + } + ], + "render": { + "type": "table" + }, + "versions": "EQ(*)" } ], "pip_dependencies": { diff --git a/zscaler_connector.py b/zscaler_connector.py index dd0686c..ba539db 100644 --- a/zscaler_connector.py +++ b/zscaler_connector.py @@ -990,6 +990,30 @@ def _handle_remove_group_user(self, param): return action_result.set_status(phantom.APP_SUCCESS) + def _handle_update_user(self, param): + self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) + action_result = self.add_action_result(ActionResult(dict(param))) + user_id = param['user_id'] + + try: + data = json.loads(param["user"]) + except Exception as e: + return action_result.set_status( + phantom.APP_ERROR, + "User object needs to be valid json: {}".format(e) + ) + + ret_val, response = self._make_rest_call_helper(f'/api/v1/users/{user_id}', action_result, data=data, method='put') + + if phantom.is_fail(ret_val): + return action_result.get_status() + + self.debug_print(response) + action_result.add_data(response) + summary = action_result.update_summary({}) + summary['message'] = "User updated" + return action_result.set_status(phantom.APP_SUCCESS) + def handle_action(self, param): ret_val = phantom.APP_SUCCESS @@ -1056,6 +1080,9 @@ def handle_action(self, param): elif action_id == 'remove_group_user': ret_val = self._handle_remove_group_user(param) + elif action_id == "update_user": + ret_val = self._handle_update_user(param) + return ret_val def initialize(self): From 7ce74a948e472a65f91d35b0705ec46be9bb0fbc Mon Sep 17 00:00:00 2001 From: splunk-soar-connectors-admin Date: Mon, 5 Aug 2024 22:54:26 +0000 Subject: [PATCH 02/16] Update README.md --- README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/README.md b/README.md index e954575..569137a 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,7 @@ VARIABLE | REQUIRED | TYPE | DESCRIPTION [get groups](#action-get-groups) - Gets a list of groups [add group user](#action-add-group-user) - Add user to group [remove group user](#action-remove-group-user) - Remove user from group +[update user](#action-update-user) - Update user with given id ## action: 'test connectivity' Validate the asset configuration for connectivity using supplied configuration @@ -745,4 +746,39 @@ action_result.summary.message | string | | test User removed from group action_result.message | string | | test User removed from group summary.message | string | | summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 + +## action: 'update user' +Update user with given id + +Type: **correct** +Read only: **False** + +#### Action Parameters +PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS +--------- | -------- | ----------- | ---- | -------- +**user_id** | required | ZScaler User Id | numeric | `zscaler user id` +**user** | optional | JSON object containing the user details (see https://help.zscaler.com/zia/user-management#/users/{userId}-put) | string | + +#### Action Output +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | test success test failed +action_result.parameter.user | string | | +action_result.parameter.user_id | numeric | `zscaler user id` | 889814 +action_result.data.\*.adminUser | boolean | | True False +action_result.data.\*.comments | string | | test This is test user +action_result.data.\*.deleted | boolean | | True False +action_result.data.\*.department.id | numeric | | 81896690 +action_result.data.\*.department.name | string | | test IT +action_result.data.\*.email | string | `email` | test first.last@domain.com +action_result.data.\*.groups.\*.id | numeric | `zscaler group id` | 8894813 +action_result.data.\*.groups.\*.name | string | | test Super Admin +action_result.data.\*.id | numeric | `zscaler user id` | 889814 +action_result.data.\*.name | string | | test First Last +action_result.summary | string | | +action_result.summary.message | string | | test User removed from group +action_result.message | string | | test User removed from group +summary.message | string | | +summary.total_objects | numeric | | 1 summary.total_objects_successful | numeric | | 1 \ No newline at end of file From 3540483cc7f3a84a961a0ac59d7cd9692ad241e3 Mon Sep 17 00:00:00 2001 From: Tapish Jain Date: Mon, 5 Aug 2024 16:57:03 -0700 Subject: [PATCH 03/16] PAPP-34461: Create destination group action done --- zscaler.json | 379 +++++++++++++++++++++++++++++++++++++++++++ zscaler_connector.py | 32 ++++ 2 files changed, 411 insertions(+) diff --git a/zscaler.json b/zscaler.json index 5ed9741..7a6b43e 100644 --- a/zscaler.json +++ b/zscaler.json @@ -3000,6 +3000,385 @@ "type": "table" }, "versions": "EQ(*)" + }, + { + "action": "create destination group", + "identifier": "create_destination_group", + "description": "Create destination group", + "type": "generic", + "read_only": false, + "parameters": { + "name": { + "description": "Destination IP group name", + "data_type": "string", + "required": true, + "primary": true, + "order": 0 + }, + "type": { + "description": "Destination IP group type (i.e., the group can contain destination IP addresses, countries, URL categories or FQDNs)", + "data_type": "string", + "required": true, + "primary": true, + "example_values": [ + "DSTN_IP", + "DSTN_FQDN", + "DSTN_DOMAIN", + "DSTN_OTHER" + ], + "order": 1 + }, + "addresses": { + "description": "Comma seperated string of destination IP addresses, FQDNs, or wildcard FQDNs added to the group", + "data_type": "string", + "order": 2 + }, + "description": { + "description": "Additional information about the destination IP group.", + "data_type": "string", + "order": 3 + }, + "ip_categories": { + "description": "Destination IP address URL categories", + "data_type": "string", + "order": 4 + }, + "countries": { + "description": "Destination IP address countries. You can identify destinations based on the location of a server.", + "data_type": "string", + "order": 5 + } + }, + "output": [ + { + "data_path": "action_result.status", + "data_type": "string", + "column_name": "Status", + "column_order": 2, + "example_values": [ + "test success", + "test failed" + ] + }, + { + "data_path": "action_result.parameter.countries", + "data_type": "string", + "column_name": "Countries", + "column_order": 4 + }, + { + "data_path": "action_result.parameter.ip_categories", + "data_type": "string", + "column_name": "Ip Categories", + "column_order": 3 + }, + { + "data_path": "action_result.parameter.addresses", + "data_type": "string", + "column_name": "Addresses", + "column_order": 2 + }, + { + "data_path": "action_result.parameter.type", + "data_type": "string", + "column_name": "Type", + "column_order": 1 + }, + { + "data_path": "action_result.parameter.name", + "data_type": "string", + "column_name": "Name", + "column_order": 0 + }, + { + "data_path": "action_result.data.*.id", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.name", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.type", + "data_type": "string", + "example_values": [ + "DSTN_IP", + "DSTN_FQDN", + "DSTN_DOMAIN", + "DSTN_OTHER" + ] + }, + { + "data_path": "action_result.data.*.addresses", + "data_type": "string", + "example_values": [ + "192.168.1.1" + ] + }, + { + "data_path": "action_result.data.*.countries", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.description", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.ipCategories", + "data_type": "string", + "example_values": [ + "TRADING_BROKARAGE_INSURANCE" + ] + }, + { + "data_path": "action_result.summary", + "data_type": "string" + }, + { + "data_path": "action_result.summary.message", + "data_type": "string", + "example_values": [ + "test User removed from group" + ] + }, + { + "data_path": "action_result.message", + "data_type": "string", + "example_values": [ + "test User removed from group" + ] + }, + { + "data_path": "summary.message", + "data_type": "string" + }, + { + "data_path": "summary.total_objects", + "data_type": "numeric", + "example_values": [ + 1 + ] + }, + { + "data_path": "summary.total_objects_successful", + "data_type": "numeric", + "example_values": [ + 1 + ] + } + ], + "render": { + "type": "table" + }, + "versions": "EQ(*)" + }, + { + "action": "list destination group", + "identifier": "list_destination_group", + "description": "List destination group", + "type": "investigate", + "read_only": false, + "parameters": { + "ip_group_id": { + "description": "A comma-separated list of unique identifiers for the IP destination groups", + "data_type": "string", + "primary": true, + "order": 0 + }, + "exclude_type": { + "description": "The IP group type to be excluded from the results", + "data_type": "string", + "primary": true, + "example_values": [ + "DSTN_IP", + "DSTN_FQDN", + "DSTN_DOMAIN", + "DSTN_OTHER" + ], + "order": 1 + }, + "category_type": { + "description": "The IP group type to be filtered from results. This argument is only supported when the 'lite' argument is set to True", + "data_type": "string", + "example_values": [ + "DSTN_IP", + "DSTN_FQDN", + "DSTN_DOMAIN", + "DSTN_OTHER" + ], + "order": 2 + }, + "include_ipv6": { + "description": "Retrieve IPv6 destination groups", + "data_type": "boolean", + "example_values": [ + true, + false + ], + "default": false, + "order": 3 + }, + "limit": { + "description": "Limit of the results to be retrieved", + "data_type": "numeric", + "default": 50, + "order": 4 + }, + "all_results": { + "description": "Whether to retrieve all results at once", + "data_type": "boolean", + "example_values": [ + true, + false + ], + "default": false, + "order": 5 + }, + "lite": { + "description": "Whether to retrieve only limited information of IP destination groups. Includes ID, name and type of the IP destination groups", + "data_type": "boolean", + "example_values": [ + true, + false + ], + "default": false, + "order": 6 + } + }, + "output": [ + { + "data_path": "action_result.status", + "data_type": "string", + "column_name": "Status", + "column_order": 2, + "example_values": [ + "test success", + "test failed" + ] + }, + { + "data_path": "action_result.parameter.lite", + "data_type": "boolean", + "column_name": "Lite", + "column_order": 6 + }, + { + "data_path": "action_result.parameter.all_reuslts", + "data_type": "boolean", + "column_name": "All Results", + "column_order": 5 + }, + { + "data_path": "action_result.parameter.limit", + "data_type": "numeric", + "column_name": "Limit", + "column_order": 4 + }, + { + "data_path": "action_result.parameter.include_ipv6", + "data_type": "boolean", + "column_name": "Include Ipv6", + "column_order": 3 + }, + { + "data_path": "action_result.parameter.category_type", + "data_type": "string", + "column_name": "Category Type", + "column_order": 2 + }, + { + "data_path": "action_result.parameter.exclude_type", + "data_type": "string", + "column_name": "Exclude Type", + "column_order": 1 + }, + { + "data_path": "action_result.parameter.ip_group_id", + "data_type": "string", + "column_name": "Ip Group ID", + "column_order": 0 + }, + { + "data_path": "action_result.data.*.id", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.name", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.type", + "data_type": "string", + "example_values": [ + "DSTN_IP", + "DSTN_FQDN", + "DSTN_DOMAIN", + "DSTN_OTHER" + ] + }, + { + "data_path": "action_result.data.*.addresses", + "data_type": "string", + "example_values": [ + "192.168.1.1" + ] + }, + { + "data_path": "action_result.data.*.countries", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.description", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.ipCategories", + "data_type": "string", + "example_values": [ + "TRADING_BROKARAGE_INSURANCE" + ] + }, + { + "data_path": "action_result.summary", + "data_type": "string" + }, + { + "data_path": "action_result.summary.message", + "data_type": "string", + "example_values": [ + "Retreived Destination Groups" + ] + }, + { + "data_path": "action_result.message", + "data_type": "string", + "example_values": [ + "Retreived Destination Groups" + ] + }, + { + "data_path": "summary.message", + "data_type": "string" + }, + { + "data_path": "summary.total_objects", + "data_type": "numeric", + "example_values": [ + 1 + ] + }, + { + "data_path": "summary.total_objects_successful", + "data_type": "numeric", + "example_values": [ + 1 + ] + } + ], + "render": { + "type": "table" + }, + "versions": "EQ(*)" } ], "pip_dependencies": { diff --git a/zscaler_connector.py b/zscaler_connector.py index dd0686c..600e90b 100644 --- a/zscaler_connector.py +++ b/zscaler_connector.py @@ -990,6 +990,35 @@ def _handle_remove_group_user(self, param): return action_result.set_status(phantom.APP_SUCCESS) + def _handle_create_destination_group(self, param): + self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) + action_result = self.add_action_result(ActionResult(dict(param))) + + addresses = param.get("addresses", "") + ip_categories = param.get("ip_categories", "") + countries = param.get("countries", "") + + data = {} + data["name"] = param["name"] + data["type"] = param["type"] + if addresses: + data["addresses"] = [item.strip() for item in addresses.split(',')] + data["description"] = param.get("description", "") + if ip_categories: + data["ip_categories"] = [item.strip() for item in ip_categories.split(',')] + if countries: + data["countries"] = [item.strip() for item in countries.split(',')] + + ret_val, response = self._make_rest_call_helper('/api/v1/ipDestinationGroups', action_result, data=data, method='post') + if phantom.is_fail(ret_val): + return action_result.get_status() + + action_result.add_data(response) + summary = action_result.update_summary({}) + summary['message'] = "Destination IP added" + + return action_result.set_status(phantom.APP_SUCCESS) + def handle_action(self, param): ret_val = phantom.APP_SUCCESS @@ -1056,6 +1085,9 @@ def handle_action(self, param): elif action_id == 'remove_group_user': ret_val = self._handle_remove_group_user(param) + elif action_id == 'create_destination_group': + ret_val = self._handle_create_destination_group(param) + return ret_val def initialize(self): From e62fbc8563f101378d43a95be8664643a7130ed3 Mon Sep 17 00:00:00 2001 From: splunk-soar-connectors-admin Date: Mon, 5 Aug 2024 23:57:42 +0000 Subject: [PATCH 04/16] Update README.md --- README.md | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/README.md b/README.md index e954575..8bdb88e 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,8 @@ VARIABLE | REQUIRED | TYPE | DESCRIPTION [get groups](#action-get-groups) - Gets a list of groups [add group user](#action-add-group-user) - Add user to group [remove group user](#action-remove-group-user) - Remove user from group +[create destination group](#action-create-destination-group) - Create destination group +[list destination group](#action-list-destination-group) - List destination group ## action: 'test connectivity' Validate the asset configuration for connectivity using supplied configuration @@ -745,4 +747,85 @@ action_result.summary.message | string | | test User removed from group action_result.message | string | | test User removed from group summary.message | string | | summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 + +## action: 'create destination group' +Create destination group + +Type: **generic** +Read only: **False** + +#### Action Parameters +PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS +--------- | -------- | ----------- | ---- | -------- +**name** | required | Destination IP group name | string | +**type** | required | Destination IP group type (i.e., the group can contain destination IP addresses, countries, URL categories or FQDNs) | string | +**addresses** | optional | Comma seperated string of destination IP addresses, FQDNs, or wildcard FQDNs added to the group | string | +**description** | optional | Additional information about the destination IP group. | string | +**ip_categories** | optional | Destination IP address URL categories | string | +**countries** | optional | Destination IP address countries. You can identify destinations based on the location of a server. | string | + +#### Action Output +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | test success test failed +action_result.parameter.countries | string | | +action_result.parameter.ip_categories | string | | +action_result.parameter.addresses | string | | +action_result.parameter.type | string | | +action_result.parameter.name | string | | +action_result.data.\*.id | numeric | | +action_result.data.\*.name | string | | +action_result.data.\*.type | string | | DSTN_IP DSTN_FQDN DSTN_DOMAIN DSTN_OTHER +action_result.data.\*.addresses | string | | 192.168.1.1 +action_result.data.\*.countries | string | | +action_result.data.\*.description | string | | +action_result.data.\*.ipCategories | string | | TRADING_BROKARAGE_INSURANCE +action_result.summary | string | | +action_result.summary.message | string | | test User removed from group +action_result.message | string | | test User removed from group +summary.message | string | | +summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 + +## action: 'list destination group' +List destination group + +Type: **investigate** +Read only: **False** + +#### Action Parameters +PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS +--------- | -------- | ----------- | ---- | -------- +**ip_group_id** | optional | A comma-separated list of unique identifiers for the IP destination groups | string | +**exclude_type** | optional | The IP group type to be excluded from the results | string | +**category_type** | optional | The IP group type to be filtered from results. This argument is only supported when the 'lite' argument is set to True | string | +**include_ipv6** | optional | Retrieve IPv6 destination groups | boolean | +**limit** | optional | Limit of the results to be retrieved | numeric | +**all_results** | optional | Whether to retrieve all results at once | boolean | +**lite** | optional | Whether to retrieve only limited information of IP destination groups. Includes ID, name and type of the IP destination groups | boolean | + +#### Action Output +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | test success test failed +action_result.parameter.lite | boolean | | +action_result.parameter.all_reuslts | boolean | | +action_result.parameter.limit | numeric | | +action_result.parameter.include_ipv6 | boolean | | +action_result.parameter.category_type | string | | +action_result.parameter.exclude_type | string | | +action_result.parameter.ip_group_id | string | | +action_result.data.\*.id | numeric | | +action_result.data.\*.name | string | | +action_result.data.\*.type | string | | DSTN_IP DSTN_FQDN DSTN_DOMAIN DSTN_OTHER +action_result.data.\*.addresses | string | | 192.168.1.1 +action_result.data.\*.countries | string | | +action_result.data.\*.description | string | | +action_result.data.\*.ipCategories | string | | TRADING_BROKARAGE_INSURANCE +action_result.summary | string | | +action_result.summary.message | string | | Retreived Destination Groups +action_result.message | string | | Retreived Destination Groups +summary.message | string | | +summary.total_objects | numeric | | 1 summary.total_objects_successful | numeric | | 1 \ No newline at end of file From 538805ba814654b9539ebc5ef4752308772ac613 Mon Sep 17 00:00:00 2001 From: Tapish Jain Date: Tue, 6 Aug 2024 12:02:37 -0700 Subject: [PATCH 05/16] PAPP-34461: Destination ip group actions complete --- zscaler.json | 280 ++++++++++++++++++++++++++++++++++++++++++- zscaler_connector.py | 193 +++++++++++++++++++++++++++++ 2 files changed, 470 insertions(+), 3 deletions(-) diff --git a/zscaler.json b/zscaler.json index 7a6b43e..50bf19d 100644 --- a/zscaler.json +++ b/zscaler.json @@ -3064,12 +3064,18 @@ "data_path": "action_result.parameter.countries", "data_type": "string", "column_name": "Countries", - "column_order": 4 + "column_order": 5 }, { "data_path": "action_result.parameter.ip_categories", "data_type": "string", "column_name": "Ip Categories", + "column_order": 4 + }, + { + "data_path": "action_result.parameter.description", + "data_type": "string", + "column_name": "Description", "column_order": 3 }, { @@ -3179,7 +3185,7 @@ "type": "investigate", "read_only": false, "parameters": { - "ip_group_id": { + "ip_group_ids": { "description": "A comma-separated list of unique identifiers for the IP destination groups", "data_type": "string", "primary": true, @@ -3198,7 +3204,7 @@ "order": 1 }, "category_type": { - "description": "The IP group type to be filtered from results. This argument is only supported when the 'lite' argument is set to True", + "description": "Comma seperated list of IP group types to be filtered from results. This argument is only supported when the 'lite' argument is set to True", "data_type": "string", "example_values": [ "DSTN_IP", @@ -3379,6 +3385,274 @@ "type": "table" }, "versions": "EQ(*)" + }, + { + "action": "edit destination group", + "identifier": "edit_destination_group", + "description": "Edit destination group", + "type": "generic", + "read_only": false, + "parameters": { + "ip_group_id": { + "description": "The unique identifier for the IP destination group", + "data_type": "numeric", + "required": true, + "primary": true, + "order": 0 + }, + "name": { + "description": "Destination IP group name", + "data_type": "string", + "primary": true, + "order": 1 + }, + "addresses": { + "description": "Comma seperated string of destination IP addresses, FQDNs, or wildcard FQDNs added to the group", + "data_type": "string", + "order": 2 + }, + "description": { + "description": "Additional information about the destination IP group.", + "data_type": "string", + "order": 3 + }, + "ip_categories": { + "description": "Destination IP address URL categories", + "data_type": "string", + "order": 4 + }, + "countries": { + "description": "Destination IP address countries. You can identify destinations based on the location of a server.", + "data_type": "string", + "order": 5 + }, + "is_non_editable": { + "description": "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", + "data_type": "boolean", + "default": false, + "example_values": [ + true, + false + ], + "order": 6 + } + }, + "output": [ + { + "data_path": "action_result.status", + "data_type": "string", + "column_name": "Status", + "column_order": 2, + "example_values": [ + "test success", + "test failed" + ] + }, + { + "data_path": "action_result.parameter.is_non_editable", + "data_type": "boolean", + "column_name": "Is Non Editab;e", + "column_order": 6 + }, + { + "data_path": "action_result.parameter.countries", + "data_type": "string", + "column_name": "Countries", + "column_order": 5 + }, + { + "data_path": "action_result.parameter.ip_categories", + "data_type": "string", + "column_name": "Ip Categories", + "column_order": 4 + }, + { + "data_path": "action_result.parameter.description", + "data_type": "string", + "column_name": "Description", + "column_order": 3 + }, + { + "data_path": "action_result.parameter.addresses", + "data_type": "string", + "column_name": "Addresses", + "column_order": 2 + }, + { + "data_path": "action_result.parameter.name", + "data_type": "string", + "column_name": "Name", + "column_order": 1 + }, + { + "data_path": "action_result.parameter.ip_group_id", + "data_type": "numeric", + "column_name": "IP Group Id", + "column_order": 1 + }, + { + "data_path": "action_result.data.*.id", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.name", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.type", + "data_type": "string", + "example_values": [ + "DSTN_IP", + "DSTN_FQDN", + "DSTN_DOMAIN", + "DSTN_OTHER" + ] + }, + { + "data_path": "action_result.data.*.addresses", + "data_type": "string", + "example_values": [ + "192.168.1.1" + ] + }, + { + "data_path": "action_result.data.*.countries", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.description", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.ipCategories", + "data_type": "string", + "example_values": [ + "TRADING_BROKARAGE_INSURANCE" + ] + }, + { + "data_path": "action_result.data.*.creatorContext", + "data_type": "string" + }, + { + "data_path": "action_result.summary", + "data_type": "string" + }, + { + "data_path": "action_result.summary.message", + "data_type": "string", + "example_values": [ + "test User removed from group" + ] + }, + { + "data_path": "action_result.message", + "data_type": "string", + "example_values": [ + "test User removed from group" + ] + }, + { + "data_path": "summary.message", + "data_type": "string" + }, + { + "data_path": "summary.total_objects", + "data_type": "numeric", + "example_values": [ + 1 + ] + }, + { + "data_path": "summary.total_objects_successful", + "data_type": "numeric", + "example_values": [ + 1 + ] + } + ], + "render": { + "type": "table" + }, + "versions": "EQ(*)" + }, + { + "action": "delete destination group", + "identifier": "delete_destination_group", + "description": "Delete destination group", + "type": "generic", + "read_only": false, + "parameters": { + "ip_group_ids": { + "description": "A comma-separated list of unique identifiers for the IP destination groups", + "data_type": "string", + "primary": true, + "order": 0 + } + }, + "output": [ + { + "data_path": "action_result.status", + "data_type": "string", + "column_name": "Status", + "column_order": 2, + "example_values": [ + "test success", + "test failed" + ] + }, + { + "data_path": "action_result.parameter.ip_group_ids", + "data_type": "string", + "column_name": "IP Group Ids", + "column_order": 0 + }, + { + "data_path": "action_result.data.*.ip_group_ids", + "data_type": "string" + }, + { + "data_path": "action_result.summary", + "data_type": "string" + }, + { + "data_path": "action_result.summary.message", + "data_type": "string", + "example_values": [ + "test User removed from group" + ] + }, + { + "data_path": "action_result.message", + "data_type": "string", + "example_values": [ + "test User removed from group" + ] + }, + { + "data_path": "summary.message", + "data_type": "string" + }, + { + "data_path": "summary.total_objects", + "data_type": "numeric", + "example_values": [ + 1 + ] + }, + { + "data_path": "summary.total_objects_successful", + "data_type": "numeric", + "example_values": [ + 1 + ] + } + ], + "render": { + "type": "table" + }, + "versions": "EQ(*)" + } ], "pip_dependencies": { diff --git a/zscaler_connector.py b/zscaler_connector.py index 600e90b..a495112 100644 --- a/zscaler_connector.py +++ b/zscaler_connector.py @@ -991,6 +991,16 @@ def _handle_remove_group_user(self, param): return action_result.set_status(phantom.APP_SUCCESS) def _handle_create_destination_group(self, param): + """ + This action is used to create an IP Destination Group + :param name: IP destination group name + :param type: IP destination group type + :param addresses: Destination IP addresses, FQDNs, or wildcard FQDNs + :param description: Additional information about the destination IP group + :param ip_categories: Destination IP address URL categories + :param countries: Destination IP address countries + :return: status phantom.APP_ERROR/phantom.APP_SUCCESS(along with appropriate message) + """ self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) @@ -1019,6 +1029,180 @@ def _handle_create_destination_group(self, param): return action_result.set_status(phantom.APP_SUCCESS) + def _get_destination_group(self, id, action_result, exclude_type=None, category_type=None, lite=False): + + ret_val, response = self._make_rest_call_helper(f'/api/v1/ipDestinationGroups/{id}', action_result) + if phantom.is_fail(ret_val): + return action_result.get_status(), None + + group_type = response["type"] + + if group_type == exclude_type: + return phantom.APP_SUCCESS, None + + if lite: + if category_type and group_type not in category_type: + return phantom.APP_SUCCESS, None + + lite_resp = {"id": response["id"], "name": response["name"], "type": group_type} + return phantom.APP_SUCCESS, lite_resp + + return phantom.APP_SUCCESS, response + + def _get_batched_groups(self, endpoint, params, action_result): + limit = params['pageSize'] + + while True: + params['pageSize'] = min(limit, ZSCALER_MAX_PAGESIZE) + ret_val, get_groups = self._make_rest_call_helper('/api/v1' + endpoint, action_result, params=params) + self.debug_print("get groups is {0}".format(get_groups)) + if phantom.is_fail(ret_val): + return action_result.get_status() + for group in get_groups: + if "extensions" in group: + extensions = group.pop("extensions") + for key in extensions: + group[key] = extensions[key] + action_result.add_data(group) + limit = limit - params['pageSize'] + if limit <= 0 or len(get_groups) == 0: + break + params['page'] += 1 + + return phantom.APP_SUCCESS + + def _handle_list_destination_group(self, param): + """ + This action is used to list IP Destination Groups + :param ip_group_ids: Destination groups to retrieve + :param exclude_type: Group types to exclude from search + :param category_type: Destination types to filter by + :param include_ipv6: Retrieve IPv6 groups + :param limit: Number of groups to retrieve + :param lite: Retrieve limited information for each group + :param all_results: + :return: status phantom.APP_ERROR/phantom.APP_SUCCESS(along with appropriate message) + """ + self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) + action_result = self.add_action_result(ActionResult(dict(param))) + + ip_group_ids = param.get("ip_group_ids", "") + ip_ids_lst = [item.strip() for item in ip_group_ids.split(',') if item.strip()] + exclude_type = param.get("exclude_type", "") + category_type = param.get("category_type", "") + category_type_list = [item.strip() for item in category_type.split(',') if item.strip()] + include_ipv6 = param.get("include_ipv6", False) + limit = param.get("limit", 50) + # all_results = param.get("all_results", False) + lite = param.get("lite", False) + + params = {} + endpoint = '/ipDestinationGroups' + params['excludeType'] = exclude_type + self.debug_print("ip id list {0}".format(ip_ids_lst)) + if ip_ids_lst: + for ip in ip_ids_lst: + ret_val, response = self._get_destination_group(ip, action_result, exclude_type, category_type, lite) + if phantom.is_fail(ret_val): + return action_result.get_status() + action_result.add_data(response) + + summary = action_result.update_summary({}) + summary['message'] = "Destination groups retrieved" + return action_result.set_status(phantom.APP_SUCCESS) + + elif lite: + endpoint = '/ipDestinationGroups/lite' + params['type'] = category_type_list + + params['page'] = 1 + params['pageSize'] = limit + ret_val = self._get_batched_groups(endpoint, params, action_result) + if phantom.is_fail(ret_val): + return action_result.get_status() + + if include_ipv6: + self.save_progress("Retrieving ipv6 destination groups") + params['page'] = 1 + params['pageSize'] = limit + endpoint = '/ipDestinationGroups/ipv6DestinationGroups/lite' if lite else '/ipDestinationGroups/ipv6DestinationGroups' + ret_val = self._get_batched_groups(endpoint, params, action_result) + if phantom.is_fail(ret_val): + return action_result.get_status() + + # action_result.add_data(destination_groups) + summary = action_result.update_summary({}) + summary['message'] = "Destination groups retrieved" + return action_result.set_status(phantom.APP_SUCCESS) + + def _handle_edit_destination_group(self, param): + """ + This action is used to edit an IP Destination Group + :param ip_group_id: Id of destination group to edit + :param name: IP destination group name + :param addresses: Destination IP addresses, FQDNs, or wildcard FQDNs + :param description: Additional information about the destination IP group + :param ip_categories: Destination IP address URL categories + :param countries: Destination IP address countries + :param is_non_editable: If set to true, the destination IP address group is non-editable + :return: status phantom.APP_ERROR/phantom.APP_SUCCESS(along with appropriate message) + """ + self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) + action_result = self.add_action_result(ActionResult(dict(param))) + + group_id = param['ip_group_id'] + + ret_val, group_resp = self._get_destination_group(group_id, action_result) + if phantom.is_fail(ret_val): + return action_result.get_status() + self.debug_print("handle edit response {0}".format(group_resp)) + if param.get("name"): + group_resp["name"] = param["name"] + if param.get('addresses'): + addresses = param["addresses"] + group_resp["addresses"] = [item.strip() for item in addresses.split(',') if item.strip()] + if param.get("description"): + group_resp["description"] = param["description"] + if param.get("ip_categories"): + ip_categories = param["ip_categories"] + group_resp["ip_categories"] = [item.strip() for item in ip_categories.split(',') if item.strip()] + if param.get("countries"): + countries = param["countries"] + group_resp["countries"] = [item.strip() for item in countries.split(',') if item.strip()] + group_resp["isNonEditable"] = param["is_non_editable"] + + ret_val, response = self._make_rest_call_helper(f'/api/v1/ipDestinationGroups/{group_id}', action_result, data=group_resp, method='put') + if phantom.is_fail(ret_val): + return action_result.get_status() + + action_result.add_data(response) + summary = action_result.update_summary({}) + summary['message'] = "Destination IP edited" + + return action_result.set_status(phantom.APP_SUCCESS) + + def _handle_delete_destination_group(self, param): + """ + This action is used to delete IP Destination Groups + :param ip_group_ids: Ids of destination group to delete + :return: status phantom.APP_ERROR/phantom.APP_SUCCESS(along with appropriate message) + """ + self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) + action_result = self.add_action_result(ActionResult(dict(param))) + + group_ids = param.get("ip_group_ids", "") + list_group_ids = [item.strip() for item in group_ids.split(',') if item.strip()] + + for group_id in list_group_ids: + ret_val, response = self._make_rest_call_helper(f'/api/v1/ipDestinationGroups/{group_id}', action_result, method='delete') + if phantom.is_fail(ret_val): + return action_result.get_status() + action_result.add_data({"ip_group_id": group_id}) + + summary = action_result.update_summary({}) + summary['message'] = "Destination groups deleted" + return action_result.set_status(phantom.APP_SUCCESS) + def handle_action(self, param): ret_val = phantom.APP_SUCCESS @@ -1088,6 +1272,15 @@ def handle_action(self, param): elif action_id == 'create_destination_group': ret_val = self._handle_create_destination_group(param) + elif action_id == 'list_destination_group': + ret_val = self._handle_list_destination_group(param) + + elif action_id == 'edit_destination_group': + ret_val = self._handle_edit_destination_group(param) + + elif action_id == 'delete_destination_group': + ret_val = self._handle_delete_destination_group(param) + return ret_val def initialize(self): From 2de414809a155b6c516b45cac00fd50f516addd7 Mon Sep 17 00:00:00 2001 From: splunk-soar-connectors-admin Date: Tue, 6 Aug 2024 19:03:59 +0000 Subject: [PATCH 06/16] Update README.md --- README.md | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8bdb88e..9506fe8 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,8 @@ VARIABLE | REQUIRED | TYPE | DESCRIPTION [remove group user](#action-remove-group-user) - Remove user from group [create destination group](#action-create-destination-group) - Create destination group [list destination group](#action-list-destination-group) - List destination group +[edit destination group](#action-edit-destination-group) - Edit destination group +[delete destination group](#action-delete-destination-group) - Delete destination group ## action: 'test connectivity' Validate the asset configuration for connectivity using supplied configuration @@ -771,6 +773,7 @@ DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES action_result.status | string | | test success test failed action_result.parameter.countries | string | | action_result.parameter.ip_categories | string | | +action_result.parameter.description | string | | action_result.parameter.addresses | string | | action_result.parameter.type | string | | action_result.parameter.name | string | | @@ -797,9 +800,9 @@ Read only: **False** #### Action Parameters PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS --------- | -------- | ----------- | ---- | -------- -**ip_group_id** | optional | A comma-separated list of unique identifiers for the IP destination groups | string | +**ip_group_ids** | optional | A comma-separated list of unique identifiers for the IP destination groups | string | **exclude_type** | optional | The IP group type to be excluded from the results | string | -**category_type** | optional | The IP group type to be filtered from results. This argument is only supported when the 'lite' argument is set to True | string | +**category_type** | optional | Comma seperated list of IP group types to be filtered from results. This argument is only supported when the 'lite' argument is set to True | string | **include_ipv6** | optional | Retrieve IPv6 destination groups | boolean | **limit** | optional | Limit of the results to be retrieved | numeric | **all_results** | optional | Whether to retrieve all results at once | boolean | @@ -828,4 +831,71 @@ action_result.summary.message | string | | Retreived Destination Groups action_result.message | string | | Retreived Destination Groups summary.message | string | | summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 + +## action: 'edit destination group' +Edit destination group + +Type: **generic** +Read only: **False** + +#### Action Parameters +PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS +--------- | -------- | ----------- | ---- | -------- +**ip_group_id** | required | The unique identifier for the IP destination group | numeric | +**name** | optional | Destination IP group name | string | +**addresses** | optional | Comma seperated string of destination IP addresses, FQDNs, or wildcard FQDNs added to the group | string | +**description** | optional | Additional information about the destination IP group. | string | +**ip_categories** | optional | Destination IP address URL categories | string | +**countries** | optional | Destination IP address countries. You can identify destinations based on the location of a server. | string | +**is_non_editable** | optional | 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 | boolean | + +#### Action Output +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | test success test failed +action_result.parameter.is_non_editable | boolean | | +action_result.parameter.countries | string | | +action_result.parameter.ip_categories | string | | +action_result.parameter.description | string | | +action_result.parameter.addresses | string | | +action_result.parameter.name | string | | +action_result.parameter.ip_group_id | numeric | | +action_result.data.\*.id | numeric | | +action_result.data.\*.name | string | | +action_result.data.\*.type | string | | DSTN_IP DSTN_FQDN DSTN_DOMAIN DSTN_OTHER +action_result.data.\*.addresses | string | | 192.168.1.1 +action_result.data.\*.countries | string | | +action_result.data.\*.description | string | | +action_result.data.\*.ipCategories | string | | TRADING_BROKARAGE_INSURANCE +action_result.data.\*.creatorContext | string | | +action_result.summary | string | | +action_result.summary.message | string | | test User removed from group +action_result.message | string | | test User removed from group +summary.message | string | | +summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 + +## action: 'delete destination group' +Delete destination group + +Type: **generic** +Read only: **False** + +#### Action Parameters +PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS +--------- | -------- | ----------- | ---- | -------- +**ip_group_ids** | optional | A comma-separated list of unique identifiers for the IP destination groups | string | + +#### Action Output +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | test success test failed +action_result.parameter.ip_group_ids | string | | +action_result.data.\*.ip_group_ids | string | | +action_result.summary | string | | +action_result.summary.message | string | | test User removed from group +action_result.message | string | | test User removed from group +summary.message | string | | +summary.total_objects | numeric | | 1 summary.total_objects_successful | numeric | | 1 \ No newline at end of file From abe77a1387342e72f8406c7745c425addf961e2d Mon Sep 17 00:00:00 2001 From: Tapish Jain Date: Wed, 7 Aug 2024 09:29:55 -0700 Subject: [PATCH 07/16] PAPP-34460: categories work --- zscaler.json | 143 +++++++++++++++++++++++++++++++++++++++++++ zscaler_connector.py | 36 +++++++++++ 2 files changed, 179 insertions(+) diff --git a/zscaler.json b/zscaler.json index 5ed9741..4e234ef 100644 --- a/zscaler.json +++ b/zscaler.json @@ -3000,6 +3000,149 @@ "type": "table" }, "versions": "EQ(*)" + }, + { + "action": "add category url", + "description": "Add urls to a cetgory", + "type": "generic", + "identifier": "add_category_url", + "read_only": false, + "parameters": { + "category_id": { + "description": "The ID of the category to add the specified URLs to", + "data_type": "string", + "order": 0, + "example_values": [ + "RADIO_STATIONS" + ], + "primary": true, + "required": true + }, + "urls": { + "description": "A comma-separated list of URLs to add to the specified category", + "data_type": "string", + "order": 1, + "primary": true + }, + "retaining-parent-category-url": { + "description": "A comma-separated list of URLs to add to the retaining parent category section inside the specified category", + "data_type": "string", + "primary": true, + "order": 2 + } + }, + "output": [ + { + "data_path": "action_result.status", + "data_type": "string", + "example_values": [ + "success", + "failed" + ] + }, + { + "data_path": "action_result.parameter.category_id", + "data_type": "string", + "example_values": [ + "RADIO_STATIONS" + ] + }, + { + "data_path": "action_result.parameter.urls", + "data_type": "string" + }, + { + "data_path": "action_result.parameter.retaining-parent-category-url", + "data_type": "string" + }, + { + "data_path": "action_result.message", + "data_type": "string", + "example_values": [ + "Total messages returned: 1" + ] + }, + { + "data_path": "summary.total_objects", + "data_type": "numeric", + "example_values": [ + 1 + ] + }, + { + "data_path": "summary.total_objects_successful", + "data_type": "numeric", + "example_values": [ + 1 + ] + } + ], + "render": { + "type": "table" + }, + "versions": "EQ(*)" + }, + { + "action": "get categories", + "description": "Retrieve categories", + "type": "investigative", + "identifier": "get_categories", + "read_only": false, + "parameters": { + "get_ids_and_names_only": { + "description": "Whether to retrieve only a list containing URL category IDs and names. Even if displayURL is set to true, URLs will not be returned", + "data_type": "boolean", + "order": 0, + "default": false, + "example_values": [ + true, + false + ], + "primary": true + } + }, + "output": [ + { + "data_path": "action_result.status", + "data_type": "string", + "example_values": [ + "success", + "failed" + ] + }, + { + "data_path": "action_result.parameter.get_ids_and_names_only", + "data_type": "string", + "example_values": [ + "RADIO_STATIONS" + ] + }, + { + "data_path": "action_result.message", + "data_type": "string", + "example_values": [ + "Total messages returned: 1" + ] + }, + { + "data_path": "summary.total_objects", + "data_type": "numeric", + "example_values": [ + 1 + ] + }, + { + "data_path": "summary.total_objects_successful", + "data_type": "numeric", + "example_values": [ + 1 + ] + } + ], + "render": { + "type": "table" + }, + "versions": "EQ(*)" } ], "pip_dependencies": { diff --git a/zscaler_connector.py b/zscaler_connector.py index dd0686c..675d162 100644 --- a/zscaler_connector.py +++ b/zscaler_connector.py @@ -989,6 +989,36 @@ def _handle_remove_group_user(self, param): summary['message'] = "User removed from group" return action_result.set_status(phantom.APP_SUCCESS) + + def _get_category_details(self, id, action_result): + ret_val, response = self._make_rest_call_helper(f'/api/v1/urlCategories/{id}', action_result) + if phantom.is_fail(ret_val): + return action_result.get_status(), None + return phantom.APP_SUCCESS, response + + def _handle_add_category_url(self, param): + self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) + action_result = self.add_action_result(ActionResult(dict(param))) + category_id = param["category_id"] + + ret_val, category_details = self._get_category_details(category_id, action_result) + if phantom.is_fail(ret_val): + return action_result.get_status() + + configuredName = category_details["configuredName"] + urls = param["urls"] + urls_list = [item.strip() for item in urls.split(',') if item.strip()] + retaining_parent_category_url = param["retaining-parent-category-url"] + parent_urls = [item.strip() for item in retaining_parent_category_url.split(',') if item.strip()] + data = {} + data["configuredName"] = configuredName + data["urls"] = urls_list + #do get_categories because custom categories need name so just pass name with every call + + def _handle_get_categories(self, param): + self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) + action_result = self.add_action_result(ActionResult(dict(param))) + get_ids_and_names_only = param["get_ids_and_names_only"] def handle_action(self, param): @@ -1055,6 +1085,12 @@ def handle_action(self, param): elif action_id == 'remove_group_user': ret_val = self._handle_remove_group_user(param) + + elif action_id == 'add_category_url': + ret_val = self._handle_add_category_url(param) + + elif action_id == 'get_categories': + ret_val = self._handle_get_categories(param) return ret_val From 166154a5736ed7cb27a92ef6fa3d188121e1efc9 Mon Sep 17 00:00:00 2001 From: splunk-soar-connectors-admin Date: Wed, 7 Aug 2024 16:30:39 +0000 Subject: [PATCH 08/16] Update README.md --- README.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/README.md b/README.md index e954575..ec4a31a 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,8 @@ VARIABLE | REQUIRED | TYPE | DESCRIPTION [get groups](#action-get-groups) - Gets a list of groups [add group user](#action-add-group-user) - Add user to group [remove group user](#action-remove-group-user) - Remove user from group +[add category url](#action-add-category-url) - Add urls to a cetgory +[get categories](#action-get-categories) - Retrieve categories ## action: 'test connectivity' Validate the asset configuration for connectivity using supplied configuration @@ -745,4 +747,48 @@ action_result.summary.message | string | | test User removed from group action_result.message | string | | test User removed from group summary.message | string | | summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 + +## action: 'add category url' +Add urls to a cetgory + +Type: **generic** +Read only: **False** + +#### Action Parameters +PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS +--------- | -------- | ----------- | ---- | -------- +**category_id** | required | The ID of the category to add the specified URLs to | string | +**urls** | optional | A comma-separated list of URLs to add to the specified category | string | +**retaining-parent-category-url** | optional | A comma-separated list of URLs to add to the retaining parent category section inside the specified category | string | + +#### Action Output +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | success failed +action_result.parameter.category_id | string | | RADIO_STATIONS +action_result.parameter.urls | string | | +action_result.parameter.retaining-parent-category-url | string | | +action_result.message | string | | Total messages returned: 1 +summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 + +## action: 'get categories' +Retrieve categories + +Type: **investigative** +Read only: **False** + +#### Action Parameters +PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS +--------- | -------- | ----------- | ---- | -------- +**get_ids_and_names_only** | optional | Whether to retrieve only a list containing URL category IDs and names. Even if displayURL is set to true, URLs will not be returned | boolean | + +#### Action Output +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | success failed +action_result.parameter.get_ids_and_names_only | string | | RADIO_STATIONS +action_result.message | string | | Total messages returned: 1 +summary.total_objects | numeric | | 1 summary.total_objects_successful | numeric | | 1 \ No newline at end of file From 6684e59677cd00d07eae0542c0eb6ddf8f624824 Mon Sep 17 00:00:00 2001 From: Tapish Jain Date: Wed, 7 Aug 2024 12:36:04 -0700 Subject: [PATCH 09/16] PAPP-34461: removing all_results parameter --- zscaler.json | 18 +----------------- zscaler_connector.py | 2 -- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/zscaler.json b/zscaler.json index 50bf19d..eee0c34 100644 --- a/zscaler.json +++ b/zscaler.json @@ -3230,16 +3230,6 @@ "default": 50, "order": 4 }, - "all_results": { - "description": "Whether to retrieve all results at once", - "data_type": "boolean", - "example_values": [ - true, - false - ], - "default": false, - "order": 5 - }, "lite": { "description": "Whether to retrieve only limited information of IP destination groups. Includes ID, name and type of the IP destination groups", "data_type": "boolean", @@ -3248,7 +3238,7 @@ false ], "default": false, - "order": 6 + "order": 5 } }, "output": [ @@ -3266,12 +3256,6 @@ "data_path": "action_result.parameter.lite", "data_type": "boolean", "column_name": "Lite", - "column_order": 6 - }, - { - "data_path": "action_result.parameter.all_reuslts", - "data_type": "boolean", - "column_name": "All Results", "column_order": 5 }, { diff --git a/zscaler_connector.py b/zscaler_connector.py index a495112..3e9e1ca 100644 --- a/zscaler_connector.py +++ b/zscaler_connector.py @@ -1080,7 +1080,6 @@ def _handle_list_destination_group(self, param): :param include_ipv6: Retrieve IPv6 groups :param limit: Number of groups to retrieve :param lite: Retrieve limited information for each group - :param all_results: :return: status phantom.APP_ERROR/phantom.APP_SUCCESS(along with appropriate message) """ self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) @@ -1093,7 +1092,6 @@ def _handle_list_destination_group(self, param): category_type_list = [item.strip() for item in category_type.split(',') if item.strip()] include_ipv6 = param.get("include_ipv6", False) limit = param.get("limit", 50) - # all_results = param.get("all_results", False) lite = param.get("lite", False) params = {} From b875ce5584b13038c4e1ded2314e918d9584aa3a Mon Sep 17 00:00:00 2001 From: splunk-soar-connectors-admin Date: Wed, 7 Aug 2024 19:37:19 +0000 Subject: [PATCH 10/16] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 9506fe8..5db35b3 100644 --- a/README.md +++ b/README.md @@ -805,7 +805,6 @@ PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS **category_type** | optional | Comma seperated list of IP group types to be filtered from results. This argument is only supported when the 'lite' argument is set to True | string | **include_ipv6** | optional | Retrieve IPv6 destination groups | boolean | **limit** | optional | Limit of the results to be retrieved | numeric | -**all_results** | optional | Whether to retrieve all results at once | boolean | **lite** | optional | Whether to retrieve only limited information of IP destination groups. Includes ID, name and type of the IP destination groups | boolean | #### Action Output @@ -813,7 +812,6 @@ DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES --------- | ---- | -------- | -------------- action_result.status | string | | test success test failed action_result.parameter.lite | boolean | | -action_result.parameter.all_reuslts | boolean | | action_result.parameter.limit | numeric | | action_result.parameter.include_ipv6 | boolean | | action_result.parameter.category_type | string | | From bfe732a51d91b53bc797c0ac0b6b28099fb710f8 Mon Sep 17 00:00:00 2001 From: Tapish Jain Date: Mon, 12 Aug 2024 09:19:20 -0700 Subject: [PATCH 11/16] PAPP-34460: category actions completed --- zscaler.json | 500 +++++++++++++++++++++++++++++++++++++++++-- zscaler_connector.py | 167 +++++++++++++-- 2 files changed, 635 insertions(+), 32 deletions(-) diff --git a/zscaler.json b/zscaler.json index 4e234ef..0abf6c9 100644 --- a/zscaler.json +++ b/zscaler.json @@ -316,7 +316,19 @@ "description": "List all URL categories", "type": "investigate", "read_only": true, - "parameters": {}, + "parameters": { + "get_ids_and_names_only": { + "description": "Whether to retrieve only a list containing URL category IDs and names. Even if displayURL is set to true, URLs will not be returned", + "data_type": "boolean", + "order": 0, + "default": false, + "example_values": [ + true, + false + ], + "primary": true + } + }, "output": [ { "data_path": "action_result.status", @@ -326,6 +338,13 @@ "test failed" ] }, + { + "data_path": "action_result.parameter.get_ids_and_names_only", + "data_type": "string", + "example_values": [ + "RADIO_STATIONS" + ] + }, { "data_path": "action_result.data.*.configuredName", "data_type": "string", @@ -3055,13 +3074,81 @@ "data_path": "action_result.parameter.retaining-parent-category-url", "data_type": "string" }, + { + "data_path": "action_result.data.*.id", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.val", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.type", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.urls", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.scopes.*.Type", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.editable", + "data_type": "boolean" + }, + { + "data_path": "action_result.data.*.keywords", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.description", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.configuredName", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.customCategory", + "data_type": "boolean" + }, + { + "data_path": "action_result.data.*.customUrlsCount", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.dbCategorizedUrls", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.customIpRangesCount", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.keywordsRetainingParentCategory", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.urlsRetainingParentCategoryCount", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.ipRangesRetainingParentCategoryCount", + "data_type": "numeric" + }, { "data_path": "action_result.message", "data_type": "string", "example_values": [ - "Total messages returned: 1" + "Message: Category urs updated" ] }, + { + "data_path": "action_result.summary", + "data_type": "string" + }, { "data_path": "summary.total_objects", "data_type": "numeric", @@ -3083,22 +3170,33 @@ "versions": "EQ(*)" }, { - "action": "get categories", - "description": "Retrieve categories", - "type": "investigative", - "identifier": "get_categories", + "action": "add category ip", + "description": "Add IPs to a cetgory", + "type": "generic", + "identifier": "add_category_ip", "read_only": false, "parameters": { - "get_ids_and_names_only": { - "description": "Whether to retrieve only a list containing URL category IDs and names. Even if displayURL is set to true, URLs will not be returned", - "data_type": "boolean", + "category_id": { + "description": "The ID of the category to add the specified URLs to", + "data_type": "string", "order": 0, - "default": false, "example_values": [ - true, - false + "RADIO_STATIONS" ], + "primary": true, + "required": true + }, + "ips": { + "description": "A comma-separated list of IP addresses to add to the specified category", + "data_type": "string", + "order": 1, "primary": true + }, + "retaining-parent-category-ip": { + "description": "A comma-separated list of IPs to add to the retaining parent category section inside the specified category", + "data_type": "string", + "primary": true, + "order": 2 } }, "output": [ @@ -3111,19 +3209,393 @@ ] }, { - "data_path": "action_result.parameter.get_ids_and_names_only", + "data_path": "action_result.parameter.category_id", + "data_type": "string", + "example_values": [ + "RADIO_STATIONS" + ] + }, + { + "data_path": "action_result.parameter.ips", + "data_type": "string" + }, + { + "data_path": "action_result.parameter.retaining-parent-category-ip", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.id", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.val", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.type", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.urls", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.scopes.*.Type", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.editable", + "data_type": "boolean" + }, + { + "data_path": "action_result.data.*.keywords", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.description", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.configuredName", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.customCategory", + "data_type": "boolean" + }, + { + "data_path": "action_result.data.*.customUrlsCount", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.dbCategorizedUrls", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.customIpRangesCount", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.keywordsRetainingParentCategory", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.urlsRetainingParentCategoryCount", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.ipRangesRetainingParentCategoryCount", + "data_type": "numeric" + }, + { + "data_path": "action_result.message", + "data_type": "string", + "example_values": [ + "Message: Category ips updated" + ] + }, + { + "data_path": "action_result.summary", + "data_type": "string" + }, + { + "data_path": "summary.total_objects", + "data_type": "numeric", + "example_values": [ + 1 + ] + }, + { + "data_path": "summary.total_objects_successful", + "data_type": "numeric", + "example_values": [ + 1 + ] + } + ], + "render": { + "type": "table" + }, + "versions": "EQ(*)" + }, + { + "action": "remove category url", + "description": "Add urls to a cetgory", + "type": "generic", + "identifier": "remove_category_url", + "read_only": false, + "parameters": { + "category_id": { + "description": "The ID of the category to add the specified URLs to", + "data_type": "string", + "order": 0, + "example_values": [ + "RADIO_STATIONS" + ], + "primary": true, + "required": true + }, + "urls": { + "description": "A comma-separated list of URLs to remove from the specified category", + "data_type": "string", + "order": 1, + "primary": true + }, + "retaining-parent-category-url": { + "description": "A comma-separated list of URLs to remove from the retaining parent category section inside the specified category", + "data_type": "string", + "primary": true, + "order": 2 + } + }, + "output": [ + { + "data_path": "action_result.status", + "data_type": "string", + "example_values": [ + "success", + "failed" + ] + }, + { + "data_path": "action_result.parameter.category_id", + "data_type": "string", + "example_values": [ + "RADIO_STATIONS" + ] + }, + { + "data_path": "action_result.parameter.urls", + "data_type": "string" + }, + { + "data_path": "action_result.parameter.retaining-parent-category-url", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.id", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.val", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.type", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.urls", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.scopes.*.Type", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.editable", + "data_type": "boolean" + }, + { + "data_path": "action_result.data.*.keywords", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.description", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.configuredName", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.customCategory", + "data_type": "boolean" + }, + { + "data_path": "action_result.data.*.customUrlsCount", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.dbCategorizedUrls", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.customIpRangesCount", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.keywordsRetainingParentCategory", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.urlsRetainingParentCategoryCount", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.ipRangesRetainingParentCategoryCount", + "data_type": "numeric" + }, + { + "data_path": "action_result.message", + "data_type": "string", + "example_values": [ + "Message: Category urls removed" + ] + }, + { + "data_path": "action_result.summary", + "data_type": "string" + }, + { + "data_path": "summary.total_objects", + "data_type": "numeric", + "example_values": [ + 1 + ] + }, + { + "data_path": "summary.total_objects_successful", + "data_type": "numeric", + "example_values": [ + 1 + ] + } + ], + "render": { + "type": "table" + }, + "versions": "EQ(*)" + }, + { + "action": "remove category ip", + "description": "Remove IPs to a cetgory", + "type": "generic", + "identifier": "remove_category_ip", + "read_only": false, + "parameters": { + "category_id": { + "description": "The ID of the category to add the specified URLs to", + "data_type": "string", + "order": 0, + "example_values": [ + "RADIO_STATIONS" + ], + "primary": true, + "required": true + }, + "ips": { + "description": "A comma-separated list of IP addresses to add to the specified category", + "data_type": "string", + "order": 1, + "primary": true + }, + "retaining-parent-category-ip": { + "description": "A comma-separated list of IPs to add to the retaining parent category section inside the specified category", + "data_type": "string", + "primary": true, + "order": 2 + } + }, + "output": [ + { + "data_path": "action_result.status", + "data_type": "string", + "example_values": [ + "success", + "failed" + ] + }, + { + "data_path": "action_result.parameter.category_id", "data_type": "string", "example_values": [ "RADIO_STATIONS" ] }, + { + "data_path": "action_result.parameter.ips", + "data_type": "string" + }, + { + "data_path": "action_result.parameter.retaining-parent-category-ip", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.id", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.val", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.type", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.urls", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.scopes.*.Type", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.editable", + "data_type": "boolean" + }, + { + "data_path": "action_result.data.*.keywords", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.description", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.configuredName", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.customCategory", + "data_type": "boolean" + }, + { + "data_path": "action_result.data.*.customUrlsCount", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.dbCategorizedUrls", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.customIpRangesCount", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.keywordsRetainingParentCategory", + "data_type": "string" + }, + { + "data_path": "action_result.data.*.urlsRetainingParentCategoryCount", + "data_type": "numeric" + }, + { + "data_path": "action_result.data.*.ipRangesRetainingParentCategoryCount", + "data_type": "numeric" + }, { "data_path": "action_result.message", "data_type": "string", "example_values": [ - "Total messages returned: 1" + "Message: Category ips removed" ] }, + { + "data_path": "action_result.summary", + "data_type": "string" + }, { "data_path": "summary.total_objects", "data_type": "numeric", diff --git a/zscaler_connector.py b/zscaler_connector.py index 675d162..24106e7 100644 --- a/zscaler_connector.py +++ b/zscaler_connector.py @@ -739,8 +739,17 @@ def _handle_list_url_categories(self, param): if phantom.is_fail(ret_val): return action_result.get_status() + get_ids_and_names_only = param["get_ids_and_names_only"] + for url_category in list_url_categories: - action_result.add_data(url_category) + if get_ids_and_names_only: + category_lite = {} + category_lite["id"] = url_category["id"] + if "configuredName" in url_category: + category_lite["configuredName"] = url_category["configuredName"] + action_result.add_data(category_lite) + else: + action_result.add_data(url_category) summary = action_result.update_summary({}) summary['total_url_categories'] = action_result.get_data_size() @@ -989,36 +998,152 @@ def _handle_remove_group_user(self, param): summary['message'] = "User removed from group" return action_result.set_status(phantom.APP_SUCCESS) - + def _get_category_details(self, id, action_result): ret_val, response = self._make_rest_call_helper(f'/api/v1/urlCategories/{id}', action_result) if phantom.is_fail(ret_val): return action_result.get_status(), None return phantom.APP_SUCCESS, response + def _add_to_category(self, data, parent_data, category_details, category_id, action_result): + new_data = category_details.get("urls", []) + new_data.extend(data) + if new_data: + category_details["urls"] = new_data + self.debug_print("add_to_category new data {0}".format(category_details["urls"])) + + new_parent_data = category_details.get("dbCategorizedUrls", []) + new_parent_data.extend(parent_data) + if new_parent_data: + category_details["dbCategorizedUrls"] = new_parent_data + self.debug_print("add_to_category new parent data {0}".format(category_details["dbCategorizedUrls"])) + + ret_val, response = self._make_rest_call_helper(f'/api/v1/urlCategories/{category_id}', action_result, data=category_details, method='put') + return ret_val, response + def _handle_add_category_url(self, param): self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) category_id = param["category_id"] - + ret_val, category_details = self._get_category_details(category_id, action_result) if phantom.is_fail(ret_val): return action_result.get_status() - - configuredName = category_details["configuredName"] - urls = param["urls"] + + is_custom_category = category_details.get("customCategory", False) + + if not is_custom_category: + action_result.set_status(phantom.APP_ERROR, "Category with {0} is a default category, which cannot be modified" + .format(category_id)) + return action_result.get_status() + + urls = param.get("urls", "") urls_list = [item.strip() for item in urls.split(',') if item.strip()] - retaining_parent_category_url = param["retaining-parent-category-url"] + retaining_parent_category_url = param.get("retaining-parent-category-url", "") parent_urls = [item.strip() for item in retaining_parent_category_url.split(',') if item.strip()] - data = {} - data["configuredName"] = configuredName - data["urls"] = urls_list - #do get_categories because custom categories need name so just pass name with every call - - def _handle_get_categories(self, param): + ret_val, response = self._add_to_category(urls_list, parent_urls, category_details, category_id, action_result) + + if phantom.is_fail(ret_val): + return action_result.get_status() + + action_result.add_data(response) + summary = action_result.update_summary({}) + summary['message'] = "Category urls updated" + + return action_result.set_status(phantom.APP_SUCCESS) + + def _handle_add_category_ips(self, param): self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) - get_ids_and_names_only = param["get_ids_and_names_only"] + category_id = param["category_id"] + + ret_val, category_details = self._get_category_details(category_id, action_result) + if phantom.is_fail(ret_val): + return action_result.get_status() + + ips = param.get("ips", "") + ips_list = [item.strip() for item in ips.split(',') if item.strip()] + retaining_parent_category_ip = param.get("retaining-parent-category-ip", "") + parent_ips = [item.strip() for item in retaining_parent_category_ip.split(',') if item.strip()] + ret_val, response = self._add_to_category(ips_list, parent_ips, category_details, category_id, action_result) + + if phantom.is_fail(ret_val): + return action_result.get_status() + + action_result.add_data(response) + summary = action_result.update_summary({}) + summary['message'] = "Category ips updated" + + return action_result.set_status(phantom.APP_SUCCESS) + + def _remove_from_category(self, data, parent_data, category_details, category_id, action_result): + data_set = set(data) + new_data = [] + for point in category_details.get("urls", []): + if point not in data_set: + new_data.append(point) + + parent_data_set = set(parent_data) + new_parent_data = [] + for point in category_details.get("dbCategorizedUrls", []): + if point not in parent_data_set: + new_parent_data.append(point) + + category_details["urls"] = new_data + category_details["dbCategorizedUrls"] = new_parent_data + + ret_val, response = self._make_rest_call_helper(f'/api/v1/urlCategories/{category_id}', action_result, data=category_details, method='put') + return ret_val, response + + def _handle_remove_category_urls(self, param): + self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) + action_result = self.add_action_result(ActionResult(dict(param))) + category_id = param["category_id"] + + ret_val, category_details = self._get_category_details(category_id, action_result) + if phantom.is_fail(ret_val): + return action_result.get_status() + + urls = param.get("urls", "") + urls_to_remove = [item.strip() for item in urls.split(',') if item.strip()] + retaining_parent_category_url = param.get("retaining-parent-category-url", "") + parent_urls_to_remove = [item.strip() for item in retaining_parent_category_url.split(',') if item.strip()] + + ret_val, response = self._remove_from_category(urls_to_remove, parent_urls_to_remove, category_details, category_id, action_result) + + if phantom.is_fail(ret_val): + return action_result.get_status() + + action_result.add_data(response) + summary = action_result.update_summary({}) + summary['message'] = "Category urls removed" + + return action_result.set_status(phantom.APP_SUCCESS) + + def _handle_remove_category_ips(self, param): + self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) + action_result = self.add_action_result(ActionResult(dict(param))) + category_id = param["category_id"] + + ret_val, category_details = self._get_category_details(category_id, action_result) + if phantom.is_fail(ret_val): + return action_result.get_status() + + ips = param.get("ips", "") + ips_to_remove = [item.strip() for item in ips.split(',') if item.strip()] + retaining_parent_category_ips = param.get("retaining-parent-category-ip", "") + parent_ips_to_remove = [item.strip() for item in retaining_parent_category_ips.split(',') if item.strip()] + + ret_val, response = self._remove_from_category(ips_to_remove, parent_ips_to_remove, category_details, category_id, action_result) + + if phantom.is_fail(ret_val): + return action_result.get_status() + + action_result.add_data(response) + summary = action_result.update_summary({}) + summary['message'] = "Category ips removed" + + return action_result.set_status(phantom.APP_SUCCESS) def handle_action(self, param): @@ -1085,12 +1210,18 @@ def handle_action(self, param): elif action_id == 'remove_group_user': ret_val = self._handle_remove_group_user(param) - + elif action_id == 'add_category_url': ret_val = self._handle_add_category_url(param) - - elif action_id == 'get_categories': - ret_val = self._handle_get_categories(param) + + elif action_id == 'add_category_ip': + ret_val = self._handle_add_category_ips(param) + + elif action_id == 'remove_category_url': + ret_val = self._handle_remove_category_urls(param) + + elif action_id == 'remove_category_ip': + ret_val = self._handle_remove_category_ips(param) return ret_val From f261c81ddfad4b30464f8718cb6c3d4de4de1ed8 Mon Sep 17 00:00:00 2001 From: splunk-soar-connectors-admin Date: Mon, 12 Aug 2024 16:20:11 +0000 Subject: [PATCH 12/16] Update README.md --- README.md | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 134 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ec4a31a..66d068c 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,9 @@ VARIABLE | REQUIRED | TYPE | DESCRIPTION [add group user](#action-add-group-user) - Add user to group [remove group user](#action-remove-group-user) - Remove user from group [add category url](#action-add-category-url) - Add urls to a cetgory -[get categories](#action-get-categories) - Retrieve categories +[add category ip](#action-add-category-ip) - Add IPs to a cetgory +[remove category url](#action-remove-category-url) - Add urls to a cetgory +[remove category ip](#action-remove-category-ip) - Remove IPs to a cetgory ## action: 'test connectivity' Validate the asset configuration for connectivity using supplied configuration @@ -187,12 +189,15 @@ Type: **investigate** Read only: **True** #### Action Parameters -No parameters are required for this action +PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS +--------- | -------- | ----------- | ---- | -------- +**get_ids_and_names_only** | optional | Whether to retrieve only a list containing URL category IDs and names. Even if displayURL is set to true, URLs will not be returned | boolean | #### Action Output DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES --------- | ---- | -------- | -------------- action_result.status | string | | test success test failed +action_result.parameter.get_ids_and_names_only | string | | RADIO_STATIONS action_result.data.\*.configuredName | string | | test Test-Caution action_result.data.\*.customCategory | boolean | | True False action_result.data.\*.customIpRangesCount | numeric | | 0 @@ -769,26 +774,146 @@ action_result.status | string | | success failed action_result.parameter.category_id | string | | RADIO_STATIONS action_result.parameter.urls | string | | action_result.parameter.retaining-parent-category-url | string | | -action_result.message | string | | Total messages returned: 1 +action_result.data.\*.id | string | | +action_result.data.\*.val | numeric | | +action_result.data.\*.type | string | | +action_result.data.\*.urls | string | | +action_result.data.\*.scopes.\*.Type | string | | +action_result.data.\*.editable | boolean | | +action_result.data.\*.keywords | string | | +action_result.data.\*.description | string | | +action_result.data.\*.configuredName | string | | +action_result.data.\*.customCategory | boolean | | +action_result.data.\*.customUrlsCount | numeric | | +action_result.data.\*.dbCategorizedUrls | string | | +action_result.data.\*.customIpRangesCount | numeric | | +action_result.data.\*.keywordsRetainingParentCategory | string | | +action_result.data.\*.urlsRetainingParentCategoryCount | numeric | | +action_result.data.\*.ipRangesRetainingParentCategoryCount | numeric | | +action_result.message | string | | Message: Category urs updated +action_result.summary | string | | summary.total_objects | numeric | | 1 summary.total_objects_successful | numeric | | 1 -## action: 'get categories' -Retrieve categories +## action: 'add category ip' +Add IPs to a cetgory -Type: **investigative** +Type: **generic** Read only: **False** #### Action Parameters PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS --------- | -------- | ----------- | ---- | -------- -**get_ids_and_names_only** | optional | Whether to retrieve only a list containing URL category IDs and names. Even if displayURL is set to true, URLs will not be returned | boolean | +**category_id** | required | The ID of the category to add the specified URLs to | string | +**ips** | optional | A comma-separated list of IP addresses to add to the specified category | string | +**retaining-parent-category-ip** | optional | A comma-separated list of IPs to add to the retaining parent category section inside the specified category | string | #### Action Output DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES --------- | ---- | -------- | -------------- action_result.status | string | | success failed -action_result.parameter.get_ids_and_names_only | string | | RADIO_STATIONS -action_result.message | string | | Total messages returned: 1 +action_result.parameter.category_id | string | | RADIO_STATIONS +action_result.parameter.ips | string | | +action_result.parameter.retaining-parent-category-ip | string | | +action_result.data.\*.id | string | | +action_result.data.\*.val | numeric | | +action_result.data.\*.type | string | | +action_result.data.\*.urls | string | | +action_result.data.\*.scopes.\*.Type | string | | +action_result.data.\*.editable | boolean | | +action_result.data.\*.keywords | string | | +action_result.data.\*.description | string | | +action_result.data.\*.configuredName | string | | +action_result.data.\*.customCategory | boolean | | +action_result.data.\*.customUrlsCount | numeric | | +action_result.data.\*.dbCategorizedUrls | string | | +action_result.data.\*.customIpRangesCount | numeric | | +action_result.data.\*.keywordsRetainingParentCategory | string | | +action_result.data.\*.urlsRetainingParentCategoryCount | numeric | | +action_result.data.\*.ipRangesRetainingParentCategoryCount | numeric | | +action_result.message | string | | Message: Category ips updated +action_result.summary | string | | +summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 + +## action: 'remove category url' +Add urls to a cetgory + +Type: **generic** +Read only: **False** + +#### Action Parameters +PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS +--------- | -------- | ----------- | ---- | -------- +**category_id** | required | The ID of the category to add the specified URLs to | string | +**urls** | optional | A comma-separated list of URLs to remove from the specified category | string | +**retaining-parent-category-url** | optional | A comma-separated list of URLs to remove from the retaining parent category section inside the specified category | string | + +#### Action Output +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | success failed +action_result.parameter.category_id | string | | RADIO_STATIONS +action_result.parameter.urls | string | | +action_result.parameter.retaining-parent-category-url | string | | +action_result.data.\*.id | string | | +action_result.data.\*.val | numeric | | +action_result.data.\*.type | string | | +action_result.data.\*.urls | string | | +action_result.data.\*.scopes.\*.Type | string | | +action_result.data.\*.editable | boolean | | +action_result.data.\*.keywords | string | | +action_result.data.\*.description | string | | +action_result.data.\*.configuredName | string | | +action_result.data.\*.customCategory | boolean | | +action_result.data.\*.customUrlsCount | numeric | | +action_result.data.\*.dbCategorizedUrls | string | | +action_result.data.\*.customIpRangesCount | numeric | | +action_result.data.\*.keywordsRetainingParentCategory | string | | +action_result.data.\*.urlsRetainingParentCategoryCount | numeric | | +action_result.data.\*.ipRangesRetainingParentCategoryCount | numeric | | +action_result.message | string | | Message: Category urls removed +action_result.summary | string | | +summary.total_objects | numeric | | 1 +summary.total_objects_successful | numeric | | 1 + +## action: 'remove category ip' +Remove IPs to a cetgory + +Type: **generic** +Read only: **False** + +#### Action Parameters +PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS +--------- | -------- | ----------- | ---- | -------- +**category_id** | required | The ID of the category to add the specified URLs to | string | +**ips** | optional | A comma-separated list of IP addresses to add to the specified category | string | +**retaining-parent-category-ip** | optional | A comma-separated list of IPs to add to the retaining parent category section inside the specified category | string | + +#### Action Output +DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES +--------- | ---- | -------- | -------------- +action_result.status | string | | success failed +action_result.parameter.category_id | string | | RADIO_STATIONS +action_result.parameter.ips | string | | +action_result.parameter.retaining-parent-category-ip | string | | +action_result.data.\*.id | string | | +action_result.data.\*.val | numeric | | +action_result.data.\*.type | string | | +action_result.data.\*.urls | string | | +action_result.data.\*.scopes.\*.Type | string | | +action_result.data.\*.editable | boolean | | +action_result.data.\*.keywords | string | | +action_result.data.\*.description | string | | +action_result.data.\*.configuredName | string | | +action_result.data.\*.customCategory | boolean | | +action_result.data.\*.customUrlsCount | numeric | | +action_result.data.\*.dbCategorizedUrls | string | | +action_result.data.\*.customIpRangesCount | numeric | | +action_result.data.\*.keywordsRetainingParentCategory | string | | +action_result.data.\*.urlsRetainingParentCategoryCount | numeric | | +action_result.data.\*.ipRangesRetainingParentCategoryCount | numeric | | +action_result.message | string | | Message: Category ips removed +action_result.summary | string | | summary.total_objects | numeric | | 1 summary.total_objects_successful | numeric | | 1 \ No newline at end of file From d85615dc8455354dbc930be96e3e430a3869349e Mon Sep 17 00:00:00 2001 From: splunk-soar-connectors-admin Date: Mon, 12 Aug 2024 16:44:08 +0000 Subject: [PATCH 13/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9569872..26b8ed7 100644 --- a/README.md +++ b/README.md @@ -920,7 +920,7 @@ action_result.data.\*.ipRangesRetainingParentCategoryCount | numeric | | action_result.message | string | | Message: Category ips removed action_result.summary | string | | summary.total_objects | numeric | | 1 -summary.total_objects_successful | numeric | | 1 +summary.total_objects_successful | numeric | | 1 ## action: 'create destination group' Create destination group From 6b62c2f5c638a750064dc6c7ac8a364ac6fa706c Mon Sep 17 00:00:00 2001 From: Tapish Jain Date: Mon, 12 Aug 2024 11:21:15 -0700 Subject: [PATCH 14/16] PAPP-34457: param change --- zscaler_connector.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/zscaler_connector.py b/zscaler_connector.py index 6cac669..d8de1d7 100644 --- a/zscaler_connector.py +++ b/zscaler_connector.py @@ -1010,13 +1010,11 @@ def _add_to_category(self, data, parent_data, category_details, category_id, act new_data.extend(data) if new_data: category_details["urls"] = new_data - self.debug_print("add_to_category new data {0}".format(category_details["urls"])) new_parent_data = category_details.get("dbCategorizedUrls", []) new_parent_data.extend(parent_data) if new_parent_data: category_details["dbCategorizedUrls"] = new_parent_data - self.debug_print("add_to_category new parent data {0}".format(category_details["dbCategorizedUrls"])) ret_val, response = self._make_rest_call_helper(f'/api/v1/urlCategories/{category_id}', action_result, data=category_details, method='put') return ret_val, response @@ -1075,7 +1073,7 @@ def _handle_add_category_ips(self, param): summary['message'] = "Category ips updated" return action_result.set_status(phantom.APP_SUCCESS) - + def _handle_remove_category_ips(self, param): self.save_progress("In action handler for: {0}".format(self.get_action_identifier())) action_result = self.add_action_result(ActionResult(dict(param))) @@ -1135,7 +1133,7 @@ def _handle_remove_category_urls(self, param): parent_urls_to_remove = [item.strip() for item in retaining_parent_category_url.split(',') if item.strip()] ret_val, response = self._remove_from_category(urls_to_remove, parent_urls_to_remove, category_details, category_id, action_result) - + if phantom.is_fail(ret_val): return action_result.get_status() @@ -1143,6 +1141,8 @@ def _handle_remove_category_urls(self, param): summary = action_result.update_summary({}) summary['message'] = "Category urls removed" + return action_result.set_status(phantom.APP_SUCCESS) + def _handle_create_destination_group(self, param): """ This action is used to create an IP Destination Group @@ -1168,7 +1168,7 @@ def _handle_create_destination_group(self, param): data["addresses"] = [item.strip() for item in addresses.split(',')] data["description"] = param.get("description", "") if ip_categories: - data["ip_categories"] = [item.strip() for item in ip_categories.split(',')] + data["ipCategories"] = [item.strip() for item in ip_categories.split(',')] if countries: data["countries"] = [item.strip() for item in countries.split(',')] @@ -1310,16 +1310,16 @@ def _handle_edit_destination_group(self, param): if param.get("name"): group_resp["name"] = param["name"] if param.get('addresses'): - addresses = param["addresses"] - group_resp["addresses"] = [item.strip() for item in addresses.split(',') if item.strip()] + new_addresses = [item.strip() for item in param["addresses"].split(',') if item.strip()] + group_resp["addresses"] = new_addresses if param.get("description"): group_resp["description"] = param["description"] if param.get("ip_categories"): - ip_categories = param["ip_categories"] - group_resp["ip_categories"] = [item.strip() for item in ip_categories.split(',') if item.strip()] + new_ip_categories = [item.strip() for item in param["ip_categories"].split(',') if item.strip()] + group_resp["ipCategories"] = new_ip_categories if param.get("countries"): - countries = param["countries"] - group_resp["countries"] = [item.strip() for item in countries.split(',') if item.strip()] + new_countries = [item.strip() for item in param["countries"].split(',') if item.strip()] + group_resp["countries"] = new_countries group_resp["isNonEditable"] = param["is_non_editable"] ret_val, response = self._make_rest_call_helper(f'/api/v1/ipDestinationGroups/{group_id}', action_result, data=group_resp, method='put') From 741403e43e3bf1af569e74e98638292b72c6039a Mon Sep 17 00:00:00 2001 From: splunk-soar-connectors-admin Date: Mon, 12 Aug 2024 18:35:13 +0000 Subject: [PATCH 15/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f53d1f..63491f0 100644 --- a/README.md +++ b/README.md @@ -792,7 +792,7 @@ action_result.summary.message | string | | test User removed from group action_result.message | string | | test User removed from group summary.message | string | | summary.total_objects | numeric | | 1 -summary.total_objects_successful | numeric | | 1 +summary.total_objects_successful | numeric | | 1 ## action: 'add category url' Add urls to a cetgory From 6dd48ece34499fc2071af6370bd17950f5067a8a Mon Sep 17 00:00:00 2001 From: Tapish Jain Date: Mon, 12 Aug 2024 11:40:22 -0700 Subject: [PATCH 16/16] PAPP-34457: liniting changes --- zscaler_connector.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zscaler_connector.py b/zscaler_connector.py index 967793b..87a7dba 100644 --- a/zscaler_connector.py +++ b/zscaler_connector.py @@ -1013,10 +1013,10 @@ def _handle_update_user(self, param): ) ret_val, response = self._make_rest_call_helper(f'/api/v1/users/{user_id}', action_result, data=data, method='put') - + if phantom.is_fail(ret_val): return action_result.get_status() - + self.debug_print(response) action_result.add_data(response) summary = action_result.update_summary({}) @@ -1446,7 +1446,7 @@ def handle_action(self, param): elif action_id == "update_user": ret_val = self._handle_update_user(param) - + elif action_id == 'add_category_url': ret_val = self._handle_add_category_url(param)