CiscoWSAv2

Cisco Secure Web Appliance protects your organization by automatically blocking risky sites and testing unknown sites before allowing users to click on them.

Network Security · Cisco WSA

Details

IDCiscoWSAv2
ProviderCisco Systems
CategoryNetwork Security
From Version6.2.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

Cisco Secure Web Appliance protects your organization by automatically blocking risky sites and testing unknown sites before allowing users to click on them.
This integration was integrated and tested with version 14.0.3-014 of Cisco WSA V2

Some changes have been made that might affect your existing content.
If you are upgrading from a previous version of this integration, see Breaking Changes.

Configure Cisco WSA V2 in Cortex

Parameter Required
Server URL True
Username True
Password True
Use system proxy settings False
Trust any certificate (not secure) False

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

cisco-wsa-access-policy-list


Retrieve access policies.
Access policies contain allowed/blocked URL categories in the network.

Base Command

cisco-wsa-access-policy-list

Input

Argument Name Description Required
policy_names Policy names to retrieve. Optional
page The page number of the results to retrieve.
Minimum value is 1.
Optional
page_size The number of results per page. The maximum value is 100. Optional
limit The maximum number of records to retrieve. Default is 50. Optional

Context Output

Path Type Description
CiscoWSA.AccessPolicy.policy_expiry String Policy expiry date.
CiscoWSA.AccessPolicy.policy_status String Policy status.
CiscoWSA.AccessPolicy.policy_name String Policy name.
CiscoWSA.AccessPolicy.policy_description String Policy description.
CiscoWSA.AccessPolicy.membership Unknown Identification Profiles info.
CiscoWSA.AccessPolicy.objects Unknown Policy custom objects blocking settings.
CiscoWSA.AccessPolicy.protocols_user_agents Unknown Policy protocols and user agents settings.
CiscoWSA.AccessPolicy.http_rewrite_profile Unknown Policy HTTP rewrite profile settings.
CiscoWSA.AccessPolicy.avc Unknown Application visibility and control.
CiscoWSA.AccessPolicy.url_filtering Unknown URL filtering settings.
CiscoWSA.AccessPolicy.amw_reputation Unknown Anti-Malware and reputation settings.

Command example

!cisco-wsa-access-policy-list page=1 page_size=3

Context Example

{
    "CiscoWSA": {
        "AccessPolicy": {
            "amw_reputation": {
                "adv_malware_protection": {
                    "file_analysis": "enable",
                    "file_reputation": {
                        "monitor": [
                            "Known Malicious and High-Risk Files"
                        ]
                    },
                    "file_reputation_filtering": "enable"
                },
                "cisco_dvs_amw": {
                    "amw_scanning": {
                        "amw_scan_status": "enable"
                    },
                    "malware_categories": {
                        "monitor": [
                            "Trojan Phisher",
                            "Generic Spyware",
                            "Adware",
                            "Browser Helper Object",
                            "Hijacker",
                            "System Monitor",
                            "Trojan Downloader",
                            "Trojan Horse",
                            "Dialer",
                            "Commercial System Monitor",
                            "PUA",
                            "Other Malware",
                            "Virus",
                            "Worm",
                            "Phishing URL"
                        ]
                    },
                    "other_categories": {
                        "block": [
                            "Outbreak Heuristics"
                        ],
                        "monitor": [
                            "Encrypted File",
                            "Unscannable"
                        ]
                    },
                    "suspect_user_agent_scanning": "scan"
                },
                "web_reputation": {
                    "filtering": "enable"
                }
            },
            "avc": {
                "applications": {
                    "Blogging": {
                        "monitor": {
                            "BlogChina": {},
                            "Blogbus": {},
                            "Blogcom": {},
                            "Blogger": {},
                            "Blogster": {},
                            "Bokee": {},
                            "CNBlogs": {},
                            "DianDian": {},
                            "Disqus": {},
                            "Edublogs": {},
                            "FC2 Blog": {},
                            "HatenaBlog": {},
                            "LeiPhone": {},
                            "LiveJournal": {},
                            "LivedoorBlog": {},
                            "Lofter": {},
                            "Medium": {},
                            "Pen.io": {},
                            "SeesaaBlog": {},
                            "Tackk": {},
                            "Tumblr": {},
                            "Wordpress": {},
                            "Youdaonote": {}
                        }
                    },
                    "Collaboration": {
                        "monitor": {
                            "Answers.com": {},
                            "Baike": {},
                            "PBWorks": {},
                            "Pastebin": {},
                            "SogouBaike": {},
                            "Wikihow": {},
                            "Wikipedia": {},
                            "eHow": {}
                        }
                    },
                    "Enterprise Applications": {
                        "monitor": {
                            "Amazon S3": {},
                            "Concur": {},
                            "Microsoft Dynamics CRM": {},
                            "Salesforce": {},
                            "SharePoint": {},
                            "SugarCRM": {}
                        }
                    },
                    "Facebook": {
                        "default_bandwidth_limit": "",
                        "monitor": {
                            "Facebook Applications: Entertainment": {},
                            "Facebook Applications: Games": {},
                            "Facebook Applications: Other": {},
                            "Facebook Applications: Sports": {},
                            "Facebook Applications: Utilities": {},
                            "Facebook Events": {},
                            "Facebook General": {},
                            "Facebook Messages and Chat": {},
                            "Facebook Notes": {},
                            "Facebook Photos and Videos": {}
                        }
                    },
                    "File Sharing": {
                        "monitor": {
                            "115.com": {},
                            "4shared": {},
                            "ADrive": {},
                            "Amazon Cloud Drive": {},
                            "AxiFile": {},
                            "Baiduyun": {},
                            "BitTorrent": {},
                            "Box.net": {},
                            "DBank": {},
                            "Datei.to": {},
                            "DepositFiles": {},
                            "Docin": {},
                            "Dropbox": {},
                            "File Rio": {},
                            "FileDropper": {},
                            "FileFactory": {},
                            "FileHost.ro": {},
                            "FileServe": {},
                            "FileSnack": {},
                            "Filemail": {},
                            "Filer.cx": {},
                            "Fluxiom": {},
                            "HighTail/YouSendIt": {},
                            "ImageBam": {},
                            "Imgur": {},
                            "Issuu": {},
                            "Kuaipan": {},
                            "LeapFile": {},
                            "MediaFire": {},
                            "Megashares": {},
                            "Okurin": {},
                            "PhotoSnack": {},
                            "PutLocker": {},
                            "RayFile": {},
                            "ShareFile": {},
                            "Slideshare": {},
                            "Station8": {},
                            "TYDisk": {},
                            "TransferBigFiles": {},
                            "WeTransfer": {},
                            "Weiyun": {},
                            "Yahoo Box": {},
                            "Yunpan": {},
                            "Zbigz": {},
                            "ZippyShare": {},
                            "cloud.mail.ru": {},
                            "dl free": {},
                            "files.mail.ru": {},
                            "iCloud": {},
                            "sendspace": {}
                        }
                    },
                    "Games": {
                        "monitor": {
                            "Evony": {},
                            "Game Center": {},
                            "Hangame.co.jp": {},
                            "Pogo": {},
                            "Wii": {},
                            "games.mail.ru": {}
                        }
                    },
                    "Google+": {
                        "monitor": {
                            "Google+ General": {},
                            "Google+ Hangouts/Chat": {},
                            "Google+ Photos": {},
                            "Google+ Videos": {}
                        }
                    },
                    "Instant Messaging": {
                        "monitor": {
                            "AirAIM": {},
                            "Baiduhi": {},
                            "CGIIRC": {},
                            "Chatroulette": {},
                            "Google Talk": {},
                            "ILoveIM": {},
                            "Icq2go": {},
                            "Mail.Ru Agent": {},
                            "Mibbit": {},
                            "Sinawebuc": {},
                            "WebQQ": {},
                            "Webfetion": {},
                            "Webwangwang": {},
                            "Wechat_web": {}
                        }
                    },
                    "Internet Utilities": {
                        "monitor": {
                            "Evernote": {},
                            "Google Analytics": {},
                            "Google App Engine": {},
                            "Google Maps": {},
                            "Google Play Books": {},
                            "Google Translate": {},
                            "PlayStore": {},
                            "Yahoo Toolbar": {},
                            "eBay": {},
                            "iOS Maps": {},
                            "iOS Stock": {},
                            "iOS Weather": {}
                        }
                    },
                    "LinkedIn": {
                        "monitor": {
                            "LinkedIn Contacts": {},
                            "LinkedIn General": {},
                            "LinkedIn Inbox": {},
                            "LinkedIn Jobs": {},
                            "LinkedIn Profile": {}
                        }
                    },
                    "Media": {
                        "default_bandwidth_limit": "",
                        "monitor": {
                            "1x.com": {},
                            "500px": {},
                            "56.com": {},
                            "ASF": {},
                            "AcFun": {},
                            "Adnstream": {},
                            "BaoFeng": {},
                            "BaoMiHua": {},
                            "Break": {},
                            "ChaoXing Video": {},
                            "Dailymotion": {},
                            "Deezer": {},
                            "DeviantArt": {},
                            "Earthcam": {},
                            "Flash Video": {},
                            "Flickr": {},
                            "Fotki": {},
                            "FotoThing": {},
                            "FreeeTV": {},
                            "Funshion": {},
                            "Google Play Movie": {},
                            "Google Play Music": {},
                            "Gyao": {},
                            "Hulu": {},
                            "IMDb": {},
                            "ImageShack": {},
                            "Jango": {},
                            "KanKan": {},
                            "Ku6": {},
                            "Last.fm": {},
                            "Letv": {},
                            "Livestream": {},
                            "MPEG": {},
                            "MangoTV": {},
                            "Metacafe": {},
                            "Netflix": {},
                            "Nico Nico Douga": {},
                            "PPS.tv": {},
                            "PPTV": {},
                            "Pandora": {},
                            "Pandora TV": {},
                            "Photobucket": {},
                            "QQMusic": {},
                            "QQvideo": {},
                            "QuickTime": {},
                            "RealMedia": {},
                            "Shutterfly": {},
                            "Silverlight": {},
                            "SmugMug": {},
                            "Sohu Video": {},
                            "SoundCloud": {},
                            "StageVu": {},
                            "TinyPic": {},
                            "Tudou": {},
                            "TwitchTV": {},
                            "Ustream": {},
                            "V1cn": {},
                            "Veoh": {},
                            "Viddler": {},
                            "Vimeo": {},
                            "Winamp Remote": {},
                            "Windows Media": {},
                            "Xiami": {},
                            "YouTube": {},
                            "Youku": {},
                            "iFeng Video": {},
                            "iHeartRadio": {},
                            "iQiyi": {},
                            "m1905.com": {}
                        }
                    },
                    "Myspace": {
                        "monitor": {
                            "Myspace General": {},
                            "Myspace Music": {},
                            "Myspace Photos": {},
                            "Myspace Videos": {}
                        }
                    },
                    "Office Suites": {
                        "monitor": {
                            "Google Calendar": {},
                            "Google Drive": {},
                            "Office 365/OneDrive": {},
                            "ZOHO Docs": {}
                        }
                    },
                    "Presentation / Conferencing": {
                        "monitor": {
                            "JoinMe": {},
                            "TeamViewer": {},
                            "Techinline": {},
                            "Twiddla": {},
                            "Vyew.com": {},
                            "WebEx": {},
                            "eRoom.net": {}
                        }
                    },
                    "Proxies": {
                        "monitor": {
                            "ASProxy": {},
                            "Avoidr": {},
                            "CGIProxy": {},
                            "CamoProxy": {},
                            "CoralCDN": {},
                            "FlyProxy": {},
                            "Glype": {},
                            "Guardster": {},
                            "KProxy": {},
                            "Megaproxy": {},
                            "Other Web Proxy": {},
                            "PHPProxy": {},
                            "Proxono": {},
                            "Socks2HTTP": {},
                            "Suresome": {},
                            "Surrogafier": {},
                            "Vtunnel": {},
                            "Zelune": {}
                        }
                    },
                    "Social Networking": {
                        "monitor": {
                            "51.com": {},
                            "58.com": {},
                            "Ameba": {},
                            "AmebaPigg": {},
                            "Ask.fm": {},
                            "Badoo": {},
                            "BaiSheHui": {},
                            "Baidu Tieba": {},
                            "BaiduZhidao": {},
                            "Baixing": {},
                            "Chan4": {},
                            "Classmates": {},
                            "DaZhiHui": {},
                            "Delicious": {},
                            "Dianping": {},
                            "Digg": {},
                            "Douban": {},
                            "Foursquare": {},
                            "Ganji": {},
                            "Gewara": {},
                            "Google Groups": {},
                            "Gree": {},
                            "HatenaSpace": {},
                            "Howardforums": {},
                            "Instagram": {},
                            "Kaixin001": {},
                            "LivedoorGourmet": {},
                            "Lokalisten": {},
                            "Meetup": {},
                            "MeinVZ": {},
                            "Mixi": {},
                            "Mop.com": {},
                            "Mtime": {},
                            "Netlog": {},
                            "Odnoklassniki.Ru": {},
                            "Pinterest": {},
                            "Pixiv": {},
                            "Plaxo": {},
                            "Plurk": {},
                            "PocoCN": {},
                            "QQzone": {},
                            "Quora": {},
                            "Reddit": {},
                            "RenRen": {},
                            "Scribd": {},
                            "Seesaa": {},
                            "Slashdot": {},
                            "Snapchat": {},
                            "Sohu Weibo": {},
                            "StackOverflow": {},
                            "StayFriends": {},
                            "StumbleUpon": {},
                            "Tencent Weibo": {},
                            "Tianya": {},
                            "Tonghuashun": {},
                            "Toutiao.com": {},
                            "Twitter": {},
                            "Two Channel": {},
                            "VK": {},
                            "Viadeo": {},
                            "Weheartit": {},
                            "Weibo": {},
                            "Wetpaint": {},
                            "Wikia": {},
                            "XING": {},
                            "Yahoo Mobage": {},
                            "Yelp": {},
                            "Zhihu": {},
                            "iFeng": {},
                            "my.mail.ru": {}
                        }
                    },
                    "Software Updates": {
                        "monitor": {
                            "McAfee AutoUpdate": {},
                            "Sophos Update": {},
                            "Symantec Liveupdate": {},
                            "Trendmicro Antivirus Update": {},
                            "Windows Update": {}
                        }
                    },
                    "Webmail": {
                        "monitor": {
                            "189Mail": {},
                            "AOL Mail": {},
                            "Comcast Webmail": {},
                            "Eclipso.de Freemail": {},
                            "ExciteMailJapan": {},
                            "Eyejot": {},
                            "Fastmail": {},
                            "Freenet.de Email": {},
                            "GMX E-Mail": {},
                            "Gmail": {},
                            "Hushmail": {},
                            "Mail.Ru": {},
                            "Mail.com": {},
                            "Mail21cn": {},
                            "NeteaseMail": {},
                            "Outlook.com": {},
                            "QQMail": {},
                            "Rambler-Mail": {},
                            "SinaMail": {},
                            "SohuMail": {},
                            "T-Online.de Email": {},
                            "Tommail": {},
                            "Web.de Freemail": {},
                            "Yahoo Mail": {},
                            "Yandex Mail": {},
                            "ZOHO Mail": {}
                        }
                    },
                    "iTunes": {
                        "monitor": {
                            "iTunes Desktop": {},
                            "iTunes iPad": {},
                            "iTunes iPhone": {},
                            "iTunes iPod": {}
                        }
                    }
                }
            },
            "http_rewrite_profile": "None",
            "membership": {
                "identification_profiles": [
                    {
                        "_all_": {
                            "auth": "No Authentication"
                        }
                    }
                ]
            },
            "objects": {
                "block_custom_mime_types": [],
                "max_object_size_mb": {
                    "ftp": 0,
                    "http_or_https": 0
                },
                "object_type": {
                    "Archives": {
                        "monitor": [
                            "StuffIt",
                            "BinHex",
                            "LHARC",
                            "ARC",
                            "ARJ"
                        ]
                    },
                    "Document Types": {
                        "monitor": [
                            "PostScript Document (PS)",
                            "OpenOffice Document",
                            "OASIS Open Document Format",
                            "XML Document",
                            "Microsoft Office",
                            "Portable Document Format (PDF)",
                            "FrameMaker Document (FM)",
                            "Rich Text Format (RTF)"
                        ]
                    },
                    "Executable Code": {
                        "monitor": [
                            "UNIX Executable",
                            "Windows Executable",
                            "Java Applet"
                        ]
                    },
                    "Inspectable Archives": {
                        "allow": [
                            "CPIO",
                            "7zip",
                            "RAR",
                            "LHA",
                            "GZIP",
                            "ZIP Archive",
                            "TAR",
                            "Microsoft CAB"
                        ],
                        "block": [
                            "BZIP2",
                            "Compress Archive (Z)"
                        ]
                    },
                    "Installers": {
                        "monitor": [
                            "UNIX/LINUX Packages"
                        ]
                    },
                    "Media": {
                        "monitor": [
                            "Photographic Images",
                            "Video",
                            "Audio"
                        ]
                    },
                    "Miscellaneous": {
                        "monitor": [
                            "Calendar Data"
                        ]
                    },
                    "P2P Metafiles": {
                        "monitor": [
                            "BitTorrent Links (.torrent)"
                        ]
                    },
                    "Web Page Content": {
                        "monitor": [
                            "Images",
                            "Flash"
                        ]
                    }
                },
                "state": "custom"
            },
            "policy_description": "Default settings",
            "policy_expiry": "",
            "policy_name": "global_policy",
            "policy_status": "enable",
            "protocols_user_agents": {
                "allow_connect_ports": [
                    "8080",
                    "21",
                    "443",
                    "563",
                    "4431",
                    "6443",
                    "8443",
                    "20",
                    "6080"
                ],
                "block_custom_user_agents": [],
                "block_protocols": [],
                "state": "custom"
            },
            "url_filtering": {
                "content_rating": {
                    "status": "disable"
                },
                "custom_cats": {
                    "block": [
                        "test"
                    ],
                    "exclude": [
                        "Adult"
                    ]
                },
                "exception_referred_embedded_content": {
                    "state": "disable"
                },
                "predefined_cats": {
                    "monitor": [
                        "Adult",
                        "Advertisements",
                        "Alcohol",
                        "Animals and Pets",
                        "Arts",
                        "Astrology",
                        "Auctions",
                        "Business and Industry",
                        "Cannabis",
                        "Chat and Instant Messaging",
                        "Cheating and Plagiarism",
                        "Child Abuse Content",
                        "Cloud and Data Centers",
                        "Computer Security",
                        "Computers and Internet",
                        "Conventions, Conferences and Trade Shows",
                        "Cryptocurrency",
                        "Cryptomining",
                        "DIY Projects",
                        "DNS-Tunneling",
                        "Dating",
                        "Digital Postcards",
                        "Dining and Drinking",
                        "DoH and DoT",
                        "Dynamic DNS Provider",
                        "Dynamic and Residential",
                        "Education",
                        "Entertainment",
                        "Extreme",
                        "Fashion",
                        "File Transfer Services",
                        "Filter Avoidance",
                        "Finance",
                        "Freeware and Shareware",
                        "Gambling",
                        "Games",
                        "Government and Law",
                        "Hacking",
                        "Hate Speech",
                        "Health and Medicine",
                        "Humor",
                        "Hunting",
                        "Illegal Activities",
                        "Illegal Downloads",
                        "Illegal Drugs",
                        "Infrastructure and Content Delivery Networks",
                        "Internet Telephony",
                        "Internet of Things",
                        "Job Search",
                        "Lingerie and Swimsuits",
                        "Lotteries",
                        "Military",
                        "Mobile Phones",
                        "Museums",
                        "Nature and Conservation",
                        "News",
                        "Non-governmental Organizations",
                        "Non-sexual Nudity",
                        "Not Actionable",
                        "Online Communities",
                        "Online Document Sharing and Collaboration",
                        "Online Meetings",
                        "Online Storage and Backup",
                        "Online Trading",
                        "Organizational Email",
                        "Paranormal",
                        "Parked Domains",
                        "Peer File Transfer",
                        "Personal Sites",
                        "Personal VPN",
                        "Photo Search and Images",
                        "Politics",
                        "Pornography",
                        "Private IP Addresses as Host",
                        "Professional Networking",
                        "Real Estate",
                        "Recipes and Food",
                        "Reference",
                        "Regional Restricted Sites (Germany)",
                        "Regional Restricted Sites (Great Britain)",
                        "Regional Restricted Sites (Italy)",
                        "Regional Restricted Sites (Poland)",
                        "Religion",
                        "SaaS and B2B",
                        "Safe for Kids",
                        "Science and Technology",
                        "Search Engines and Portals",
                        "Sex Education",
                        "Shopping",
                        "Social Networking",
                        "Social Science",
                        "Society and Culture",
                        "Software Updates",
                        "Sports and Recreation",
                        "Streaming Audio",
                        "Streaming Video",
                        "Terrorism and Violent Extremism",
                        "Tobacco",
                        "Transportation",
                        "Travel",
                        "URL Shorteners",
                        "Weapons",
                        "Web Cache and Archives",
                        "Web Hosting",
                        "Web Page Translation",
                        "Web-based Email"
                    ]
                },
                "safe_search": {
                    "status": "disable"
                },
                "uncategorized_url": "monitor",
                "update_cats_action": "least restrictive",
                "yt_cats": {
                    "block": [
                        "Autos & Vehicles",
                        "Comedy"
                    ],
                    "monitor": [
                        "Music",
                        "Pets & Animals",
                        "Sports",
                        "Travel & Events",
                        "People & Blogs",
                        "Entertainment",
                        "News & Politics",
                        "Howto & Style",
                        "Education",
                        "Science & Technology",
                        "Nonprofits & Activism"
                    ],
                    "warn": [
                        "Film & Animation",
                        "Gaming"
                    ]
                }
            }
        }
    }
}

Human Readable Output

Access Policies

Policy Name Policy Status Policy Description
global_policy enable Default settings

cisco-wsa-access-policy-create


Create an access policy.
This command enables you to create the access policy object. To define more settings you can use the dependencies commands:
cisco-wsa-access-policy-protocols-user-agents-update (Update the Protocols and User Agents policy for access policy).
cisco-wsa-access-policy-url-filtering-update (Update the URL filtering policy for access policy).
cisco-wsa-access-policy-applications-update (Update the applications policy for access policy. Only applicable for global_policy).
cisco-wsa-access-policy-objects-update (Update the objects policy for access policy).
cisco-wsa-access-policy-anti-malware-update (Update the anti-malware policy for access policy).

Base Command

cisco-wsa-access-policy-create

Input

Argument Name Description Required
policy_name Policy name. Required
policy_status Policy status. Possible values are: enable, disable. Required
policy_description Policy description. Optional
policy_order Index of the policies in the collection. Required
policy_expiry Policy expiry date, format yyyy-MM-ddTHH:mm:ssZ, e.g., 2023-02-21T16:16:29Z. Optional
identification_profiles Comma-separated list of valid identification profile name. (Dependencies - use cisco-wsa-identification-profiles-list command to get all the identification profiles.). Required

Context Output

There is no context output for this command.

Command example

!cisco-wsa-access-policy-create policy_name=test policy_status=enable policy_description=test policy_order=1 identification_profile_name=global_identification_profile identification_profiles=test7

Human Readable Output

Created “test” access policy successfully.

cisco-wsa-access-policy-update


Update the access policy.

Base Command

cisco-wsa-access-policy-update

Input

Argument Name Description Required
policy_name Policy name to update. Required
new_policy_name New policy name. Optional
policy_status Policy status. Possible values are: enable, disable. Optional
policy_order Index of policies in the collection. Not applicable for global_policy. Optional
policy_expiry Policy expiry date, format yyyy-MM-ddTHH:mm:ssZ, e.g., 2023-02-21T16:16:29Z. Optional
policy_description Policy description to update. Optional

Context Output

There is no context output for this command.

Command example

!cisco-wsa-access-policy-update policy_name=test policy_description=test1

Human Readable Output

Updated “test” access policy successfully.

cisco-wsa-access-policy-protocols-user-agents-update


Update the Protocols and User Agents policy for access policy.

Base Command

cisco-wsa-access-policy-protocols-user-agents-update

Input

Argument Name Description Required
policy_name Policy name to update. Required
settings_status Settings status for the Protocols and User Agents. Possible values are: custom, use_global, disable. Default is custom. Optional
block_custom_user_agents Comma-separated list of custom user agents to block, in regular expression format.
Pattern examples:
All Firefox versions: “Mozilla/.Gecko/. Firefox/”
Firefox versions 1.5.x: “Mozilla/.Gecko/. Firefox/1.5”
All Internet Explorer versions: “Mozilla/.compatible; MSIE”
Internet Explorer version 5.5: “Mozilla/.
compatible; MSIE 5.5”
Specific user agent: Mozilla/4.0 (compatible; MSIE 5.5;): “Mozilla/4.0 (compatible; MSIE 5.5;)“
Relevant while settings_status is custom.
Optional
allow_connect_ports Comma-separated list of HTTP connect ports.
HTTP CONNECT enables applications to tunnel outbound traffic over HTTP,
unless the protocol is blocked above.
Traffic tunneled through HTTP CONNECT will not be scanned,
except for SSL ports (specified on Security Services > HTTPS Proxy)
e.g. 1-65535,20,21.
Relevant while settings_status is custom.
Optional
block_protocols Block network protocols. Relevant while settings_status is custom. Possible values are: ftp, http. Optional

Context Output

There is no context output for this command.

Command example

!cisco-wsa-access-policy-protocols-user-agents-update policy_name=test block_custom_user_agents=test allow_connect_ports=22,24 block_protocols=http

Human Readable Output

Updated “test” access policy successfully.

cisco-wsa-access-policy-url-filtering-update


Update the URL filtering policy for access policy.

Base Command

cisco-wsa-access-policy-url-filtering-update

Input

Argument Name Description Required
policy_name Policy name to update. Required
predefined_categories_action Predefined categories action. Possible values are: block, monitor, warn. Optional
predefined_categories Comma-separated list of predefined categories. (Dependencies - use cisco-wsa-url-categories-list command to get all the custom & predefined categories.). Optional
youtube_categories_action YouTube categories action. Possible values are: block, monitor, allow. Optional
youtube_categories Comma-separated list of YouTube categories. Optional
custom_categories_action Custom categories action. Possible values are: block, monitor, warn. Optional
custom_categories Comma-separated list of custom categories. (Dependencies - use cisco-wsa-url-categories-list command to get all the custom & predefined categories.). Optional
uncategorized_url Uncategorized URL action. Possible values are: use_global, block, monitor, warn. Optional
update_categories_action When predefined URL categories are periodically updated,
new categories may be introduced, or two (or more) existing categories may be merged.
Select whether the most or least restrictive action should be applied in these cases.
For new categories, in Access policies,
most restrictive is always Block and least restrictive is always Monitor.
For merged categories, the most or least restrictive setting will be selected out of the
settings previously assigned.
For instance, if category A was set to Block, and category B was set to Warn,
and the two are merged into category C,
the most restrictive action will be Block and the least restrictive action will be Warn. Possible values are: use_global, most restrictive, least restrictive.
Optional
content_rating_status When Site Content Rating is enabled, user access to web content rated as adult oriented or
explicit on sites that support content rating will be denied.
Supported sites include Flickr, Craigslist and YouTube.
However, users can still access content on these websites that is not rated as adult oriented or explicit. Possible values are: enable, disable.
Optional
content_rating_action Action if site setting (content_rating_status) allows adult/explicit content. Possible values are: block, warn. Optional
safe_search_status When Safe Search is enabled, non-safe content, including the cached non-safe content
will be blocked from the search result from the following search engines:
Dogpile, Yandex, Google, Yahoo, Bing, WebCrawler, DuckDuckGo, Dailymotion and eBay.
If safe search failed to be enforced on a supported search engine, it will be blocked. Possible values are: enable, disable.
Optional
unsupported_safe_search_engine Action for search engines that don’t support safe search. Possible values are: block, monitor. Optional

Context Output

There is no context output for this command.

Command example

!cisco-wsa-access-policy-url-filtering-update policy_name=test predefined_categories_action=monitor predefined_categories=Astrology custom_categories_action=block custom_categories=test

Human Readable Output

Updated “test” access policy successfully.

cisco-wsa-access-policy-applications-update


Update applications policy for access policy. Only applicable for global_policy.

Base Command

cisco-wsa-access-policy-applications-update

Input

Argument Name Description Required
policy_name Policy name to update. Required
settings_status Applications settings status. Possible values are: custom, use_global. Default is custom. Optional
application Application type to perform the action on. Possible values are: Games, Enterprise Applications, Media, Collaboration, Instant Messaging, Facebook, Social Networking, Internet Utilities, Webmail, Proxies, Presentation / Conferencing, Software Updates, iTunes, Google+, File Sharing, Myspace, Blogging, LinkedIn, Office Suites. Required
action Application action. Possible values are: monitor, block. Required
values Comma-separated list of application values to perform the action on. Required

Context Output

There is no context output for this command.

Command example

!cisco-wsa-access-policy-applications-update policy_name=test application=Blogging action=block values=Blogger

Human Readable Output

Updated “test” access policy successfully.

cisco-wsa-access-policy-objects-update


Update objects policy for access policy.

Base Command

cisco-wsa-access-policy-objects-update

Input

Argument Name Description Required
policy_name Policy name to update. Required
object_type Object type to perform the action on. Possible values are: Executable Code, Web Page Content, Media, P2P Metafiles, Miscellaneous, Document Types, Archives, Installers, Inspectable Archives. Optional
object_action Object action.
Note: “inspect” and “allow” actions are only valid when the object type is “Inspectable Archives”. Possible values are: monitor, block, allow, inspect.
Optional
object_values Comma-separated list of object values to perform the action on. Optional
block_custom_mime_types Block custom MIME types, e.g., audio/x-mpeg3 or audio/*. Optional
http_or_https_max_object_size_mb HTTP/HTTPS maximum download size. Optional
ftp_max_object_size_mb FTP maximum download size. Optional

Context Output

There is no context output for this command.

Command example

!cisco-wsa-access-policy-objects-update policy_name=test object_type=Media object_action=block object_values=Audio http_or_https_max_object_size_mb=30 ftp_max_object_size_mb=20

Human Readable Output

Updated “test” access policy successfully.

cisco-wsa-access-policy-anti-malware-update


Update the anti-malware policy for access policy.

Base Command

cisco-wsa-access-policy-anti-malware-update

Input

Argument Name Description Required
policy_name Policy name to update. Required
settings_status Settings status for the anti-malware. Possible values are: custom, use_global. Default is custom. Optional
web_reputation_status Web Reputation Filters will automatically block transactions with a low Web Reputation score.
For transactions with a higher Web Reputation score,
scanning will be performed using the services selected by Adaptive Scanning.
If Web Reputation Filtering is disabled in this policy,
transactions will not be automatically blocked based on low Web Reputation Score.
Blocking of sites that contain malware or other high-risk content is controlled by the additional arguments. Possible values are: enable, disable.
Optional
file_reputation_filtering_status File Reputation Filters will identify transactions containing known malicious or high-risk files.
Files that are unknown may be forwarded to the cloud for file analysis. Possible values are: enable, disable.
Optional
file_reputation_action File Reputation action. Possible values are: monitor, block. Optional
anti_malware_scanning_status Anti-Malware scanning status. Possible values are: enable, disable. Optional
suspect_user_agent_scanning Suspect user agent scanning action.
Required while anti_malware_scanning_status is enabled.
Not relevant while anti_malware_scanning_status is disabled. Possible values are: block, scan, none.
Optional
block_malware_categories Comma-separated list of malware categories to block. Required while anti_malware_scanning_status is enabled. Not relevant while anti_malware_scanning_status is disabled. Possible values are: Adware, Browser Helper Object, Commercial System Monitor, Dialer, Generic Spyware, Hijacker, Other Malware, Phishing URL, PUA, System Monitor, Trojan Downloader, Trojan Horse, Trojan Phisher, Virus, Worm. Optional
block_other_categories Comma-separated list of other categories to block. Required while anti_malware_scanning_status is enabled. Not relevant while anti_malware_scanning_status is disabled. Possible values are: Encrypted File, Outbreak Heuristics, Unscannable. Optional

Context Output

There is no context output for this command.

Command example

!cisco-wsa-access-policy-anti-malware-update policy_name=test web_reputation_status=enable file_reputation_filtering_status=enable file_reputation_action=block anti_malware_scanning_status=enable suspect_user_agent_scanning=block block_malware_categories=Adware block_other_categories=Unscannable

Human Readable Output

Updated “test” access policy successfully.

cisco-wsa-access-policy-delete


Delete access policy.

Base Command

cisco-wsa-access-policy-delete

Input

Argument Name Description Required
policy_names Comma-separated list of policy names to delete. Required

Context Output

There is no context output for this command.

Command example

!cisco-wsa-access-policy-delete policy_names=test

Human Readable Output

Deleted Access policy profiles successfully.

cisco-wsa-domain-map-list


Retrieve domains mapping.
Domain maps are DNS mappings of domain to IP addresses.

Base Command

cisco-wsa-domain-map-list

Input

Argument Name Description Required
domain_names Comma-separated list of domain names to retrieve. Optional
ip_addresses Comma-separated list of IP addresses to search for.
This argument will retrieve the domain map record if one of the IP addresses specified is mapped to the domain. .
Optional
page The page number of the results to retrieve.
Minimum value is 1.
Optional
page_size The number of results per page. The maximum value is 100. Optional
limit The maximum number of records to retrieve. Default is 50. Optional

Context Output

Path Type Description
CiscoWSA.DomainMap.domain_name String Domain name.
CiscoWSA.DomainMap.ip_addresses String Mapped IP addresses.
CiscoWSA.DomainMap.order Number Index of the domain map in the collection.

Command example

!cisco-wsa-domain-map-list limit=5

Context Example

{
    "CiscoWSA": {
        "DomainMap": [
            {
                "IP_addresses": [
                    "19.23.2.23"
                ],
                "domain_name": "ascxcdfdgdfgsfvd",
                "order": 1
            },
            {
                "IP_addresses": [
                    "19.23.2.23"
                ],
                "domain_name": "ascxcdsfvd",
                "order": 2
            },
            {
                "IP_addresses": [
                    "19.23.2.2"
                ],
                "domain_name": "ascxcvd",
                "order": 3
            },
            {
                "IP_addresses": [
                    "19.2.2.2"
                ],
                "domain_name": "asd",
                "order": 4
            },
            {
                "IP_addresses": [],
                "domain_name": "cccc",
                "order": 5
            }
        ]
    }
}

Human Readable Output

Domain Map

Domain Name Ip Addresses Order
ascxcdfdgdfgsfvd 19.23.2.23 1
ascxcdsfvd 19.23.2.23 2
ascxcvd 19.23.2.2 3
asd 19.2.2.2 4
cccc   5

cisco-wsa-domain-map-create


Create domain mapping for IP addresses.

Base Command

cisco-wsa-domain-map-create

Input

Argument Name Description Required
domain_name The domain name to create. Required
order Index of the domain map in the collection. Required
ip_addresses Comma-separated list of IP addresses to map for the domain. Required

Context Output

There is no context output for this command.

Command example

!cisco-wsa-domain-map-create domain_name=test.com order=1 ip_addresses=1.1.1.1

Human Readable Output

Domain “test.com” mapping created successfully.

cisco-wsa-domain-map-update


Update the domain map.

Base Command

cisco-wsa-domain-map-update

Input

Argument Name Description Required
domain_name The domain name to update. Required
new_domain_name New domain name. Optional
order Index of the domain map in the collection. Optional
ip_addresses Comma-separated list of IP addresses to map for the domain.
Updating this will overwrite the existing IP addresses.
Optional

Context Output

There is no context output for this command.

Command example

!cisco-wsa-domain-map-update domain_name=test.com new_domain_name=test1.com order=2 ip_addresses=1.1.1.1,2.2.2.2

Human Readable Output

Domain “test.com” mapping updated successfully.

cisco-wsa-domain-map-delete


Delete domain map.

Base Command

cisco-wsa-domain-map-delete

Input

Argument Name Description Required
domain_names Comma-separated list of domain names to delete. Required

Context Output

There is no context output for this command.

Command example

!cisco-wsa-domain-map-delete domain_names=test1.com

Human Readable Output

Domain “test1.com” deleted successfully.

cisco-wsa-identification-profiles-list


Retrieve identification profiles.
Identification profiles are classifications of users, defining authentication requirements.

Base Command

cisco-wsa-identification-profiles-list

Input

Argument Name Description Required
profile_names Comma-separated list of profile names to retrieve. Optional
page The page number of the results to retrieve.
Minimum value is 1.
Optional
page_size The number of results per page. The maximum value is 100. Optional
limit The maximum number of records to retrieve. Default is 50. Optional

Context Output

Path Type Description
CiscoWSA.IdentificationProfile.status String Identification Profile status.
CiscoWSA.IdentificationProfile.profile_name String Identification Profile name.
CiscoWSA.IdentificationProfile.description String Identification Profile description.
CiscoWSA.IdentificationProfile.protocols String Identification Profile protocol.
CiscoWSA.IdentificationProfile.order Number Identification Profile order in the list.
CiscoWSA.IdentificationProfile.UrlCategories.predefined String Identification Profile predefined URL categories.
CiscoWSA.IdentificationProfile.UrlCategories.custom String Identification Profile custom URL categories.
CiscoWSA.IdentificationProfile.UrlCategories.uncategorized String Identification Profile uncategorized URL categories status.
CiscoWSA.IdentificationProfile.ip String Identification Profile IP.
CiscoWSA.IdentificationProfile.proxy_port String Identification Profile proxy port.
CiscoWSA.IdentificationProfile.UserAgents.predefined String The predefined user-agent.
CiscoWSA.IdentificationProfile.UserAgents.custom String User-agent custom.

Command example

!cisco-wsa-identification-profiles-list page=1 page_size=2

Context Example

{
    "CiscoWSA": {
        "IdentificationProfile": [
            {
                "description": "Sample description",
                "ip": [
                    "12.2.2.6"
                ],
                "order": 1,
                "profile_name": "hello",
                "protocols": [
                    "http",
                    "https",
                    "ftp"
                ],
                "status": "enable"
            },
            {
                "description": "test",
                "ip": [
                    "10.10.10.10"
                ],
                "order": 2,
                "profile_name": "test123",
                "protocols": [
                    "http",
                    "https",
                    "ftp",
                    "socks"
                ],
                "status": "enable"
            }
        ]
    }
}

Human Readable Output

Identification Profiles

Order Profile Name Status Description Members
1 hello enable Sample description ip: 12.2.2.6
protocols: http,
https,
ftp
proxy_ports: 4000,
5006
2 test123 enable test ip: 10.10.10.10
protocols: http,
https,
ftp,
socks
proxy_ports: 20-200,
966

cisco-wsa-identification-profiles-create


Create an identification profile.

Base Command

cisco-wsa-identification-profiles-create

Input

Argument Name Description Required
profile_name Profile name to create. Required
status Status of new identification profile. Possible values are: enable, disable. Default is enable. Optional
description Description of new identification profile. Required
order Index of the identification profiles in the collection.
Not applicable for global_identification_profile. Default is 1.
Optional
protocols Comma-separated list of network protocols of identification profile. Possible values are: HTTPS, SOCKS. Default is HTTPS. Optional
proxy_ports Comma-separated list of proxy ports.
Membership is defined by proxy port for forward connections,
where certain clients have been configured to use a specific connecting port.
For transparent connections, membership by proxy port applies to the port of the destination URL.
Leave this field blank if membership by connecting proxy port is not needed.
e.g., 22-1000,3331.
Optional
members_by_subnet Comma-separated list of members by Subnet. e.g., 10.1.1.0,10.1.1.0/24,10.1.1.1-10,2001:420:80:1::5. Optional
predefined_url_categories Comma-separated list of URL categories to use as membership criteria.
Leave blank if membership by URL category is not needed.
(Dependencies - use cisco-wsa-url-categories-list command to get all the custom & predefined categories.).
Optional
custom_url_categories Comma-separated list of URL categories to use as membership criteria.
Leave blank if membership by URL category is not needed.
(Dependencies - use cisco-wsa-url-categories-list command to get all the custom & predefined categories.).
Optional

Context Output

There is no context output for this command.

Command example

!cisco-wsa-identification-profiles-create profile_name=test status=enable description=test protocols=HTTPS order=1

Human Readable Output

Created identification profile “test” successfully.

cisco-wsa-identification-profiles-update


Update the identification profile. This command rewrites the profile values (does not append). For example, if the proxy_ports is defined as 4000,5000 and you insert proxy_ports=8000, the proxy_ports will be 8000.

Base Command

cisco-wsa-identification-profiles-update

Input

Argument Name Description Required
profile_name Profile name to update. Required
new_profile_name New profile name for the identification profile. Optional
status Updated the status of the identification profile. Possible values are: enable, disable. Optional
description Updated description of the identification profile. Optional
order Index of the Identification profile in the collection.
Not applicable for global_identification_profile.
Optional
protocols Comma-separated list of network protocols of the identification profile. Possible values are: HTTPS, SOCKS. Default is HTTPS. Optional
proxy_ports Comma-separated list of proxy ports.
Membership is defined by the proxy port for forward connections,
where certain clients have been configured to use a specific connecting port.
For transparent connections, membership by proxy port applies to the port of the destination URL.
Leave this field blank if membership by connecting proxy port is not needed.
e.g., 22-1000,3331.
Optional
members_by_subnet Comma-separated list of members by subnet. e.g., 10.1.1.0,10.1.1.0/24,10.1.1.1-10,2001:420:80:1::5. Optional
predefined_url_categories Comma-separated list of URL categories to use as membership criteria.
Leave blank if membership by URL category is not needed.
(Dependencies - use cisco-wsa-url-categories-list command to get all the custom & predefined categories.).
Optional
custom_url_categories Comma-separated list of URL categories to use as membership criteria.
Leave blank if membership by URL category is not needed.
(Dependencies - use cisco-wsa-url-categories-list command to get all the custom & predefined categories.).
Optional

Context Output

There is no context output for this command.

Command example

!cisco-wsa-identification-profiles-update profile_name=test description=testtest protocols=HTTPS,SOCKS order=2

Human Readable Output

Updated identification profile “test” successfully.

cisco-wsa-identification-profiles-delete


Delete identification profiles.

Base Command

cisco-wsa-identification-profiles-delete

Input

Argument Name Description Required
profile_names Comma-separated list of profile names to delete. Required

Context Output

There is no context output for this command.

Command example

!cisco-wsa-identification-profiles-delete profile_names=test

Human Readable Output

Deleted identification profiles successfully.

cisco-wsa-url-categories-list


Retrieve URL categories of available categories to allow/block in access policies.

Base Command

cisco-wsa-url-categories-list

Input

Argument Name Description Required
contain A string that contains the category to search for. Optional
type Type of category. Possible values are: custom, predefined. Optional

Context Output

Path Type Description
CiscoWSA.UrlCategory.predefined String Predefined URL categories.
CiscoWSA.UrlCategory.custom String Custom URL categories.

Command example


#### Context Example

```json
{
    "CiscoWSA": {
        "UrlCategory": {
            "custom": [
                "test",
                "Adult"
            ],
            "predefined": [
                "Adult",
                "Advertisements",
                "Alcohol",
                "Animals and Pets",
                "Arts",
                "Astrology",
                "Auctions",
                "Business and Industry",
                "Cannabis",
                "Chat and Instant Messaging",
                "Cheating and Plagiarism",
                "Child Abuse Content",
                "Cloud and Data Centers",
                "Computer Security",
                "Computers and Internet",
                "Conventions, Conferences and Trade Shows",
                "Cryptocurrency",
                "Cryptomining",
                "DIY Projects",
                "DNS-Tunneling",
                "Dating",
                "Digital Postcards",
                "Dining and Drinking",
                "DoH and DoT",
                "Dynamic DNS Provider",
                "Dynamic and Residential",
                "Education",
                "Entertainment",
                "Extreme",
                "Fashion",
                "File Transfer Services",
                "Filter Avoidance",
                "Finance",
                "Freeware and Shareware",
                "Gambling",
                "Games",
                "Government and Law",
                "Hacking",
                "Hate Speech",
                "Health and Medicine",
                "Humor",
                "Hunting",
                "Illegal Activities",
                "Illegal Downloads",
                "Illegal Drugs",
                "Infrastructure and Content Delivery Networks",
                "Internet Telephony",
                "Internet of Things",
                "Job Search",
                "Lingerie and Swimsuits",
                "Lotteries",
                "Military",
                "Mobile Phones",
                "Museums",
                "Nature and Conservation",
                "News",
                "Non-governmental Organizations",
                "Non-sexual Nudity",
                "Not Actionable",
                "Online Communities",
                "Online Document Sharing and Collaboration",
                "Online Meetings",
                "Online Storage and Backup",
                "Online Trading",
                "Organizational Email",
                "Paranormal",
                "Parked Domains",
                "Peer File Transfer",
                "Personal Sites",
                "Personal VPN",
                "Photo Search and Images",
                "Politics",
                "Pornography",
                "Private IP Addresses as Host",
                "Professional Networking",
                "Real Estate",
                "Recipes and Food",
                "Reference",
                "Regional Restricted Sites (Germany)",
                "Regional Restricted Sites (Great Britain)",
                "Regional Restricted Sites (Italy)",
                "Regional Restricted Sites (Poland)",
                "Religion",
                "SaaS and B2B",
                "Safe for Kids",
                "Science and Technology",
                "Search Engines and Portals",
                "Sex Education",
                "Shopping",
                "Social Networking",
                "Social Science",
                "Society and Culture",
                "Software Updates",
                "Sports and Recreation",
                "Streaming Audio",
                "Streaming Video",
                "Terrorism and Violent Extremism",
                "Tobacco",
                "Transportation",
                "Travel",
                "URL Shorteners",
                "Weapons",
                "Web Cache and Archives",
                "Web Hosting",
                "Web Page Translation",
                "Web-based Email"
            ]
        }
    }
}

Human Readable Output

URL categories

Custom Predefined
test,
Adult
Adult,
Advertisements,
Alcohol,
Animals and Pets,
Arts,
Astrology,
Auctions,
Business and Industry,
Cannabis,
Chat and Instant Messaging,
Cheating and Plagiarism,
Child Abuse Content,
Cloud and Data Centers,
Computer Security,
Computers and Internet,
Conventions, Conferences and Trade Shows,
Cryptocurrency,
Cryptomining,
DIY Projects,
DNS-Tunneling,
Dating,
Digital Postcards,
Dining and Drinking,
DoH and DoT,
Dynamic DNS Provider,
Dynamic and Residential,
Education,
Entertainment,
Extreme,
Fashion,
File Transfer Services,
Filter Avoidance,
Finance,
Freeware and Shareware,
Gambling,
Games,
Government and Law,
Hacking,
Hate Speech,
Health and Medicine,
Humor,
Hunting,
Illegal Activities,
Illegal Downloads,
Illegal Drugs,
Infrastructure and Content Delivery Networks,
Internet Telephony,
Internet of Things,
Job Search,
Lingerie and Swimsuits,
Lotteries,
Military,
Mobile Phones,
Museums,
Nature and Conservation,
News,
Non-governmental Organizations,
Non-sexual Nudity,
Not Actionable,
Online Communities,
Online Document Sharing and Collaboration,
Online Meetings,
Online Storage and Backup,
Online Trading,
Organizational Email,
Paranormal,
Parked Domains,
Peer File Transfer,
Personal Sites,
Personal VPN,
Photo Search and Images,
Politics,
Pornography,
Private IP Addresses as Host,
Professional Networking,
Real Estate,
Recipes and Food,
Reference,
Regional Restricted Sites (Germany),
Regional Restricted Sites (Great Britain),
Regional Restricted Sites (Italy),
Regional Restricted Sites (Poland),
Religion,
SaaS and B2B,
Safe for Kids,
Science and Technology,
Search Engines and Portals,
Sex Education,
Shopping,
Social Networking,
Social Science,
Society and Culture,
Software Updates,
Sports and Recreation,
Streaming Audio,
Streaming Video,
Terrorism and Violent Extremism,
Tobacco,
Transportation,
Travel,
URL Shorteners,
Weapons,
Web Cache and Archives,
Web Hosting,
Web Page Translation,
Web-based Email

Configuration parameters

  • base_url — Server URL (required)
  • credentials — Username (required)
  • proxy — Use system proxy settings
  • insecure — Trust any certificate (not secure)

Commands (18)

  • cisco-wsa-access-policy-anti-malware-update

    Update the anti-malware policy for access policy.

  • cisco-wsa-access-policy-applications-update

    Update applications policy for access policy. Only applicable for global_policy.

  • cisco-wsa-access-policy-create

    Create an access policy. This command enables you to create the access policy object. To define more settings you can use the dependencies commands: cisco-wsa-access-policy-protocols-user-agents-update (Update the Protocols and User Agents policy for access policy). cisco-wsa-access-policy-url-filtering-update (Update the URL filtering policy for access policy). cisco-wsa-access-policy-applications-update (Update the applications policy for access policy. Only applicable for global_policy). cisco-wsa-access-policy-objects-update (Update the objects policy for access policy). cisco-wsa-access-policy-anti-malware-update (Update the anti-malware policy for access policy).

  • cisco-wsa-access-policy-delete

    Delete access policy.

  • cisco-wsa-access-policy-list

    Retrieve access policies. Access policies contain allowed/blocked URL categories in the network.

  • cisco-wsa-access-policy-objects-update

    Update objects policy for access policy.

  • cisco-wsa-access-policy-protocols-user-agents-update

    Update the Protocols and User Agents policy for access policy.

  • cisco-wsa-access-policy-update

    Update the access policy.

  • cisco-wsa-access-policy-url-filtering-update

    Update the URL filtering policy for access policy.

  • cisco-wsa-domain-map-create

    Create domain mapping for IP addresses.

  • cisco-wsa-domain-map-delete

    Delete domain map.

  • cisco-wsa-domain-map-list

    Retrieve domains mapping. Domain maps are DNS mappings of domain to IP addresses.

  • cisco-wsa-domain-map-update

    Update the domain map.

  • cisco-wsa-identification-profiles-create

    Create an identification profile.

  • cisco-wsa-identification-profiles-delete

    Delete identification profiles.

  • cisco-wsa-identification-profiles-list

    Retrieve identification profiles. Identification profiles are classifications of users, defining authentication requirements.

  • cisco-wsa-identification-profiles-update

    Update the identification profile. This command rewrites the profile values (does not append). For example, if the proxy_ports is defined as 4000,5000 and you insert proxy_ports=8000, the proxy_ports will be 8000.

  • cisco-wsa-url-categories-list

    Retrieve URL categories of available categories to allow/block in access policies.

from http import HTTPStatus

import demistomock as demisto  # noqa: F401
from CommonServerPython import *  # noqa: F401
from requests import Response

JWT_TOKEN_EXPIRATION_PERIOD = 30
V2_PREFIX = "v2.0"
V3_PREFIX = "v3.0"
HTTPS_PROTOCOLS = ["http", "https", "ftp"]
SOCKS_PROTOCOL = ["socks"]
ISO8601_CONFIG = "%Y-%m-%dT%H:%M:%SZ"
API_DATE_CONFIG = "%m/%d/%Y %H:%M"


class Client(BaseClient):
    """Client class to interact with Cisco WSA API."""

    def __init__(self, server_url: str, username: str, password: str, verify: bool, proxy: bool):
        super().__init__(base_url=server_url, headers={}, verify=verify, proxy=proxy)
        self.username = username
        self.password = password
        self.handle_request_headers()

    def handle_request_headers(self):
        """Retrieve and save to integration context JWT token for authorized client class API requests."""
        integration_context = get_integration_context()
        jwt_token = integration_context.get("jwt_token")
        jwt_token_issued_time = integration_context.get("jwt_token_issued_time")
        if jwt_token and jwt_token_issued_time >= datetime.timestamp(
            datetime.now() - timedelta(minutes=JWT_TOKEN_EXPIRATION_PERIOD)
        ):
            self._headers["jwtToken"] = jwt_token
        else:
            jwt_token = self.retrieve_jwt_token()
            set_integration_context({"jwt_token": jwt_token, "jwt_token_issued_time": time.time()})
            self._headers["jwtToken"] = jwt_token

    def retrieve_jwt_token(self) -> str:
        """
        Retrieve JWT token from Cisco WSA.

        Returns:
            str: JWT token from Cisco WSA.
        """
        data = {
            "data": {
                "userName": b64_encode(self.username),
                "passphrase": b64_encode(self.password),
            }
        }
        try:
            response = self._http_request("POST", f"{V2_PREFIX}/login", json_data=data)
            return dict_safe_get(response, ["data", "jwtToken"])

        except DemistoException as error:
            if error.res is not None and error.res.status_code == HTTPStatus.UNAUTHORIZED:
                raise DemistoException("Authorization Error: make sure username and password are set correctly.")
            raise error

    def _http_request(self, *args, **kwargs):
        """HTTP request handler for Cisco WSA API.
        In some cases, the API status code is 200 but there are errors.

        Raises:
            DemistoException: Error to get to the API.

        """
        res = super()._http_request(*args, **kwargs)
        if isinstance(res, dict) and all([res.get("res_code"), res.get("res_code") == HTTPStatus.BAD_REQUEST]):
            raise DemistoException(message=res)
        return res

    def access_policy_list(self, policy_names: str | None) -> dict[str, Any]:
        """
        Access Policies list.

        Args:
            policy_names (str | None): Policies names to retrieve.

        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        params = assign_params(policy_names=policy_names)

        return self._http_request("GET", f"{V3_PREFIX}/web_security/access_policies", params=params, ok_codes=[HTTPStatus.OK])

    def access_policy_create(
        self,
        policy_name: str,
        policy_status: str,
        identification_profiles: str,
        policy_order: int | None,
        policy_description: str | None,
        policy_expiry: str | None,
    ) -> dict[str, Any]:
        """
        Create an access policy.

        Args:
            policy_name (str): Policy name to create.
            policy_status (str): Policy status.
            identification_profiles (str): Identification profile name.
            policy_order (int | None): Policy order.
            policy_description (str | None): Policy description.
            policy_expiry (str | None): Policy expiration date.

        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        data = remove_empty_elements(
            {
                "access_policies": [
                    {
                        "policy_name": policy_name,
                        "policy_order": policy_order,
                        "policy_status": policy_status,
                        "policy_description": policy_description,
                        "policy_expiry": policy_expiry,
                        "membership": {
                            "identification_profiles": [
                                {
                                    "auth": "No Authentication",
                                    "profile_name": profile,
                                }
                                for profile in identification_profiles
                            ],
                        },
                    }
                ]
            }
        )

        return self._http_request(
            "POST",
            f"{V3_PREFIX}/web_security/access_policies",
            json_data=data,
            resp_type="response",
            ok_codes=[HTTPStatus.NO_CONTENT],
        )

    def access_policy_update(
        self,
        policy_name: str,
        new_policy_name: str | None,
        policy_status: str | None,
        policy_description: str | None,
        policy_order: int | None,
        policy_expiry: str | None,
    ) -> dict[str, Any]:
        """
        Update an access policy.

        Args:
            policy_name (str): Policy name to update.
            new_policy_name (str | None): Policy status.
            policy_status (str | None): Policy status.
            policy_description (str | None): Policy description.
            policy_order (int | None): Policy order.
            policy_expiry (str | None): Policy expiry.

        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        data = remove_empty_elements(
            {
                "access_policies": [
                    {
                        "policy_name": policy_name,
                        "new_policy_name": new_policy_name,
                        "policy_status": policy_status,
                        "policy_description": policy_description,
                        "policy_order": policy_order,
                        "policy_expiry": policy_expiry,
                    }
                ]
            }
        )

        return self._http_request(
            "PUT",
            f"{V3_PREFIX}/web_security/access_policies",
            json_data=data,
            resp_type="response",
            ok_codes=[HTTPStatus.NO_CONTENT],
        )

    def access_policy_protocols_user_agents_update(
        self,
        policy_name: str,
        block_custom_user_agents: List[str] | None,
        allow_connect_ports: List[str] | None,
        block_protocols: List[str] | None,
        settings_status: str,
    ) -> dict[str, Any]:
        """
        Update access policy's objects settings.

        Args:
            policy_name (str): Policy name to update.
            block_custom_user_agents (List[str] | None): Block custom user agents.
            allow_connect_ports (List[str] | None): Allow connect ports.
            block_protocols (List[str] | None): Block protocols.
            settings_status (str): Settings status for the policy.
        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        data = remove_empty_elements(
            {
                "access_policies": [
                    {
                        "policy_name": policy_name,
                        "protocols_user_agents": {
                            "block_custom_user_agents": block_custom_user_agents,
                            "allow_connect_ports": allow_connect_ports,
                            "block_protocols": block_protocols,
                            "state": settings_status,
                        },
                    }
                ]
            }
        )

        return self._http_request(
            "PUT",
            f"{V3_PREFIX}/web_security/access_policies",
            json_data=data,
            resp_type="response",
            ok_codes=[HTTPStatus.NO_CONTENT],
        )

    def access_policy_url_filtering_update(
        self,
        policy_name: str,
        predefined_categories_action: str | None,
        predefined_categories: List[str] | None,
        youtube_categories_action: str | None,
        youtube_categories: List[str] | None,
        custom_categories_action: str | None,
        custom_categories: List[str] | None,
        uncategorized_url: str | None,
        update_categories_action: str | None,
        content_rating_action: str | None,
        content_rating_status: str | None,
        safe_search_status: str | None,
        unsupported_safe_search_engine: str | None,
    ) -> dict[str, Any]:
        """
        Update access policy's URL filtering settings.

        Args:
            policy_name (str): Policy name to update.
            predefined_categories_action (str | None): Predefined categories action.
            predefined_categories (List[str] | None): Predefined categories.
            youtube_categories_action (str | None): YouTube categories action.
            youtube_categories (List[str] | None): YouTube categories.
            custom_categories_action (str | None): Custom categories action.
            custom_categories (List[str] | None): Custom categories.
            uncategorized_url (str | None): Uncategorized URL action.
            update_categories_action (str | None): Update categories action.
            content_rating_action (str | None): Content rating action.
            content_rating_status (str | None): Content rating status.
            safe_search_status (str | None): Safe search status.
            unsupported_safe_search_engine (str | None): Unsupported safe search engine.
        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        data = remove_empty_elements(
            {
                "access_policies": [
                    {
                        "policy_name": policy_name,
                        "url_filtering": {
                            "predefined_cats": {predefined_categories_action: predefined_categories},
                            "yt_cats": {youtube_categories_action: youtube_categories},
                            "custom_cats": {custom_categories_action: custom_categories},
                            "uncategorized_url": uncategorized_url,
                            "update_cats_action": update_categories_action,
                            "content_rating": {
                                "status": content_rating_status,
                                "action": content_rating_action,
                            },
                            "safe_search": {
                                "status": safe_search_status,
                                "unsupported_safe_search_engine": unsupported_safe_search_engine,
                            },
                        },
                    }
                ]
            }
        )
        return self._http_request(
            "PUT",
            f"{V3_PREFIX}/web_security/access_policies",
            json_data=data,
            resp_type="response",
            ok_codes=[HTTPStatus.NO_CONTENT],
        )

    def access_policy_applications_update(
        self,
        policy_name: str,
        application: str,
        action: str,
        values: dict[str, Any],
        settings_status: str,
    ) -> dict[str, Any]:
        """
        Update access policy's applications settings.

        Args:
            policy_name (str): Policy name to update.
            application (str): Application to update.
            action (str): Action to perform on values.
            values (dict[str, Any]): Values to perform action on.
            settings_status (str): Settings status for the policy.

        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        data = {
            "access_policies": [
                {
                    "policy_name": policy_name,
                    "avc": {
                        "applications": {
                            application: {action: values} if action == "block" else {action: {value: {} for value in values}},
                        },
                        "state": settings_status,
                    },
                }
            ]
        }

        return self._http_request(
            "PUT",
            f"{V3_PREFIX}/web_security/access_policies",
            json_data=data,
            resp_type="response",
            ok_codes=[HTTPStatus.NO_CONTENT],
        )

    def access_policy_objects_update(
        self,
        policy_name: str,
        objects: dict[str, Any],
        object_type: str | None,
        object_action: str | None,
        object_values: List[str] | None,
        block_custom_mime_types: List[str] | None,
        http_or_https_max_object_size_mb: int | None,
        ftp_max_object_size_mb: int | None,
    ) -> dict[str, Any]:
        """
        Update access policy's objects settings.

        Args:
            policy_name (str): Policy name to update.
            objects (dict[str, Any]): Policies objects.
            object_type (str | None): Object type.
            object_action (str | None): Object action.
            object_values (List[str] | None): Object values.
            block_custom_mime_types (List[str] | None): Block custom MIME types.
            http_or_https_max_object_size_mb (int | None): HTTP(S) max object size MB.
            ftp_max_object_size_mb (int | None): FTP max object size MB.

        Raises:
            DemistoException: Policy was not found.
            DemistoException: Update failed, objects were not found.

        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        organize_policy_object_data(
            objects=objects,
            object_type=object_type,
            object_action=object_action,
            object_values=object_values,
            block_custom_mime_types=block_custom_mime_types,
            http_or_https_max_object_size_mb=http_or_https_max_object_size_mb,
            ftp_max_object_size_mb=ftp_max_object_size_mb,
        )

        data = {"access_policies": [{"policy_name": policy_name, "objects": objects}]}
        return self._http_request(
            "PUT",
            f"{V3_PREFIX}/web_security/access_policies",
            json_data=data,
            resp_type="response",
            ok_codes=[HTTPStatus.NO_CONTENT],
        )

    def access_policy_anti_malware_update(
        self,
        policy_name: str,
        web_reputation_status: str | None,
        file_reputation_filtering_status: str | None,
        file_reputation_action: str | None,
        anti_malware_scanning_status: str | None,
        suspect_user_agent_scanning: str | None,
        block_malware_categories: List[str] | None,
        block_other_categories: List[str] | None,
        settings_status: str,
    ) -> dict[str, Any]:
        """
        Update access policy's applications settings.

        Args:
            policy_name (str): Policy name to update.
            web_reputation_status (str | None): Web reputation status.
            file_reputation_filtering_status (str | None): File reputation filtering status.
            file_reputation_action (str | None): File reputation action.
            anti_malware_scanning_status (str | None): Anti-malware scanning status.
            suspect_user_agent_scanning (str | None): Suspect user agent scanning.
            block_malware_categories (List[str] | None): Malware categories to block.
            block_other_categories (List[str] | None): Other categories to block.
            settings_status (str): Application settings status.
        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        data = remove_empty_elements(
            {
                "access_policies": [
                    {
                        "policy_name": policy_name,
                        "amw_reputation": {
                            "web_reputation": {"filtering": web_reputation_status},
                            "adv_malware_protection": {
                                "file_reputation_filtering": file_reputation_filtering_status,
                                "file_reputation": {file_reputation_action: ["Known Malicious and High-Risk Files"]}
                                if file_reputation_action
                                else {},
                            },
                            "cisco_dvs_amw": {
                                "amw_scanning": {"amw_scan_status": anti_malware_scanning_status},
                                "suspect_user_agent_scanning": suspect_user_agent_scanning,
                                "block_malware_categories": block_malware_categories,
                                "block_other_categories": block_other_categories,
                            },
                            "state": settings_status,
                        }
                        if settings_status == "custom"
                        else {"state": settings_status},
                    }
                ]
            }
        )
        return self._http_request(
            "PUT",
            f"{V3_PREFIX}/web_security/access_policies",
            json_data=data,
            resp_type="response",
            ok_codes=[HTTPStatus.NO_CONTENT],
        )

    def access_policy_delete(self, policy_names: str) -> Response:
        """
        Delete access policy.

        Args:
            policy_names (str): Comma separated policy names to delete.

        Returns:
            Response: API response from Cisco WSA.
        """
        params = assign_params(policy_names=",".join(policy_names))
        return self._http_request(
            "DELETE",
            f"{V3_PREFIX}/web_security/access_policies",
            params=params,
            resp_type="response",
            ok_codes=[HTTPStatus.NO_CONTENT, HTTPStatus.MULTI_STATUS],
        )

    def domain_map_list(self) -> dict[str, Any]:
        """
        List domain mappings.

        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        return self._http_request("GET", f"{V2_PREFIX}/configure/web_security/domain_map", ok_codes=[HTTPStatus.OK])

    def domain_map_create(self, domain_name: str, ip_addresses: List[str], order: int) -> dict[str, Any]:
        """
        Create domain mapping.

        Args:
            domain_name (str): Domain name.
            ip_addresses (List[str]): IP addresses to map to the domain.
            order (int): Index of domain map in the collection.

        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        data = [{"IP_addresses": ip_addresses, "domain_name": domain_name, "order": order}]

        return self._http_request(
            "POST", f"{V2_PREFIX}/configure/web_security/domain_map", json_data=data, ok_codes=[HTTPStatus.OK]
        )

    def domain_map_update(
        self,
        domain_name: str,
        new_domain_name: str | None,
        ip_addresses: str | None,
        order: int | None,
    ) -> dict[str, Any]:
        """
        Update domain map.

        Args:
            domain_name (str): Domain name to update.
            new_domain_name (str | None): New domain name.
            ip_addresses (str | None): IP addresses to map.
            order (int | None): Index of domain map.

        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        data = remove_empty_elements(
            [
                {
                    "domain_name": domain_name,
                    "new_domain_name": new_domain_name,
                    "IP_addresses": ip_addresses,
                    "order": order,
                }
            ]
        )

        return self._http_request(
            "PUT", f"{V2_PREFIX}/configure/web_security/domain_map", json_data=data, ok_codes=[HTTPStatus.OK]
        )

    def domain_map_delete(self, domain_name: str) -> dict[str, Any]:
        """
        Delete domain map.

        Args:
            domain_name (str): Domain name to delete.

        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        data = {"domain_name": domain_name}

        return self._http_request(
            "DELETE",
            f"{V2_PREFIX}/configure/web_security/domain_map",
            json_data=data,
            ok_codes=[HTTPStatus.OK, HTTPStatus.PARTIAL_CONTENT],
        )

    def identification_profiles_list(
        self,
        profile_names: List[str] | None,
    ) -> dict[str, Any]:
        """
        Get identification profiles.

        Args:
            profile_names (List[str] | None): Profile names to list.

        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        params = assign_params(profile_names=",".join(profile_names) if profile_names else None)

        return self._http_request(
            "GET", f"{V3_PREFIX}/web_security/identification_profiles", params=params, ok_codes=[HTTPStatus.OK]
        )

    def identification_profiles_create(
        self,
        profile_name: str,
        status: str,
        description: str,
        order: int | None,
        protocols: List[str],
        proxy_ports: List[str] | None,
        members_by_subnet: List[str] | None,
        predefined_url_categories: List[str] | None,
        custom_url_categories: List[str] | None,
    ) -> dict[str, Any]:
        """
        Create identification profile.

        Args:
            profile_name (str): Identification profile name.
            status (str): Status - enable/disable.
            description (str): Description of identification profile.
            order (int | None): Index of Identification profile in the collection.
            protocols (List[str]): Protocols - HTTPS/SOCKS.
            proxy_ports (List[str] | None): Proxy ports.
            members_by_subnet (List[str] | None): Members by subnet.
            predefined_url_categories (List[str] | None): Predefined URL categories.
            custom_url_categories (List[str] | None): Custom URL categories.

        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """

        data = remove_empty_elements(
            {
                "identification_profiles": [
                    {
                        "profile_name": profile_name,
                        "description": description,
                        "status": status,
                        "order": order,
                        "members": {
                            "protocols": protocols,
                            "proxy_ports": proxy_ports,
                            "ip": members_by_subnet,
                            "url_categories": {
                                "predefined": predefined_url_categories,
                                "custom": custom_url_categories,
                            },
                        },
                    }
                ]
            }
        )

        return self._http_request(
            "POST",
            f"{V3_PREFIX}/web_security/identification_profiles",
            json_data=data,
            resp_type="response",
            ok_codes=[HTTPStatus.NO_CONTENT],
        )

    def identification_profiles_update(
        self,
        profile_name: str,
        new_profile_name: str | None,
        status: str | None,
        description: str | None,
        order: int | None,
        protocols: List[str] | None,
        proxy_ports: List[str] | None,
        members_by_subnet: List[str] | None,
        predefined_url_categories: List[str] | None,
        custom_url_categories: List[str] | None,
    ) -> dict[str, Any]:
        """
        Update identification profile.

        Args:
            profile_name (str): Identification profile name.
            new_profile_name (str | None): Identification profile name to update.
            status (str | None): Status - enable/disable.
            description (str | None): Description of identification profile.
            order (int | None): Index of Identification profile in the collection.
            protocols (List[str] | None): Protocols - HTTPS/SOCKS.
            proxy_ports (List[str] | None): Proxy ports.
            members_by_subnet (List[str] | None): Members by subnet.
            predefined_url_categories (List[str] | None): Predefined URL categories.
            custom_url_categories (List[str] | None): Custom URL categories.

        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """

        data = remove_empty_elements(
            {
                "identification_profiles": [
                    {
                        "profile_name": profile_name,
                        "new_profile_name": new_profile_name,
                        "description": description,
                        "status": status,
                        "order": order,
                        "members": {
                            "protocols": protocols,
                            "proxy_ports": proxy_ports,
                            "ip": members_by_subnet,
                            "url_categories": {
                                "predefined": predefined_url_categories,
                                "custom": custom_url_categories,
                            },
                        },
                    }
                ]
            }
        )

        return self._http_request(
            "PUT",
            f"{V3_PREFIX}/web_security/identification_profiles",
            json_data=data,
            resp_type="response",
            ok_codes=[HTTPStatus.NO_CONTENT],
        )

    def identification_profiles_delete(self, profile_names: List[str]) -> Response:
        """
        Delete identification profiles.

        Args:
            profile_names (List[str]): Identification profile names to delete.

        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        params = assign_params(profile_names=",".join(profile_names))

        return self._http_request(
            "DELETE",
            f"{V3_PREFIX}/web_security/identification_profiles",
            params=params,
            resp_type="response",
            ok_codes=[HTTPStatus.NO_CONTENT, HTTPStatus.MULTI_STATUS],
        )

    def url_categories_list(self) -> dict[str, Any]:
        """
        List URL categories.

        Returns:
            dict[str, Any]: API response from Cisco WSA.
        """
        return self._http_request("GET", f"{V3_PREFIX}/generic_resources/url_categories")


def list_access_policy_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    List access policies.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    policy_names = args.get("policy_names")
    response = client.access_policy_list(policy_names=policy_names).get("access_policies", [])

    paginated_response = pagination(response=response, args=args)
    outputs = access_policy_output_handler(response=paginated_response)

    readable_output = tableToMarkdown(
        name="Access Policies",
        t=outputs,
        headers=[
            "policy_name",
            "policy_status",
            "policy_order",
            "policy_description",
            "policy_expiry",
        ],
        headerTransform=string_to_table_header,
        removeNull=True,
    )

    return CommandResults(
        readable_output=readable_output,
        outputs_prefix="CiscoWSA.AccessPolicy",
        outputs_key_field="policy_name",
        outputs=outputs,
        raw_response=response,
    )


def create_access_policy_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Create an access policy.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """

    policy_name = args["policy_name"]
    policy_status = args["policy_status"]
    policy_order = arg_to_number(args["policy_order"])
    identification_profiles = argToList(args["identification_profiles"])
    policy_description = args.get("policy_description")
    policy_expiry_date = arg_to_datetime(args.get("policy_expiry"))
    policy_expiry = policy_expiry_date.strftime(API_DATE_CONFIG) if policy_expiry_date else None

    client.access_policy_create(
        policy_name=policy_name,
        policy_status=policy_status,
        policy_order=policy_order,
        identification_profiles=identification_profiles,
        policy_description=policy_description,
        policy_expiry=policy_expiry,
    )

    return CommandResults(readable_output=f'Created "{policy_name}" access policy successfully.')


def update_access_policy_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Update an access policy.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    policy_name = args["policy_name"]
    new_policy_name = args.get("new_policy_name")
    policy_status = args.get("policy_status")
    policy_description = args.get("policy_description")
    policy_order = arg_to_number(args.get("policy_order"))
    policy_expiry_date = arg_to_datetime(args.get("policy_expiry"))
    policy_expiry = policy_expiry_date.strftime(API_DATE_CONFIG) if policy_expiry_date else None

    client.access_policy_update(
        policy_name=policy_name,
        new_policy_name=new_policy_name,
        policy_status=policy_status,
        policy_description=policy_description,
        policy_order=policy_order,
        policy_expiry=policy_expiry,
    )

    return CommandResults(
        readable_output=f'Updated "{policy_name}" access policy successfully.',
    )


def update_access_policy_protocols_user_agents_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Update access policy's protocols and user agents settings.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    policy_name = args["policy_name"]
    block_custom_user_agents = argToList(args.get("block_custom_user_agents"))
    allow_connect_ports = argToList(args.get("allow_connect_ports"))
    block_protocols = argToList(args.get("block_protocols"))
    settings_status = args["settings_status"]
    client.access_policy_protocols_user_agents_update(
        policy_name=policy_name,
        block_custom_user_agents=block_custom_user_agents,
        allow_connect_ports=allow_connect_ports,
        block_protocols=block_protocols,
        settings_status=settings_status,
    )

    return CommandResults(
        readable_output=f'Updated "{policy_name}" access policy successfully.',
    )


def update_access_policy_url_filtering_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Update access policy's URL filtering settings.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    policy_name = args["policy_name"]
    predefined_categories_action = args.get("predefined_categories_action")
    predefined_categories = argToList(args.get("predefined_categories"))
    youtube_categories_action = args.get("youtube_categories_action")
    youtube_categories = argToList(args.get("youtube_categories"))
    custom_categories_action = args.get("custom_categories_action")
    custom_categories = argToList(args.get("custom_categories"))
    uncategorized_url = args.get("uncategorized_url")
    update_categories_action = args.get("update_categories_action")
    content_rating_action = args.get("content_rating_action")
    content_rating_status = args.get("content_rating_status")
    safe_search_status = args.get("safe_search_status")
    unsupported_safe_search_engine = args.get("unsupported_safe_search_engine")

    client.access_policy_url_filtering_update(
        policy_name=policy_name,
        predefined_categories_action=predefined_categories_action,
        predefined_categories=predefined_categories,
        youtube_categories_action=youtube_categories_action,
        youtube_categories=youtube_categories,
        custom_categories_action=custom_categories_action,
        custom_categories=custom_categories,
        uncategorized_url=uncategorized_url,
        update_categories_action=update_categories_action,
        content_rating_action=content_rating_action,
        content_rating_status=content_rating_status,
        safe_search_status=safe_search_status,
        unsupported_safe_search_engine=unsupported_safe_search_engine,
    )

    return CommandResults(
        readable_output=f'Updated "{policy_name}" access policy successfully.',
    )


def update_access_policy_applications_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Update access policy's applications settings.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    policy_name = args["policy_name"]
    application = args["application"]
    action = args["action"]
    values = argToList(args["values"])
    settings_status = args["settings_status"]

    client.access_policy_applications_update(
        policy_name=policy_name,
        application=application,
        action=action,
        values=values,
        settings_status=settings_status,
    )

    return CommandResults(
        readable_output=f'Updated "{policy_name}" access policy successfully.',
    )


def update_access_policy_objects_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Update access policy's objects settings.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    policy_name = args["policy_name"]
    object_type = args.get("object_type")
    object_action = args.get("object_action")
    object_values = argToList(args.get("object_values"))
    block_custom_mime_types = argToList(args.get("block_custom_mime_types"))
    http_or_https_max_object_size_mb = arg_to_number(args.get("http_or_https_max_object_size_mb"))
    ftp_max_object_size_mb = arg_to_number(args.get("ftp_max_object_size_mb"))

    objects = access_policy_objects_get(client=client, policy_name=policy_name)

    client.access_policy_objects_update(
        policy_name=policy_name,
        objects=objects,
        object_type=object_type,
        object_action=object_action,
        object_values=object_values,
        block_custom_mime_types=block_custom_mime_types,
        http_or_https_max_object_size_mb=http_or_https_max_object_size_mb,
        ftp_max_object_size_mb=ftp_max_object_size_mb,
    )

    return CommandResults(
        readable_output=f'Updated "{policy_name}" access policy successfully.',
    )


def update_access_policy_anti_malware_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Update access policy's anti-malware and reputation settings.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    policy_name = args["policy_name"]
    web_reputation_status = args.get("web_reputation_status")
    file_reputation_filtering_status = args.get("file_reputation_filtering_status")
    file_reputation_action = args.get("file_reputation_action")
    anti_malware_scanning_status = args.get("anti_malware_scanning_status")
    suspect_user_agent_scanning = args.get("suspect_user_agent_scanning")
    block_malware_categories = argToList(args.get("block_malware_categories"))
    block_other_categories = argToList(args.get("block_other_categories"))
    settings_status = args["settings_status"]
    client.access_policy_anti_malware_update(
        policy_name=policy_name,
        web_reputation_status=web_reputation_status,
        file_reputation_filtering_status=file_reputation_filtering_status,
        file_reputation_action=file_reputation_action,
        anti_malware_scanning_status=anti_malware_scanning_status,
        suspect_user_agent_scanning=suspect_user_agent_scanning,
        block_malware_categories=block_malware_categories,
        block_other_categories=block_other_categories,
        settings_status=settings_status,
    )

    return CommandResults(
        readable_output=f'Updated "{policy_name}" access policy successfully.',
    )


def delete_access_policy_command(client: Client, args: dict[str, Any]) -> Union[List[CommandResults], CommandResults]:
    """
    Delete access policy.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        Union[List[CommandResults], CommandResults]: Readable outputs for XSOAR.
    """
    policy_names = argToList(args["policy_names"])

    response = client.access_policy_delete(policy_names)

    return delete_handler(
        response=response,
        obj_key="policy_name",
        readable_obj_name="Access Policy",
        success_readable_output="Deleted Access policy profiles successfully.",
    )


def list_domain_map_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Get domain mappings.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    domain_names = argToList(args.get("domain_names"))
    ip_addresses = argToList(args.get("ip_addresses"))

    response = client.domain_map_list().get("res_data", [])

    if domain_names or ip_addresses:
        response = [
            domain
            for domain in response
            if domain.get("domain_name") in domain_names or any(address in domain.get("IP_addresses") for address in ip_addresses)
        ]

    paginated_response = pagination(response=response, args=args)

    readable_output = tableToMarkdown(
        name="Domain Map",
        t=paginated_response,
        headers=["domain_name", "IP_addresses", "order"],
        headerTransform=string_to_table_header,
        removeNull=True,
    )

    return CommandResults(
        readable_output=readable_output,
        outputs_prefix="CiscoWSA.DomainMap",
        outputs_key_field="domain_name",
        outputs=paginated_response,
        raw_response=paginated_response,
    )


def create_domain_map_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Create domain mappings.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    domain_name = args["domain_name"]
    ip_addresses = argToList(args["ip_addresses"])
    order = arg_to_number(args["order"])
    if not order:
        raise DemistoException("Please enter correct number to order argument.")
    response = client.domain_map_create(
        domain_name=domain_name,
        ip_addresses=ip_addresses,
        order=order,
    )

    readable_output = f'Domain "{domain_name}" mapping created successfully.'

    return CommandResults(readable_output=readable_output, raw_response=response)


def update_domain_map_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Update domain mappings.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    domain_name = args["domain_name"]
    new_domain_name = args.get("new_domain_name")
    ip_addresses = argToList(args.get("ip_addresses"))
    order = arg_to_number(args.get("order"))

    response = client.domain_map_update(
        domain_name=domain_name,
        new_domain_name=new_domain_name,
        ip_addresses=ip_addresses,
        order=order,
    )

    readable_output = f'Domain "{domain_name}" mapping updated successfully.'

    return CommandResults(readable_output=readable_output, raw_response=response)


def delete_domain_map_command(client: Client, args: dict[str, Any]) -> Union[List[CommandResults], CommandResults]:
    """
    Delete domain mappings.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Raises:
        DemistoException: In cases that the response code is 200 and the output [res_code] is not 200/206.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    domain_name = argToList(args["domain_names"])

    response = client.domain_map_delete(domain_name=domain_name)
    if response.get("res_code") == HTTPStatus.OK:
        readable_output = f'Domain{"s" if len(domain_name) > 1 else ""} "{", ".join(domain_name)}" ' "deleted successfully."  # noqa: ISC001
        return CommandResults(readable_output=readable_output, raw_response=response)
    elif response.get("res_code") == HTTPStatus.PARTIAL_CONTENT:
        command_results_list = []
        for domain_map in dict_safe_get(response, ["res_data", "delete_success"]):
            readable_output = f'Domain "{domain_map}" mapping deleted successfully.'
            command_results_list.append(CommandResults(readable_output=readable_output, raw_response=response))

        readable_output = dict_safe_get(response, ["res_data", "delete_failure", "error_msg"])
        if readable_output:
            command_results_list.append(CommandResults(readable_output=readable_output, raw_response=response))
        return command_results_list
    raise DemistoException(message=response)


def list_identification_profiles_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Get identification profiles.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    profile_names = argToList(args.get("profile_names"))

    response = client.identification_profiles_list(profile_names=profile_names).get("identification_profiles", [])

    paginated_response = pagination(response, args)

    readable_output = tableToMarkdown(
        name="Identification Profiles",
        t=paginated_response,
        headers=[
            "order",
            "profile_name",
            "status",
            "description",
            "members",
            "identification_method",
        ],
        headerTransform=string_to_table_header,
        removeNull=True,
    )
    filtered_data = identification_profile_mapper(paginated_response)
    return CommandResults(
        readable_output=readable_output,
        outputs_prefix="CiscoWSA.IdentificationProfile",
        outputs_key_field="profile_name",
        outputs=filtered_data,
        raw_response=paginated_response,
    )


def create_identification_profiles_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Create identification profiles.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    profile_name = args["profile_name"]

    client.identification_profiles_create(
        status=args["status"],
        description=args["description"],
        profile_name=profile_name,
        order=arg_to_number(args["order"]),
        protocols=protocols_handler(protocols=argToList(args["protocols"])),
        proxy_ports=argToList(args.get("proxy_ports")),
        members_by_subnet=argToList(args.get("members_by_subnet")),
        predefined_url_categories=argToList(args.get("predefined_url_categories")),
        custom_url_categories=argToList(args.get("custom_url_categories")),
    )

    return CommandResults(readable_output=f'Created identification profile "{profile_name}" successfully.')


def update_identification_profiles_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Update identification profiles.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    profile_name = args["profile_name"]
    client.identification_profiles_update(
        profile_name=profile_name,
        new_profile_name=args.get("new_profile_name"),
        description=args.get("description"),
        status=args.get("status"),
        protocols=protocols_handler(protocols=argToList(args.get("protocols"))),
        order=arg_to_number(args.get("order")),
        proxy_ports=argToList(args.get("proxy_ports")),
        members_by_subnet=argToList(args.get("members_by_subnet")),
        predefined_url_categories=argToList(args.get("predefined_url_categories")),
        custom_url_categories=argToList(args.get("custom_url_categories")),
    )

    return CommandResults(readable_output=f'Updated identification profile "{profile_name}" successfully.')


def delete_identification_profiles_command(client: Client, args: dict[str, Any]) -> Union[List[CommandResults], CommandResults]:
    """
    Delete identification profiles.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    profile_names = argToList(args.get("profile_names"))

    response = client.identification_profiles_delete(profile_names)

    return delete_handler(
        response=response,
        obj_key="profile_name",
        readable_obj_name="Identification profile",
        success_readable_output="Deleted identification profiles successfully.",
    )


def list_url_categories_command(client: Client, args: dict[str, Any]) -> CommandResults:
    """
    Get URL categories.

    Args:
        client (Client): Cisco WSA API client.
        args (dict[str, Any]): Command arguments from XSOAR.

    Returns:
        CommandResults: readable outputs for XSOAR.
    """
    response = client.url_categories_list()

    outputs = categories_output_filter(response=response, contain=args.get("contain"), type_=args.get("type"))

    readable_output = tableToMarkdown(
        name="URL categories",
        t=outputs,
        headerTransform=string_to_table_header,
        removeNull=True,
    )

    return CommandResults(
        readable_output=readable_output,
        outputs_prefix="CiscoWSA.UrlCategory",
        outputs=outputs,
        raw_response=response,
    )


def test_module(client: Client) -> str:
    """
    Validates the correctness of the instance parameters and connectivity to Cisco WSA API service.

    Args:
        client (Client): Cisco WSA API client.
    """
    client.url_categories_list()
    return "ok"


""" HELPER FUNCTIONS """


def categories_output_filter(response: dict[str, Any], contain: str | None = None, type_: str | None = None) -> dict[str, Any]:
    """Filter categories response.

    Args:
        response (dict[str, Any]): API response.
        contain (str | None, optional): A string that contains in the categories. Defaults to None.
        type_ (str | None, optional): The type of the categories. Defaults to None.

    Returns:
        dict[str, Any]: Filtered output.
    """
    outputs: dict[str, Any] = {}
    if all([not contain, not type_]):
        return response
    if type_ is not None:
        response = {type_: response.get(type_)}.copy()
        if not contain:
            return response
    if contain is not None:
        for key, categories in response.items():
            for category in categories:
                if contain in category:
                    if isinstance(outputs.get(key), list):
                        outputs[key].append(category)
                    else:
                        outputs[key] = [category]
    return outputs


def multi_status_delete_handler(response: Response, obj_key: str, readable_obj_name: str) -> List[CommandResults]:
    """Handling with 207 delete code response, in cases that some of the objects deleted and some didn't.

    Args:
        response (Response): API response from Cisco WSA (with 207 status code).
        obj_key (str): The key of the argument in the response.
        readable_obj_name (str): Readable name for the object.

    Returns:
        List[CommandResults]: Readable outputs for XSOAR.
    """
    output_data = response.json()
    command_results_list = []
    for profile in output_data.get("success_list"):
        readable_output = f'{readable_obj_name} "{profile.get(obj_key)}" was successfully deleted.'
        command_results_list.append(CommandResults(readable_output=readable_output))
    for profile in output_data.get("failure_list"):
        readable_output = f'{readable_obj_name} "{profile.get(obj_key)}" deletion failed, message: "{profile.get("message")}".'
        command_results_list.append(CommandResults(readable_output=readable_output))

    return command_results_list


def identification_profile_mapper(data: List[dict[str, Any]]) -> List[dict[str, Any]]:
    """Map API identification profile response to XSOAR output.

    Args:
        data (List[dict[str, Any]]): API response from Cisco WSA.

    Returns:
        List[dict[str, Any]]: Identification profile output.
    """
    filtered_data = []
    for profile in data:
        filtered_data.append(
            {
                "status": profile["status"],
                "profile_name": profile["profile_name"],
                "description": profile["description"],
                "protocols": dict_safe_get(profile, ["members", "protocols"]),
                "order": profile["order"],
                "UrlCategories": {
                    "predefined": dict_safe_get(profile, ["members", "url_categories", "predefined"]),
                    "custom": dict_safe_get(profile, ["members", "url_categories", "custom"]),
                    "uncategorized": dict_safe_get(profile, ["members", "url_categories", "uncategorized"]),
                },
                "ip": dict_safe_get(profile, ["members", "ip"]),
                "proxy_port": dict_safe_get(profile, ["members", "proxy_port"]),
                "UserAgents": {
                    "predefined": dict_safe_get(profile, ["members", "user_agents", "predefined"]),
                    "custom": dict_safe_get(profile, ["members", "user_agents", "custom"]),
                },
            }
        )
    return remove_empty_elements(filtered_data)


def access_policy_output_handler(response: List[dict[str, Any]]) -> List[dict[str, Any]]:
    """Handling with access policy handler (ISO 8061), updating to XSOAR standards.

    Args:
        response (List[dict[str, Any]]): Access policy response.

    Returns:
        List[dict[str, Any]]: Fixed outputs
    """
    outputs = []
    for policy in response:
        if (policy_expiry := policy.get("policy_expiry")) and (policy_datetime := arg_to_datetime(policy_expiry)):
            policy["policy_expiry"] = policy_datetime.strftime(ISO8601_CONFIG)

        outputs.append(policy)
    return outputs


def pagination(response: List[dict[str, Any]], args: dict[str, Any]) -> List[dict[str, Any]]:
    """
    Executing Manual paginate_results (using the page and page size arguments)

    Args:
        response (List[dict[str, Any]]): API response.
        args (dict[str, Any]): Command arguments from XSOAR.
    Returns:
        List[dict[str, Any]]: Paginated results.
    """
    page = arg_to_number(args.get("page"))
    page_size = arg_to_number(args.get("page_size"))
    limit = arg_to_number(args.get("limit"))

    if limit and limit < 0:
        raise ValueError("Limit has to be positive number.")
    if page and page < 0:
        raise ValueError("page has to be positive number.")
    if page_size and page_size < 0:
        raise ValueError("page_size has to be positive number.")
    if (page and not page_size) or (not page and page_size):
        raise ValueError("Please insert page and page_size.")
    if page and page_size:
        offset = (page - 1) * page_size
        return response[offset : offset + page_size]
    else:
        return response[:limit]


def organize_policy_object_data(
    objects: dict[str, Any],
    object_type: str | None,
    object_action: str | None,
    object_values: List[str] | None,
    block_custom_mime_types: List[str] | None,
    http_or_https_max_object_size_mb: int | None,
    ftp_max_object_size_mb: int | None,
):
    """
    Organize policy object update data.

    Args:
        objects (dict[str, Any]): Original objects.
        object_type (str | None): Object type to update.
        object_action (str | None): Object action to update.
        object_values (List[str] | None): Object values to update.
        block_custom_mime_types (List[str] | None): Block custom MIME types.
        http_or_https_max_object_size_mb (int | None): HTTP(S) max object size MB.
        ftp_max_object_size_mb (int | None): FTP max object size MB.
    """
    if object_type and object_action and object_values:
        original_obj_actions = dict_safe_get(objects, ["object_type", object_type])
        if original_obj_actions:
            for original_obj_action in original_obj_actions:
                if original_obj_action == object_action:
                    object_values.extend(dict_safe_get(objects, ["object_type", object_type, object_action]))
                else:
                    original_obj_actions[original_obj_action] = [
                        value for value in original_obj_actions[original_obj_action] if value not in object_values
                    ]

            objects["object_type"][object_type].update({object_action: object_values})

    elif any([object_type, object_action, object_values]):
        raise ValueError("object_type, object_action, object_values should be used in conjunction.")
    if block_custom_mime_types:
        objects["block_custom_mime_types"] = block_custom_mime_types

    objects["max_object_size_mb"] = remove_empty_elements(
        {
            "http_or_https": http_or_https_max_object_size_mb,
            "ftp": ftp_max_object_size_mb,
        }
    )


def access_policy_objects_get(client: Client, policy_name: str) -> dict[str, Any]:
    """Get the objects data of access policy.

    Args:
        client (Client): Cisco WSA API client.
        policy_name (str): The access policy name.

    Raises:
        DemistoException: Policy was not found.
        DemistoException: Update failed, objects were not found.

    Returns:
        dict[str, Any]: Objects data.
    """
    access_policies = client.access_policy_list(policy_name).get("access_policies", [])
    if not access_policies:
        raise DemistoException("Policy was not found.")

    if not access_policies[0].get("objects"):
        raise DemistoException("Update failed, objects were not found.")

    return access_policies[0].get("objects")


def protocols_handler(protocols: List[str]) -> List[str]:
    """Protocols handler.

    Args:
        protocols (List[str]): User chosen protocol.

    Returns:
        List[str]: Organized protocols list.
    """
    organized_protocols = []
    if "HTTPS" in protocols:
        organized_protocols.extend(HTTPS_PROTOCOLS)
    if "SOCKS" in protocols:
        organized_protocols.extend(SOCKS_PROTOCOL)
    return organized_protocols


def delete_handler(
    response: Response, obj_key: str, readable_obj_name: str, success_readable_output: str
) -> CommandResults | List[CommandResults]:
    """Handling with delete response.

    Args:
        response (Response): API response from Cisco WSA (with 207 status code).
        obj_key (str): The key of the argument in the response.
        readable_obj_name (str): Readable name for the object.
        success_readable_output (str): Readable output text for success.

    Returns:
        CommandResults | List[CommandResults]: Readable outputs for XSOAR.
    """
    if response.status_code == HTTPStatus.MULTI_STATUS:
        return multi_status_delete_handler(response=response, obj_key=obj_key, readable_obj_name=readable_obj_name)

    return CommandResults(readable_output=success_readable_output)


def main() -> None:
    params: dict[str, Any] = demisto.params()
    args: dict[str, Any] = demisto.args()

    base_url = params.get("base_url")
    username = params.get("credentials", {}).get("identifier")
    password = params.get("credentials", {}).get("password")

    verify_certificate: bool = not params.get("insecure", False)
    proxy = params.get("proxy", False)

    command = demisto.command()

    commands = {
        "cisco-wsa-access-policy-list": list_access_policy_command,
        "cisco-wsa-access-policy-create": create_access_policy_command,
        "cisco-wsa-access-policy-update": update_access_policy_command,
        "cisco-wsa-access-policy-protocols-user-agents-update": update_access_policy_protocols_user_agents_command,
        "cisco-wsa-access-policy-url-filtering-update": update_access_policy_url_filtering_command,
        "cisco-wsa-access-policy-applications-update": update_access_policy_applications_command,
        "cisco-wsa-access-policy-objects-update": update_access_policy_objects_command,
        "cisco-wsa-access-policy-anti-malware-update": update_access_policy_anti_malware_command,
        "cisco-wsa-access-policy-delete": delete_access_policy_command,
        "cisco-wsa-domain-map-list": list_domain_map_command,
        "cisco-wsa-domain-map-create": create_domain_map_command,
        "cisco-wsa-domain-map-update": update_domain_map_command,
        "cisco-wsa-domain-map-delete": delete_domain_map_command,
        "cisco-wsa-identification-profiles-list": list_identification_profiles_command,
        "cisco-wsa-identification-profiles-create": create_identification_profiles_command,
        "cisco-wsa-identification-profiles-update": update_identification_profiles_command,
        "cisco-wsa-identification-profiles-delete": delete_identification_profiles_command,
        "cisco-wsa-url-categories-list": list_url_categories_command,
    }
    try:
        client: Client = Client(
            urljoin(base_url, "/wsa/api"),
            username,
            password,
            verify_certificate,
            proxy,
        )

        if command == "test-module":
            return_results(test_module(client))
        elif command in commands:
            return_results(commands[command](client, args))
        else:
            raise NotImplementedError(f"{command} command is not implemented.")

    except Exception as e:
        return_error(str(e))


if __name__ in ["__main__", "builtin", "builtins"]:
    main()