diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ddbd2d6f067f..344cfab7f508 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -26,6 +26,7 @@ /Packs/ContentManagement/* @adi88d /Packs/TAXIIServer/Integrations/TAXII2Server/* @Ni-Knight /Packs/FeedTAXII/Integrations/FeedTAXII2/* @Ni-Knight +/Packs/rasterize/Integrations/rasterize/* @ilaredo # Important Scripts /Packs/CommonScripts/Scripts/SetGridField/* @altmannyarden diff --git a/.github/content_roles.json b/.github/content_roles.json index 9397e327741e..04edef36496d 100644 --- a/.github/content_roles.json +++ b/.github/content_roles.json @@ -11,11 +11,11 @@ "aaron1535" ], "CONTRIBUTION_TL": "jbabazadeh", - "CONTRIBUTION_SECURITY_REVIEWER": ["tomer-pan"], + "CONTRIBUTION_SECURITY_REVIEWER": ["idovandijk"], "ON_CALL_DEVS": [ "sshuker", - "acarmi" + "yhayun" ], - "DOC_REVIEWER": "ShirleyDenkberg", + "DOC_REVIEWER": "richardbluestone", "TIM_REVIEWER": "MLainer1" } diff --git a/.github/github_workflow_scripts/handle_external_pr.py b/.github/github_workflow_scripts/handle_external_pr.py index c33977dbac97..c8432b53f8f7 100755 --- a/.github/github_workflow_scripts/handle_external_pr.py +++ b/.github/github_workflow_scripts/handle_external_pr.py @@ -589,9 +589,6 @@ def main(): f'(https://xsoar.pan.dev/docs/packs/packs-format#contributorsjson).' if XSOAR_SUPPORT_LEVEL_LABEL or COMMUNITY_SUPPORT_LEVEL_LABEL in labels_to_add and ver != '1.0.0': pr.create_issue_comment(contributors_body) - pr.create_issue_comment('Hello,\nThank you for your contribution.\nUnfortunately, your PR review will be slightly delayed ' - 'because of an Israeli holiday in the upcoming two weeks (16-26.10.24). Thank you in advance ' - 'for the patience.') if __name__ == "__main__": diff --git a/.pre-commit-config_template.yaml b/.pre-commit-config_template.yaml index c49315c95529..3b5221e9cf3b 100644 --- a/.pre-commit-config_template.yaml +++ b/.pre-commit-config_template.yaml @@ -16,7 +16,9 @@ repos: min_py_version: '3.7' files: .+_test.py$ - id: check-added-large-files - args: ['--maxkb=5120'] + args: ['--maxkb=5120', --enforce-all] + skip:nightly: true + - id: check-case-conflict - repo: https://github.com/python-poetry/poetry rev: 1.8.2 hooks: diff --git a/Documentation/doc-howto.json b/Documentation/doc-howto.json index baf0c0dd9b4b..917e11d611ad 100644 --- a/Documentation/doc-howto.json +++ b/Documentation/doc-howto.json @@ -20,7 +20,7 @@ "editorType": "automation" }, { - "body": "\u003col\u003e\n \u003cli\u003e\n \u003cstrong\u003eReturn result as simple text entry to the War Room\u003c/strong\u003e\u003cbr\u003e\n return \"Mission Accomplished\";\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eReturn result as a complex entry to the War Room\u003c/strong\u003e\u003cbr\u003e\n \u003ch3\u003eFields\u003c/h3\u003e\n \u003ctable style=\"height:26px\" width=\"409\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:405px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eField\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Type\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExpected Values\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e\u003cspan style=\"font-size:13px\"\u003e:\u0026nbsp;\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003eThe value is the number that corresponds to the entry type: \"1 (note)\", \"3 (file)\", \"4 (error)\", \"7 (image)\". There are several additional entry types that Demisto uses internally. \u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eDescription\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Specifies the type of entry. Default is \"note\".\u0026nbsp;\u003c/span\u003e\u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExample\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Specifies the type of entry. Default is \"note\".\u0026nbsp;\u003c/span\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cbr\u003e\n \u003ctable style=\"height:26px\" width=\"409\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:405px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eField\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Contents\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExpected Values\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: N/A\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eDescription\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Raw data of the command or script. If no HumanReadable is provided, this also displays in the War Room.\u003c/span\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cbr\u003e\n \u003ctable style=\"height:88px\" width=\"433\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:429px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eField\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: ContentsFormat\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExpected Values\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: \"json\", \"markdown\", \"text\", \"image\", \"html\"\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eDescription\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Format of the content from the Content field.\u003c/span\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cbr\u003e\n \u003ctable style=\"height:26px\" width=\"409\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:405px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eField\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: HumanReadable\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExpected Values\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: N/A\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eDescription\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Content that displays in the War Room.\u003c/span\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cbr\u003e\n \u003ctable style=\"height:26px\" width=\"409\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:405px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eField\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: ReadableContentsFormat\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExpected Values\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: \"json\", \"markdown\"\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eDescription\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Format of the content from the HumanReadable field.\u003c/span\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cbr\u003e\n \u003ctable style=\"height:26px\" width=\"409\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:405px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eField\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: EntryContext\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExpected Values\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: N/A\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eDescription\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Data added to the investigation context (Output Context), which you can use in playbooks.\u003c/span\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cbr\u003e\n \u003ctable style=\"height:26px\" width=\"409\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:405px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eField\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Tags\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExpected Values\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: List of strings\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eDescription\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Tags to apply to the War Room entry.\u003c/span\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cbr\u003e\n \u003ch3\u003eExample\u003c/h3\u003e\n \u003cp\u003e\n entry = {'Type' : entryTypes.note,\u003cbr\u003e\n 'Contents': data,\u003cbr\u003e\n 'ContentsFormat' : formats.json,\u003cbr\u003e\n 'HumanReadable': md,\u003cbr\u003e\n 'ReadableContentsFormat' : formats.markdown,\u003cbr\u003e\n 'EntryContext' : context,\u003cbr\u003e\n 'Tags' : ['tag1', 'tag2']}\n \u003c/p\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eReturn data to the War Room as a file\u003c/strong\u003e\u003cbr\u003e\n return saveFile(res.Body);\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eReturn an error to the War Room\u003c/strong\u003e\u003cbr\u003e\n return { ContentsFormat: formats.text, Type: entryTypes.error, Contents:\n 'First part of the script failed.' };\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eReturn multiple entries to the War Room\u003cbr\u003e\u003c/strong\u003evar output =\n [];\u003cbr\u003e\n output.push( { ContentsFormat: formats.text, Type: entryTypes.error, Contents:\n 'First part of the script failed.' } );\u003cbr\u003e\n output.push( { ContentsFormat: formats.text, Type: entryTypes.note, Contents:\n 'Second part of the script completed successfully.' } );\u003cbr\u003e\n return output;\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eGetting time and other metadata for War Room entries\u003c/strong\u003e\u003cbr\u003e\n !js script=\"e = executeCommand('getEntry', {id: '270@4dfc3b65-9da2-46c5-8751-ebe959f31a7b'});\n return e[0].Metadata.Created;\"\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eGetting metadata for War Room entries in JSON\u003c/strong\u003e\u003cbr\u003e\n !js script=\"e = executeCommand('getEntry', {id: '60@4751'}); return JSON.stringify(e[0].Metadata,\n null, 2);\"\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eExecute Commands\u003c/strong\u003e\u003cbr\u003e\n var arrResultEntries = executeCommand('ip', { ip: '8.8.8.8' } );\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eGet Context value\u003c/strong\u003e\u003cbr\u003e\n Fetches the value from the context by it's key. dq(invContext,'key.path')\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eSet Context\u003c/strong\u003e\u003cbr\u003e\n setContext(args.key, args.value);\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eSend notifications (e.g. Email)\u003c/strong\u003e\u003cbr\u003e\n var arrResultEntries = executeCommand('send-mail', { to : 'user@domain.com',\n cc : 'also@domain.com', subject : 'Update on Demisto investigation', body\n : 'Contents of your message.'\u0026nbsp; });\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eSending an HTTP request or file\u003c/strong\u003e\u003cbr\u003e\n http(url,{Method: method,Headers: headers,Body: body, Username: username,Password:\n password},params.insecure,params.proxy);\u003cbr\u003e\n httpMultipart(url,file_id,{Headers: headers, Username: username,Password:\n password},body,params.insecure,params.proxy,false,'uploadFile', file_name,true);\u003cbr\u003e\n \u003cstrong\u003ehttp\u003c/strong\u003e sends a request and receives a response and\u0026nbsp;\u003cstrong\u003ehttpMultipart\u003c/strong\u003e\n sends a file in HTTP protocol\u003cbr\u003e\n where:\u003cbr\u003e\n \u003cstrong\u003eURL\u003c/strong\u003e: the site url (mandatory)\u003cbr\u003e\n method is the http method such as 'GET', 'POST', 'PUT' (mandatory)\u003cbr\u003e\n fileID is the entry ID of the file in the War room\u003cbr\u003e\n headers is the HTTP request headers\u003cbr\u003e\n body is the http request body\u003cbr\u003e\n username and password are the authentication details if needed\u003cbr\u003e\n insecure is a Boolean parameter that is true if secure and false if not secure.\u003cbr\u003e\n proxy is a Boolean parameter that is true to use proxy and false if not use\n proxy.\u003cbr\u003e\n file_name is the name of the file that is sent. Can be different than the\n file ID.;\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eHandle Errors\u003c/strong\u003e\u003cbr\u003e\n \u003ctable style=\"height:452px\" width=\"720\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:716px;background-color:#d3d3d3\"\u003e\n \u003col\u003e\n \u003cli\u003e\n \u003cp\u003eif (res[0].Type == entryTypes.error) {\u003c/p\u003e\n \u003cp\u003e\n \u0026nbsp;\u0026nbsp;\u0026nbsp; // Return the error to war\n room no results to parse.\n \u003c/p\u003e\n \u003cp\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp; return res[0];\u003c/p\u003e\n \u003cp\u003e} else {\u003c/p\u003e\n \u003cp\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp; var usersOnCall = res[0].Contents;\u003c/p\u003e\n \u003cp\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp; var selectedUser = usersOnCall[0];\u003c/p\u003e\n \u003cp\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp; if (selectedUser === null) {\u003c/p\u003e\n \u003cp\u003e\n return { ContentsFormat: formats.text, Type:\n entryTypes.error, Contents: 'error : did not\n receive any users from PagerDutyGetUsersOnCallNow!'\n };\n \u003c/p\u003e\n \u003cp\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp; } else {\u003c/p\u003e\n \u003cp\u003e\n \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;return\n selectedUser.name;\n \u003c/p\u003e\n \u003cp\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp; }\u003c/p\u003e\n }var res = executeCommand('PagerDutyGetUsersOnCallNow',\n { });\n \u003c/li\u003e\n \u003c/ol\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eExecute Another Script\u003cbr\u003e\u003c/strong\u003eYou can execute other scripts\n just as you execute commands, using `executeCommand`.\n \u003cp\u003e\n var arrResultEntries = executeCommand('IPReputation', { ip: '8.8.8.8'\n } );\n \u003c/p\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eSave data in playbook\u003cbr\u003e\u003c/strong\u003e\n \u003cp\u003e\n Saves data into context for later task scripts within the currently executing\n playbook.\n \u003c/p\u003e\n \u003cp\u003esetContext('myIPs', ['1.1.1.1','2.2.2.2']);\u003c/p\u003e\n \u003cp\u003esetContext('sender', 'john@acme.com');\u003c/p\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cp\u003e\n \u003cstrong\u003eFormat Results as a table\u003cbr\u003e\u003c/strong\u003eIn addition to plain text,\n you can return results to the war room formatted as a table. Error entries\n can also be formatted as tables, by setting the `entryType` to `error`.\n \u003c/p\u003e\n \u003cp\u003e\n rows = [ { col1 : 'val1', col2 : 1 } , { col1 : 'val2', col2 : 2 } ]\n \u003c/p\u003e\n \u003cp\u003e\n return {ContentsFormat: formats.table, Type: entryTypes.note, Contents:\n rows};\n \u003c/p\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eFormat Results using Markdown\u003c/strong\u003e\u003cbr\u003e\n \u003cp\u003e\n Results can also be formatted using\n \u003ca href=\"https://en.wikipedia.org/wiki/Markdown\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eMarkdown\u003c/a\u003e.\n \u003c/p\u003e\n \u003cp\u003evar res = '## My title\\n### My subsection\\n'\u003c/p\u003e\n \u003cp\u003e\n rows = [ { col1 : 'val1', col2 : 1 } , { col1 : 'val2', col2 : 2 } ]\n \u003c/p\u003e\n \u003cp\u003emarkdownBasedTable = 'num|col1|col2\\n'\u003c/p\u003e\n \u003cp\u003emarkdownBasedTable += '---|---|---\\n'\u003c/p\u003e\n \u003cp\u003efor (var i = 0; i \u0026lt; rows.length; i++)\u003c/p\u003e\n \u003cp\u003e\n markdownBasedTable += (i+1) + '|' + rows[i].col1 + '|' + rows[i].col2\n + '\\n'\n \u003c/p\u003e\n \u003cp\u003eres += markdownBasedTable\u003c/p\u003e\n return { ContentsFormat: formats.markdown, Type: entryTypes.note, Contents:\n res } ;\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eSet Results As Notes\u003c/strong\u003e\u003cbr\u003e\n \u003cp\u003eResults can be set as notes\u003c/p\u003e\n \u003cp\u003evar res = '## This is a note\\n';\u003c/p\u003e\n \u003cp\u003eres += 'It has important information\\n';\u003c/p\u003e\n return { ContentsFormat: formats.markdown, Type: entryTypes.note, Contents:\n res, Note: true } ;\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eBase 64\u003cbr\u003e\u003c/strong\u003e\n \u003cp\u003ebtoa: encode string to base 64\u003c/p\u003e\n \u003cp\u003eatob: decode base 64 to string\u003c/p\u003e\n \u003cp\u003e\n entrytoa: gets a file entry ID and returns the file in base 64.\n \u003c/p\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eAccess Investigation Metadata\u003c/strong\u003e\n \u003cp\u003e\n When you run a script in a War Room, whether manually or through a playbook,\n sometimes there is a need to access the investigation metadata, which\n is accessible through the `investigation` and `incidents` objects which\n are mapped into the script by the platform. Try the following example\n in a war room, and in the playground, to see the structure of the object\n in different investigations. Then you can extract the fields that interest\n your for your script's logic and purpose.\n \u003c/p\u003e\n \u003cp\u003eTo see the structure of the investigation metadata object:\u003c/p\u003e\n \u003cp\u003ereturn investigation;\u003c/p\u003e\n \u003cp\u003eTo see the structure of the incidents metadata object:\u003c/p\u003e\n \u003cp\u003ereturn incidents;\u003c/p\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003ePrinting to Log\u003cbr\u003e\u003c/strong\u003e\n \u003cp\u003eTo print to war room: log(...)\u003c/p\u003e\n \u003cp\u003eTo print to demisto log in INFO: logInfo(...)\u003c/p\u003e\n \u003cp\u003eTo print to demisto log in DEBUG: logDebug(...)\u003c/p\u003e\n \u003cp\u003eTo print to demisto log in ERROR: logError(...)\u003c/p\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eClose the current investigation\u003cbr\u003e\u003c/strong\u003ecloseInvestigation({Reason:\n 'Automated malware playbook completed.'});\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eAdvanced How To\u003cbr\u003e\u003c/strong\u003eTo be added soon:\u003cbr\u003e\n 1. Access War Room entries from within a script – return entries matching\n a specific condition, aggregate content from entries, run a regex-based search\n against all text in the war room to collect a list of identifiers, and more.\u003cbr\u003e\n 2. Send files from war room as email attachments.\u003cbr\u003e\n 3. Access context data directly disregarding arguments.\u003cbr\u003e\n 4.More tips and use cases to come.\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eReturn a map to the War Room\u003c/strong\u003e\u003cbr\u003e\n return {\u003cbr\u003e\n Type: entryTypes.map,\u003cbr\u003e\n ContentsFormat: formats.json,\u003cbr\u003e\n Contents: {\u003cbr\u003e\n lat: \u0026lt;latitude-coordinate\u0026gt;,\u003cbr\u003e\n lng: \u0026lt;longitude-coordinate\u0026gt;,\u003cbr\u003e\n }\u003cbr\u003e\n };\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eIncident Severity Levels\u003c/strong\u003e\u003cbr\u003e\n \u003cul\u003e\n \u003cli\u003eUnknown: 0\u003c/li\u003e\n \u003cli\u003eInformational: 0.5\u003c/li\u003e\n \u003cli\u003eLow: 1\u003c/li\u003e\n \u003cli\u003eMedium: 2\u003c/li\u003e\n \u003cli\u003eHigh: 3\u003c/li\u003e\n \u003cli\u003eCritical: 4\u003c/li\u003e\n \u003c/ul\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eIncident Statuses\u003c/strong\u003e\u003cbr\u003e\n \u003cul\u003e\n \u003cli\u003ePending: 0\u003c/li\u003e\n \u003cli\u003eActive: 1\u003c/li\u003e\n \u003cli\u003eDone: 2\u003c/li\u003e\n \u003cli\u003eArchive: 3\u003c/li\u003e\n \u003c/ul\u003e\n \u003c/li\u003e\n\u003c/ol\u003e", + "body": "\u003col\u003e\n \u003cli\u003e\n \u003cstrong\u003eReturn result as simple text entry to the War Room\u003c/strong\u003e\u003cbr\u003e\n return \"Mission Accomplished\";\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eReturn result as a complex entry to the War Room\u003c/strong\u003e\u003cbr\u003e\n \u003ch3\u003eFields\u003c/h3\u003e\n \u003ctable style=\"height:26px\" width=\"409\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:405px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eField\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Type\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExpected Values\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e\u003cspan style=\"font-size:13px\"\u003e:\u0026nbsp;\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003eThe value is the number that corresponds to the entry type: \"1 (note)\", \"3 (file)\", \"4 (error)\", \"7 (image)\". There are several additional entry types that Demisto uses internally. \u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eDescription\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Specifies the type of entry. Default is \"note\".\u0026nbsp;\u003c/span\u003e\u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExample\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Specifies the type of entry. Default is \"note\".\u0026nbsp;\u003c/span\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cbr\u003e\n \u003ctable style=\"height:26px\" width=\"409\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:405px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eField\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Contents\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExpected Values\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: N/A\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eDescription\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Raw data of the command or script. If no HumanReadable is provided, this also displays in the War Room.\u003c/span\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cbr\u003e\n \u003ctable style=\"height:88px\" width=\"433\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:429px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eField\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: ContentsFormat\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExpected Values\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: \"json\", \"markdown\", \"text\", \"image\", \"html\"\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eDescription\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Format of the content from the Content field.\u003c/span\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cbr\u003e\n \u003ctable style=\"height:26px\" width=\"409\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:405px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eField\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: HumanReadable\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExpected Values\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: N/A\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eDescription\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Content that displays in the War Room.\u003c/span\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cbr\u003e\n \u003ctable style=\"height:26px\" width=\"409\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:405px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eField\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: ReadableContentsFormat\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExpected Values\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: \"json\", \"markdown\"\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eDescription\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Format of the content from the HumanReadable field.\u003c/span\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cbr\u003e\n \u003ctable style=\"height:26px\" width=\"409\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:405px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eField\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: EntryContext\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExpected Values\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: N/A\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eDescription\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Data added to the investigation context (Output Context), which you can use in playbooks.\u003c/span\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cbr\u003e\n \u003ctable style=\"height:26px\" width=\"409\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:405px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eField\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Tags\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eExpected Values\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: List of strings\u0026nbsp;\u003c/span\u003e\u003cbr style=\"font-size:13px\"\u003e\n \u003cspan style=\"font-weight:bolder;font-size:13px\"\u003eDescription\u003c/span\u003e\u003cspan style=\"font-size:13px\"\u003e: Tags to apply to the War Room entry.\u003c/span\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003cbr\u003e\n \u003ch3\u003eExample\u003c/h3\u003e\n \u003cp\u003e\n entry = {'Type' : entryTypes.note,\u003cbr\u003e\n 'Contents': data,\u003cbr\u003e\n 'ContentsFormat' : formats.json,\u003cbr\u003e\n 'HumanReadable': md,\u003cbr\u003e\n 'ReadableContentsFormat' : formats.markdown,\u003cbr\u003e\n 'EntryContext' : context,\u003cbr\u003e\n 'Tags' : ['tag1', 'tag2']}\n \u003c/p\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eReturn data to the War Room as a file\u003c/strong\u003e\u003cbr\u003e\n return saveFile(res.Body);\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eReturn an error to the War Room\u003c/strong\u003e\u003cbr\u003e\n return { ContentsFormat: formats.text, Type: entryTypes.error, Contents:\n 'First part of the script failed.' };\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eReturn multiple entries to the War Room\u003cbr\u003e\u003c/strong\u003evar output =\n [];\u003cbr\u003e\n output.push( { ContentsFormat: formats.text, Type: entryTypes.error, Contents:\n 'First part of the script failed.' } );\u003cbr\u003e\n output.push( { ContentsFormat: formats.text, Type: entryTypes.note, Contents:\n 'Second part of the script completed successfully.' } );\u003cbr\u003e\n return output;\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eGetting time and other metadata for War Room entries\u003c/strong\u003e\u003cbr\u003e\n !js script=\"e = executeCommand('getEntry', {id: '270@4dfc3b65-9da2-46c5-8751-ebe959f31a7b'});\n return e[0].Metadata.Created;\"\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eGetting metadata for War Room entries in JSON\u003c/strong\u003e\u003cbr\u003e\n !js script=\"e = executeCommand('getEntry', {id: '60@4751'}); return JSON.stringify(e[0].Metadata,\n null, 2);\"\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eExecute Commands\u003c/strong\u003e\u003cbr\u003e\n var arrResultEntries = executeCommand('ip', { ip: '8.8.8.8' } );\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eGet Context value\u003c/strong\u003e\u003cbr\u003e\n Fetches the value from the context by it's key. dq(invContext,'key.path')\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eSet Context\u003c/strong\u003e\u003cbr\u003e\n setContext(args.key, args.value);\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eSend notifications (e.g. Email)\u003c/strong\u003e\u003cbr\u003e\n var arrResultEntries = executeCommand('send-mail', { to : 'user@domain.com',\n cc : 'also@domain.com', subject : 'Update on Demisto investigation', body\n : 'Contents of your message.'\u0026nbsp; });\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eSending an HTTP request or file\u003c/strong\u003e\u003cbr\u003e\n http(url,{Method: method,Headers: headers,Body: body, Username: username,Password:\n password},params.insecure,params.proxy);\u003cbr\u003e\n httpMultipart(url,file_id,{Headers: headers, Username: username,Password:\n password},body,params.insecure,params.proxy,false,'uploadFile', file_name,true);\u003cbr\u003e\n \u003cstrong\u003ehttp\u003c/strong\u003e sends a request and receives a response and\u0026nbsp;\u003cstrong\u003ehttpMultipart\u003c/strong\u003e\n sends a file in HTTP protocol\u003cbr\u003e\n where:\u003cbr\u003e\n \u003cstrong\u003eURL\u003c/strong\u003e: the site url (mandatory)\u003cbr\u003e\n method is the http method such as 'GET', 'POST', 'PUT' (mandatory)\u003cbr\u003e\n fileID is the entry ID of the file in the War room\u003cbr\u003e\n headers is the HTTP request headers\u003cbr\u003e\n body is the http request body\u003cbr\u003e\n username and password are the authentication details if needed\u003cbr\u003e\n insecure is a Boolean parameter that is true if secure and false if not secure.\u003cbr\u003e\n proxy is a Boolean parameter that is true to use proxy and false if not use\n proxy.\u003cbr\u003e\n file_name is the name of the file that is sent. Can be different than the\n file ID.;\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eHandle Errors\u003c/strong\u003e\u003cbr\u003e\n \u003ctable style=\"height:452px\" width=\"720\"\u003e\n \u003ctbody\u003e\n \u003ctr\u003e\n \u003ctd style=\"width:716px\"\u003e\n \u003col\u003e\n \u003cli\u003e\n \u003cp\u003eif (res[0].Type == entryTypes.error) {\u003c/p\u003e\n \u003cp\u003e\n \u0026nbsp;\u0026nbsp;\u0026nbsp; // Return the error to war\n room no results to parse.\n \u003c/p\u003e\n \u003cp\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp; return res[0];\u003c/p\u003e\n \u003cp\u003e} else {\u003c/p\u003e\n \u003cp\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp; var usersOnCall = res[0].Contents;\u003c/p\u003e\n \u003cp\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp; var selectedUser = usersOnCall[0];\u003c/p\u003e\n \u003cp\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp; if (selectedUser === null) {\u003c/p\u003e\n \u003cp\u003e\n return { ContentsFormat: formats.text, Type:\n entryTypes.error, Contents: 'error : did not\n receive any users from PagerDutyGetUsersOnCallNow!'\n };\n \u003c/p\u003e\n \u003cp\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp; } else {\u003c/p\u003e\n \u003cp\u003e\n \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;return\n selectedUser.name;\n \u003c/p\u003e\n \u003cp\u003e\u0026nbsp;\u0026nbsp;\u0026nbsp; }\u003c/p\u003e\n }var res = executeCommand('PagerDutyGetUsersOnCallNow',\n { });\n \u003c/li\u003e\n \u003c/ol\u003e\n \u003c/td\u003e\n \u003c/tr\u003e\n \u003c/tbody\u003e\n \u003c/table\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eExecute Another Script\u003cbr\u003e\u003c/strong\u003eYou can execute other scripts\n just as you execute commands, using `executeCommand`.\n \u003cp\u003e\n var arrResultEntries = executeCommand('IPReputation', { ip: '8.8.8.8'\n } );\n \u003c/p\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eSave data in playbook\u003cbr\u003e\u003c/strong\u003e\n \u003cp\u003e\n Saves data into context for later task scripts within the currently executing\n playbook.\n \u003c/p\u003e\n \u003cp\u003esetContext('myIPs', ['1.1.1.1','2.2.2.2']);\u003c/p\u003e\n \u003cp\u003esetContext('sender', 'john@acme.com');\u003c/p\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cp\u003e\n \u003cstrong\u003eFormat Results as a table\u003cbr\u003e\u003c/strong\u003eIn addition to plain text,\n you can return results to the war room formatted as a table. Error entries\n can also be formatted as tables, by setting the `entryType` to `error`.\n \u003c/p\u003e\n \u003cp\u003e\n rows = [ { col1 : 'val1', col2 : 1 } , { col1 : 'val2', col2 : 2 } ]\n \u003c/p\u003e\n \u003cp\u003e\n return {ContentsFormat: formats.table, Type: entryTypes.note, Contents:\n rows};\n \u003c/p\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eFormat Results using Markdown\u003c/strong\u003e\u003cbr\u003e\n \u003cp\u003e\n Results can also be formatted using\n \u003ca href=\"https://en.wikipedia.org/wiki/Markdown\" target=\"_blank\" rel=\"noopener noreferrer\"\u003eMarkdown\u003c/a\u003e.\n \u003c/p\u003e\n \u003cp\u003evar res = '## My title\\n### My subsection\\n'\u003c/p\u003e\n \u003cp\u003e\n rows = [ { col1 : 'val1', col2 : 1 } , { col1 : 'val2', col2 : 2 } ]\n \u003c/p\u003e\n \u003cp\u003emarkdownBasedTable = 'num|col1|col2\\n'\u003c/p\u003e\n \u003cp\u003emarkdownBasedTable += '---|---|---\\n'\u003c/p\u003e\n \u003cp\u003efor (var i = 0; i \u0026lt; rows.length; i++)\u003c/p\u003e\n \u003cp\u003e\n markdownBasedTable += (i+1) + '|' + rows[i].col1 + '|' + rows[i].col2\n + '\\n'\n \u003c/p\u003e\n \u003cp\u003eres += markdownBasedTable\u003c/p\u003e\n return { ContentsFormat: formats.markdown, Type: entryTypes.note, Contents:\n res } ;\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eSet Results As Notes\u003c/strong\u003e\u003cbr\u003e\n \u003cp\u003eResults can be set as notes\u003c/p\u003e\n \u003cp\u003evar res = '## This is a note\\n';\u003c/p\u003e\n \u003cp\u003eres += 'It has important information\\n';\u003c/p\u003e\n return { ContentsFormat: formats.markdown, Type: entryTypes.note, Contents:\n res, Note: true } ;\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eBase 64\u003cbr\u003e\u003c/strong\u003e\n \u003cp\u003ebtoa: encode string to base 64\u003c/p\u003e\n \u003cp\u003eatob: decode base 64 to string\u003c/p\u003e\n \u003cp\u003e\n entrytoa: gets a file entry ID and returns the file in base 64.\n \u003c/p\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eAccess Investigation Metadata\u003c/strong\u003e\n \u003cp\u003e\n When you run a script in a War Room, whether manually or through a playbook,\n sometimes there is a need to access the investigation metadata, which\n is accessible through the `investigation` and `incidents` objects which\n are mapped into the script by the platform. Try the following example\n in a war room, and in the playground, to see the structure of the object\n in different investigations. Then you can extract the fields that interest\n your for your script's logic and purpose.\n \u003c/p\u003e\n \u003cp\u003eTo see the structure of the investigation metadata object:\u003c/p\u003e\n \u003cp\u003ereturn investigation;\u003c/p\u003e\n \u003cp\u003eTo see the structure of the incidents metadata object:\u003c/p\u003e\n \u003cp\u003ereturn incidents;\u003c/p\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003ePrinting to Log\u003cbr\u003e\u003c/strong\u003e\n \u003cp\u003eTo print to war room: log(...)\u003c/p\u003e\n \u003cp\u003eTo print to demisto log in INFO: logInfo(...)\u003c/p\u003e\n \u003cp\u003eTo print to demisto log in DEBUG: logDebug(...)\u003c/p\u003e\n \u003cp\u003eTo print to demisto log in ERROR: logError(...)\u003c/p\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eClose the current investigation\u003cbr\u003e\u003c/strong\u003ecloseInvestigation({Reason:\n 'Automated malware playbook completed.'});\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eAdvanced How To\u003cbr\u003e\u003c/strong\u003eTo be added soon:\u003cbr\u003e\n 1. Access War Room entries from within a script – return entries matching\n a specific condition, aggregate content from entries, run a regex-based search\n against all text in the war room to collect a list of identifiers, and more.\u003cbr\u003e\n 2. Send files from war room as email attachments.\u003cbr\u003e\n 3. Access context data directly disregarding arguments.\u003cbr\u003e\n 4.More tips and use cases to come.\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eReturn a map to the War Room\u003c/strong\u003e\u003cbr\u003e\n return {\u003cbr\u003e\n Type: entryTypes.map,\u003cbr\u003e\n ContentsFormat: formats.json,\u003cbr\u003e\n Contents: {\u003cbr\u003e\n lat: \u0026lt;latitude-coordinate\u0026gt;,\u003cbr\u003e\n lng: \u0026lt;longitude-coordinate\u0026gt;,\u003cbr\u003e\n }\u003cbr\u003e\n };\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eIncident Severity Levels\u003c/strong\u003e\u003cbr\u003e\n \u003cul\u003e\n \u003cli\u003eUnknown: 0\u003c/li\u003e\n \u003cli\u003eInformational: 0.5\u003c/li\u003e\n \u003cli\u003eLow: 1\u003c/li\u003e\n \u003cli\u003eMedium: 2\u003c/li\u003e\n \u003cli\u003eHigh: 3\u003c/li\u003e\n \u003cli\u003eCritical: 4\u003c/li\u003e\n \u003c/ul\u003e\n \u003c/li\u003e\n \u003cli\u003e\n \u003cstrong\u003eIncident Statuses\u003c/strong\u003e\u003cbr\u003e\n \u003cul\u003e\n \u003cli\u003ePending: 0\u003c/li\u003e\n \u003cli\u003eActive: 1\u003c/li\u003e\n \u003cli\u003eDone: 2\u003c/li\u003e\n \u003cli\u003eArchive: 3\u003c/li\u003e\n \u003c/ul\u003e\n \u003c/li\u003e\n\u003c/ol\u003e", "language": "javascript", "editorType": "automation" }, diff --git a/Packs/AWS-Lambda/Integrations/AWS_Lambda/AWS_Lambda.py b/Packs/AWS-Lambda/Integrations/AWS_Lambda/AWS_Lambda.py index 55b68bf06704..466e254c3ac5 100644 --- a/Packs/AWS-Lambda/Integrations/AWS_Lambda/AWS_Lambda.py +++ b/Packs/AWS-Lambda/Integrations/AWS_Lambda/AWS_Lambda.py @@ -771,7 +771,7 @@ def main(): case 'aws-lambda-list-aliases': list_aliases(args, aws_client) case 'aws-lambda-invoke': - invoke(args, aws_client) + return_results(invoke(args, aws_client)) case 'aws-lambda-remove-permission': remove_permission(args, aws_client) case 'aws-lambda-get-account-settings': diff --git a/Packs/AWS-Lambda/ReleaseNotes/1_3_9.md b/Packs/AWS-Lambda/ReleaseNotes/1_3_9.md new file mode 100644 index 000000000000..7373597802d4 --- /dev/null +++ b/Packs/AWS-Lambda/ReleaseNotes/1_3_9.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### AWS - Lambda + +Fixed an issue where the **aws-lambda-invoke** command did not return any results. diff --git a/Packs/AWS-Lambda/pack_metadata.json b/Packs/AWS-Lambda/pack_metadata.json index 49d68ac0722e..dd01001d5b09 100644 --- a/Packs/AWS-Lambda/pack_metadata.json +++ b/Packs/AWS-Lambda/pack_metadata.json @@ -2,7 +2,7 @@ "name": "AWS - Lambda", "description": "Amazon Web Services Serverless Compute service (lambda)", "support": "xsoar", - "currentVersion": "1.3.8", + "currentVersion": "1.3.9", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/Algosec/Integrations/AlgoSec/AlgoSec.yml b/Packs/Algosec/Integrations/AlgoSec/AlgoSec.yml index eac8fda3e4b4..dcaa394f2e14 100644 --- a/Packs/Algosec/Integrations/AlgoSec/AlgoSec.yml +++ b/Packs/Algosec/Integrations/AlgoSec/AlgoSec.yml @@ -5,7 +5,7 @@ name: AlgoSec display: AlgoSec system: true category: Network Security -description: Algosec BusinessFlow(ABF), Firewall Analyzer (AFA) and FireFlow(AFF). +description: Algosec AppViz, Firewall Analyzer (AFA) and FireFlow(AFF). configuration: - display: Server URL (e.g. https://192.168.0.1) name: server @@ -34,51 +34,51 @@ script: - name: ticketId required: true default: true - description: ID of requested change request + description: ID of requested change request. description: Retrieves a FireFlow change request by its ID - name: algosec-create-ticket arguments: - name: description - description: A free text description of the issue + description: A free text description of the issue. - name: devices - description: A list of device names, on which the change should be made + description: A list of device names, on which the change should be made. - name: action required: true description: | The device action to perform for the traffic. This can be either of the following: \U0010FC00 1 - Allow the traffic \U0010FC00 0 - Block the - traffic + traffic. predefined: - "0" - "1" - name: destAddress required: true - description: The destination address to perform the action on + description: The destination address to perform the action on. - name: sourceAddress required: true - description: The source address to perform the action on + description: The source address to perform the action on. - name: requestor required: true - description: The email address of the requestor + description: The email address of the requestor. - name: subject required: true - description: The change request's title + description: The change request's title. - name: service required: true - description: The device service or port for the connection, for example, "http" or Mandatory "tcp/123" + description: The device service or port for the connection, for example, "http" or Mandatory "tcp/123". - name: user required: true - description: The user for the connection + description: The user for the connection. - name: application required: true - description: The application for the connection + description: The application for the connection. description: Creates a new FireFlow change request - name: algosec-get-applications arguments: - name: address required: true default: true - description: The IP/Subnet to search + description: The IP/Subnet to search. - name: type auto: PREDEFINED predefined: @@ -86,14 +86,14 @@ script: - CONTAINED - CONTAINING - EXACT - description: The search method for the address - description: Find applications containing network objects related to IP address using BusinessFlow + description: The search method for the address. + description: Find applications containing network objects related to IP address using AppViz - name: algosec-get-network-object arguments: - name: address required: true default: true - description: The IP/Subnet to search + description: The IP/Subnet to search. - name: type auto: PREDEFINED predefined: @@ -101,24 +101,24 @@ script: - CONTAINED - CONTAINING - EXACT - description: The search method for the address (default is INTERSECT) + description: The search method for the address (default is INTERSECT). description: Find network objects related to IP address - name: algosec-query arguments: - name: source required: true default: true - description: source(s) for the query. Multiple values are separated by commas (,) + description: source(s) for the query. Multiple values are separated by commas (,). - name: destination required: true - description: destination(s) for the query. Multiple values are separated by commas (,) + description: destination(s) for the query. Multiple values are separated by commas (,). - name: service required: true - description: service(s) for the query. Multiple values are separated by commas (,) + description: service(s) for the query. Multiple values are separated by commas (,). - name: user - description: user for the query + description: user for the query. - name: application - description: application for the query + description: application for the query. description: Performs a batch traffic simulation query using Firewall Analyzer tests: - No tests diff --git a/Packs/Algosec/Integrations/AlgoSec/README.md b/Packs/Algosec/Integrations/AlgoSec/README.md index 881442347ccc..e937df862743 100644 --- a/Packs/Algosec/Integrations/AlgoSec/README.md +++ b/Packs/Algosec/Integrations/AlgoSec/README.md @@ -1,4 +1,4 @@ -Algosec BusinessFlow(ABF), Firewall Analyzer (AFA) and FireFlow(AFF). +Algosec AppViz, Firewall Analyzer (AFA) and FireFlow(AFF). ## Configure AlgoSec on XSOAR --- @@ -70,7 +70,7 @@ There is no context output for this command. ### 3. algosec-get-applications --- -Find applications containing network objects related to IP address using BusinessFlow +Find applications containing network objects related to IP address using AppViz ##### Base Command diff --git a/Packs/Algosec/ReleaseNotes/1_0_14.md b/Packs/Algosec/ReleaseNotes/1_0_14.md new file mode 100644 index 000000000000..8c42e7af8900 --- /dev/null +++ b/Packs/Algosec/ReleaseNotes/1_0_14.md @@ -0,0 +1,12 @@ + +#### Integrations + +##### AlgoSec + +- update description with new product name AppViz + +#### Scripts + +##### AlgosecGetApplications + +- update description with new product name AppViz diff --git a/Packs/Algosec/Scripts/AlgosecGetApplications/AlgosecGetApplications.yml b/Packs/Algosec/Scripts/AlgosecGetApplications/AlgosecGetApplications.yml index 55aada1bd66d..13cc8a9f656f 100644 --- a/Packs/Algosec/Scripts/AlgosecGetApplications/AlgosecGetApplications.yml +++ b/Packs/Algosec/Scripts/AlgosecGetApplications/AlgosecGetApplications.yml @@ -7,7 +7,7 @@ type: python subtype: python3 tags: - Algosec -comment: Find applications containing network objects related to IP address using BusinessFlow. +comment: Find applications containing network objects related to IP address using AppViz. system: true args: - name: address diff --git a/Packs/Algosec/Scripts/AlgosecGetApplications/README.md b/Packs/Algosec/Scripts/AlgosecGetApplications/README.md index b11aa7d5e114..d5e2d6adce8a 100644 --- a/Packs/Algosec/Scripts/AlgosecGetApplications/README.md +++ b/Packs/Algosec/Scripts/AlgosecGetApplications/README.md @@ -1,4 +1,4 @@ -Finds applications containing network objects related to IP address using BusinessFlow. +Finds applications containing network objects related to IP address using AppViz. ## Script Data --- diff --git a/Packs/Algosec/pack_metadata.json b/Packs/Algosec/pack_metadata.json index d8d223cb5a74..821d96fb5139 100644 --- a/Packs/Algosec/pack_metadata.json +++ b/Packs/Algosec/pack_metadata.json @@ -1,8 +1,8 @@ { "name": "AlgoSec", - "description": "Algosec BusinessFlow(ABF), Firewall Analyzer (AFA) and FireFlow(AFF).", + "description": "Algosec AppViz, Firewall Analyzer (AFA) and FireFlow(AFF).", "support": "xsoar", - "currentVersion": "1.0.13", + "currentVersion": "1.0.14", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/ApiModules/ReleaseNotes/2_2_29.md b/Packs/ApiModules/ReleaseNotes/2_2_29.md new file mode 100644 index 000000000000..3df51362d345 --- /dev/null +++ b/Packs/ApiModules/ReleaseNotes/2_2_29.md @@ -0,0 +1,5 @@ +#### Scripts + +##### OktaApiModule +- Added the `key_id` parameter for environments configured with multiple keys. +- Updated the Docker image to: *demisto/crypto:1.0.0.111961*. \ No newline at end of file diff --git a/Packs/ApiModules/Scripts/CoreIRApiModule/CoreIRApiModule.py b/Packs/ApiModules/Scripts/CoreIRApiModule/CoreIRApiModule.py index f70bcd612b10..723b44fa2e5d 100644 --- a/Packs/ApiModules/Scripts/CoreIRApiModule/CoreIRApiModule.py +++ b/Packs/ApiModules/Scripts/CoreIRApiModule/CoreIRApiModule.py @@ -2109,20 +2109,73 @@ def generate_endpoint_by_contex_standard(endpoints, ip_as_string, integration_na return standard_endpoints +def retrieve_all_endpoints(client, endpoints, endpoint_id_list, dist_name, ip_list, public_ip_list, + group_name, platform, alias_name, isolate, hostname, page_number, + limit, first_seen_gte, first_seen_lte, last_seen_gte, last_seen_lte, + sort_by_first_seen, sort_by_last_seen, status, username): + endpoints_page = endpoints + # Continue looping for as long as the latest page of endpoints retrieved is NOT empty + while endpoints_page: + page_number += 1 + endpoints_page = client.get_endpoints( + endpoint_id_list=endpoint_id_list, + dist_name=dist_name, + ip_list=ip_list, + public_ip_list=public_ip_list, + group_name=group_name, + platform=platform, + alias_name=alias_name, + isolate=isolate, + hostname=hostname, + page_number=page_number, + limit=limit, + first_seen_gte=first_seen_gte, + first_seen_lte=first_seen_lte, + last_seen_gte=last_seen_gte, + last_seen_lte=last_seen_lte, + sort_by_first_seen=sort_by_first_seen, + sort_by_last_seen=sort_by_last_seen, + status=status, + username=username + ) + endpoints += endpoints_page + return endpoints + + +def convert_timestamps_to_datestring(endpoints): + for endpoint in endpoints: + if endpoint.get('content_release_timestamp'): + endpoint['content_release_timestamp'] = timestamp_to_datestring(endpoint.get('content_release_timestamp')) + if endpoint.get('first_seen'): + endpoint['first_seen'] = timestamp_to_datestring(endpoint.get('first_seen')) + if endpoint.get('install_date'): + endpoint['install_date'] = timestamp_to_datestring(endpoint.get('install_date')) + if endpoint.get('last_content_update_time'): + endpoint['last_content_update_time'] = timestamp_to_datestring(endpoint.get('last_content_update_time')) + if endpoint.get('last_seen'): + endpoint['last_seen'] = timestamp_to_datestring(endpoint.get('last_seen')) + return endpoints + + def get_endpoints_command(client, args): integration_context_brand = args.pop('integration_context_brand', 'CoreApiModule') integration_name = args.pop("integration_name", "CoreApiModule") - page_number = arg_to_int( - arg=args.get('page', '0'), - arg_name='Failed to parse "page". Must be a number.', - required=True - ) - - limit = arg_to_int( - arg=args.get('limit', '30'), - arg_name='Failed to parse "limit". Must be a number.', - required=True - ) + all_results = argToBoolean(args.get('all_results', False)) + # When we want to get all endpoints, start at page 0 and use the max limit supported by the API (100) + if all_results: + page_number = 0 + limit = 100 + else: + page_number = arg_to_int( + arg=args.get('page', '0'), + arg_name='Failed to parse "page". Must be a number.', + required=True + ) + limit = arg_to_int( + arg=args.get('limit', '30'), + arg_name='Failed to parse "limit". Must be a number.', + required=True + ) endpoint_id_list = argToList(args.get('endpoint_id_list')) dist_name = argToList(args.get('dist_name')) @@ -2134,6 +2187,7 @@ def get_endpoints_command(client, args): isolate = args.get('isolate') hostname = argToList(args.get('hostname')) status = argToList(args.get('status')) + convert_timestamp_to_datestring = argToBoolean(args.get('convert_timestamp_to_datestring', False)) first_seen_gte = arg_to_timestamp( arg=args.get('first_seen_gte'), @@ -2182,6 +2236,17 @@ def get_endpoints_command(client, args): username=username ) + if all_results: + endpoints = retrieve_all_endpoints(client, endpoints, endpoint_id_list, dist_name, + ip_list, public_ip_list, group_name, platform, + alias_name, isolate, hostname, page_number, + limit, first_seen_gte, first_seen_lte, + last_seen_gte, last_seen_lte, sort_by_first_seen, + sort_by_last_seen, status, username) + + if convert_timestamp_to_datestring: + endpoints = convert_timestamps_to_datestring(endpoints) + standard_endpoints = generate_endpoint_by_contex_standard(endpoints, False, integration_name) endpoint_context_list = [] for endpoint in standard_endpoints: diff --git a/Packs/ApiModules/Scripts/CoreIRApiModule/CoreIRApiModule_test.py b/Packs/ApiModules/Scripts/CoreIRApiModule/CoreIRApiModule_test.py index 99c69c2b93bf..4809a2309aff 100644 --- a/Packs/ApiModules/Scripts/CoreIRApiModule/CoreIRApiModule_test.py +++ b/Packs/ApiModules/Scripts/CoreIRApiModule/CoreIRApiModule_test.py @@ -63,6 +63,89 @@ def return_extra_data_result(*args): return {}, {}, {"incident": incident_from_extra_data_command} +def test_retrieve_all_endpoints(mocker): + """ + Given: + - endpoints is populated with the first round. + When + - Retrieve_all_endpoints is called. + Then + - Retrieve all endpoints. + """ + from CoreIRApiModule import retrieve_all_endpoints + mock_endpoints_page_1 = {'reply': {'endpoints': [{'id': 1, 'hostname': 'endpoint1'}]}} + mock_endpoints_page_2 = {'reply': {'endpoints': [{'id': 2, 'hostname': 'endpoint2'}]}} + mock_endpoints_page_3 = {'reply': {'endpoints': []}} + http_request = mocker.patch.object(test_client, '_http_request') + http_request.side_effect = [mock_endpoints_page_1, mock_endpoints_page_2, mock_endpoints_page_3] + + endpoints = retrieve_all_endpoints( + client=test_client, + endpoints=[{'id': 2, 'hostname': 'endpoint2'}], + endpoint_id_list=[], + dist_name=None, + ip_list=[], + public_ip_list=[], + group_name=None, + platform=None, + alias_name=None, + isolate=None, + hostname=None, + page_number=0, + limit=10, + first_seen_gte=None, + first_seen_lte=None, + last_seen_gte=None, + last_seen_lte=None, + sort_by_first_seen=None, + sort_by_last_seen=None, + status=None, + username=None, + ) + + assert len(endpoints) == 3 + assert endpoints[1]['hostname'] == 'endpoint1' + + +def test_get_endpoints_command(mocker): + """ + When + - Retrieve_all_endpoints is called. + Then + - Retrieve all endpoints. + """ + from CoreIRApiModule import get_endpoints_command + mock_endpoints_page_1 = {'reply': {'endpoints': [{'id': 1, 'hostname': 'endpoint1'}]}} + mock_endpoints_page_2 = {'reply': {'endpoints': [{'id': 2, 'hostname': 'endpoint2'}]}} + mock_endpoints_page_3 = {'reply': {'endpoints': []}} + http_request = mocker.patch.object(test_client, '_http_request') + http_request.side_effect = [mock_endpoints_page_1, mock_endpoints_page_2, mock_endpoints_page_3] + args = {'all_results': 'true'} + result = get_endpoints_command(test_client, args) + assert result.readable_output == '### Endpoints\n|hostname|id|\n|---|---|\n| endpoint1 | 1 |\n| endpoint2 | 2 |\n' + assert result.raw_response == [{'id': 1, 'hostname': 'endpoint1'}, {'id': 2, 'hostname': 'endpoint2'}] + + +def test_convert_to_hr_timestamps(): + """ + Given + - Endpoints results. + When + - convert_to_hr_timestamps is called. + Then + - Convert to an hr date. + """ + from CoreIRApiModule import convert_timestamps_to_datestring + + expected_first_seen = "2019-12-08T09:06:09.000Z" + expected_last_seen = "2019-12-09T07:10:04.000Z" + endpoints_res = load_test_data('./test_data/get_endpoints.json').get('reply').get('endpoints') + + converted_endpoint = convert_timestamps_to_datestring(endpoints_res)[0] + assert converted_endpoint.get('first_seen') == expected_first_seen + assert converted_endpoint.get('last_seen') == expected_last_seen + + def test_get_endpoints(requests_mock): from CoreIRApiModule import get_endpoints_command, CoreClient diff --git a/Packs/ApiModules/Scripts/HTTPFeedApiModule/HTTPFeedApiModule.py b/Packs/ApiModules/Scripts/HTTPFeedApiModule/HTTPFeedApiModule.py index 0a6fc0ad0dee..6dfae2ccd97e 100644 --- a/Packs/ApiModules/Scripts/HTTPFeedApiModule/HTTPFeedApiModule.py +++ b/Packs/ApiModules/Scripts/HTTPFeedApiModule/HTTPFeedApiModule.py @@ -216,6 +216,8 @@ def build_iterator(self, **kwargs): # last_modified values in the context, for server version higher than 6.5.0. last_run = demisto.getLastRun() etag = last_run.get(url, {}).get('etag') + if etag: + etag = etag.strip('"') last_modified = last_run.get(url, {}).get('last_modified') last_updated = last_run.get(url, {}).get('last_updated') # To avoid issues with indicators expiring, if 'last_updated' is over X hours old, @@ -321,6 +323,8 @@ def get_no_update_value(response: requests.Response, url: str) -> bool: return True etag = response.headers.get('ETag') + if etag: + etag = etag.strip('"') last_modified = response.headers.get('Last-Modified') current_time = datetime.utcnow() # Save the current time as the last updated time. This will be used to indicate the last time the feed was updated in XSOAR. diff --git a/Packs/ApiModules/Scripts/HTTPFeedApiModule/HTTPFeedApiModule_test.py b/Packs/ApiModules/Scripts/HTTPFeedApiModule/HTTPFeedApiModule_test.py index 6b2a24025ad3..8f8fbe644639 100644 --- a/Packs/ApiModules/Scripts/HTTPFeedApiModule/HTTPFeedApiModule_test.py +++ b/Packs/ApiModules/Scripts/HTTPFeedApiModule/HTTPFeedApiModule_test.py @@ -533,6 +533,30 @@ class MockResponse: ' createIndicators will be executed with noUpdate=False.' +def test_get_no_update_value_etag_with_double_quotes(mocker): + """ + Given + - response with etag header that contains double-quotes. + + When + - Running get_no_update_value method. + + Then + - Ensure that the etag value in setLastRun is without double-quotes. + """ + mocker.patch.object(demisto, 'setLastRun') + + url = 'https://www.spamhaus.org/drop/asndrop.txt' + etag = 'd309ab6e51ed310cf869dab0dfd0d34b' + + class MockResponse: + headers = {'Last-Modified': 'Fri, 30 Jul 2021 00:24:13 GMT', # guardrails-disable-line + 'ETag': f'"{etag}"'} # guardrails-disable-line + status_code = 200 + get_no_update_value(MockResponse(), url) + assert demisto.setLastRun.mock_calls[0][1][0][url]['etag'] == etag + + def test_build_iterator_not_modified_header(mocker): """ Given @@ -643,3 +667,34 @@ def test_build_iterator__with_and_without_passed_time_threshold(mocker, has_pass client.build_iterator() assert mock_session.call_args[1].get('headers') == expected_result + + +def test_build_iterator_etag_with_double_quotes(mocker): + """ + Given + - getLastRun with etag header that contains double-quotes. + + When + - Running build_iterator method. + + Then + - Ensure the next request header contains 'etag' without double-quotes. + """ + + etag = 'd309ab6e51ed310cf869dab0dfd0d34b' + + mocker.patch('CommonServerPython.get_demisto_version', return_value={"version": "6.5.0"}) + mock_session = mocker.patch.object(requests, 'get') + mocker.patch('HTTPFeedApiModule.has_passed_time_threshold', return_value=False) + mocker.patch('demistomock.getLastRun', return_value={ + 'https://api.github.com/meta': { + 'etag': f'"{etag}"', + 'last_modified': '2023-05-29T12:34:56Z', + 'last_updated': '2023-05-05T09:09:06Z' + }}) + client = Client( + url='https://api.github.com/meta', + credentials={'identifier': 'user', 'password': 'password'}) + + client.build_iterator() + assert mock_session.call_args[1]['headers']['If-None-Match'] == etag diff --git a/Packs/ApiModules/Scripts/MicrosoftGraphMailApiModule/MicrosoftGraphMailApiModule.py b/Packs/ApiModules/Scripts/MicrosoftGraphMailApiModule/MicrosoftGraphMailApiModule.py index b297a5d3b0f1..b473c1cc43fe 100644 --- a/Packs/ApiModules/Scripts/MicrosoftGraphMailApiModule/MicrosoftGraphMailApiModule.py +++ b/Packs/ApiModules/Scripts/MicrosoftGraphMailApiModule/MicrosoftGraphMailApiModule.py @@ -1,8 +1,8 @@ -from urllib.parse import quote import binascii import uuid -from MicrosoftApiModule import * # noqa: E402 +from urllib.parse import quote +from MicrosoftApiModule import * # noqa: E402 API_DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ' @@ -1267,23 +1267,60 @@ def assert_pages(pages: str | int) -> int: return 1 @staticmethod - def item_result_creator(raw_attachment, user_id) -> CommandResults: + def item_result_creator(raw_attachment, user_id, args, client) -> dict[str, Any] | CommandResults: + """ + Create a result object for an attachment item. + This method processes raw attachment data and returns either an XSOAR file result or a command result + based on the attachment type and provided arguments. + + Args: + raw_attachment (dict): The raw attachment data from the API response. + user_id (str): The ID of the user associated with the attachment. + args (dict): Additional arguments for processing the attachment. + client (MsGraphMailBaseClient, optional): The client instance for making additional API calls. + + Returns: + dict[str, Any] | CommandResults: + - If the attachment is a message and should be downloaded, returns a dict containing file result. + - If the attachment is a message but should not be downloaded, returns a CommandResults with message details. + - If the attachment is of an unsupported type, returns a CommandResults with an error message. + + Note: + - The method handles different types of attachments, particularly focusing on message attachments. + It can either return the attachment as a downloadable file or as structured data in the command results. + - 'client' function argument is only relevant when 'should_download_message_attachment' command argument is True. + """ item = raw_attachment.get('item', {}) item_type = item.get('@odata.type', '') if 'message' in item_type: - message_id = raw_attachment.get('id') - item['id'] = message_id - mail_context = GraphMailUtils.build_mail_object(item, user_id=user_id, get_body=True) - human_readable = tableToMarkdown( - f'Attachment ID {message_id} \n **message details:**', - mail_context, - headers=['ID', 'Subject', 'SendTime', 'Sender', 'From', 'HasAttachments', 'Body'] - ) - return CommandResults(outputs_prefix='MSGraphMail', - outputs_key_field='ID', - outputs=mail_context, - readable_output=human_readable, - raw_response=raw_attachment) + return_message_attachment_as_downloadable_file: bool = client and argToBoolean( + args.get('should_download_message_attachment', False)) + if return_message_attachment_as_downloadable_file: + # return the message attachment as a file result + attachment_content = client._get_attachment_mime( + args.get('message_id'), + args.get('attachment_id'), + user_id, False) + attachment_name: str = (item.get("name") or item.get('subject') + or "untitled_attachment").replace(' ', '_') + '.eml' + demisto.debug(f'Email attachment of type "microsoft.graph.message" acquired successfully, {attachment_name=}') + return fileResult(attachment_name, attachment_content) + else: + # return the message attachment as a command result + message_id = raw_attachment.get('id') + item['id'] = message_id + mail_context = GraphMailUtils.build_mail_object(item, user_id=user_id, get_body=True) + human_readable = tableToMarkdown( + f'Attachment ID {message_id} \n **message details:**', + mail_context, + headers=['ID', 'Subject', 'SendTime', 'Sender', 'From', 'HasAttachments', 'Body'] + ) + + return CommandResults(outputs_prefix='MSGraphMail', + outputs_key_field='ID', + outputs=mail_context, + readable_output=human_readable, + raw_response=raw_attachment) else: human_readable = f'Integration does not support attachments from type {item_type}' return CommandResults(readable_output=human_readable, raw_response=raw_attachment) @@ -1314,13 +1351,12 @@ def file_result_creator(raw_attachment: dict, legacy_name=False) -> dict: raise DemistoException('Attachment could not be decoded') @staticmethod - def create_attachment(raw_attachment, user_id, legacy_name=False) -> CommandResults | dict: - + def create_attachment(raw_attachment, user_id, args, client, legacy_name=False) -> CommandResults | dict: attachment_type = raw_attachment.get('@odata.type', '') # Documentation about the different attachment types # https://docs.microsoft.com/en-us/graph/api/attachment-get?view=graph-rest-1.0&tabs=http if 'itemAttachment' in attachment_type: - return GraphMailUtils.item_result_creator(raw_attachment, user_id) + return GraphMailUtils.item_result_creator(raw_attachment, user_id, args, client) elif 'fileAttachment' in attachment_type: return GraphMailUtils.file_result_creator(raw_attachment, legacy_name) else: @@ -1831,8 +1867,8 @@ def get_attachment_command(client: MsGraphMailBaseClient, args) -> list[CommandR kwargs = {arg_key: args.get(arg_key) for arg_key in ['message_id', 'folder_id', 'attachment_id']} kwargs['user_id'] = args.get('user_id', client._mailbox_to_fetch) raw_response = client.get_attachment(**kwargs) - return [GraphMailUtils.create_attachment(attachment, user_id=kwargs['user_id'], legacy_name=client.legacy_name) - for attachment in raw_response] + return [GraphMailUtils.create_attachment(raw_attachment=attachment, user_id=kwargs['user_id'], args=args, client=client, + legacy_name=client.legacy_name) for attachment in raw_response] def create_folder_command(client: MsGraphMailBaseClient, args) -> CommandResults: diff --git a/Packs/ApiModules/Scripts/MicrosoftGraphMailApiModule/MicrosoftGraphMailApiModule.yml b/Packs/ApiModules/Scripts/MicrosoftGraphMailApiModule/MicrosoftGraphMailApiModule.yml index 6f1a601f4744..2439b8d931c7 100644 --- a/Packs/ApiModules/Scripts/MicrosoftGraphMailApiModule/MicrosoftGraphMailApiModule.yml +++ b/Packs/ApiModules/Scripts/MicrosoftGraphMailApiModule/MicrosoftGraphMailApiModule.yml @@ -13,7 +13,7 @@ system: true scripttarget: 0 dependson: {} timeout: 0s -dockerimage: demisto/crypto:1.0.0.98336 +dockerimage: demisto/crypto:1.0.0.111961 fromversion: 6.5.0 tests: - No test diff --git a/Packs/ApiModules/Scripts/OktaApiModule/OktaApiModule.py b/Packs/ApiModules/Scripts/OktaApiModule/OktaApiModule.py index d6e0eb735409..47c5357acb3b 100644 --- a/Packs/ApiModules/Scripts/OktaApiModule/OktaApiModule.py +++ b/Packs/ApiModules/Scripts/OktaApiModule/OktaApiModule.py @@ -29,7 +29,7 @@ class AuthType(Enum): class OktaClient(BaseClient): def __init__(self, auth_type: AuthType = AuthType.API_TOKEN, api_token: str | None = None, client_id: str | None = None, scopes: list[str] | None = None, private_key: str | None = None, - jwt_algorithm: JWTAlgorithm | None = None, *args, **kwargs): + jwt_algorithm: JWTAlgorithm | None = None, key_id: str | None = None, *args, **kwargs): """ Args: auth_type (AuthType, optional): The type of authentication to use. @@ -50,6 +50,7 @@ def __init__(self, auth_type: AuthType = AuthType.API_TOKEN, api_token: str | No self.scopes = scopes self.jwt_algorithm = jwt_algorithm self.private_key = private_key + self.key_id = key_id missing_required_params = [] @@ -106,17 +107,24 @@ def generate_jwt_token(self, url: str) -> str: current_time = datetime.utcnow() expiration_time = current_time + timedelta(minutes=TOKEN_EXPIRATION_TIME) + payload = { + 'aud': url, + 'iat': int((current_time - datetime(1970, 1, 1)).total_seconds()), + 'exp': int((expiration_time - datetime(1970, 1, 1)).total_seconds()), + 'iss': self.client_id, + 'sub': self.client_id, + 'jti': str(uuid.uuid4()), + } + + headers = {} + if self.key_id: + headers['kid'] = self.key_id + return jwt.encode( - payload={ - 'aud': url, - 'iat': int((current_time - datetime(1970, 1, 1)).total_seconds()), - 'exp': int((expiration_time - datetime(1970, 1, 1)).total_seconds()), - 'iss': self.client_id, - 'sub': self.client_id, - 'jti': str(uuid.uuid4()), - }, + payload=payload, key=self.private_key, # type: ignore[arg-type] algorithm=self.jwt_algorithm.value, # type: ignore[union-attr] + headers=headers ) def generate_oauth_token(self, scopes: list[str]) -> dict: diff --git a/Packs/ApiModules/Scripts/OktaApiModule/OktaApiModule.yml b/Packs/ApiModules/Scripts/OktaApiModule/OktaApiModule.yml index 50fa873e4222..8ccc3850809c 100644 --- a/Packs/ApiModules/Scripts/OktaApiModule/OktaApiModule.yml +++ b/Packs/ApiModules/Scripts/OktaApiModule/OktaApiModule.yml @@ -13,7 +13,7 @@ system: true scripttarget: 0 dependson: {} timeout: 0s -dockerimage: demisto/crypto:1.0.0.82278 +dockerimage: demisto/crypto:1.0.0.111961 fromversion: 5.0.0 tests: - No test diff --git a/Packs/ApiModules/Scripts/OktaApiModule/README.md b/Packs/ApiModules/Scripts/OktaApiModule/README.md new file mode 100644 index 000000000000..82d33bdee495 --- /dev/null +++ b/Packs/ApiModules/Scripts/OktaApiModule/README.md @@ -0,0 +1,18 @@ +Common Okta client code that will be appended into each Okta based integration when it's deployed + +## Script Data +--- + +| **Name** | **Description** | +| --- | --- | +| Script Type | python3 | +| Tags | infra, server | +| Cortex XSOAR Version | 5.5.0 | + +## Inputs +--- +There are no inputs for this script. + +## Outputs +--- +There are no outputs for this script. diff --git a/Packs/ApiModules/pack_metadata.json b/Packs/ApiModules/pack_metadata.json index fc003f9ec5e2..8414cd422700 100644 --- a/Packs/ApiModules/pack_metadata.json +++ b/Packs/ApiModules/pack_metadata.json @@ -2,7 +2,7 @@ "name": "ApiModules", "description": "API Modules", "support": "xsoar", - "currentVersion": "2.2.28", + "currentVersion": "2.2.29", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/AutoFocus/.secrets-ignore b/Packs/AutoFocus/.secrets-ignore index 99ccc435017a..302bff59980e 100644 --- a/Packs/AutoFocus/.secrets-ignore +++ b/Packs/AutoFocus/.secrets-ignore @@ -133,3 +133,4 @@ demsito\\.com/some/aditional/path autofocus.paloaltos.com docs.paloaltos.com https://us-cert.cisa.gov +https://palo diff --git a/Packs/AutoFocus/Integrations/AutofocusV2/AutofocusV2.py b/Packs/AutoFocus/Integrations/AutofocusV2/AutofocusV2.py index 8871e9288a19..e8b4a0e8add8 100644 --- a/Packs/AutoFocus/Integrations/AutofocusV2/AutofocusV2.py +++ b/Packs/AutoFocus/Integrations/AutofocusV2/AutofocusV2.py @@ -1263,7 +1263,8 @@ def convert_non_ascii_chars(non_ascii): # converts non-ASCII chars to IDNA notation return str(non_ascii.group(0)).encode('idna').decode("utf-8") - return re.sub('([^a-zA-Z\W]+)', convert_non_ascii_chars, url_name) + # Regex to catch all non ascii chars (from 0 to 127 in hexadecimal). + return re.sub(r'[^\x00-\x7F]+', convert_non_ascii_chars, url_name) ''' COMMANDS''' diff --git a/Packs/AutoFocus/Integrations/AutofocusV2/AutofocusV2_test.py b/Packs/AutoFocus/Integrations/AutofocusV2/AutofocusV2_test.py index 3898ee89640f..4f98f377d535 100644 --- a/Packs/AutoFocus/Integrations/AutofocusV2/AutofocusV2_test.py +++ b/Packs/AutoFocus/Integrations/AutofocusV2/AutofocusV2_test.py @@ -434,6 +434,7 @@ def test_create_relationships_list(): ("www.Müünchen.com", "www.Mxn--tdaanchen.com"), ("www.MükÖnchen.com", "www.Mxn--tdakxn--ndanchen.com"), ("www.こんにちは.com", 'www.xn--28j2a3ar1p.com'), + ("https://paloaltonetworks–test.com", "https://paloaltonetworksxn--7ugtest.com") # noqa: RUF001 ] diff --git a/Packs/AutoFocus/ReleaseNotes/2_2_6.md b/Packs/AutoFocus/ReleaseNotes/2_2_6.md new file mode 100644 index 000000000000..bb4ed4eafff2 --- /dev/null +++ b/Packs/AutoFocus/ReleaseNotes/2_2_6.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Palo Alto Networks AutoFocus v2 + +- Fixed and issue in ***url*** command where not all non ascii characters were parsed correctly. diff --git a/Packs/AutoFocus/pack_metadata.json b/Packs/AutoFocus/pack_metadata.json index 5bf9bff75a32..2ca7bbc18e92 100644 --- a/Packs/AutoFocus/pack_metadata.json +++ b/Packs/AutoFocus/pack_metadata.json @@ -2,7 +2,7 @@ "name": "AutoFocus by Palo Alto Networks", "description": "Use the Palo Alto Networks AutoFocus integration to distinguish the most\n important threats from everyday commodity attacks.", "support": "xsoar", - "currentVersion": "2.2.5", + "currentVersion": "2.2.6", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/AzureLogAnalytics/Integrations/AzureLogAnalytics/AzureLogAnalytics.py b/Packs/AzureLogAnalytics/Integrations/AzureLogAnalytics/AzureLogAnalytics.py index 0599a2f73c84..bb92a964e0a0 100644 --- a/Packs/AzureLogAnalytics/Integrations/AzureLogAnalytics/AzureLogAnalytics.py +++ b/Packs/AzureLogAnalytics/Integrations/AzureLogAnalytics/AzureLogAnalytics.py @@ -37,8 +37,8 @@ def __init__(self, self_deployed, refresh_token, auth_and_token_url, enc_key, re + f"providers/Microsoft.OperationalInsights/workspaces/{workspace_name}" ) auth_code_scope = ( - f"{self.azure_cloud.endpoints.log_analytics_resource_id}" - + f"/Data.Read%20{self.azure_cloud.endpoints.resource_manager}user_impersonation" + f"{urljoin(self.azure_cloud.endpoints.log_analytics_resource_id, 'Data.Read')} " + f"{urljoin(self.azure_cloud.endpoints.resource_manager, 'user_impersonation')}" ) resources_list = [self.azure_cloud.endpoints.resource_manager, self.azure_cloud.endpoints.log_analytics_resource_id] base_url = urljoin(url=self.azure_cloud.endpoints.resource_manager, suffix=suffix) diff --git a/Packs/AzureLogAnalytics/Integrations/AzureLogAnalytics/AzureLogAnalytics_test.py b/Packs/AzureLogAnalytics/Integrations/AzureLogAnalytics/AzureLogAnalytics_test.py index 5166c5d87a0f..35982865d120 100644 --- a/Packs/AzureLogAnalytics/Integrations/AzureLogAnalytics/AzureLogAnalytics_test.py +++ b/Packs/AzureLogAnalytics/Integrations/AzureLogAnalytics/AzureLogAnalytics_test.py @@ -317,7 +317,8 @@ def test_generate_login_url(mocker: MockerFixture) -> None: "credentials": {"identifier": client_id, "password": "client_secret"}, "subscriptionID": "subscriptionID", "resourceGroupName": "resourceGroupName", - "workspaceName": "workspaceName" + "workspaceName": "workspaceName", + "server_url": None } mocker.patch.object(demisto, "params", return_value=mocked_params) mocker.patch.object( diff --git a/Packs/AzureLogAnalytics/ReleaseNotes/1_1_39.md b/Packs/AzureLogAnalytics/ReleaseNotes/1_1_39.md new file mode 100644 index 000000000000..853ee5533135 --- /dev/null +++ b/Packs/AzureLogAnalytics/ReleaseNotes/1_1_39.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Azure Log Analytics + +Fixed an issue where the ***azure-log-analytics-generate-login-url*** command generated an incorrect login URL when the Azure cloud parameter was missing. \ No newline at end of file diff --git a/Packs/AzureLogAnalytics/pack_metadata.json b/Packs/AzureLogAnalytics/pack_metadata.json index 09005115de53..10e45a1e9a08 100644 --- a/Packs/AzureLogAnalytics/pack_metadata.json +++ b/Packs/AzureLogAnalytics/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Azure Log Analytics", "description": "Log Analytics is a service that helps you collect and analyze data generated by resources in your cloud and on-premises environments.", "support": "xsoar", - "currentVersion": "1.1.38", + "currentVersion": "1.1.39", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel.py b/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel.py index f57a2d3823f6..5502a0c704c4 100644 --- a/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel.py +++ b/Packs/AzureSentinel/Integrations/AzureSentinel/AzureSentinel.py @@ -689,10 +689,13 @@ def update_incident_request(client: AzureSentinelClient, incident_id: str, data: if any(field not in data for field in required_fields): raise DemistoException(f'Update incident request is missing one of the required fields for the ' f'API: {required_fields}') + + severity = data.get('severity', '') + properties = { 'title': data.get('title'), 'description': delta.get('description'), - 'severity': LEVEL_TO_SEVERITY[data.get('severity', '')], + 'severity': severity if severity in LEVEL_TO_SEVERITY.values() else LEVEL_TO_SEVERITY[severity], 'status': 'Active', 'firstActivityTimeUtc': delta.get('firstActivityTimeUtc'), 'lastActivityTimeUtc': delta.get('lastActivityTimeUtc'), diff --git a/Packs/AzureSentinel/ReleaseNotes/1_5_50.md b/Packs/AzureSentinel/ReleaseNotes/1_5_50.md new file mode 100644 index 000000000000..14894d21857a --- /dev/null +++ b/Packs/AzureSentinel/ReleaseNotes/1_5_50.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Microsoft Sentinel + +- Fixed an issue where XSOAR incident closures were not mirrored to Microsoft Sentinel. diff --git a/Packs/AzureSentinel/pack_metadata.json b/Packs/AzureSentinel/pack_metadata.json index e4dc3356e562..d38c2c49238c 100644 --- a/Packs/AzureSentinel/pack_metadata.json +++ b/Packs/AzureSentinel/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Microsoft Sentinel", "description": "Microsoft Sentinel is a cloud-native security information and event manager (SIEM) platform that uses built-in AI to help analyze large volumes of data across an enterprise.", "support": "xsoar", - "currentVersion": "1.5.49", + "currentVersion": "1.5.50", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/Base/ReleaseNotes/1_34_42.md b/Packs/Base/ReleaseNotes/1_34_42.md new file mode 100644 index 000000000000..9e245a09dd82 --- /dev/null +++ b/Packs/Base/ReleaseNotes/1_34_42.md @@ -0,0 +1,7 @@ +<~XSIAM> +#### Scripts + +##### CommonServerPython + +Changed the snapshot id used for fetching assets to always start with a timestamp. + \ No newline at end of file diff --git a/Packs/Base/Scripts/CommonServerPython/CommonServerPython.py b/Packs/Base/Scripts/CommonServerPython/CommonServerPython.py index b718a064963e..4ba4040df2a5 100644 --- a/Packs/Base/Scripts/CommonServerPython/CommonServerPython.py +++ b/Packs/Base/Scripts/CommonServerPython/CommonServerPython.py @@ -11927,7 +11927,10 @@ def send_data_to_xsiam(data, vendor, product, data_format=None, url_key='url', n if data_type == ASSETS: if not snapshot_id: snapshot_id = str(round(time.time() * 1000)) - headers['snapshot-id'] = instance_name + snapshot_id + + # We are setting a time stamp ahead of the instance name since snapshot-ids must be configured in ascending + # alphabetical order such that first_snapshot < second_snapshot etc. + headers['snapshot-id'] = snapshot_id + instance_name headers['total-items-count'] = str(items_count) header_msg = 'Error sending new {data_type} into XSIAM.\n'.format(data_type=data_type) diff --git a/Packs/Base/Scripts/CommonServerPython/CommonServerPython_test.py b/Packs/Base/Scripts/CommonServerPython/CommonServerPython_test.py index e4e29eb89ec5..533cbfc76bd1 100644 --- a/Packs/Base/Scripts/CommonServerPython/CommonServerPython_test.py +++ b/Packs/Base/Scripts/CommonServerPython/CommonServerPython_test.py @@ -68,7 +68,7 @@ "instance-name": "test_integration_instance", "final-reporting-device": "www.test_url.com", "collector-type": "assets", - "snapshot-id": "test_integration_instance123000", + "snapshot-id": "123000test_integration_instance", "total-items-count": "2" }} diff --git a/Packs/Base/pack_metadata.json b/Packs/Base/pack_metadata.json index 71708eb40c0e..06e55f687465 100644 --- a/Packs/Base/pack_metadata.json +++ b/Packs/Base/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Base", "description": "The base pack for Cortex XSOAR.", "support": "xsoar", - "currentVersion": "1.34.41", + "currentVersion": "1.34.42", "author": "Cortex XSOAR", "serverMinVersion": "6.0.0", "url": "https://www.paloaltonetworks.com/cortex", diff --git a/Packs/BmcITSM/Integrations/BmcITSM/BmcITSM.py b/Packs/BmcITSM/Integrations/BmcITSM/BmcITSM.py index 3ceefa71ef5e..b6e8c06f5f73 100644 --- a/Packs/BmcITSM/Integrations/BmcITSM/BmcITSM.py +++ b/Packs/BmcITSM/Integrations/BmcITSM/BmcITSM.py @@ -1004,7 +1004,7 @@ def update_task_request( "TaskType": task_type, "Priority": priority, "RootRequestName": root_request_name, - "Support Company": assigned_support_company, + "Assignee Company": assigned_support_company, "Assignee Organization": assigned_support_organization, "Assignee Group": assigned_support_group_name, "Company": company, diff --git a/Packs/BmcITSM/ReleaseNotes/1_0_28.md b/Packs/BmcITSM/ReleaseNotes/1_0_28.md new file mode 100644 index 000000000000..23648f0b9b5c --- /dev/null +++ b/Packs/BmcITSM/ReleaseNotes/1_0_28.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### BMC Helix ITSM + +Fixed an issue where the ***bmc-itsm-task-update*** command failed when using the *support_company* argument. \ No newline at end of file diff --git a/Packs/BmcITSM/pack_metadata.json b/Packs/BmcITSM/pack_metadata.json index 32bf652442b1..9ddbcbfb2b44 100644 --- a/Packs/BmcITSM/pack_metadata.json +++ b/Packs/BmcITSM/pack_metadata.json @@ -2,7 +2,7 @@ "name": "BMC Helix ITSM", "description": "BMC Helix ITSM allows customers to manage service request, incident, change request, task, problem investigation, known error and work order tickets.", "support": "xsoar", - "currentVersion": "1.0.27", + "currentVersion": "1.0.28", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/Box/Integrations/BoxEventsCollector/BoxEventsCollector.py b/Packs/Box/Integrations/BoxEventsCollector/BoxEventsCollector.py index 0f769a3942c8..9bdeeda88046 100644 --- a/Packs/Box/Integrations/BoxEventsCollector/BoxEventsCollector.py +++ b/Packs/Box/Integrations/BoxEventsCollector/BoxEventsCollector.py @@ -142,7 +142,7 @@ def _create_authorization_body(self): self.box_credentials.boxAppSettings.appAuth ) assertion = jwt.encode( - payload=claims.dict(), + payload=claims.model_dump(mode='json'), # type: ignore[attr-defined] key=decrypted_private_key, algorithm='RS512', headers={ diff --git a/Packs/Box/ReleaseNotes/3_2_2.md b/Packs/Box/ReleaseNotes/3_2_2.md new file mode 100644 index 000000000000..2e164d7e804c --- /dev/null +++ b/Packs/Box/ReleaseNotes/3_2_2.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Box Event Collector + +- Fixed an issue caused by migration to python pedantic V2 causing failures. diff --git a/Packs/Box/pack_metadata.json b/Packs/Box/pack_metadata.json index 2176ca4ad40d..89cc05ef5647 100644 --- a/Packs/Box/pack_metadata.json +++ b/Packs/Box/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Box", "description": "Manage Box users", "support": "xsoar", - "currentVersion": "3.2.1", + "currentVersion": "3.2.2", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/CVE_2024_47575/.pack-ignore b/Packs/CVE_2024_47575/.pack-ignore new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/Packs/CVE_2024_47575/.secrets-ignore b/Packs/CVE_2024_47575/.secrets-ignore new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/Packs/CVE_2024_47575/Playbooks/playbook-CVE-2024-47575_-_FortiManager_Authentication_Bypass.yml b/Packs/CVE_2024_47575/Playbooks/playbook-CVE-2024-47575_-_FortiManager_Authentication_Bypass.yml new file mode 100644 index 000000000000..6c557257810f --- /dev/null +++ b/Packs/CVE_2024_47575/Playbooks/playbook-CVE-2024-47575_-_FortiManager_Authentication_Bypass.yml @@ -0,0 +1,625 @@ +id: CVE-2024-47575 - FortiManager Authentication Bypass +version: -1 +name: CVE-2024-47575 - FortiManager Authentication Bypass +description: "CVE-2024-47575, also known as **FortiJump**, is a critical zero-day vulnerability affecting **FortiManager**, a centralized management platform for Fortinet devices. The vulnerability arises due to missing authentication checks in specific FortiManager REST API endpoints. An unauthenticated attacker with network access to the FortiManager device can exploit this flaw to execute arbitrary code or commands, potentially leading to complete system compromise.\n\n---\n\n## Affected Versions\n\n| FortiManager Version | Status |\n|------------------------|--------------------|\n| **7.2.0 to 7.2.3** | Affected |\n| **7.0.0 to 7.0.7** | Affected |\n| **6.4.0 to 6.4.11** | Affected |\n| **6.2.x and earlier** | Potentially Affected |\n| **7.2.4 and above** | **Patched** |\n| **7.0.8 and above** | **Patched** |\n| **6.4.12 and above** | **Patched** |\n\n*Note:*\n\nOld FortiAnalyzer models 1000E, 1000F, 2000E, 3000E, 3000F, 3000G, 3500E, 3500F, 3500G, 3700F, 3700G, 3900E with the following feature enabled (FortiManager on FortiAnalyzer):\n\nconfig system global\nset fmg-status enable\nend\n\nAnd at least one interface with the fgfm service enabled is also impacted by this vulnerability.\n\n---\n\n## Playbook Flow\n\n1. Create, Tag, and Block Indicators\n\n2. Hunt **Automatically** for Suspicious Behavior Related to the exploitation flow using XQL\n**Note: The 'fortinet_fortimanager_raw' dataset must be available for the XQL queries completion.**\n\n3. Provide Mitigations and Workarounds\n\n---\n\n**References**:\n\n- [Fortinet PSIRT Advisory FG-IR-24-423](https://www.fortiguard.com/psirt/FG-IR-24-423)\n\n---\n\nBy following this playbook, organizations can effectively respond to and mitigate the risks associated with **CVE-2024-47575 (FortiJump)**. \n" +tags: +- FortiJump +- CVE-2024-47575 +- FortiManager Vulnerability +starttaskid: "0" +tasks: + "0": + id: "0" + taskid: e638d977-c697-44e9-8caf-9711598be275 + type: start + task: + id: e638d977-c697-44e9-8caf-9711598be275 + version: -1 + name: "" + iscommand: false + brand: "" + description: '' + nexttasks: + '#none#': + - "1" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 480, + "y": 50 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "1": + id: "1" + taskid: 3e555db3-5358-4a2c-8541-3977d0dfa466 + type: regular + task: + id: 3e555db3-5358-4a2c-8541-3977d0dfa466 + version: -1 + name: Extract indicators from hardcoded input + description: commands.local.cmd.extract.indicators + script: Builtin|||extractIndicators + type: regular + iscommand: true + brand: Builtin + nexttasks: + '#none#': + - "2" + scriptarguments: + text: + simple: ${inputs.rawIoCs} + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 480, + "y": 195 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "2": + id: "2" + taskid: 23a45588-c954-4d0c-8f0b-61d032408181 + type: title + task: + id: 23a45588-c954-4d0c-8f0b-61d032408181 + version: -1 + name: Create and Tag Indicators + type: title + iscommand: false + brand: "" + description: '' + nexttasks: + '#none#': + - "3" + - "4" + - "9" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 480, + "y": 370 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "3": + id: "3" + taskid: be1ec492-d8f8-40cb-804b-c31e573a9f4f + type: regular + task: + id: be1ec492-d8f8-40cb-804b-c31e573a9f4f + version: -1 + name: IP Indicators + description: commands.local.cmd.new.indicator + script: Builtin|||createNewIndicator + type: regular + iscommand: true + brand: Builtin + nexttasks: + '#none#': + - "6" + scriptarguments: + tags: + simple: FortiManager Vulnerability, CVE-2024-47575, FortiJump + type: + simple: IP + value: + simple: ${ExtractedIndicators.IP} + verdict: + simple: Malicious + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 480, + "y": 515 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "4": + id: "4" + taskid: cbce2eae-896c-4e8c-894b-a4ffd3d34e4e + type: regular + task: + id: cbce2eae-896c-4e8c-894b-a4ffd3d34e4e + version: -1 + name: CVE Indicators + description: commands.local.cmd.new.indicator + script: Builtin|||createNewIndicator + type: regular + iscommand: true + brand: Builtin + nexttasks: + '#none#': + - "6" + scriptarguments: + tags: + simple: FortiManager Vulnerability, CVE-2024-47575, FortiJump + type: + simple: CVE + value: + simple: ${ExtractedIndicators.CVE} + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 910, + "y": 515 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "6": + id: "6" + taskid: 8ab19925-9fbe-4fcd-8b82-a156cf3753d7 + type: title + task: + id: 8ab19925-9fbe-4fcd-8b82-a156cf3753d7 + version: -1 + name: XQL Hunting Queries + type: title + iscommand: false + brand: "" + description: '' + nexttasks: + '#none#': + - "7" + - "8" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 480, + "y": 690 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "7": + id: "7" + taskid: 7391477e-4356-4c10-8351-431248a5a355 + type: regular + task: + id: 7391477e-4356-4c10-8351-431248a5a355 + version: -1 + name: Unusual configuration changes + description: |- + Execute an XQL query and retrieve results of an executed XQL query API. The command will be executed every 10 seconds until results are retrieved or until a timeout error is raised. + When more than 1000 results are retrieved, the command will return a compressed gzipped JSON format file, + unless the argument 'parse_result_file_to_context' is set to true and then the results will be extracted to the context. + script: '|||xdr-xql-generic-query' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "13" + scriptarguments: + query: + simple: "config case_sensitive = false \n| dataset = fortinet_fortimanager_raw \n| filter _raw_log in (\"*Add device*\",\"*Modify device*\")\n| alter elog_changes = regextract(_raw_log, \"changes=\\\"(.*)\\\"\")\n| alter elog_msg = regextract(_raw_log, \"msg=\\\"(.*)\\\"\")" + query_name: + simple: FortiManager_CVE-2024-47575_Unusual_Configuration_Changes + time_frame: + simple: 90 days ago + separatecontext: false + continueonerror: true + continueonerrortype: "" + view: |- + { + "position": { + "x": 265, + "y": 835 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "8": + id: "8" + taskid: 3972d968-ea7a-4ef4-8b39-ca3ca0695684 + type: regular + task: + id: 3972d968-ea7a-4ef4-8b39-ca3ca0695684 + version: -1 + name: Known IOCs and post-exploitation artifacts + description: |- + Execute an XQL query and retrieve results of an executed XQL query API. The command will be executed every 10 seconds until results are retrieved or until a timeout error is raised. + When more than 1000 results are retrieved, the command will return a compressed gzipped JSON format file, + unless the argument 'parse_result_file_to_context' is set to true and then the results will be extracted to the context. + script: '|||xdr-xql-generic-query' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "13" + scriptarguments: + query: + simple: "config case_sensitive = false \n| dataset = fortinet_fortimanager_raw \n| filter _raw_log in (\"*tmp/\",\"*45.32.41.202*\",\"*104.238.141.143*\",\"*158.247.199.37*\",\"*195.85.114.78*\",\"*VMTM23017412*\",\"*Unregistered device localhost add succeeded*\",\"*0qsc137p@justdefinition.com*\",\"*Purity Supreme*\")\n| alter elog_changes = regextract(_raw_log, \"changes=\\\"(.*)\\\"\")\n| alter elog_msg = regextract(_raw_log, \"msg=\\\"(.*)\\\"\")" + query_name: + simple: FortiManager_CVE-2024-47575_Known_IoCs + time_frame: + simple: 90 days ago + separatecontext: false + continueonerror: true + continueonerrortype: "" + view: |- + { + "position": { + "x": 695, + "y": 835 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "9": + id: "9" + taskid: 7aeb2930-cf52-48bc-8414-6aa5fb39cc3d + type: regular + task: + id: 7aeb2930-cf52-48bc-8414-6aa5fb39cc3d + version: -1 + name: Email Indicators + description: commands.local.cmd.new.indicator + script: Builtin|||createNewIndicator + type: regular + iscommand: true + brand: Builtin + nexttasks: + '#none#': + - "6" + scriptarguments: + tags: + simple: FortiManager Vulnerability, CVE-2024-47575, FortiJump + type: + simple: Email + value: + simple: ${ExtractedIndicators.Email} + verdict: + simple: Malicious + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 515 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "10": + id: "10" + taskid: 492ead9e-256f-4fff-8762-9475fd141bea + type: title + task: + id: 492ead9e-256f-4fff-8762-9475fd141bea + version: -1 + name: Mitigations + type: title + iscommand: false + brand: "" + description: '' + nexttasks: + '#none#': + - "11" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 480, + "y": 1350 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "11": + id: "11" + taskid: 314858a6-69de-4ac4-8686-084e6fafffa7 + type: regular + task: + id: 314858a6-69de-4ac4-8686-084e6fafffa7 + version: -1 + name: Recommended Mitigations and Workarounds + description: |2+ + + ## Official Workarounds + + According to the [Fortinet PSIRT Advisory FG-IR-24-423](https://www.fortiguard.com/psirt/FG-IR-24-423), the following workarounds are recommended to mitigate the risk associated with CVE-2024-47575: + + #### 1. Restrict Access to the FortiManager Interface + + Apply local-in policies on FortiManager versions 7.2.0 and above to whitelist the IP addresses of FortiGates that are allowed to connect. + + ``` + config system local-in-policy + edit 1 + set action accept + set dport 541 + set src + next + edit 2 + set dport 541 + set action deny + next + end + ``` + + #### 2. Deny Unknown Devices - FortiManager versions 7.0.12 or above, 7.2.5 or above, 7.4.3 or above (but not 7.6.0). + + ``` + config system global + (global)# set fgfm-deny-unknown enable + (global)# end + ``` + Warning: With this setting enabled, be aware that if a FortiGate's SN is not in the device list, FortiManager will prevent it from connecting to register upon being deployed, even when a model device with PSK is matching. + + #### 3. Custom Certificates - FortiManager versions 7.2.2 and above, 7.4.0 and above, 7.6.0 and above. + + ``` + config system global + set fgfm-ca-cert + set fgfm-cert-exclusive enable + end + ``` + And install that certificate on FortiGates. Only this CA will be valid, this can act as a workaround, providing the attacker cannot obtain a certificate signed by this CA via an alternate channel. + + type: regular + iscommand: false + brand: "" + nexttasks: + '#none#': + - "12" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 480, + "y": 1495 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "12": + id: "12" + taskid: dccebff4-50c0-4ace-82d3-ce860a805802 + type: title + task: + id: dccebff4-50c0-4ace-82d3-ce860a805802 + version: -1 + name: Done + type: title + iscommand: false + brand: "" + description: '' + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 480, + "y": 1670 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "13": + id: "13" + taskid: 349b8b51-9af2-41e1-81f6-326621c7b307 + type: condition + task: + id: 349b8b51-9af2-41e1-81f6-326621c7b307 + version: -1 + name: Suspicious activity detected? + description: Check if results returned from the XQL queries + type: condition + iscommand: false + brand: "" + nexttasks: + '#default#': + - "10" + "yes": + - "14" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: isNotEqualString + left: + value: + simple: PaloAltoNetworksXQL.GenericQuery.number_of_results + iscontext: true + right: + value: + simple: "0" + continueonerrortype: "" + view: |- + { + "position": { + "x": 480, + "y": 1010 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "14": + id: "14" + taskid: bf114df4-8aa2-43e8-80e9-c29c67f3dad0 + type: collection + task: + id: bf114df4-8aa2-43e8-80e9-c29c67f3dad0 + version: -1 + name: Threat Hunting findings acknowledgement + description: Require the analyst to acknowledge results were found + type: collection + iscommand: false + brand: "" + nexttasks: + '#none#': + - "10" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 480, + "y": 1190 + } + } + note: false + timertriggers: [] + ignoreworker: false + message: + to: + subject: + body: + methods: [] + format: "" + bcc: + cc: + timings: + retriescount: 2 + retriesinterval: 360 + completeafterreplies: 1 + completeafterv2: true + completeaftersla: false + form: + questions: + - id: "0" + label: "" + labelarg: + simple: Did you review the suspicious activity detected? + required: true + gridcolumns: [] + defaultrows: [] + type: singleSelect + options: [] + optionsarg: + - simple: "Yes" + - simple: "No" + fieldassociated: "" + placeholder: "" + tooltip: "" + readonly: false + title: Analyst Acknowledgement + description: Requires the analyst to acknowledge the findings + sender: "" + expired: false + totalanswers: 0 + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false +view: |- + { + "linkLabelsPosition": { + "13_14_yes": 0.4 + }, + "paper": { + "dimensions": { + "height": 1685, + "width": 1240, + "x": 50, + "y": 50 + } + } + } +inputs: +- key: rawIoCs + value: + simple: 195.85.114[.]78, 104.238.141[.]143, 45.32.41[.]202, 158.247.199[.]37, CVE-2024-47575, 0qsc137p@justdefinition[.]com + required: false + description: FortiGuard Labs IoCs + playbookInputQuery: +inputSections: +- inputs: + - rawIoCs + name: General (Inputs group) + description: Generic group for inputs +outputSections: +- outputs: [] + name: General (Outputs group) + description: Generic group for outputs +outputs: [] +tests: +- No tests (auto formatted) +fromversion: 6.10.0 diff --git a/Packs/CVE_2024_47575/Playbooks/playbook-CVE-2024-47575_-_FortiManager_Authentication_Bypass_README.md b/Packs/CVE_2024_47575/Playbooks/playbook-CVE-2024-47575_-_FortiManager_Authentication_Bypass_README.md new file mode 100644 index 000000000000..03dfa635c16f --- /dev/null +++ b/Packs/CVE_2024_47575/Playbooks/playbook-CVE-2024-47575_-_FortiManager_Authentication_Bypass_README.md @@ -0,0 +1,88 @@ +CVE-2024-47575, also known as **FortiJump**, is a critical zero-day vulnerability affecting **FortiManager**, a centralized management platform for Fortinet devices. The vulnerability arises due to missing authentication checks in specific FortiManager REST API endpoints. An unauthenticated attacker with network access to the FortiManager device can exploit this flaw to execute arbitrary code or commands, potentially leading to complete system compromise. + +--- + +## Affected Versions + +| FortiManager Version | Status | +|------------------------|--------------------| +| **7.2.0 to 7.2.3** | Affected | +| **7.0.0 to 7.0.7** | Affected | +| **6.4.0 to 6.4.11** | Affected | +| **6.2.x and earlier** | Potentially Affected | +| **7.2.4 and above** | **Patched** | +| **7.0.8 and above** | **Patched** | +| **6.4.12 and above** | **Patched** | + +*Note:* + +Old FortiAnalyzer models 1000E, 1000F, 2000E, 3000E, 3000F, 3000G, 3500E, 3500F, 3500G, 3700F, 3700G, 3900E with the following feature enabled (FortiManager on FortiAnalyzer): + +config system global +set fmg-status enable +end + +And at least one interface with the fgfm service enabled is also impacted by this vulnerability. + +--- + +## Playbook Flow + +1. Create, Tag, and Block Indicators + +2. Hunt **Automatically** for Suspicious Behavior Related to the exploitation flow using XQL +**Note: The 'fortinet_fortimanager_raw' dataset must be available for the XQL queries completion.** + +3. Provide Mitigations and Workarounds + +--- + +**References**: + +- [Fortinet PSIRT Advisory FG-IR-24-423](https://www.fortiguard.com/psirt/FG-IR-24-423) + +--- + +By following this playbook, organizations can effectively respond to and mitigate the risks associated with **CVE-2024-47575 (FortiJump)**. + + +## Dependencies + +This playbook uses the following sub-playbooks, integrations, and scripts. + +### Sub-playbooks + +This playbook does not use any sub-playbooks. + +### Integrations + +This playbook does not use any integrations. + +### Scripts + +This playbook does not use any scripts. + +### Commands + +* createNewIndicator +* extractIndicators +* xdr-xql-generic-query + +## Playbook Inputs + +--- + +| **Name** | **Description** | **Default Value** | **Required** | +| --- | --- | --- | --- | +| rawIoCs | FortiGuard Labs IoCs | 195.85.114[.]78, 104.238.141[.]143, 45.32.41[.]202, 158.247.199[.]37, CVE-2024-47575, 0qsc137p@justdefinition[.]com | Optional | + +## Playbook Outputs + +--- +There are no outputs for this playbook. + +## Playbook Image + +--- + +![CVE-2024-47575 - FortiManager Authentication Bypass](../doc_files/CVE-2024-47575_-_FortiManager_Authentication_Bypass.png) diff --git a/Packs/CVE_2024_47575/README.md b/Packs/CVE_2024_47575/README.md new file mode 100644 index 000000000000..cd9c93c9586a --- /dev/null +++ b/Packs/CVE_2024_47575/README.md @@ -0,0 +1,31 @@ +## FortiJump Vulnerability (CVE-2024-47575) + +On October 25, 2023, a critical zero-day vulnerability was disclosed in **FortiManager**, a centralized management platform for Fortinet devices. This vulnerability, known as **FortiJump** and tracked as **CVE-2024-47575**, allows an unauthenticated attacker with network access to execute arbitrary code or commands on the affected system, potentially leading to complete system compromise. This vulnerability has been rated **Critical** severity (CVSS 9.8). + +### Impacted Versions + +The vulnerability impacts the following FortiManager versions: + +- FortiManager versions **7.2.0** to **7.2.3** +- FortiManager versions **7.0.0** to **7.0.7** +- FortiManager versions **6.4.0** to **6.4.11** +- FortiManager versions **6.2.x** and earlier (Potentially Affected) + +### Patched Versions + +- FortiManager versions **7.2.4** and above +- FortiManager versions **7.0.8** and above +- FortiManager versions **6.4.12** and above + +### This pack provides you with a first response kit which includes: + +* Collect, Extract, and Enrich Indicators + +* Threat Hunting using XQL Query Engine + + * Note: The 'fortinet_fortimanager_raw' dataset must be available for the XQL queries to function. + +* Mitigations and Workarounds + +#### References +[Fortinet PSIRT Advisory FG-IR-24-423](https://www.fortiguard.com/psirt/FG-IR-24-423) \ No newline at end of file diff --git a/Packs/CVE_2024_47575/doc_files/CVE-2024-47575_-_FortiManager_Authentication_Bypass.png b/Packs/CVE_2024_47575/doc_files/CVE-2024-47575_-_FortiManager_Authentication_Bypass.png new file mode 100644 index 000000000000..0d70dac6b639 Binary files /dev/null and b/Packs/CVE_2024_47575/doc_files/CVE-2024-47575_-_FortiManager_Authentication_Bypass.png differ diff --git a/Packs/CVE_2024_47575/pack_metadata.json b/Packs/CVE_2024_47575/pack_metadata.json new file mode 100644 index 000000000000..3337c9d23373 --- /dev/null +++ b/Packs/CVE_2024_47575/pack_metadata.json @@ -0,0 +1,28 @@ +{ + "name": "CVE-2024-47575 - FortiManager Authentication Bypass", + "description": "This pack handles CVE-2024-47575 - FortiManager Authentication Bypass vulnerability", + "support": "xsoar", + "currentVersion": "1.0.0", + "author": "Cortex XSOAR", + "url": "https://www.paloaltonetworks.com/cortex", + "email": "", + "categories": [ + "Case Management" + ], + "tags": [], + "useCases": [], + "keywords": [ + "zero-day", + "0-day", + "zero day", + "Fortinet", + "FortiManager", + "CVE-2024-47575", + "47575", + "FortiJump" + ], + "marketplaces": [ + "xsoar", + "marketplacev2" + ] +} \ No newline at end of file diff --git a/Packs/CommonPlaybooks/Playbooks/playbook-Block_Indicators_-_Generic_v3.yml b/Packs/CommonPlaybooks/Playbooks/playbook-Block_Indicators_-_Generic_v3.yml index 717bfb5e1440..16a6fc5635a7 100644 --- a/Packs/CommonPlaybooks/Playbooks/playbook-Block_Indicators_-_Generic_v3.yml +++ b/Packs/CommonPlaybooks/Playbooks/playbook-Block_Indicators_-_Generic_v3.yml @@ -1174,7 +1174,7 @@ tasks: type: condition task: id: 4b64da5f-53b9-4fdd-8e65-5a133c6700d6 - description: "" + description: "Looks for available indicators to process" version: -1 name: Are there indicators to block? type: condition @@ -1551,12 +1551,7 @@ inputs: value: simple: "True" required: false - description: |- - Possible values: True/False. Default: True. - Should the given indicators be automatically blocked, or should the user be given the option to choose? - - If set to False - no prompt will appear, and all provided indicators will be blocked automatically. - If set to True - the user will be prompted to select which indicators to block. + description: "Should the given indicators be automatically blocked, or should the user be prompted to select whether to block them?\n\nPossible values: True/False. \nDefault value: True.\n\nIf set to True - No prompt will appear. All of the provided indicators will be blocked automatically.\n\nIf set to False - The user will be prompted to select which indicators to block." playbookInputQuery: - key: CustomBlockRule value: diff --git a/Packs/CommonPlaybooks/Playbooks/playbook-Block_Indicators_-_Generic_v3_README.md b/Packs/CommonPlaybooks/Playbooks/playbook-Block_Indicators_-_Generic_v3_README.md index 2d310574bd70..30b5500cca42 100644 --- a/Packs/CommonPlaybooks/Playbooks/playbook-Block_Indicators_-_Generic_v3_README.md +++ b/Packs/CommonPlaybooks/Playbooks/playbook-Block_Indicators_-_Generic_v3_README.md @@ -13,12 +13,12 @@ This playbook uses the following sub-playbooks, integrations, and scripts. ### Sub-playbooks +* Block Account - Generic v2 * Block Domain - Generic v2 -* Block URL - Generic v2 * Block Email - Generic v2 -* Block IP - Generic v3 * Block File - Generic v2 -* Block Account - Generic v2 +* Block IP - Generic v3 +* Block URL - Generic v2 ### Integrations @@ -46,7 +46,7 @@ This playbook does not use any integrations. | FilesToBlock | Array of malicious file hashes to block. | DBotScore.Indicator | Optional | | DomainToBlock | The domain that you wish to block. | DBotScore.Indicator | Optional | | EmailToBlock | The email address that you wish to block. | DBotScore.Indicator | Optional | -| AutoBlockIndicators | Possible values: True/False. Default: True.
Should the given indicators be automatically blocked, or should the user be given the option to choose?

If set to False - no prompt will appear, and all provided indicators will be blocked automatically.
If set to True - the user will be prompted to select which indicators to block. | True | Optional | +| AutoBlockIndicators | Should the given indicators be automatically blocked, or should the user be prompted to select whether to block them?

Possible values: True/False.
Default value: True.

If set to True - No prompt will appear. All of the provided indicators will be blocked automatically.

If set to False - The user will be prompted to select which indicators to block. | True | Optional | | CustomBlockRule | This input determines whether Palo Alto Networks Panorama or Firewall Custom Block Rules are used.
Specify "True" to create new Custom Block Rules \(2 FW rules inside the PAN-OS device\).
For "False" - no rules will be created. | True | Optional | | LogForwarding | Panorama log forwarding object name. Indicate what type of Log Forwarding setting will be specified in the PAN-OS custom rules. | | Optional | | AutoCommit | This input determines whether to commit the configuration automatically on PAN-OS devices and other FWs.
Yes - Commit automatically.
No - Commit manually. | No | Optional | diff --git a/Packs/CommonPlaybooks/Playbooks/playbook-Containment_Plan_-_Block_Indicators.yml b/Packs/CommonPlaybooks/Playbooks/playbook-Containment_Plan_-_Block_Indicators.yml index e6c6d917ef27..cafa50d357e3 100644 --- a/Packs/CommonPlaybooks/Playbooks/playbook-Containment_Plan_-_Block_Indicators.yml +++ b/Packs/CommonPlaybooks/Playbooks/playbook-Containment_Plan_-_Block_Indicators.yml @@ -59,7 +59,7 @@ tasks: brand: "" nexttasks: '#none#': - - "10" + - "32" scriptarguments: comment: complex: @@ -122,8 +122,8 @@ tasks: view: |- { "position": { - "x": 680, - "y": 1520 + "x": 690, + "y": 1710 } } note: false @@ -208,7 +208,7 @@ tasks: { "position": { "x": 470, - "y": 760 + "y": 990 } } note: false @@ -246,7 +246,7 @@ tasks: { "position": { "x": 230, - "y": 1350 + "y": 1530 } } note: false @@ -412,7 +412,7 @@ tasks: brand: "" nexttasks: '#none#': - - "29" + - "31" scriptarguments: comment: complex: @@ -612,7 +612,7 @@ tasks: { "position": { "x": 230, - "y": 990 + "y": 1170 } } note: false @@ -651,7 +651,7 @@ tasks: { "position": { "x": -10, - "y": 760 + "y": 990 } } note: false @@ -692,7 +692,93 @@ tasks: { "position": { "x": 230, - "y": 1160 + "y": 1340 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "31": + id: "31" + taskid: 5e12fc6b-2fa0-43d0-8a46-d2f213525a45 + type: condition + task: + id: 5e12fc6b-2fa0-43d0-8a46-d2f213525a45 + version: -1 + name: Is the file hash was added to the block list? + description: Checks whether the file hash exists. + type: condition + iscommand: false + brand: "" + nexttasks: + '#default#': + - "28" + "yes": + - "29" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: isNotEmpty + left: + value: + simple: Core.blocklist.added_hashes.fileHash + iscontext: true + right: + value: {} + continueonerrortype: "" + view: |- + { + "position": { + "x": -10, + "y": 780 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "32": + id: "32" + taskid: 5df17f17-1825-4ac0-8edf-c0e89f437551 + type: condition + task: + id: 5df17f17-1825-4ac0-8edf-c0e89f437551 + version: -1 + name: Is the file hash was added to the block list? + description: Checks whether the file hash exists. + type: condition + iscommand: false + brand: "" + nexttasks: + '#default#': + - "28" + "yes": + - "10" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: isNotEmpty + left: + value: + simple: Core.blocklist.added_hashes.fileHash + iscontext: true + right: + value: {} + continueonerrortype: "" + view: |- + { + "position": { + "x": 470, + "y": 780 } } note: false @@ -710,13 +796,15 @@ view: |- "26_28_#default#": 0.29, "30_11_yes": 0.52, "30_2_#default#": 0.38, + "31_29_yes": 0.51, + "32_10_yes": 0.57, "3_25_yes": 0.43, "3_2_#default#": 0.12 }, "paper": { "dimensions": { - "height": 1775, - "width": 1070, + "height": 1965, + "width": 1080, "x": -10, "y": -190 } diff --git a/Packs/CommonPlaybooks/Playbooks/playbook-Endpoint_Investigation_Plan.yml b/Packs/CommonPlaybooks/Playbooks/playbook-Endpoint_Investigation_Plan.yml index bd4151895605..e70ce6f1f1b8 100644 --- a/Packs/CommonPlaybooks/Playbooks/playbook-Endpoint_Investigation_Plan.yml +++ b/Packs/CommonPlaybooks/Playbooks/playbook-Endpoint_Investigation_Plan.yml @@ -1572,7 +1572,7 @@ tasks: - "9" scriptarguments: query: - simple: agentsid:${inputs.agentID} and caseid:${parentIncidentFields.incident_id} + simple: agentid:${inputs.agentID} and caseid:${parentIncidentFields.incident_id} separatecontext: false view: |- { diff --git a/Packs/CommonPlaybooks/ReleaseNotes/2_6_44.md b/Packs/CommonPlaybooks/ReleaseNotes/2_6_44.md new file mode 100644 index 000000000000..45b9a1191d2a --- /dev/null +++ b/Packs/CommonPlaybooks/ReleaseNotes/2_6_44.md @@ -0,0 +1,6 @@ + +#### Playbooks + +##### Block Indicators - Generic v3 + +- Fixes the 'AutoBlockIndicators' input description. diff --git a/Packs/CommonPlaybooks/ReleaseNotes/2_6_45.md b/Packs/CommonPlaybooks/ReleaseNotes/2_6_45.md new file mode 100644 index 000000000000..33d938f6fde9 --- /dev/null +++ b/Packs/CommonPlaybooks/ReleaseNotes/2_6_45.md @@ -0,0 +1,6 @@ + +#### Playbooks + +##### Endpoint Investigation Plan + +Fixed an issue with the 'SearchAlertsV2' query for hunt by host ID. diff --git a/Packs/CommonPlaybooks/ReleaseNotes/2_6_46.md b/Packs/CommonPlaybooks/ReleaseNotes/2_6_46.md new file mode 100644 index 000000000000..b8c6cbc1e893 --- /dev/null +++ b/Packs/CommonPlaybooks/ReleaseNotes/2_6_46.md @@ -0,0 +1,6 @@ + +#### Playbooks + +##### Containment Plan - Block Indicators + +Added new tasks to verify if the file hash was added to the block list. \ No newline at end of file diff --git a/Packs/CommonPlaybooks/TestPlaybooks/playbook-Containment_Plan-Test.yml b/Packs/CommonPlaybooks/TestPlaybooks/playbook-Containment_Plan-Test.yml index cc2a289b80e0..260cb246d319 100644 --- a/Packs/CommonPlaybooks/TestPlaybooks/playbook-Containment_Plan-Test.yml +++ b/Packs/CommonPlaybooks/TestPlaybooks/playbook-Containment_Plan-Test.yml @@ -56,7 +56,7 @@ tasks: { "position": { "x": 60, - "y": 710 + "y": 890 } } note: false @@ -93,7 +93,7 @@ tasks: { "position": { "x": 60, - "y": -1050 + "y": -870 } } note: false @@ -132,7 +132,7 @@ tasks: { "position": { "x": 60, - "y": -1390 + "y": -1210 } } note: false @@ -157,7 +157,7 @@ tasks: brand: "" nexttasks: '#none#': - - "150" + - "186" scriptarguments: key: simple: Hash @@ -206,7 +206,7 @@ tasks: { "position": { "x": 60, - "y": -10 + "y": 170 } } note: false @@ -243,7 +243,7 @@ tasks: { "position": { "x": 60, - "y": -190 + "y": -10 } } note: false @@ -282,7 +282,7 @@ tasks: { "position": { "x": 60, - "y": 175 + "y": 355 } } note: false @@ -332,7 +332,7 @@ tasks: { "position": { "x": 60, - "y": 360 + "y": 540 } } note: false @@ -367,7 +367,7 @@ tasks: { "position": { "x": 310, - "y": 540 + "y": 720 } } note: false @@ -603,7 +603,7 @@ tasks: { "position": { "x": 60, - "y": -560 + "y": -380 } } note: false @@ -640,7 +640,7 @@ tasks: { "position": { "x": 60, - "y": -1220 + "y": -1040 } } note: false @@ -999,7 +999,7 @@ tasks: { "position": { "x": 60, - "y": -890 + "y": -710 } } note: false @@ -1036,7 +1036,7 @@ tasks: { "position": { "x": 60, - "y": -730 + "y": -550 } } note: false @@ -1073,7 +1073,43 @@ tasks: { "position": { "x": 60, - "y": -385 + "y": -205 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "186": + id: "186" + taskid: af8cc56d-d7b3-4805-8f2c-66ff1d31b61b + type: regular + task: + id: af8cc56d-d7b3-4805-8f2c-66ff1d31b61b + version: -1 + name: Remove hash from blocklist + description: Removes requested files from block list. + script: '|||core-remove-blocklist-files' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "150" + scriptarguments: + hash_list: + simple: 724e1e4079191f086c3a2bcc15133b4309ce5125dbb31c5443262599ca992601 + separatecontext: false + continueonerror: true + continueonerrortype: "" + view: |- + { + "position": { + "x": 60, + "y": -1400 } } note: false @@ -1090,7 +1126,7 @@ view: |- }, "paper": { "dimensions": { - "height": 4485, + "height": 4665, "width": 650, "x": 60, "y": -3710 diff --git a/Packs/CommonPlaybooks/doc_files/Containment_Plan_-_Block_Indicators.png b/Packs/CommonPlaybooks/doc_files/Containment_Plan_-_Block_Indicators.png index 64e9947357d0..19ef27900872 100644 Binary files a/Packs/CommonPlaybooks/doc_files/Containment_Plan_-_Block_Indicators.png and b/Packs/CommonPlaybooks/doc_files/Containment_Plan_-_Block_Indicators.png differ diff --git a/Packs/CommonPlaybooks/pack_metadata.json b/Packs/CommonPlaybooks/pack_metadata.json index a522bd6888ab..811c230a7269 100644 --- a/Packs/CommonPlaybooks/pack_metadata.json +++ b/Packs/CommonPlaybooks/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Common Playbooks", "description": "Frequently used playbooks pack.", "support": "xsoar", - "currentVersion": "2.6.43", + "currentVersion": "2.6.46", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/CommonScripts/ReleaseNotes/1_15_74.md b/Packs/CommonScripts/ReleaseNotes/1_15_74.md new file mode 100644 index 000000000000..953a2ff2fab7 --- /dev/null +++ b/Packs/CommonScripts/ReleaseNotes/1_15_74.md @@ -0,0 +1,8 @@ + +#### Scripts + +##### SearchIncidentsV2 +<~XSIAM> +- Added the *includeinformational* argument. + +- Updated the Docker image to: *demisto/python3:3.11.10.111526*. diff --git a/Packs/CommonScripts/ReleaseNotes/1_15_75.md b/Packs/CommonScripts/ReleaseNotes/1_15_75.md new file mode 100644 index 000000000000..ed2697d772ec --- /dev/null +++ b/Packs/CommonScripts/ReleaseNotes/1_15_75.md @@ -0,0 +1,11 @@ + +#### Scripts + +##### PreProcessImage + +- Updated the Docker image to: *demisto/processing-image-file:1.0.0.113909*. + +##### PcapHTTPExtractor +- Updated the Docker image to: *demisto/pcap-http-extractor:1.0.0.113908*. + + diff --git a/Packs/CommonScripts/ReleaseNotes/1_15_76.md b/Packs/CommonScripts/ReleaseNotes/1_15_76.md new file mode 100644 index 000000000000..d95c1371bc6f --- /dev/null +++ b/Packs/CommonScripts/ReleaseNotes/1_15_76.md @@ -0,0 +1,6 @@ + +#### Scripts + +##### SSDeepSimilarity + +- Updated the Docker image to: *demisto/ssdeep:1.0.0.114703*. diff --git a/Packs/CommonScripts/ReleaseNotes/1_15_77.md b/Packs/CommonScripts/ReleaseNotes/1_15_77.md new file mode 100644 index 000000000000..b0f7f2fdd022 --- /dev/null +++ b/Packs/CommonScripts/ReleaseNotes/1_15_77.md @@ -0,0 +1,6 @@ + +#### Scripts + +##### FailedInstances + +Fixed an issue where the script was ignoring instances in an error state. \ No newline at end of file diff --git a/Packs/CommonScripts/Scripts/FailedInstances/FailedInstances.js b/Packs/CommonScripts/Scripts/FailedInstances/FailedInstances.js index 18b372c11945..106cfc316201 100644 --- a/Packs/CommonScripts/Scripts/FailedInstances/FailedInstances.js +++ b/Packs/CommonScripts/Scripts/FailedInstances/FailedInstances.js @@ -7,7 +7,8 @@ var countSuccess = 0; var instances = []; Object.keys(all).forEach(function(m) { - if (all[m].state === 'active' && all[m].defaultIgnored !== 'true' && INTERNAL_MODULES_BRANDS.indexOf(all[m].brand) === -1) { + var isShouldBeTesting = all[m].defaultIgnored !== 'true' && INTERNAL_MODULES_BRANDS.indexOf(all[m].brand) === -1; + if (all[m].state === 'active' && isShouldBeTesting) { var cmd = m.replace(/\s/g,'_') + '-test-module'; var firstRest = executeCommand("addEntries", {"entries": JSON.stringify([{ Type: entryTypes.note, @@ -43,6 +44,16 @@ Object.keys(all).forEach(function(m) { instances.push({instance: m, brand: all[m].brand, category: all[m].category, information: 'succeed', status: 'success' }); } + } else if (all[m].state === 'error' && isShouldBeTesting) { + var errorMessage = 'The instance is in an error state, potentially due to an issue with the engine.'; + executeCommand("addEntries", {"entries": JSON.stringify([{ + Type: entryTypes.note, + Contents: 'done testing **' + m + '**:\n' + errorMessage, + HumanReadable: 'done testing **' + m + '**:\n' + errorMessage, + ContentsFormat: formats.markdown + }])}); + countFailed++; + failedInstances.push({instance: m, brand: all[m].brand, category: all[m].category, information: errorMessage, status: 'failure' }); } }); diff --git a/Packs/CommonScripts/Scripts/PcapHTTPExtractor/PcapHTTPExtractor.yml b/Packs/CommonScripts/Scripts/PcapHTTPExtractor/PcapHTTPExtractor.yml index 05941f634971..9f85e76d91a5 100644 --- a/Packs/CommonScripts/Scripts/PcapHTTPExtractor/PcapHTTPExtractor.yml +++ b/Packs/CommonScripts/Scripts/PcapHTTPExtractor/PcapHTTPExtractor.yml @@ -67,7 +67,7 @@ tags: - http timeout: '0' type: python -dockerimage: demisto/pcap-http-extractor:1.0.0.112272 +dockerimage: demisto/pcap-http-extractor:1.0.0.113908 tests: - PcapHTTPExtractor-Test subtype: python3 diff --git a/Packs/CommonScripts/Scripts/PreProcessImage/PreProcessImage.yml b/Packs/CommonScripts/Scripts/PreProcessImage/PreProcessImage.yml index c0888a702928..529056eb66ea 100644 --- a/Packs/CommonScripts/Scripts/PreProcessImage/PreProcessImage.yml +++ b/Packs/CommonScripts/Scripts/PreProcessImage/PreProcessImage.yml @@ -31,7 +31,7 @@ script: '-' subtype: python3 timeout: 480ns type: python -dockerimage: demisto/processing-image-file:1.0.0.93358 +dockerimage: demisto/processing-image-file:1.0.0.113909 tests: - No tests (auto formatted) fromversion: 6.9.0 diff --git a/Packs/CommonScripts/Scripts/SSDeepSimilarity/SSDeepSimilarity.yml b/Packs/CommonScripts/Scripts/SSDeepSimilarity/SSDeepSimilarity.yml index 2af4a03f9684..25c3a398fe27 100644 --- a/Packs/CommonScripts/Scripts/SSDeepSimilarity/SSDeepSimilarity.yml +++ b/Packs/CommonScripts/Scripts/SSDeepSimilarity/SSDeepSimilarity.yml @@ -30,7 +30,7 @@ outputs: type: string scripttarget: 0 subtype: python3 -dockerimage: demisto/ssdeep:1.0.0.112284 +dockerimage: demisto/ssdeep:1.0.0.114703 runas: DBotWeakRole fromversion: 5.5.0 tests: diff --git a/Packs/CommonScripts/Scripts/SearchIncidentsV2/README.md b/Packs/CommonScripts/Scripts/SearchIncidentsV2/README.md index c04b30916a2a..8d5786eec73d 100644 --- a/Packs/CommonScripts/Scripts/SearchIncidentsV2/README.md +++ b/Packs/CommonScripts/Scripts/SearchIncidentsV2/README.md @@ -60,31 +60,32 @@ Spring Core and Cloud Function SpEL RCEs ## Inputs --- -| **Argument Name** | **Description** | -|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| id | A comma-separated list of incident IDs by which to filter the results. | -| name | A comma-separated list of incident names by which to filter the results. | -| status | A comma-separated list of incident statuses by which to filter the results. For example: assigned. | -| notstatus | A comma-separated list of incident statuses to exclude from the results. For example: assigned. | -| reason | A comma-separated list of incident close reasons by which to filter the results. | -| fromdate | Filter by from date \(e.g. "3 days ago" or 2006-01-02T15:04:05\+07:00 or 2006-01-02T15:04:05Z\) | -| todate | Filter by to date \(e.g. "3 days ago" or 2006-01-02T15:04:05\+07:00 or 2006-01-02T15:04:05Z\) | -| fromclosedate | Filter by from close date \(e.g. 2006-01-02T15:04:05\+07:00 or 2006-01-02T15:04:05Z\) | -| toclosedate | Filter by to close date \(e.g. 2006-01-02T15:04:05\+07:00 or 2006-01-02T15:04:05Z\) | -| fromduedate | Filter by from due date \(e.g. 2006-01-02T15:04:05\+07:00 or 2006-01-02T15:04:05Z\) | -| toduedate | Filter by to due date \(e.g. 2006-01-02T15:04:05\+07:00 or 2006-01-02T15:04:05Z\) | -| level | Filter by Severity | -| owner | Filter by incident owners | -| details | Filter by incident details | -| type | Filter by incident type | -| query | Use free form query \(use Lucene syntax\) as filter. All other filters will be ignored when this filter is used. | -| page | Filter by the page number (deprecated) | -| trimevents | The number of events to return from the alert JSON. The default is 0, which returns all events.
Note that the count is from the head of the list, regardless of event time or other properties. | -| size | Number of incidents per page \(per fetch\) (deprecated) | -| sort | Sort in format of field.asc,field.desc,... | -| searchresultslabel | If provided, the value of this argument will be set under the searchResultsLabel context key for each incident found. | -| summarizedversion | If enabled runs a summarized version of this script. Disables auto-extract, sets fromDate to 30 days, and minimizes the context output. You can add sepcific fields to context using the add_fields_to_summarize_context argument. Default is false. | -| limit | The maximum number of incidents to be returned. Default is 100. | +| **Argument Name** | **Description** | +|--------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| id | A comma-separated list of incident IDs by which to filter the results. | +| name | A comma-separated list of incident names by which to filter the results. | +| status | A comma-separated list of incident statuses by which to filter the results. For example: assigned. | +| notstatus | A comma-separated list of incident statuses to exclude from the results. For example: assigned. | +| reason | A comma-separated list of incident close reasons by which to filter the results. | +| fromdate | Filter by from date \(e.g. "3 days ago" or 2006-01-02T15:04:05\+07:00 or 2006-01-02T15:04:05Z\) | +| todate | Filter by to date \(e.g. "3 days ago" or 2006-01-02T15:04:05\+07:00 or 2006-01-02T15:04:05Z\) | +| fromclosedate | Filter by from close date \(e.g. 2006-01-02T15:04:05\+07:00 or 2006-01-02T15:04:05Z\) | +| toclosedate | Filter by to close date \(e.g. 2006-01-02T15:04:05\+07:00 or 2006-01-02T15:04:05Z\) | +| fromduedate | Filter by from due date \(e.g. 2006-01-02T15:04:05\+07:00 or 2006-01-02T15:04:05Z\) | +| toduedate | Filter by to due date \(e.g. 2006-01-02T15:04:05\+07:00 or 2006-01-02T15:04:05Z\) | +| level | Filter by Severity | +| owner | Filter by incident owners | +| details | Filter by incident details | +| type | Filter by incident type | +| query | Use free form query \(use Lucene syntax\) as filter. All other filters will be ignored when this filter is used. | +| page | Filter by the page number (deprecated) | +| trimevents | The number of events to return from the alert JSON. The default is 0, which returns all events.
Note that the count is from the head of the list, regardless of event time or other properties. | +| size | Number of incidents per page \(per fetch\) (deprecated) | +| sort | Sort in format of field.asc,field.desc,... | +| searchresultslabel | If provided, the value of this argument will be set under the searchResultsLabel context key for each incident found. | +| summarizedversion | If enabled runs a summarized version of this script. Disables auto-extract, sets fromDate to 30 days, and minimizes the context output. You can add sepcific fields to context using the add_fields_to_summarize_context argument. Default is false. | +| includeinformational | Supported only in XSIAM. When the value is set to 'True', informational severity alerts will return as part of the results. The ‘fromdate’ and ‘todate’ arguments must be provided to use this argument. The maximum value currently supported for the 'fromdate' argument to retrieve informational incidents is 5 hours. If a value greater than this is provided, it will be adjusted to 5 hours ago. To retrieve only informational incidents, use the `query` argument and include this limitation within the query. Default is false. | +| limit | The maximum number of incidents to be returned. Default is 100. | ## Outputs --- diff --git a/Packs/CommonScripts/Scripts/SearchIncidentsV2/SearchIncidentsV2.py b/Packs/CommonScripts/Scripts/SearchIncidentsV2/SearchIncidentsV2.py index 29a682974e14..c4cdb7106bd0 100644 --- a/Packs/CommonScripts/Scripts/SearchIncidentsV2/SearchIncidentsV2.py +++ b/Packs/CommonScripts/Scripts/SearchIncidentsV2/SearchIncidentsV2.py @@ -134,7 +134,8 @@ def transform_to_alert_data(incidents: List): return incidents -def search_incidents(args: Dict): # pragma: no cover +def search_incidents(args: Dict): # pragma: no cover + hr_prefix = '' is_summarized_version = argToBoolean(args.get('summarizedversion', False)) platform = get_demisto_version().get('platform', 'xsoar') if not is_valid_args(args): @@ -155,6 +156,22 @@ def search_incidents(args: Dict): # pragma: no cover if args.get('trimevents') == '0': args.pop('trimevents') + if includeinformational := argToBoolean(args.get('includeinformational', False)): + if not is_xsiam(): + raise ValueError('The includeinformational argument is supported only in XSIAM.') + if not (args.get('fromdate') and args.get('todate')): + raise ValueError('The includeinformational argument requires fromdate and todate arguments.') + + if (datetime.utcnow() - fromdate).total_seconds() > 5 * 60 * 60: # type: ignore + args['fromdate'] = arg_to_datetime('5 hours ago').isoformat() # type: ignore + hr_prefix = (f'fromdate: {fromdate} is more than 5 hours ago. We support ' + f'querying informational incidents for up to the last 5 hours. The fromdate has been' + f' adjusted to 5 hours ago.') + args['includeinformational'] = includeinformational + + else: + args.pop('includeinformational', None) + # handle list of ids if args.get('id'): args['id'] = ','.join(argToList(args.get('id'), transform=str)) @@ -162,9 +179,11 @@ def search_incidents(args: Dict): # pragma: no cover res: List = execute_command('getIncidents', args, extract_contents=False) incident_found: bool = check_if_found_incident(res) if not incident_found: + if hr_prefix: + hr_prefix = f'{hr_prefix}\n' if platform == 'x2': - return 'Alerts not found.', {}, {} - return 'Incidents not found.', {}, {} + return f'{hr_prefix}Alerts not found.', {}, {} + return f'{hr_prefix}Incidents not found.', {}, {} limit = arg_to_number(args.get('limit')) or DEFAULT_LIMIT all_found_incidents = res[0]["Contents"]["data"] demisto.debug( @@ -215,6 +234,8 @@ def search_incidents(args: Dict): # pragma: no cover md = tableToMarkdown(name="Incidents found", t=all_found_incidents, headers=headers + additional_headers, url_keys=['incidentLink']) + if hr_prefix: + md = f'{hr_prefix}\n{md}' demisto.debug(f'amount of all the incidents that were found {len(all_found_incidents)}') return md, all_found_incidents, res diff --git a/Packs/CommonScripts/Scripts/SearchIncidentsV2/SearchIncidentsV2.yml b/Packs/CommonScripts/Scripts/SearchIncidentsV2/SearchIncidentsV2.yml index 6f9209a8aa1e..3a43bc9f8ae9 100644 --- a/Packs/CommonScripts/Scripts/SearchIncidentsV2/SearchIncidentsV2.yml +++ b/Packs/CommonScripts/Scripts/SearchIncidentsV2/SearchIncidentsV2.yml @@ -64,6 +64,13 @@ args: predefined: - "false" - "true" +- description: Supported only in XSIAM. When the value is set to 'True', informational severity alerts will return as part of the results. The ‘fromdate’ and ‘todate’ arguments must be provided to use this argument. The maximum value currently supported for the 'fromdate' argument to retrieve informational incidents is 5 hours. If a value greater than this is provided, it will be adjusted to 5 hours ago. To retrieve only informational incidents, use the `query` argument and include this limitation within the query. Default is false. + name: includeinformational + auto: PREDEFINED + predefined: + - "false" + - "true" + defaultValue: "false" - description: A comma seperated list of fields to add to context when using summarized version, (default- id,name,type,severity,status,owner,created,closed). name: add_fields_to_summarize_context comment: |- @@ -123,7 +130,7 @@ tags: - Utility timeout: '0' type: python -dockerimage: demisto/python3:3.10.13.83255 +dockerimage: demisto/python3:3.11.10.111526 fromversion: 5.0.0 tests: - No tests (auto formatted) diff --git a/Packs/CommonScripts/Scripts/SearchIncidentsV2/SearchIncidentsV2_test.py b/Packs/CommonScripts/Scripts/SearchIncidentsV2/SearchIncidentsV2_test.py index 654c08d1a223..17041ada41bc 100644 --- a/Packs/CommonScripts/Scripts/SearchIncidentsV2/SearchIncidentsV2_test.py +++ b/Packs/CommonScripts/Scripts/SearchIncidentsV2/SearchIncidentsV2_test.py @@ -1,5 +1,6 @@ from SearchIncidentsV2 import * import pytest +import datetime as dt data_test_check_if_found_incident = [ ([], 'failed to get incidents from xsoar.\nGot: []'), @@ -208,6 +209,110 @@ def test_filter_events(mocker, args, filtered_args, expected_result): assert execute_mock.call_args[0][1] == filtered_args +def get_incidents_mock_include_informational(_, args, extract_contents=True, fail_on_error=True): + incidents = [ + {'id': '1', 'informational': False}, + {'id': '2', 'informational': False}, + ] + + includeinformational = args.get('includeinformational', None) + + if includeinformational: + incidents.extend([ + {'id': '3', 'informational': True}, + {'id': '4', 'informational': True}, + ]) + + if not extract_contents: + return [{'Contents': {'data': incidents, 'total': len(incidents)}}] + + return {'Contents': {'data': incidents}} + + +INCLUDE_INFORMATIONAL_FIXED_TIME = dt.datetime(2024, 10, 1, 15, 0, 0) +INCLUDE_INFORMATIONAL_NOW = INCLUDE_INFORMATIONAL_FIXED_TIME.isoformat() +INCLUDE_INFORMATIONAL_5_HOURS_AGO = dt.datetime(2024, 10, 1, 10, 0, 0).isoformat() +INCLUDE_INFORMATIONAL_3_HOURS_AGO = dt.datetime(2024, 10, 1, 12, 0, 0).isoformat() + + +@pytest.mark.parametrize('args,expected_filtered_args,expected_result', [ + ({'includeinformational': 'true', 'fromdate': '3 hours ago', 'todate': 'now'}, + {'includeinformational': True, + 'fromdate': INCLUDE_INFORMATIONAL_3_HOURS_AGO, + 'todate': INCLUDE_INFORMATIONAL_NOW}, + ['1', '2', '3', '4']), + ({'includeinformational': 'true', 'fromdate': '6 hours ago', 'todate': 'now'}, + {'includeinformational': True, + 'fromdate': INCLUDE_INFORMATIONAL_5_HOURS_AGO, + 'todate': INCLUDE_INFORMATIONAL_NOW}, + ['1', '2', '3', '4']), + ({'includeinformational': 'true'}, {}, ValueError), + ({'includeinformational': 'false'}, {}, ['1', '2']), + ({}, {}, ['1', '2']), + ({'includeinformational': 'true', 'todate': 'now'}, {}, ValueError), + ({'includeinformational': 'true', 'fromdate': '3 hours ago'}, {}, ValueError), +]) +def test_includeinformational_logic(mocker, args, expected_filtered_args, expected_result): + """ + Given: + - Case A: includeinformational=True, with relative fromdate and todate provided, both dates within 5 hours from + current time. + - Case B: includeinformational=true, fromdate is more than 5 hours ago, requiring an adjustment of fromdate. + - Case C: includeinformational=true, but fromdate and todate are missing, should raise a ValueError. + - Case D: includeinformational=false, meaning no informational incidents should be returned. + - Case E: includeinformational not present, should behave like false and no informational incidents should be returned. + - Case F: includeinformational=true,but fromdate is missing, should raise a ValueError. + - Case G: includeinformational=true, but todate is missing, should raise a ValueError. + + When: + - Running the search_incidents function to process the input args. + + Then: + - Case A: Ensure both regular and informational incidents are returned when includeinformational=true. + - Case B: Ensure fromdate is adjusted to 5 hours ago and incidents (regular + informational) are fetched correctly. + - Case C: Verify that a ValueError is raised due to missing fromdate and todate when includeinformational=true. + - Case D: Ensure only regular incidents are returned when includeinformational=false. + - Case E: Ensure only regular incidents are returned when includeinformational=None (default behavior). + - Case F: Ensure that a ValueError is raised when fromdate is missing but includeinformational=true. + - Case G: Ensure that a ValueError is raised when todate is missing but includeinformational=true. + """ + import SearchIncidentsV2 + mocker.patch.object(dt, 'datetime', autospec=True) + mocker.patch.object(SearchIncidentsV2, 'is_xsiam', return_value=True) + dt.datetime.utcnow.return_value = INCLUDE_INFORMATIONAL_FIXED_TIME + + class MockDateTime: + def utcnow(self): + return INCLUDE_INFORMATIONAL_FIXED_TIME + + mocker.patch('SearchIncidentsV2.datetime', MockDateTime()) + + # mock arg to datetime since internally uses utc which is not the same as the fixed datetime + mocker.patch.object(SearchIncidentsV2, 'arg_to_datetime', side_effect=lambda x: None if x is None + else INCLUDE_INFORMATIONAL_FIXED_TIME - dt.timedelta( + hours=int(x.split()[0])) if 'hours ago' in x else INCLUDE_INFORMATIONAL_FIXED_TIME) + + execute_mock = mocker.patch.object(SearchIncidentsV2, 'execute_command', side_effect=get_incidents_mock_include_informational) + + if expected_result == ValueError: + with pytest.raises(ValueError): + SearchIncidentsV2.search_incidents(args) + else: + _, res, _ = SearchIncidentsV2.search_incidents(args) + assert [incident['id'] for incident in res] == expected_result + assert execute_mock.call_count == 1 + assert execute_mock.call_args[0][1] == expected_filtered_args + + +def test_includeinformational_raises_error_in_xsoar(mocker): + import SearchIncidentsV2 + mocker.patch.object(SearchIncidentsV2, 'is_xsiam', return_value=False) + mocker.patch.object(SearchIncidentsV2, 'execute_command', side_effect=get_incidents_mock_include_informational) + + with pytest.raises(ValueError): + SearchIncidentsV2.search_incidents({'includeinformational': 'true'}) + + @pytest.mark.parametrize('platform, version, link_type, expected_result', [ ('x2', '', 'alertLink', 'alerts?action:openAlertDetails='), ('xsoar', '6.10.0', 'incidentLink', '#/Details/'), diff --git a/Packs/CommonScripts/Scripts/UnzipFile/UnzipFile.py b/Packs/CommonScripts/Scripts/UnzipFile/UnzipFile.py index ae8aed9af1dd..e648708dc2a0 100644 --- a/Packs/CommonScripts/Scripts/UnzipFile/UnzipFile.py +++ b/Packs/CommonScripts/Scripts/UnzipFile/UnzipFile.py @@ -122,9 +122,9 @@ def extract_using_unrar(file_path, dir_path, password=None): :param password: password if the zip file is encrypted """ if password: - cmd = 'unrar x -p{} {} {}'.format(password, file_path, dir_path) + cmd = f'unrar x -p{password} {file_path} {dir_path}' else: - cmd = 'unrar x -p- {} {}'.format(file_path, dir_path) + cmd = f'unrar x -p- {file_path} {dir_path}' process = Popen(shlex.split(cmd), stdout=PIPE, stderr=PIPE) # process = Popen([cmd], shell=True, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() @@ -139,9 +139,9 @@ def extract_using_unrar(file_path, dir_path, password=None): def extract_using_tarfile(file_path: str, dir_path: str, file_name: str) -> str: if '.tar.gz' in file_name: - cmd = 'tar -xzvf {} -C {}'.format(file_path, dir_path) + cmd = f'tar -xzvf {file_path} -C {dir_path}' elif file_name.endswith('.tar'): - cmd = 'tar -xf {} -C {}'.format(file_path, dir_path) + cmd = f'tar -xf {file_path} -C {dir_path}' process = Popen(shlex.split(cmd), stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() stdout = str(stdout) @@ -158,7 +158,7 @@ def extract_using_7z(file_path, dir_path, password=None): :param dir_path: directory that the file will be extract to :param password: password if the zip file is encrypted """ - cmd = '7z x -p{} -o{} {}'.format(password, dir_path, file_path) + cmd = f'7z x -p{password} -o{dir_path} {file_path}' process = Popen(shlex.split(cmd), stdout=PIPE, stderr=PIPE) # process = Popen([cmd], shell=True, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() diff --git a/Packs/CommonScripts/Scripts/UnzipFile/UnzipFile.yml b/Packs/CommonScripts/Scripts/UnzipFile/UnzipFile.yml index 1112cad78f52..da1cb5400b3a 100644 --- a/Packs/CommonScripts/Scripts/UnzipFile/UnzipFile.yml +++ b/Packs/CommonScripts/Scripts/UnzipFile/UnzipFile.yml @@ -35,7 +35,7 @@ tags: - file timeout: '0' type: python -dockerimage: demisto/unzip:1.0.0.112289 +dockerimage: demisto/unzip:1.0.0.114702 tests: - ZipFile-Test - UnzipFile-Test diff --git a/Packs/CommonScripts/Scripts/UnzipFile/UnzipFile_test.py b/Packs/CommonScripts/Scripts/UnzipFile/UnzipFile_test.py index c9b33d59243d..eaa3e6af3321 100644 --- a/Packs/CommonScripts/Scripts/UnzipFile/UnzipFile_test.py +++ b/Packs/CommonScripts/Scripts/UnzipFile/UnzipFile_test.py @@ -228,7 +228,7 @@ def test_get_password_invalid(): with pytest.raises(ValueError) as e: get_password(ARGS_BOTH_PASSWORDS_NOT_IDENTICAL) if not e: - assert False + raise AssertionError def test_archive_with_slash_in_path(): diff --git a/Packs/CommonScripts/pack_metadata.json b/Packs/CommonScripts/pack_metadata.json index 09edf1c24fd2..c73d03670af7 100644 --- a/Packs/CommonScripts/pack_metadata.json +++ b/Packs/CommonScripts/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Common Scripts", "description": "Frequently used scripts pack.", "support": "xsoar", - "currentVersion": "1.15.73", + "currentVersion": "1.15.77", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/CommunityCommonDashboards/Dashboards/CISOMetrics.json b/Packs/CommunityCommonDashboards/Dashboards/CISOMetrics.json index ca5d7147ba3a..82cae7f69b81 100644 --- a/Packs/CommunityCommonDashboards/Dashboards/CISOMetrics.json +++ b/Packs/CommunityCommonDashboards/Dashboards/CISOMetrics.json @@ -1497,6 +1497,6 @@ "description": "", "isPredefined": true, "marketplaces": [ - "xsoar_on_prem" + "xsoar" ] } \ No newline at end of file diff --git a/Packs/CommunityCommonDashboards/ReleaseNotes/2_0_4.md b/Packs/CommunityCommonDashboards/ReleaseNotes/2_0_4.md new file mode 100644 index 000000000000..3ff8daf47a22 --- /dev/null +++ b/Packs/CommunityCommonDashboards/ReleaseNotes/2_0_4.md @@ -0,0 +1,6 @@ + +#### Dashboards + +##### CISOMetrics + +- Added support for XSOAR marketplace. diff --git a/Packs/CommunityCommonDashboards/pack_metadata.json b/Packs/CommunityCommonDashboards/pack_metadata.json index 17c0f7c5da0d..365bc011df2d 100644 --- a/Packs/CommunityCommonDashboards/pack_metadata.json +++ b/Packs/CommunityCommonDashboards/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Community Common Dashboards", "description": "A pack that contains community dashboards", "support": "community", - "currentVersion": "2.0.3", + "currentVersion": "2.0.4", "author": "Randy Uhrlaub", "url": "", "email": "", diff --git a/Packs/CommunityCommonScripts/ReleaseNotes/1_3_1.md b/Packs/CommunityCommonScripts/ReleaseNotes/1_3_1.md new file mode 100644 index 000000000000..35c8ec5767a1 --- /dev/null +++ b/Packs/CommunityCommonScripts/ReleaseNotes/1_3_1.md @@ -0,0 +1,12 @@ + +#### Scripts + +##### jq + +- Updated the Docker image to: *demisto/jq:1.0.0.113893*. +##### CreatePlbkDoc + +- Updated the Docker image to: *demisto/sane-doc-reports:1.0.0.114696*. +##### PHash + +- Updated the Docker image to: *demisto/python-phash:1.0.0.114718*. diff --git a/Packs/CommunityCommonScripts/Scripts/CreatePlbkDoc/CreatePlbkDoc.yml b/Packs/CommunityCommonScripts/Scripts/CreatePlbkDoc/CreatePlbkDoc.yml index 39d5f9aca371..c78654a5daa2 100644 --- a/Packs/CommunityCommonScripts/Scripts/CreatePlbkDoc/CreatePlbkDoc.yml +++ b/Packs/CommunityCommonScripts/Scripts/CreatePlbkDoc/CreatePlbkDoc.yml @@ -27,7 +27,7 @@ commonfields: contentitemexportablefields: contentitemfields: fromServerVersion: "6.0.0" -dockerimage: demisto/sane-doc-reports:1.0.0.82656 +dockerimage: demisto/sane-doc-reports:1.0.0.114696 enabled: true name: CreatePlbkDoc runas: DBotWeakRole diff --git a/Packs/CommunityCommonScripts/Scripts/Jq/Jq.yml b/Packs/CommunityCommonScripts/Scripts/Jq/Jq.yml index 804004243dfc..468fd9144e3b 100644 --- a/Packs/CommunityCommonScripts/Scripts/Jq/Jq.yml +++ b/Packs/CommunityCommonScripts/Scripts/Jq/Jq.yml @@ -14,7 +14,7 @@ contentitemexportablefields: fromServerVersion: '' dependson: must: [] -dockerimage: demisto/jq:1.0.0.100247 +dockerimage: demisto/jq:1.0.0.113893 enabled: true name: jq outputs: diff --git a/Packs/CommunityCommonScripts/Scripts/PHash/PHash.yml b/Packs/CommunityCommonScripts/Scripts/PHash/PHash.yml index 7ea13e598541..ea4dcf52ebf8 100644 --- a/Packs/CommunityCommonScripts/Scripts/PHash/PHash.yml +++ b/Packs/CommunityCommonScripts/Scripts/PHash/PHash.yml @@ -9,7 +9,7 @@ commonfields: contentitemexportablefields: contentitemfields: fromServerVersion: '' -dockerimage: demisto/python-phash:1.0.0.100267 +dockerimage: demisto/python-phash:1.0.0.114718 enabled: true name: PHash outputs: diff --git a/Packs/CommunityCommonScripts/pack_metadata.json b/Packs/CommunityCommonScripts/pack_metadata.json index e40412e24a9c..6fbba668d5ff 100644 --- a/Packs/CommunityCommonScripts/pack_metadata.json +++ b/Packs/CommunityCommonScripts/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Community Common Scripts", "description": "A pack that contains community scripts", "support": "community", - "currentVersion": "1.3.0", + "currentVersion": "1.3.1", "author": "", "url": "https://live.paloaltonetworks.com/t5/cortex-xsoar-discussions/bd-p/Cortex_XSOAR_Discussions", "email": "", diff --git a/Packs/ComputerVisionEngine/Integrations/ComputerVisionEngine/ComputerVisionEngine.yml b/Packs/ComputerVisionEngine/Integrations/ComputerVisionEngine/ComputerVisionEngine.yml index 4e4dca169978..2336c9507a55 100644 --- a/Packs/ComputerVisionEngine/Integrations/ComputerVisionEngine/ComputerVisionEngine.yml +++ b/Packs/ComputerVisionEngine/Integrations/ComputerVisionEngine/ComputerVisionEngine.yml @@ -28,7 +28,7 @@ script: - contextPath: ComputerVision description: The key holds down the information about detected objects in the picture. type: Unknown - dockerimage: demisto/yolo-coco:1.0.0.98891 + dockerimage: demisto/yolo-coco:1.0.0.113048 runonce: false script: '-' subtype: python3 diff --git a/Packs/ComputerVisionEngine/ReleaseNotes/1_0_3.md b/Packs/ComputerVisionEngine/ReleaseNotes/1_0_3.md new file mode 100644 index 000000000000..a24c4839c47e --- /dev/null +++ b/Packs/ComputerVisionEngine/ReleaseNotes/1_0_3.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Computer Vision Engine + +- Updated the Docker image to: *demisto/yolo-coco:1.0.0.113048*. diff --git a/Packs/ComputerVisionEngine/pack_metadata.json b/Packs/ComputerVisionEngine/pack_metadata.json index 897add789252..3509534dc44d 100644 --- a/Packs/ComputerVisionEngine/pack_metadata.json +++ b/Packs/ComputerVisionEngine/pack_metadata.json @@ -2,7 +2,7 @@ "name": "ComputerVisionEngine", "description": "The ComputerVision Integration by using the Deep-learning library yolo-coco and OpenCV is able to recognize objects on photographs, i.e. planes, luggage, people, dogs, cats, etc.\nThe integration can be used in playbooks to extract objects on rasterized websites in phishing campaigns and making IOCs out of them.\nAdditionally, the integration is useful in CCTV systems significantly reducing the number of false - positives and creating custom workflows in XSOAR playbooks for on-prem physical security!", "support": "community", - "currentVersion": "1.0.2", + "currentVersion": "1.0.3", "author": "Maciej Drobniuch", "url": "drobniuch.pl", "email": "maciej@drobniuch.pl", diff --git a/Packs/Core/Integrations/CortexCoreIR/CortexCoreIR.yml b/Packs/Core/Integrations/CortexCoreIR/CortexCoreIR.yml index bf7aa45d8665..f94ec8d6f488 100644 --- a/Packs/Core/Integrations/CortexCoreIR/CortexCoreIR.yml +++ b/Packs/Core/Integrations/CortexCoreIR/CortexCoreIR.yml @@ -320,6 +320,20 @@ script: - name: username description: The usernames to query for, accepts a single user, or comma-separated list of usernames. isArray: true + - auto: PREDEFINED + defaultValue: "false" + description: Whether to return all endpoints. If true, will override the 'limit' and 'page' arguments. + name: all_results + predefined: + - "false" + - "true" + - auto: PREDEFINED + defaultValue: "false" + description: Whether to return timestamp or date string values. + name: convert_timestamp_to_datestring + predefined: + - "false" + - "true" description: Gets a list of endpoints, according to the passed filters. If there are no filters, all endpoints are returned. Filtering by multiple fields will be concatenated using AND condition (OR is not supported). Maximum result set size is 100. Offset is the zero-based number of endpoint from the start of the result set (start by counting from 0). name: core-get-endpoints outputs: diff --git a/Packs/Core/Playbooks/playbook-Netcat_Makes_or_Gets_Connections.yml b/Packs/Core/Playbooks/playbook-Netcat_Makes_or_Gets_Connections.yml new file mode 100644 index 000000000000..bc84398684b5 --- /dev/null +++ b/Packs/Core/Playbooks/playbook-Netcat_Makes_or_Gets_Connections.yml @@ -0,0 +1,1034 @@ +id: Netcat Makes or Gets Connections +version: -1 +name: Netcat Makes or Gets Connections +description: "This playbook is designed to handle the following alerts:\n \n- Netcat makes or gets connections\n\nThe playbook executes the following stages:\n\nAnalysis:\n\n- Investigate the IP and Domain reputation\n- Search previous similar alerts\n\nRemediation:\n \n- Handles malicious alerts by terminating the causality process." +tags: +- T1090 - Proxy +- TA0011 - Command and Control +starttaskid: "0" +tasks: + "0": + id: "0" + taskid: c2e37c25-ae9c-4fd9-86ac-e7a3ab82bd53 + type: start + task: + id: c2e37c25-ae9c-4fd9-86ac-e7a3ab82bd53 + version: -1 + name: "" + iscommand: false + brand: "" + description: '' + nexttasks: + '#none#': + - "48" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": -430 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "13": + id: "13" + taskid: b3351b14-149a-4979-80f2-e6adada9cbf6 + type: title + task: + id: b3351b14-149a-4979-80f2-e6adada9cbf6 + version: -1 + name: Analysis + type: title + iscommand: false + brand: "" + description: '' + nexttasks: + '#none#': + - "35" + - "36" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 425 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "15": + id: "15" + taskid: 2b932894-ad39-45a2-8195-adf6cf9e1310 + type: regular + task: + id: 2b932894-ad39-45a2-8195-adf6cf9e1310 + version: -1 + name: Get IP prevalence + description: Get the prevalence of an IP, identified by ip_address. + script: '|||core-get-IP-analytics-prevalence' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "21" + scriptarguments: + ip_address: + complex: + root: alert + accessor: remoteip + transformers: + - operator: uniq + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 730, + "y": 900 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "16": + id: "16" + taskid: 98d0d4cc-dd10-4282-8706-129362de2573 + type: regular + task: + id: 98d0d4cc-dd10-4282-8706-129362de2573 + version: -1 + name: Get Domain Name reputation + description: Checks the reputation of a domain. + script: '|||domain' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "21" + scriptarguments: + domain: + simple: ${Core.OriginalAlert.raw_abioc.event.dst_action_external_hostname} + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 140, + "y": 900 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "18": + id: "18" + taskid: a5f8583c-7a45-4e75-845f-0633a5c03441 + type: regular + task: + id: a5f8583c-7a45-4e75-845f-0633a5c03441 + version: -1 + name: Get destination IP reputation + description: Checks the specified IP address against the AbuseIP database. + script: '|||ip' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "15" + scriptarguments: + ip: + complex: + root: alert + accessor: remoteip + transformers: + - operator: uniq + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 730, + "y": 715 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "19": + id: "19" + taskid: 30d6024b-0ba2-4dce-8069-f3e029c70305 + type: title + task: + id: 30d6024b-0ba2-4dce-8069-f3e029c70305 + version: -1 + name: Execute Remediation + type: title + iscommand: false + brand: "" + description: '' + nexttasks: + '#none#': + - "41" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 2175 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "20": + id: "20" + taskid: 78252ce0-493f-4161-8bce-41c2add220e9 + type: condition + task: + id: 78252ce0-493f-4161-8bce-41c2add220e9 + version: -1 + name: Check if Domain Name Exist? + description: Checks if the domain name in the alert exists. + type: condition + iscommand: false + brand: "" + nexttasks: + '#default#': + - "21" + "yes": + - "16" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: isNotEmpty + left: + value: + simple: Core.OriginalAlert.raw_abioc.event.dst_action_external_hostname + iscontext: true + right: + value: {} + continueonerrortype: "" + view: |- + { + "position": { + "x": 140, + "y": 715 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "21": + id: "21" + taskid: 1f0bfec1-5d6c-4ef6-8a82-87e300f58d18 + type: condition + task: + id: 1f0bfec1-5d6c-4ef6-8a82-87e300f58d18 + version: -1 + name: Check if Command Line exist? + description: Get the prevalence of a process_command_line, identified by process_command_line. + type: condition + iscommand: false + brand: "" + nexttasks: + '#default#': + - "30" + "yes": + - "43" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: isNotEmpty + left: + value: + simple: alert.initiatorcmd + iscontext: true + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 1075 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "23": + id: "23" + taskid: d5ad5db4-2f81-4f7e-88ce-d6c5816133a7 + type: title + task: + id: d5ad5db4-2f81-4f7e-88ce-d6c5816133a7 + version: -1 + name: Done + description: commands.local.cmd.close.inv + type: title + iscommand: false + brand: Builtin + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 2850 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "24": + id: "24" + taskid: 2e173da3-70ab-4819-8cff-398f49230173 + type: title + task: + id: 2e173da3-70ab-4819-8cff-398f49230173 + version: -1 + name: Investigation + type: title + iscommand: false + brand: "" + description: '' + nexttasks: + '#none#': + - "39" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 1680 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "30": + id: "30" + taskid: 1f947551-b967-46be-8909-8d67c4ff696b + type: condition + task: + id: 1f947551-b967-46be-8909-8d67c4ff696b + version: -1 + name: Malicious reputation found? + description: '' + type: condition + iscommand: false + brand: "" + nexttasks: + '#default#': + - "24" + Malicious: + - "19" + Prevalent: + - "32" + separatecontext: false + conditions: + - label: Malicious + condition: + - - operator: isNotEmpty + left: + value: + simple: IP.Malicious + iscontext: true + right: + value: {} + - operator: isNotEmpty + left: + value: + simple: Domain.Malicious + iscontext: true + ignorecase: true + - label: Prevalent + condition: + - - operator: isEqualString + left: + value: + simple: Core.AnalyticsPrevalence.Ip.data.local_prevalence.value + iscontext: true + right: + value: + simple: "True" + ignorecase: true + - - operator: isEqualString + left: + value: + simple: Core.AnalyticsPrevalence.Cmd.data.local_prevalence.value + iscontext: true + right: + value: + simple: "True" + ignorecase: true + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 1475 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "31": + id: "31" + taskid: dc4b41b8-382b-4b8a-868b-52c9d8c492f2 + type: condition + task: + id: dc4b41b8-382b-4b8a-868b-52c9d8c492f2 + version: -1 + name: Found Relevant Previous Alert? + description: Checks if there are any relevant previous alerts. + type: condition + iscommand: false + brand: "" + nexttasks: + '#default#': + - "32" + True Positive: + - "19" + separatecontext: false + conditions: + - label: True Positive + condition: + - - operator: isNotEmpty + left: + value: + simple: foundIncidents + iscontext: true + right: + value: {} + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 1990 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "32": + id: "32" + taskid: a402685d-d13d-4230-84cf-a9c944a013cf + type: title + task: + id: a402685d-d13d-4230-84cf-a9c944a013cf + version: -1 + name: False Positive + description: Set a value in context under the key you entered. + type: title + iscommand: false + brand: Builtin + nexttasks: + '#none#': + - "40" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 950, + "y": 2175 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "33": + id: "33" + taskid: de2809e5-8f9b-441d-8dae-2906b35449d5 + type: condition + task: + id: de2809e5-8f9b-441d-8dae-2906b35449d5 + version: -1 + name: Similar False Positive Alerts Found? + description: Checks if similar false positive alerts have been found. + type: condition + iscommand: false + brand: "" + nexttasks: + '#default#': + - "13" + "yes": + - "32" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: isNotEmpty + left: + value: + simple: foundIncidents + iscontext: true + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 240 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "34": + id: "34" + taskid: 1d708279-bef2-41a0-896a-777378045861 + type: regular + task: + id: 1d708279-bef2-41a0-896a-777378045861 + version: -1 + name: Close the Alert as True Positive + description: commands.local.cmd.close.inv + script: Builtin|||closeInvestigation + type: regular + iscommand: true + brand: Builtin + nexttasks: + '#none#': + - "23" + scriptarguments: + closeReason: + simple: Resolved - Handled by the playbook "Netcat makes or gets connections" as True Positive + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 2675 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "35": + id: "35" + taskid: a87830ee-7271-4d99-8f6e-2518001d92af + type: title + task: + id: a87830ee-7271-4d99-8f6e-2518001d92af + version: -1 + name: IP + type: title + iscommand: false + brand: "" + description: '' + nexttasks: + '#none#': + - "18" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 730, + "y": 570 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "36": + id: "36" + taskid: 6c9a12cf-b704-42f1-8a69-7bc21b9ae610 + type: title + task: + id: 6c9a12cf-b704-42f1-8a69-7bc21b9ae610 + version: -1 + name: Domain + type: title + iscommand: false + brand: "" + description: '' + nexttasks: + '#none#': + - "20" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 140, + "y": 570 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "39": + id: "39" + taskid: caf85c97-751f-424d-8db1-93642a0fb048 + type: regular + task: + id: caf85c97-751f-424d-8db1-93642a0fb048 + version: -1 + name: Search related alerts by MITRE technique + description: | + This task searches for suspicious alerts related to an incident by mitre techniques that may indicate a compromised user. + Focus on identifying alerts associated with the following MITRE techniques & tactics: + - T1059- Command and Scripting Interpreter + - T1072 - Software Deployment Tools + - TA0010 - Exfiltration + - T0006 - Credential Access + scriptName: SearchIncidentsV2 + type: regular + iscommand: false + brand: "" + nexttasks: + '#none#': + - "31" + scriptarguments: + query: + complex: + root: alert + accessor: parentXDRIncident + transformers: + - operator: Cut + args: + delimiter: + value: + simple: '-' + fields: + value: + simple: "2" + - operator: concat + args: + prefix: + value: + simple: '(mitreattcktechnique:*T1059* or mitreattcktechnique:*T1072* or mitreattcktactic:*TA0010* or mitreattcktactic:*TA0006*) and caseid:' + suffix: {} + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 1830 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "40": + id: "40" + taskid: 8f19c901-a6ff-4bd7-897a-0e9590e468a6 + type: regular + task: + id: 8f19c901-a6ff-4bd7-897a-0e9590e468a6 + version: -1 + name: Close the Alert as False Positive + description: commands.local.cmd.close.inv + script: Builtin|||closeInvestigation + type: regular + iscommand: true + brand: Builtin + nexttasks: + '#none#': + - "23" + scriptarguments: + closeReason: + simple: Resolved - Handled by the playbook "Netcat makes or gets connections" as False Positive + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 950, + "y": 2675 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "41": + id: "41" + taskid: d572bfa1-1284-41e3-88b9-c7ea4c5555e6 + type: regular + task: + id: d572bfa1-1284-41e3-88b9-c7ea4c5555e6 + version: -1 + name: Terminate Causality (CGO) + description: Terminate a process tree by its causality ID. Available only for XSIAM 2.4. + script: '|||core-terminate-causality' + type: regular + iscommand: true + brand: "" + nexttasks: + '#error#': + - "47" + '#none#': + - "34" + scriptarguments: + agent_id: + simple: ${alert.agentid} + causality_id: + simple: ${alert.cid} + separatecontext: false + continueonerror: true + continueonerrortype: errorPath + view: |- + { + "position": { + "x": 450, + "y": 2330 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "42": + id: "42" + taskid: 4851d11b-0b02-45f9-8d0f-274d42eded84 + type: regular + task: + id: 4851d11b-0b02-45f9-8d0f-274d42eded84 + version: -1 + name: Check Previous similar Alerts + description: | + Finds past similar alerts based on alert fields' similarity. + scriptName: SearchIncidentsV2 + type: regular + iscommand: false + brand: "" + nexttasks: + '#none#': + - "33" + scriptarguments: + fromdate: + simple: 3 months ago + name: + simple: ${alert.name} + query: + simple: 'resolution_status: STATUS_060_RESOLVED_FALSE_POSITIVE and hostname: ${alert.hostname}' + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 70 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 2 + isoversize: false + isautoswitchedtoquietmode: false + "43": + id: "43" + taskid: 2fba2490-e199-46fb-87ef-68d26e786be6 + type: regular + task: + id: 2fba2490-e199-46fb-87ef-68d26e786be6 + version: -1 + name: Get Commandline prevalence + description: Get the prevalence of a process_command_line, identified by process_command_line. + script: '|||core-get-cmd-analytics-prevalence' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "30" + scriptarguments: + process_command_line: + simple: ${alert.osparentcmd} + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": 1265 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "44": + id: "44" + taskid: 7d2b21cc-a875-43ed-8030-e3d6943b3307 + type: condition + task: + id: 7d2b21cc-a875-43ed-8030-e3d6943b3307 + version: -1 + name: Destination IP is External? + description: '' + type: condition + iscommand: false + brand: "" + nexttasks: + '#default#': + - "45" + External: + - "42" + separatecontext: false + conditions: + - label: External + condition: + - - operator: isEqualString + left: + value: + simple: Core.OriginalAlert.event.dst_is_internal_ip + iscontext: true + right: + value: + simple: "False" + ignorecase: true + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": -120 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "45": + id: "45" + taskid: 557e2a2f-1856-400b-84e6-09f3e5f093cb + type: title + task: + id: 557e2a2f-1856-400b-84e6-09f3e5f093cb + version: -1 + name: Insufficient data for verdict + description: Set a value in context under the key you entered. + type: title + iscommand: false + brand: Builtin + nexttasks: + '#none#': + - "23" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": -90, + "y": 2175 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "47": + id: "47" + taskid: 737ed667-8e97-45cb-8254-21df848a9c63 + type: regular + task: + id: 737ed667-8e97-45cb-8254-21df848a9c63 + version: -1 + name: Terminate Process Manually + description: |- + Dear Analyst, + + During the remediation process, the playbook couldn’t terminate the process: ${alert.cgoname} + + Please terminate the process manually if possible. + type: regular + iscommand: false + brand: "" + nexttasks: + '#none#': + - "34" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 160, + "y": 2500 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "48": + id: "48" + taskid: 011406e5-8d0d-47aa-8adf-07af58682c3c + type: regular + task: + id: 011406e5-8d0d-47aa-8adf-07af58682c3c + version: -1 + name: Get Extra Data for DNS query name + description: Returns information about each alert ID. + script: '|||core-get-cloud-original-alerts' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "44" + scriptarguments: + alert_ids: + complex: + root: alert + accessor: id + transformers: + - operator: uniq + filter_alert_fields: + simple: "false" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 450, + "y": -285 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false +view: |- + { + "linkLabelsPosition": { + "20_16_yes": 0.54, + "30_19_Malicious": 0.14, + "30_32_Prevalent": 0.13, + "31_19_True Positive": 0.89, + "41_47_#error#": 0.61, + "44_42_External": 0.53 + }, + "paper": { + "dimensions": { + "height": 3345, + "width": 1420, + "x": -90, + "y": -430 + } + } + } +inputs: [] +inputSections: +- inputs: [] + name: General (Inputs group) + description: Generic group for inputs +outputSections: +- outputs: [] + name: General (Outputs group) + description: Generic group for outputs +outputs: [] +tests: +- No tests (auto formatted) +fromversion: 8.8.0 diff --git a/Packs/Core/Playbooks/playbook-Netcat_Makes_or_Gets_Connections_README.md b/Packs/Core/Playbooks/playbook-Netcat_Makes_or_Gets_Connections_README.md new file mode 100644 index 000000000000..fee860d44557 --- /dev/null +++ b/Packs/Core/Playbooks/playbook-Netcat_Makes_or_Gets_Connections_README.md @@ -0,0 +1,58 @@ +This playbook is designed to handle the following alerts: + +- Netcat makes or gets connections + +The playbook executes the following stages: + +Analysis: + +- Investigate the IP and Domain reputation +- Search previous similar alerts + +Remediation: + +- Handles malicious alerts by terminating the causality process. + +## Dependencies + +This playbook uses the following sub-playbooks, integrations, and scripts. + +### Sub-playbooks + +This playbook does not use any sub-playbooks. + +### Integrations + +* CoreIOCs +* CortexCoreIR +* CortexCoreXQLQueryEngine + +### Scripts + +* SearchIncidentsV2 + +### Commands + +* closeInvestigation +* core-get-IP-analytics-prevalence +* core-get-cloud-original-alerts +* core-get-cmd-analytics-prevalence +* core-terminate-causality +* domain +* ip + +## Playbook Inputs + +--- +There are no inputs for this playbook. + +## Playbook Outputs + +--- +There are no outputs for this playbook. + +## Playbook Image + +--- + +![Netcat Makes or Gets Connections](../doc_files/Netcat_Makes_or_Gets_Connections.png) diff --git a/Packs/Core/Playbooks/playbook-SSO_Password_Spray.yml b/Packs/Core/Playbooks/playbook-SSO_Password_Spray.yml index 41bdc173c91e..351a95ef3f05 100644 --- a/Packs/Core/Playbooks/playbook-SSO_Password_Spray.yml +++ b/Packs/Core/Playbooks/playbook-SSO_Password_Spray.yml @@ -934,7 +934,7 @@ tasks: - - operator: isEqualString left: value: - simple: Core.RiskyUser.score + simple: Core.RiskyUser.risk_level iscontext: true right: value: diff --git a/Packs/Core/Playbooks/playbook-Unprivileged_process_opened_a_registry_hive.yml b/Packs/Core/Playbooks/playbook-Unprivileged_process_opened_a_registry_hive.yml new file mode 100644 index 000000000000..703fbd1321d1 --- /dev/null +++ b/Packs/Core/Playbooks/playbook-Unprivileged_process_opened_a_registry_hive.yml @@ -0,0 +1,582 @@ +id: Unprivileged process opened a registry hive +version: -1 +name: Unprivileged process opened a registry hive +description: |- + This playbook is designed to handle the 'Unprivileged process opened a registry hive' alert. + + Playbook Stages: + + Investigation: + The playbook is designed to investigate and respond to unprivileged processes opening registry hives. It examines the unprivileged process that triggered the alert, the command line, and searches for additional suspicious Cortex XSIAM alerts within the same incident in order to determine whether a remediation measure is required. + + Remediation: + To prevent malicious activity from continuing, the playbook terminates the causality processes that triggered the alert. +tags: +- TA0006 - Credential Access +- T1552 - Unsecured Credentials +starttaskid: "0" +tasks: + "0": + id: "0" + taskid: 48d3588d-43e5-4b43-8b35-48ca384bcb15 + type: start + task: + id: 48d3588d-43e5-4b43-8b35-48ca384bcb15 + version: -1 + name: "" + iscommand: false + brand: "" + description: '' + nexttasks: + '#none#': + - "24" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 440, + "y": -580 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "11": + id: "11" + taskid: ff3d375d-21d5-461d-89f1-3afa5ba7f00b + type: title + task: + id: ff3d375d-21d5-461d-89f1-3afa5ba7f00b + version: -1 + name: Remediation + type: title + iscommand: false + brand: "" + description: '' + nexttasks: + '#none#': + - "44" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 440, + "y": 380 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "22": + id: "22" + taskid: 7842ac2c-e9a5-4b66-8fde-abd99966ae2f + type: regular + task: + id: 7842ac2c-e9a5-4b66-8fde-abd99966ae2f + version: -1 + name: Close Alert as True Positive + description: commands.local.cmd.close.inv + script: Builtin|||closeInvestigation + type: regular + iscommand: true + brand: Builtin + nexttasks: + '#none#': + - "34" + scriptarguments: + assetid: + simple: | + Resolved - False Positive + closeNotes: + simple: Resolved - Handled by the playbook "Unprivileged process opened a registry hive" + closeReason: + simple: Resolved - True Positive + id: + complex: + root: alert + accessor: id + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 440, + "y": 670 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "24": + id: "24" + taskid: c787ef1f-6b33-43ec-8f2b-ef107513f04a + type: title + task: + id: c787ef1f-6b33-43ec-8f2b-ef107513f04a + version: -1 + name: Investigation + type: title + iscommand: false + brand: "" + description: '' + nexttasks: + '#none#': + - "49" + - "47" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 440, + "y": -445 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "34": + id: "34" + taskid: 3200a260-eb1d-4089-8bf7-6895ea662306 + type: title + task: + id: 3200a260-eb1d-4089-8bf7-6895ea662306 + version: -1 + name: Done + type: title + iscommand: false + brand: "" + description: '' + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 440, + "y": 840 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "44": + id: "44" + taskid: 041c6225-6062-47ad-86be-3b7d81f4fb19 + type: regular + task: + id: 041c6225-6062-47ad-86be-3b7d81f4fb19 + version: -1 + name: Terminate Causality (CGO) + description: Terminate a process tree by its causality ID. Available only for Cortex XSIAM 2.4. + script: '|||core-terminate-causality' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "22" + scriptarguments: + agent_id: + complex: + root: alert + accessor: agentid + transformers: + - operator: uniq + causality_id: + complex: + root: alert + accessor: cid + transformers: + - operator: uniq + timeout_in_seconds: + simple: "180" + separatecontext: false + continueonerror: true + continueonerrortype: errorPath + view: |- + { + "position": { + "x": 440, + "y": 510 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: true + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "46": + id: "46" + taskid: 02cefbac-04e3-4606-8570-a778e38fb0c0 + type: regular + task: + id: 02cefbac-04e3-4606-8570-a778e38fb0c0 + version: -1 + name: Search for suspicious-related alerts by MITRE Technique + description: "This task searches for Cortex XSIAM suspicious alerts related to the current incident by Mitre Technique, indicating that the alert is part of an attack pattern.\n\nFocus on identifying alerts associated with the following MITRE techniques:\n- T1003 - OS Credential Dumping \n- T1036 - Masquerading \n- T1552 - Unsecured Credentials \n- T1059 - Command and Scripting Interpreter" + scriptName: SearchIncidentsV2 + type: regular + iscommand: false + brand: "" + nexttasks: + '#none#': + - "53" + scriptarguments: + query: + complex: + root: alert + accessor: parentXDRIncident + transformers: + - operator: Cut + args: + delimiter: + value: + simple: '-' + fields: + value: + simple: "2" + - operator: concat + args: + prefix: + value: + simple: '(mitreattcktechnique:*T1003* or mitreattcktechnique:*T1036* or mitreattcktechnique:*T1552* or mitreattcktechnique:*T1059*) and caseid:' + suffix: {} + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 910, + "y": 45 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "47": + id: "47" + taskid: ce97d194-4dca-4f9c-8aaf-7c54ab40e966 + type: regular + task: + id: ce97d194-4dca-4f9c-8aaf-7c54ab40e966 + version: -1 + name: Get Actor CommandLine and CGO CommandLine prevalence + description: Get the prevalence of a process_command_line, identified by process_command_line. + script: '|||core-get-cmd-analytics-prevalence' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "61" + scriptarguments: + process_command_line: + complex: + root: alert + accessor: cgocmd + transformers: + - operator: AppendIfNotEmpty + args: + item: + value: + simple: alert.osparentcmd + iscontext: true + raw: {} + - operator: uniq + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 650, + "y": -300 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "49": + id: "49" + taskid: e0e01cdc-0f66-414b-8558-24155f2650e7 + type: regular + task: + id: e0e01cdc-0f66-414b-8558-24155f2650e7 + version: -1 + name: Get Actor Process and CGO Process prevalence + description: Get the prevalence of a process, identified by process_name. + script: '|||core-get-process-analytics-prevalence' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "61" + scriptarguments: + process_name: + complex: + root: alert + accessor: osparentname + transformers: + - operator: AppendIfNotEmpty + args: + item: + value: + simple: alert.cgoname + iscontext: true + raw: {} + - operator: uniq + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 230, + "y": -300 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "53": + id: "53" + taskid: 9f115642-48a0-4395-8608-b29f1d2de9ca + type: condition + task: + id: 9f115642-48a0-4395-8608-b29f1d2de9ca + version: -1 + name: Found related alerts requiring causality termination + description: A verdict is determined based on whether the incident contained any related alerts. + type: condition + iscommand: false + brand: "" + nexttasks: + '#default#': + - "60" + "Yes": + - "11" + separatecontext: false + conditions: + - label: "Yes" + condition: + - - operator: isNotEmpty + left: + value: + simple: foundIncidents + iscontext: true + right: + value: {} + continueonerrortype: "" + view: |- + { + "position": { + "x": 910, + "y": 205 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "60": + id: "60" + taskid: 0be96afe-dfcb-4780-8822-af5ad5f865df + type: regular + task: + id: 0be96afe-dfcb-4780-8822-af5ad5f865df + version: -1 + name: Close Alert as False Positive + description: commands.local.cmd.close.inv + script: Builtin|||closeInvestigation + type: regular + iscommand: true + brand: Builtin + nexttasks: + '#none#': + - "34" + scriptarguments: + closeNotes: + simple: Resolved - Handled by the playbook "Unprivileged process opened a registry hive" + closeReason: + simple: Resolved - False Positive + id: + complex: + root: alert + accessor: id + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 910, + "y": 670 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "61": + id: "61" + taskid: eca46ccf-77d3-4853-8b71-f516e49814b7 + type: condition + task: + id: eca46ccf-77d3-4853-8b71-f516e49814b7 + version: -1 + name: Check for process signatures and prevalence + description: Determines the appropriate verdict based on the Actor & CGO process signature and the prevalence of the Actor & CGO process and Actor & CGO CommandLine. + type: condition + iscommand: false + brand: "" + nexttasks: + '#default#': + - "46" + Unsigned and not prevalent: + - "11" + separatecontext: false + conditions: + - label: Unsigned and not prevalent + condition: + - - operator: isNotEqualString + left: + value: + complex: + root: alert.osparentsignature + filters: + - - operator: isNotEmpty + left: + value: + simple: alert.osparentsignature + iscontext: true + iscontext: true + right: + value: + simple: SIGNATURE_SIGNED + ignorecase: true + - operator: isNotEqualString + left: + value: + complex: + root: alert.cgosignature + filters: + - - operator: isNotEmpty + left: + value: + simple: alert.cgosignature + iscontext: true + iscontext: true + right: + value: + simple: SIGNATURE_SIGNED + ignorecase: true + - - operator: isEqualString + left: + value: + complex: + root: Core.AnalyticsPrevalence.Process + accessor: value + transformers: + - operator: uniq + iscontext: true + right: + value: + simple: "False" + ignorecase: true + - operator: isEqualString + left: + value: + complex: + root: Core.AnalyticsPrevalence.Cmd + accessor: value + transformers: + - operator: uniq + iscontext: true + right: + value: + simple: "False" + ignorecase: true + continueonerrortype: "" + view: |- + { + "position": { + "x": 440, + "y": -130 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false +view: |- + { + "linkLabelsPosition": { + "53_11_Yes": 0.17, + "61_11_Unsigned and not prevalent": 0.27 + }, + "paper": { + "dimensions": { + "height": 1485, + "width": 1060, + "x": 230, + "y": -580 + } + } + } +inputs: [] +inputSections: +- inputs: [] + name: General (Inputs group) + description: Generic group for inputs. +outputSections: +- outputs: [] + name: General (Outputs group) + description: Generic group for outputs. +outputs: [] +marketplaces: ["marketplacev2"] +tests: +- No tests (auto formatted) +fromversion: 8.0.0 diff --git a/Packs/Core/Playbooks/playbook-Unprivileged_process_opened_a_registry_hive_README.md b/Packs/Core/Playbooks/playbook-Unprivileged_process_opened_a_registry_hive_README.md new file mode 100644 index 000000000000..02ac982fea6f --- /dev/null +++ b/Packs/Core/Playbooks/playbook-Unprivileged_process_opened_a_registry_hive_README.md @@ -0,0 +1,52 @@ +This playbook is designed to handle the 'Unprivileged process opened a registry hive' alert. + +The playbook is designed to investigate and respond to an unprivileged process opening a registry hive. It examines the unprivileged process that triggered the alert, the command line, and searches for any additional suspicious Cortex XSIAM alerts using Mitre techniques in order to determine whether a remediation measure is required. + +Playbook Stages: + +Investigation: + +- The playbook is designed to investigate and respond to unprivileged processes opening registry hives. It examines the unprivileged process that triggered the alert, the command line, and searches for additional suspicious Cortex XSIAM alerts within the same incident in order to determine whether a remediation measure is required. + +Remediation: + +- To prevent malicious activity from continuing, the playbook terminates the causality processes that triggered the alert. + +## Dependencies + +This playbook uses the following sub-playbooks, integrations, and scripts. + +### Sub-playbooks + +This playbook does not use any sub-playbooks. + +### Integrations + +CortexCoreIR + +### Scripts + +SearchIncidentsV2 + +### Commands + +* core-get-process-analytics-prevalence +* core-terminate-causality +* core-get-cmd-analytics-prevalence +* closeInvestigation + +## Playbook Inputs + +--- +There are no inputs for this playbook. + +## Playbook Outputs + +--- +There are no outputs for this playbook. + +## Playbook Image + +--- + +![Unprivileged process opened a registry hive](../doc_files/Unprivileged_process_opened_a_registry_hive.png) diff --git a/Packs/Core/ReleaseNotes/3_0_82.md b/Packs/Core/ReleaseNotes/3_0_82.md new file mode 100644 index 000000000000..296b4f974e20 --- /dev/null +++ b/Packs/Core/ReleaseNotes/3_0_82.md @@ -0,0 +1,29 @@ + +#### Playbooks + +##### New: Netcat Makes or Gets Connections + +New: This playbook is designed to handle the following alerts: + +- Netcat makes or gets connections + +The playbook executes the following stages: + +Investigation: +Check the following parameters to determine if remediation actions are needed: + +- IP and Domain reputation +- IP and Command-line prevalence +- Cortex XSIAM alerts related to the hostname by MITRE tactics indicating malicious activity. + +Remediation: + +- Handles malicious alerts terminating the causality process. +- Handles non-malicious alerts identified during the investigation.<~XSIAM> (Available from Cortex XSIAM 2.4). + +#### Triggers Recommendations + +##### New: Netcat Makes or Gets Connections + +New: This trigger is responsible for handling 'Netcat Makes or Gets Connections (High severity)' alerts via the 'Netcat Makes or Gets Connections' playbook +<~XSIAM> (Available from Cortex XSIAM 2.4). \ No newline at end of file diff --git a/Packs/Core/ReleaseNotes/3_0_83.md b/Packs/Core/ReleaseNotes/3_0_83.md new file mode 100644 index 000000000000..6a0dee896455 --- /dev/null +++ b/Packs/Core/ReleaseNotes/3_0_83.md @@ -0,0 +1,6 @@ + +#### Playbooks + +##### SSO Password Spray + +- In the risky user score task changed from Core.RiskyUser.score to Core.RiskyUser.risk_level. diff --git a/Packs/Core/ReleaseNotes/3_0_84.md b/Packs/Core/ReleaseNotes/3_0_84.md new file mode 100644 index 000000000000..2b712e5bb083 --- /dev/null +++ b/Packs/Core/ReleaseNotes/3_0_84.md @@ -0,0 +1,5 @@ +#### Integrations + +##### Investigation & Response + +Added support for returning all endpoints and outputting human-readable timestamps to the command **xdr-get-endpoints**. \ No newline at end of file diff --git a/Packs/Core/ReleaseNotes/3_0_85.md b/Packs/Core/ReleaseNotes/3_0_85.md new file mode 100644 index 000000000000..d763e015a57a --- /dev/null +++ b/Packs/Core/ReleaseNotes/3_0_85.md @@ -0,0 +1,20 @@ + +#### Playbooks + +##### New: Unprivileged process opened a registry hive + +- This playbook is designed to handle the 'Unprivileged process opened a registry hive' alert. + +Playbook Stages: + +Investigation: +- The playbook is designed to investigate and respond to unprivileged processes opening registry hives. It examines the unprivileged process that triggered the alert, the command line, and searches for additional suspicious Cortex XSIAM alerts within the same incident in order to determine whether a remediation measure is required. + +Remediation: +- To prevent malicious activity from continuing, the playbook terminates the causality processes that triggered the alert. (Available from Cortex XSOAR 8.8.0). + +#### Triggers Recommendations + +##### New: Unprivileged process opened a registry hive + +- New: **Unprivileged process opened a registry hive** \ No newline at end of file diff --git a/Packs/Core/Triggers/Trigger_-_Netcat_Makes_or_Gets_Connections.json b/Packs/Core/Triggers/Trigger_-_Netcat_Makes_or_Gets_Connections.json new file mode 100644 index 000000000000..24e54cf99711 --- /dev/null +++ b/Packs/Core/Triggers/Trigger_-_Netcat_Makes_or_Gets_Connections.json @@ -0,0 +1,19 @@ +{ + "trigger_id": "907c5db410d816a487249e77cbbf411a", + "playbook_id": "Netcat Makes or Gets Connections", + "suggestion_reason": "Recommended for `Netcat Makes or Gets Connections` Alerts ", + "description": "This trigger is responsible for handling `Netcat Makes or Gets Connections` alert", + "trigger_name": "Netcat Makes or Gets Connections", + "fromVersion": "8.8.0", + "alerts_filter": { + "filter": { + "AND": [ + { + "SEARCH_FIELD": "alert_name", + "SEARCH_TYPE": "EQ", + "SEARCH_VALUE": "Netcat makes or gets connections" + } + ] + } + } +} \ No newline at end of file diff --git a/Packs/Core/Triggers/Trigger_-_Unprivileged_process_opened_a_registry_hive.json b/Packs/Core/Triggers/Trigger_-_Unprivileged_process_opened_a_registry_hive.json new file mode 100644 index 000000000000..3576e216262a --- /dev/null +++ b/Packs/Core/Triggers/Trigger_-_Unprivileged_process_opened_a_registry_hive.json @@ -0,0 +1,18 @@ +{ + "trigger_id": "a8782c70ecf48029bd6c6634f1b5beb5", + "playbook_id": "Unprivileged process opened a registry hive", + "suggestion_reason": "Recommended for 'Unprivileged process opened a registry hive' alert", + "description": "This trigger is responsible for handling the 'Unprivileged process opened a registry hive' alert", + "trigger_name": "Unprivileged process opened a registry hive", + "alerts_filter": { + "filter": { + "AND": [ + { + "SEARCH_FIELD": "alert_name", + "SEARCH_TYPE": "EQ", + "SEARCH_VALUE": "Unprivileged process opened a registry hive" + } + ] + } + } +} diff --git a/Packs/Core/doc_files/Netcat_Makes_or_Gets_Connections.png b/Packs/Core/doc_files/Netcat_Makes_or_Gets_Connections.png new file mode 100644 index 000000000000..27c7b63837f0 Binary files /dev/null and b/Packs/Core/doc_files/Netcat_Makes_or_Gets_Connections.png differ diff --git a/Packs/Core/doc_files/Unprivileged_process_opened_a_registry_hive.png b/Packs/Core/doc_files/Unprivileged_process_opened_a_registry_hive.png new file mode 100644 index 000000000000..bbd6ae3ac58d Binary files /dev/null and b/Packs/Core/doc_files/Unprivileged_process_opened_a_registry_hive.png differ diff --git a/Packs/Core/pack_metadata.json b/Packs/Core/pack_metadata.json index 61a189144c58..1276e6f1dfdf 100644 --- a/Packs/Core/pack_metadata.json +++ b/Packs/Core/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Core - Investigation and Response", "description": "Automates incident response", "support": "xsoar", - "currentVersion": "3.0.81", + "currentVersion": "3.0.85", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/CortexXDR/Integrations/CortexXDRIR/CortexXDRIR.py b/Packs/CortexXDR/Integrations/CortexXDRIR/CortexXDRIR.py index 2b29a28e8e89..ac705ec4f9c2 100644 --- a/Packs/CortexXDR/Integrations/CortexXDRIR/CortexXDRIR.py +++ b/Packs/CortexXDR/Integrations/CortexXDRIR/CortexXDRIR.py @@ -25,7 +25,6 @@ 'file_artifacts' ] - XDR_INCIDENT_FIELDS = { "status": {"description": "Current status of the incident: \"new\",\"under_" "investigation\",\"resolved_known_issue\"," @@ -1083,14 +1082,19 @@ def fetch_incidents(client, first_fetch_time, integration_instance, exclude_arti global ALERTS_LIMIT_PER_INCIDENTS # Get the last fetch time, if exists last_fetch = last_run.get('time') if isinstance(last_run, dict) else None + demisto.debug(f"{last_fetch=}") incidents_from_previous_run = last_run.get('incidents_from_previous_run', []) if isinstance(last_run, dict) else [] + demisto.debug(f"{incidents_from_previous_run=}") # Handle first time fetch, fetch incidents retroactively if last_fetch is None: last_fetch, _ = parse_date_range(first_fetch_time, to_timestamp=True) + demisto.debug(f"last_fetch after parsing date range {last_fetch}") if starred: starred_incidents_fetch_window, _ = parse_date_range(starred_incidents_fetch_window, to_timestamp=True) + demisto.debug( + f"starred_incidents_fetch_window after parsing date range {starred_incidents_fetch_window}") incidents = [] if incidents_from_previous_run: @@ -1115,6 +1119,8 @@ def fetch_incidents(client, first_fetch_time, integration_instance, exclude_arti starred_incidents_fetch_window=starred_incidents_fetch_window, exclude_artifacts=exclude_artifacts) + # demisto.debug(f"{raw_incidents=}") # uncomment to debug, otherwise spams the log + # save the last 100 modified incidents to the integration context - for mirroring purposes client.save_modified_incidents_to_integration_context() @@ -1343,16 +1349,23 @@ def main(): # pragma: no cover elif command == 'fetch-incidents': integration_instance = demisto.integrationInstance() + last_run = demisto.getLastRun().get('next_run') + demisto.debug( + f"Before starting a new cycle of fetch incidents\n{last_run=}\n{integration_instance=}") next_run, incidents = fetch_incidents(client=client, first_fetch_time=first_fetch_time, integration_instance=integration_instance, exclude_artifacts=exclude_artifacts, - last_run=demisto.getLastRun().get('next_run'), + last_run=last_run, max_fetch=max_fetch, statuses=statuses, starred=starred, starred_incidents_fetch_window=starred_incidents_fetch_window, ) + demisto.debug(f"Finished a fetch incidents cycle, {next_run=}." + f"Fetched {len(incidents)} incidents.") + # demisto.debug(f"{incidents=}") # uncomment to debug, otherwise spams the log + last_run_obj = demisto.getLastRun() last_run_obj['next_run'] = next_run demisto.setLastRun(last_run_obj) diff --git a/Packs/CortexXDR/Integrations/CortexXDRIR/CortexXDRIR.yml b/Packs/CortexXDR/Integrations/CortexXDRIR/CortexXDRIR.yml index cd6aabaf0e56..9e9aa6d3cff7 100644 --- a/Packs/CortexXDR/Integrations/CortexXDRIR/CortexXDRIR.yml +++ b/Packs/CortexXDR/Integrations/CortexXDRIR/CortexXDRIR.yml @@ -933,6 +933,20 @@ script: - name: username description: The usernames to query for. Accepts a single user, or comma-separated list of usernames. isArray: true + - auto: PREDEFINED + defaultValue: "false" + description: Whether to return all endpoints. If true, will override the 'limit' and 'page' arguments. + name: all_results + predefined: + - "false" + - "true" + - auto: PREDEFINED + defaultValue: "false" + description: Whether to return timestamp or date string values. + name: convert_timestamp_to_datestring + predefined: + - "false" + - "true" description: Gets a list of endpoints, according to the passed filters. If there are no filters, all endpoints are returned. Filtering by multiple fields will be concatenated using AND condition (OR is not supported). Maximum result set size is 100. Offset is the zero-based number of endpoint from the start of the result set. (Start by counting from 0). name: xdr-get-endpoints outputs: diff --git a/Packs/CortexXDR/Integrations/CortexXDRIR/README.md b/Packs/CortexXDR/Integrations/CortexXDRIR/README.md index b7ea057e228a..d9a947ad888a 100644 --- a/Packs/CortexXDR/Integrations/CortexXDRIR/README.md +++ b/Packs/CortexXDR/Integrations/CortexXDRIR/README.md @@ -748,6 +748,8 @@ Builtin Roles with this permission includes: "Privileged Responder", "Viewer" an | sort_by | Specifies whether to sort endpoints by the first time or last time they were seen. Can be "first_seen" or "last_seen". Possible values are: first_seen, last_seen. | Optional | | sort_order | The order by which to sort results. Can be "asc" (ascending) or "desc" ( descending). Default set to asc. Possible values are: asc, desc. Default is asc. | Optional | | username | The usernames to query for, accepts a single user, or comma-separated list of usernames. | Optional | +| all_results | Whether to return all endpoints. If true, will override the 'limit' and 'page' arguments. Possible values are: false, true. Default is false. | Optional | +| use_hr_timestamps | Whether to return timestamp values in human-readable format as opposed to Unix epoch timestamp format. Possible values are: false, true. Default is false. | Optional | #### Context Output diff --git a/Packs/CortexXDR/Playbooks/playbook-Cortex_XDR_disconnected_endpoints.yml b/Packs/CortexXDR/Playbooks/playbook-Cortex_XDR_disconnected_endpoints.yml index e212352ddcff..509b2ceca27f 100644 --- a/Packs/CortexXDR/Playbooks/playbook-Cortex_XDR_disconnected_endpoints.yml +++ b/Packs/CortexXDR/Playbooks/playbook-Cortex_XDR_disconnected_endpoints.yml @@ -34,67 +34,13 @@ tasks: description: '' nexttasks: '#none#': - - "1" + - "12" separatecontext: false view: |- { "position": { - "x": 162.5, - "y": 20 - } - } - note: false - timertriggers: [] - ignoreworker: false - skipunavailable: false - quietmode: 0 - isoversize: false - isautoswitchedtoquietmode: false - "1": - id: "1" - taskid: b438c457-bde4-4f03-8e38-f8aeee661f1b - type: regular - task: - id: b438c457-bde4-4f03-8e38-f8aeee661f1b - version: -1 - name: 'Get XDR disconnected endpoints ' - description: Gets a list of endpoints, according to the passed filters. If there - are no filters, all endpoints are returned. Filtering by multiple fields will - be concatenated using the AND condition (OR is not supported). The maximum - result set size is 100. Offset is the zero-based number of the endpoint from - the start of the result set (start by counting from 0). - script: '|||xdr-get-endpoints' - type: regular - iscommand: true - brand: "" - nexttasks: - '#none#': - - "5" - scriptarguments: - last_seen_gte: - complex: - root: inputs.LastSeenStartDate - filters: - - - operator: isNotEmpty - left: - value: - simple: inputs.LastSeenStartDate - iscontext: true - last_seen_lte: - complex: - root: inputs.LastSeenEndDate - filters: - - - operator: isNotEmpty - left: - value: - simple: inputs.LastSeenEndDate - iscontext: true - separatecontext: false - view: |- - { - "position": { - "x": 162.5, - "y": 145 + "x": 50, + "y": 50 } } note: false @@ -104,6 +50,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "2": id: "2" taskid: 12957918-32bb-4c3b-8cdc-4b149812f2f7 @@ -115,10 +62,10 @@ tasks: description: Export the given array to a CSV file. tags: - Endpoint report - scriptName: ExportToCSV type: regular iscommand: false brand: "" + script: ExportToCSV nexttasks: '#none#': - "9" @@ -150,7 +97,7 @@ tasks: { "position": { "x": 162.5, - "y": 605 + "y": 545 } } note: false @@ -160,12 +107,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "3": id: "3" - taskid: bbf59aee-7646-48d3-881d-3dda5c1f2052 + taskid: 7b27a983-42e1-408d-8c6f-2c672b3f353f type: regular task: - id: bbf59aee-7646-48d3-881d-3dda5c1f2052 + id: 7b27a983-42e1-408d-8c6f-2c672b3f353f version: -1 name: Mail disconnected endpoints report description: Sends an mail using Gmail/EWS. @@ -185,7 +133,7 @@ tasks: complex: root: inputs.MessageBody subject: - simple: Cortex XDR Discconcted endpoints + simple: Cortex XDR Disconnected Endpoints to: complex: root: inputs.Email @@ -193,8 +141,8 @@ tasks: view: |- { "position": { - "x": 162.5, - "y": 1000 + "x": 50, + "y": 895 } } note: false @@ -204,6 +152,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "4": id: "4" taskid: 6daa6400-3c03-4285-8c7a-672e14d9bf8c @@ -220,8 +169,8 @@ tasks: view: |- { "position": { - "x": 162.5, - "y": 1840 + "x": 50, + "y": 1770 } } note: false @@ -231,6 +180,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "5": id: "5" taskid: fa23f54f-4e1c-44dd-8ad7-d5c1ae59b2ca @@ -276,8 +226,8 @@ tasks: view: |- { "position": { - "x": 162.5, - "y": 330 + "x": 50, + "y": 370 } } note: false @@ -287,6 +237,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "6": id: "6" taskid: 004b7e07-9e8a-4ec3-8c63-a02e05bab64e @@ -295,8 +246,7 @@ tasks: id: 004b7e07-9e8a-4ec3-8c63-a02e05bab64e version: -1 name: Count involved users and hosts - description: Count the users and hosts involved in the incidents and insert - the amount in the incident field, + description: Count the users and hosts involved in the incidents and insert the amount in the incident field, script: Builtin|||setIncident type: regular iscommand: true @@ -356,7 +306,7 @@ tasks: { "position": { "x": 162.5, - "y": 1190 + "y": 1070 } } note: false @@ -366,6 +316,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "7": id: "7" taskid: db61aeaf-0ea6-4a74-88e1-67d2909483d2 @@ -375,17 +326,16 @@ tasks: version: -1 name: Set endpoints grid description: Creates a grid table from items or key-value pairs. - scriptName: SetGridField type: regular iscommand: false brand: "" + script: SetGridField nexttasks: '#none#': - "10" scriptarguments: columns: - simple: Endpoint Name,Endpoint Status,Endpoint OS,Endpoint ID,Endpoint Last - Seen + simple: Endpoint Name,Endpoint Status,Endpoint OS,Endpoint ID,Endpoint Last Seen context_path: simple: XDR.DisconnectedEndpoints grid_id: @@ -397,7 +347,7 @@ tasks: { "position": { "x": 162.5, - "y": 1510 + "y": 1420 } } note: false @@ -407,19 +357,25 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "8": id: "8" - taskid: fec15313-a2c7-445c-8fff-808bce828aea + taskid: 6efdd411-a1da-45eb-8e58-49fbe793acd3 type: regular task: - id: fec15313-a2c7-445c-8fff-808bce828aea + id: 6efdd411-a1da-45eb-8e58-49fbe793acd3 version: -1 name: Set disconnected endpoints - description: Set a value in context under the key you entered. - scriptName: Set + description: |- + Set a value in context under the key you entered. If no value is entered, the script doesn't do anything. + + This automation runs using the default Limited User role, unless you explicitly change the permissions. + For more information, see the section about permissions here: + https://docs-cortex.paloaltonetworks.com/r/Cortex-XSOAR/6.13/Cortex-XSOAR-Administrator-Guide/Automations type: regular iscommand: false brand: "" + script: SetAndHandleEmpty nexttasks: '#none#': - "7" @@ -451,7 +407,7 @@ tasks: { "position": { "x": 162.5, - "y": 1345 + "y": 1245 } } note: false @@ -461,6 +417,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "9": id: "9" taskid: 64c667fe-c0c9-45e5-8a98-36853b612485 @@ -492,7 +449,7 @@ tasks: { "position": { "x": 162.5, - "y": 770 + "y": 720 } } note: false @@ -502,6 +459,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "10": id: "10" taskid: 531e649f-d89d-4269-8cbd-e1e041e272f9 @@ -522,8 +480,8 @@ tasks: view: |- { "position": { - "x": 162.5, - "y": 1680 + "x": 50, + "y": 1595 } } note: false @@ -533,7 +491,64 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false -system: true + continueonerrortype: "" + "12": + continueonerrortype: "" + id: "12" + ignoreworker: false + isautoswitchedtoquietmode: false + isoversize: false + nexttasks: + '#none#': + - "5" + note: false + quietmode: 0 + scriptarguments: + all_results: + simple: "false" + last_seen_gte: + complex: + filters: + - - left: + iscontext: true + value: + simple: inputs.LastSeenStartDate + operator: isNotEmpty + root: inputs.LastSeenStartDate + last_seen_lte: + complex: + filters: + - - left: + iscontext: true + value: + simple: inputs.LastSeenEndDate + operator: isNotEmpty + root: inputs.LastSeenEndDate + status: + simple: disconnected,lost + use_hr_timestamps: + simple: "true" + separatecontext: false + skipunavailable: false + task: + brand: "" + description: Gets a list of endpoints, according to the passed filters. If there are no filters, all endpoints are returned. Filtering by multiple fields will be concatenated using AND condition (OR is not supported). Maximum result set size is 100. Offset is the zero-based number of endpoints from the start of the result set. (Start by counting from 0). + id: 731a66f9-21d4-472a-8924-abf1fc7bf686 + iscommand: true + name: Get XDR disconnected endpoints + script: '|||xdr-get-endpoints' + type: regular + version: -1 + taskid: 731a66f9-21d4-472a-8924-abf1fc7bf686 + timertriggers: [] + type: regular + view: |- + { + "position": { + "x": 50, + "y": 195 + } + } view: |- { "linkLabelsPosition": { @@ -543,10 +558,10 @@ view: |- }, "paper": { "dimensions": { - "height": 1885, - "width": 380, - "x": 162.5, - "y": 20 + "height": 1785, + "width": 492.5, + "x": 50, + "y": 50 } } } @@ -559,8 +574,7 @@ inputs: - key: LastSeenEndDate value: {} required: false - description: "Last seen end date, in relative timestamp - \"1 Day\" or \"7 days\"\ - \ \nFor the current day use \"0 days\"" + description: "Last seen end date, in relative timestamp - \"1 Day\" or \"7 days\" \nFor the current day use \"0 days\"" playbookInputQuery: - key: Email value: {} @@ -577,5 +591,18 @@ inputs: playbookInputQuery: outputs: [] tests: -- No tests (auto formatted) +- Test XDR Playbook general commands +- Test XDR Playbook fromversion: 5.5.0 +inputSections: +- description: Generic group for inputs. + inputs: + - LastSeenStartDate + - LastSeenEndDate + - Email + - MessageBody + name: General (Inputs group) +outputSections: +- description: Generic group for outputs. + name: General (Outputs group) + outputs: [] diff --git a/Packs/CortexXDR/ReleaseNotes/6_1_84.md b/Packs/CortexXDR/ReleaseNotes/6_1_84.md new file mode 100644 index 000000000000..ceb647a6b11e --- /dev/null +++ b/Packs/CortexXDR/ReleaseNotes/6_1_84.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Palo Alto Networks Cortex XDR - Investigation and Response + +- Added logs to ***fetch-incidents***, to ease debugging. diff --git a/Packs/CortexXDR/ReleaseNotes/6_1_85.md b/Packs/CortexXDR/ReleaseNotes/6_1_85.md new file mode 100644 index 000000000000..5454da05a24e --- /dev/null +++ b/Packs/CortexXDR/ReleaseNotes/6_1_85.md @@ -0,0 +1,12 @@ + +#### Integrations + +##### Palo Alto Networks Cortex XDR - Investigation and Response + +- Added support for returning all endpoints and outputting human-readable timestamps to the command **xdr-get-endpoints**. + +#### Playbooks + +##### Cortex XDR disconnected endpoints + +- Improved implementation of the playbook by returning all endpoints, outputting data with human-readable timestamps, and gracefully handling the situation where no lost or disconnected endpoints are found. diff --git a/Packs/CortexXDR/TestPlaybooks/Test_Playbook_-_Cortex_XDR_Malware_-_Incident_Enrichment.yml b/Packs/CortexXDR/TestPlaybooks/Test_Playbook_-_Cortex_XDR_Malware_-_Incident_Enrichment.yml index 2c5b8a41bd4a..fa7342ca868d 100644 --- a/Packs/CortexXDR/TestPlaybooks/Test_Playbook_-_Cortex_XDR_Malware_-_Incident_Enrichment.yml +++ b/Packs/CortexXDR/TestPlaybooks/Test_Playbook_-_Cortex_XDR_Malware_-_Incident_Enrichment.yml @@ -650,18 +650,18 @@ tasks: conditions: - label: ' Verified' condition: - - - operator: containsString + - - operator: in left: value: complex: - root: ExtractedIndicators - accessor: File + root: incident + accessor: filesha256 iscontext: true right: value: complex: - root: incident - accessor: filesha256 + root: ExtractedIndicators + accessor: File iscontext: true ignorecase: true continueonerrortype: "" @@ -1507,7 +1507,7 @@ tasks: alertsandrelatedinfo: simple: '[{"columnheader3":""},{},{}]' externalsystemid: - simple: "84" + simple: "812" separatecontext: false continueonerrortype: "" view: |- diff --git a/Packs/CortexXDR/doc_files/Cortex_XDR_disconnected_endpoints.png b/Packs/CortexXDR/doc_files/Cortex_XDR_disconnected_endpoints.png index 54e1d82a6251..4aee9966890d 100644 Binary files a/Packs/CortexXDR/doc_files/Cortex_XDR_disconnected_endpoints.png and b/Packs/CortexXDR/doc_files/Cortex_XDR_disconnected_endpoints.png differ diff --git a/Packs/CortexXDR/pack_metadata.json b/Packs/CortexXDR/pack_metadata.json index f4eb751e61df..2d9969bf7811 100644 --- a/Packs/CortexXDR/pack_metadata.json +++ b/Packs/CortexXDR/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Cortex XDR by Palo Alto Networks", "description": "Automates Cortex XDR incident response, and includes custom Cortex XDR incident views and layouts to aid analyst investigations.", "support": "xsoar", - "currentVersion": "6.1.83", + "currentVersion": "6.1.85", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/CrowdStrikeFalcon/Integrations/CrowdStrikeFalcon/CrowdStrikeFalcon.py b/Packs/CrowdStrikeFalcon/Integrations/CrowdStrikeFalcon/CrowdStrikeFalcon.py index fe1ceb269ce3..f846248e490e 100644 --- a/Packs/CrowdStrikeFalcon/Integrations/CrowdStrikeFalcon/CrowdStrikeFalcon.py +++ b/Packs/CrowdStrikeFalcon/Integrations/CrowdStrikeFalcon/CrowdStrikeFalcon.py @@ -36,6 +36,7 @@ USE_SSL = not PARAMS.get('insecure', False) # How many time before the first fetch to retrieve incidents FETCH_TIME = PARAMS.get('fetch_time', '3 days') +MAX_FETCH_SIZE = 10000 PROXY = PARAMS.get('proxy', False) BYTE_CREDS = f'{CLIENT_ID}:{SECRET}'.encode() # Headers to be sent in requests @@ -1538,7 +1539,7 @@ def get_detections(last_behavior_time=None, behavior_id=None, filter_arg=None): text_to_encode += f"+{filter_arg}" endpoint_url += urllib.parse.quote_plus(text_to_encode) demisto.debug(f"In get_detections: {LEGACY_VERSION =} and {endpoint_url=}") - return http_request('GET', endpoint_url) + return http_request('GET', endpoint_url, {'sort': 'created_timestamp.asc'}) else: endpoint_url = '/detects/queries/detects/v1' demisto.debug(f"In get_detections: {LEGACY_VERSION =} and {endpoint_url=} and {params=}") @@ -1554,8 +1555,9 @@ def get_fetch_detections(last_created_timestamp=None, filter_arg=None, offset: i Returns: Response json of the get detection endpoint (IDs of the detections) """ + sort_key = 'first_behavior.asc' if LEGACY_VERSION else 'created_timestamp.asc' params = { - 'sort': 'first_behavior.asc', + 'sort': sort_key, 'offset': offset, } if has_limit: @@ -2973,6 +2975,10 @@ def fetch_incidents(): total_detections = demisto.get(response, "meta.pagination.total") detections_offset = calculate_new_offset(detections_offset, len(detections_ids), total_detections) if detections_offset: + if detections_offset + fetch_limit > MAX_FETCH_SIZE: + demisto.debug(f"CrowdStrikeFalconMsg: The new offset: {detections_offset} + limit: {fetch_limit} reached " + f"{MAX_FETCH_SIZE}, resetting the offset to 0") + detections_offset = 0 demisto.debug(f"CrowdStrikeFalconMsg: The new detections offset is {detections_offset}") raw_res = get_detections_entities(detections_ids) @@ -3034,6 +3040,10 @@ def fetch_incidents(): total_incidents = demisto.get(response, "meta.pagination.total") incidents_offset = calculate_new_offset(incidents_offset, len(incidents_ids), total_incidents) if incidents_offset: + if incidents_offset + fetch_limit > MAX_FETCH_SIZE: + demisto.debug(f"CrowdStrikeFalconMsg: The new offset: {incidents_offset} + limit: {fetch_limit} reached " + f"{MAX_FETCH_SIZE}, resetting the offset to 0") + incidents_offset = 0 demisto.debug(f"CrowdStrikeFalconMsg: The new incidents offset is {incidents_offset}") if incidents_ids: @@ -3206,6 +3216,10 @@ def fetch_detections_by_product_type(current_fetch_info: dict, look_back: int, p total_detections = demisto.get(response, "meta.pagination.total") offset = calculate_new_offset(offset, len(detections_ids), total_detections) if offset: + if offset + fetch_limit > MAX_FETCH_SIZE: + demisto.debug(f"CrowdStrikeFalconMsg: The new offset: {offset} + limit: {fetch_limit} reached " + f"{MAX_FETCH_SIZE}, resetting the offset to 0") + offset = 0 demisto.debug(f"CrowdStrikeFalconMsg: The new {detections_type} offset is {offset}") if detections_ids: diff --git a/Packs/CrowdStrikeFalcon/Integrations/CrowdStrikeFalcon/CrowdStrikeFalcon_test.py b/Packs/CrowdStrikeFalcon/Integrations/CrowdStrikeFalcon/CrowdStrikeFalcon_test.py index 0357ae94a67b..a3f47297f978 100644 --- a/Packs/CrowdStrikeFalcon/Integrations/CrowdStrikeFalcon/CrowdStrikeFalcon_test.py +++ b/Packs/CrowdStrikeFalcon/Integrations/CrowdStrikeFalcon/CrowdStrikeFalcon_test.py @@ -7210,7 +7210,7 @@ def test_error_handler(): @pytest.mark.parametrize('Legacy_version, url_suffix, expected_len', [ (False, "alerts/queries/alerts/v2?filter=product%3A%27epp%27%2Btype%3A%27ldt%27%2Bcreated_timestamp%3A%3E%272024-06-19T15%3A25%3A00Z%27", - 2), + 3), (True, '/detects/queries/detects/v1', 3) ]) def test_get_detection___url_and_params(mocker, Legacy_version, url_suffix, expected_len): @@ -7269,7 +7269,7 @@ def test_resolve_detection(mocker, Legacy_version, tag, url_suffix, data): @pytest.mark.parametrize('Legacy_version, url_suffix, request_params', [ (False, "/alerts/queries/alerts/v2?filter=product%3A%27epp%27%2Btype%3A%27ldt%27%2Bupdated_timestamp%3A%3E%272024-06-19T15%3A25%3A00Z%27", - {'sort': 'first_behavior.asc', 'offset': 5, 'limit': 3}), + {'sort': 'created_timestamp.asc', 'offset': 5, 'limit': 3}), (True, '/detects/queries/detects/v1', {'sort': 'first_behavior.asc', 'offset': 5, 'limit': 3, 'filter': "date_updated:>'2024-06-19T15:25:00Z'"}) ]) diff --git a/Packs/CrowdStrikeFalcon/ReleaseNotes/2_0_21.md b/Packs/CrowdStrikeFalcon/ReleaseNotes/2_0_21.md new file mode 100644 index 000000000000..467746a14a16 --- /dev/null +++ b/Packs/CrowdStrikeFalcon/ReleaseNotes/2_0_21.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### CrowdStrike Falcon + +Fixed an issue where the ***fetch-incidents*** command did not fetch incidents when the offset reached the maximum. diff --git a/Packs/CrowdStrikeFalcon/ReleaseNotes/2_0_22.md b/Packs/CrowdStrikeFalcon/ReleaseNotes/2_0_22.md new file mode 100644 index 000000000000..8263af666d03 --- /dev/null +++ b/Packs/CrowdStrikeFalcon/ReleaseNotes/2_0_22.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### CrowdStrike Falcon + +Fixed an issue where detections were fetched unsorted in the post-Raptor release. diff --git a/Packs/CrowdStrikeFalcon/pack_metadata.json b/Packs/CrowdStrikeFalcon/pack_metadata.json index 2e44dee73ce4..e242ece759dd 100644 --- a/Packs/CrowdStrikeFalcon/pack_metadata.json +++ b/Packs/CrowdStrikeFalcon/pack_metadata.json @@ -2,7 +2,7 @@ "name": "CrowdStrike Falcon", "description": "The CrowdStrike Falcon OAuth 2 API (formerly the Falcon Firehose API), enables fetching and resolving detections, searching devices, getting behaviors by ID, containing hosts, and lifting host containment.", "support": "xsoar", - "currentVersion": "2.0.20", + "currentVersion": "2.0.22", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/CrowdStrikeFalconX/TestPlaybooks/CrowdStrikeFalconX_Test.yml b/Packs/CrowdStrikeFalconX/TestPlaybooks/CrowdStrikeFalconX_Test.yml index 80c322beb23f..080f2e40663b 100644 --- a/Packs/CrowdStrikeFalconX/TestPlaybooks/CrowdStrikeFalconX_Test.yml +++ b/Packs/CrowdStrikeFalconX/TestPlaybooks/CrowdStrikeFalconX_Test.yml @@ -5,10 +5,10 @@ starttaskid: "0" tasks: "0": id: "0" - taskid: b44d60dd-0f6b-44ee-8144-9cb66aab296c + taskid: c7e4d7f4-8e29-4ad8-8b48-1532ec261fe8 type: start task: - id: b44d60dd-0f6b-44ee-8144-9cb66aab296c + id: c7e4d7f4-8e29-4ad8-8b48-1532ec261fe8 version: -1 name: "" iscommand: false @@ -32,12 +32,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "1": id: "1" - taskid: b5c0b87a-ea6b-4159-8784-073ef5f8cb5e + taskid: b10694e0-0f72-49a8-8d1a-981f081c21ed type: regular task: - id: b5c0b87a-ea6b-4159-8784-073ef5f8cb5e + id: b10694e0-0f72-49a8-8d1a-981f081c21ed version: -1 name: DeleteContext script: DeleteContext @@ -65,12 +66,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "4": id: "4" - taskid: 1d8fdb38-11e7-4435-8404-99e6a8c56727 + taskid: 5b9b8efe-184d-4703-80d9-580016afd3dd type: regular task: - id: 1d8fdb38-11e7-4435-8404-99e6a8c56727 + id: 5b9b8efe-184d-4703-80d9-580016afd3dd version: -1 name: cs-fx-submit-uploaded-file script: CrowdStrike Falcon X|||cs-fx-submit-uploaded-file @@ -118,12 +120,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "5": id: "5" - taskid: 3b389614-9b0d-437f-848b-9c13f3d5ec13 + taskid: 62e80b9b-82ac-4715-8904-12acae744f51 type: condition task: - id: 3b389614-9b0d-437f-848b-9c13f3d5ec13 + id: 62e80b9b-82ac-4715-8904-12acae744f51 version: -1 name: Verify Outputs type: condition @@ -175,12 +178,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "6": id: "6" - taskid: 2dbced4c-780f-4172-8413-cdf26a7de9eb + taskid: bbfe2c8b-1a56-482e-8be8-dc42a7b25fa2 type: regular task: - id: 2dbced4c-780f-4172-8413-cdf26a7de9eb + id: bbfe2c8b-1a56-482e-8be8-dc42a7b25fa2 version: -1 name: cs-fx-get-full-report script: CrowdStrike Falcon X|||cs-fx-get-full-report @@ -194,7 +198,7 @@ tasks: extended_data: simple: "false" ids: - simple: 20879a8064904ecfbb62c118a6a19411_b8dfafbdb6bd4220aa5b11dbbd53cfaf + simple: 20879a8064904ecfbb62c118a6a19411_4a3266d4788a4277ae89d1d7b0bf11d7 separatecontext: false view: |- { @@ -210,12 +214,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "7": id: "7" - taskid: c3566d0d-0881-4421-84e1-622896496162 + taskid: b381266b-3dc1-4785-8410-898da38c9433 type: condition task: - id: c3566d0d-0881-4421-84e1-622896496162 + id: b381266b-3dc1-4785-8410-898da38c9433 version: -1 name: Verify Outputs type: condition @@ -233,6 +238,8 @@ tasks: value: simple: csfalconx.resource.sandbox.processes.sha256 iscontext: true + right: + value: {} - - operator: isNotEmpty left: value: @@ -333,11 +340,6 @@ tasks: value: simple: csfalconx.resource.architecture iscontext: true - - - operator: isNotEmpty - left: - value: - simple: csfalconx.resource.classification - iscontext: true - - operator: isNotEmpty left: value: @@ -372,12 +374,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "8": id: "8" - taskid: 816682e9-ea72-4020-85d0-eda939e44a64 + taskid: 76e9e190-dbe6-4ed3-8a12-ef8b0a07109b type: regular task: - id: 816682e9-ea72-4020-85d0-eda939e44a64 + id: 76e9e190-dbe6-4ed3-8a12-ef8b0a07109b version: -1 name: cs-fx-get-report-summary script: CrowdStrike Falcon X|||cs-fx-get-report-summary @@ -389,7 +392,7 @@ tasks: - "9" scriptarguments: ids: - simple: 20879a8064904ecfbb62c118a6a19411_b8dfafbdb6bd4220aa5b11dbbd53cfaf + simple: 20879a8064904ecfbb62c118a6a19411_4a3266d4788a4277ae89d1d7b0bf11d7 separatecontext: false view: |- { @@ -405,12 +408,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "9": id: "9" - taskid: d0bdfb65-5fff-4280-8ec5-cdd175c4de55 + taskid: 986dc69f-fb14-46ba-8e40-ba27edab1fe4 type: condition task: - id: d0bdfb65-5fff-4280-8ec5-cdd175c4de55 + id: 986dc69f-fb14-46ba-8e40-ba27edab1fe4 version: -1 name: Verify Outputs type: condition @@ -509,12 +513,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "10": id: "10" - taskid: 23f4aa75-bcfc-4274-80f8-8a778d809bac + taskid: 0902e574-df2d-416e-80e7-06409a33fc59 type: regular task: - id: 23f4aa75-bcfc-4274-80f8-8a778d809bac + id: 0902e574-df2d-416e-80e7-06409a33fc59 version: -1 name: cs-fx-get-analysis-status script: CrowdStrike Falcon X|||cs-fx-get-analysis-status @@ -526,7 +531,7 @@ tasks: - "11" scriptarguments: ids: - simple: 20879a8064904ecfbb62c118a6a19411_b8dfafbdb6bd4220aa5b11dbbd53cfaf + simple: 20879a8064904ecfbb62c118a6a19411_4a3266d4788a4277ae89d1d7b0bf11d7 separatecontext: false view: |- { @@ -542,12 +547,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "11": id: "11" - taskid: 32ae567e-6b2b-40bf-83eb-2b2904a06e92 + taskid: 9eb3ba4b-1669-477d-8c3c-25195b31f810 type: condition task: - id: 32ae567e-6b2b-40bf-83eb-2b2904a06e92 + id: 9eb3ba4b-1669-477d-8c3c-25195b31f810 version: -1 name: Verify Outputs type: condition @@ -599,12 +605,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "12": id: "12" - taskid: ee5e15ec-2fe5-4368-8068-1158852d0975 + taskid: 469be051-34c6-4f9e-89f5-339de3d71b7d type: regular task: - id: ee5e15ec-2fe5-4368-8068-1158852d0975 + id: 469be051-34c6-4f9e-89f5-339de3d71b7d version: -1 name: cs-fx-check-quota script: CrowdStrike Falcon X|||cs-fx-check-quota @@ -629,12 +636,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "13": id: "13" - taskid: 37a04796-446a-46f5-820a-6e8174e79d28 + taskid: c6df8308-4b23-4305-882a-d3be8bda0a46 type: condition task: - id: 37a04796-446a-46f5-820a-6e8174e79d28 + id: c6df8308-4b23-4305-882a-d3be8bda0a46 version: -1 name: Verify Outputs type: condition @@ -678,12 +686,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "14": id: "14" - taskid: b887b1ae-cca4-49ba-8d1a-65f9200e131b + taskid: 066a9297-8ab2-41fc-8198-a5b01dddb3b0 type: regular task: - id: b887b1ae-cca4-49ba-8d1a-65f9200e131b + id: 066a9297-8ab2-41fc-8198-a5b01dddb3b0 version: -1 name: cs-fx-find-reports script: CrowdStrike Falcon X|||cs-fx-find-reports @@ -715,12 +724,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "15": id: "15" - taskid: 4ea1c220-2f3e-4d99-8532-5e7c9e171584 + taskid: cd7136e9-ea00-4a14-80c0-1943cd49c3d5 type: condition task: - id: 4ea1c220-2f3e-4d99-8532-5e7c9e171584 + id: cd7136e9-ea00-4a14-80c0-1943cd49c3d5 version: -1 name: Verify Outputs type: condition @@ -767,12 +777,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "16": id: "16" - taskid: 7e5f6c7c-62dc-407b-8aac-ba06ed464f52 + taskid: 125e1b09-4ba9-4887-8808-9532da8270ff type: regular task: - id: 7e5f6c7c-62dc-407b-8aac-ba06ed464f52 + id: 125e1b09-4ba9-4887-8808-9532da8270ff version: -1 name: cs-fx-find-submission-id script: CrowdStrike Falcon X|||cs-fx-find-submission-id @@ -802,12 +813,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "17": id: "17" - taskid: 4da79cb4-beea-42cc-8933-f018f062b654 + taskid: f334dbb2-d328-4959-8505-a4e5806b950f type: condition task: - id: 4da79cb4-beea-42cc-8933-f018f062b654 + id: f334dbb2-d328-4959-8505-a4e5806b950f version: -1 name: Verify Outputs type: condition @@ -842,12 +854,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "18": id: "18" - taskid: baa25872-98db-4755-8276-74163e53c4a6 + taskid: 63e82917-ba75-4b90-88a3-c248087ec4fe type: regular task: - id: baa25872-98db-4755-8276-74163e53c4a6 + id: 63e82917-ba75-4b90-88a3-c248087ec4fe version: -1 name: file script: CrowdStrike Falcon X|||file @@ -875,12 +888,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "19": id: "19" - taskid: 324adce0-5d3a-40ce-89dc-a4e673a40185 + taskid: e2006480-67cc-4e7d-8184-5b5ce832515b type: condition task: - id: 324adce0-5d3a-40ce-89dc-a4e673a40185 + id: e2006480-67cc-4e7d-8184-5b5ce832515b version: -1 name: Verify Outputs type: condition @@ -982,12 +996,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "20": id: "20" - taskid: 557492ac-eaed-4db1-8582-a2f4fe708332 + taskid: 431729bc-39c2-4f00-8025-c570e095a129 type: regular task: - id: 557492ac-eaed-4db1-8582-a2f4fe708332 + id: 431729bc-39c2-4f00-8025-c570e095a129 version: -1 name: cs-fx-submit-url script: CrowdStrike Falcon X|||cs-fx-submit-url @@ -1027,12 +1042,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "21": id: "21" - taskid: 84bfcead-9a3c-4c0b-8388-8a9ed7853be1 + taskid: ded4d881-9bb0-42f8-834a-3043f18262a2 type: condition task: - id: 84bfcead-9a3c-4c0b-8388-8a9ed7853be1 + id: ded4d881-9bb0-42f8-834a-3043f18262a2 version: -1 name: Verify Outputs type: condition @@ -1081,12 +1097,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "22": id: "22" - taskid: 6acd33ed-6b3f-486e-806b-bc9422df82d4 + taskid: 519dbcc7-b054-444f-849b-bb48d002e7d5 type: regular task: - id: 6acd33ed-6b3f-486e-806b-bc9422df82d4 + id: 519dbcc7-b054-444f-849b-bb48d002e7d5 version: -1 name: cs-fx-download-ioc script: CrowdStrike Falcon X|||cs-fx-download-ioc @@ -1098,7 +1115,7 @@ tasks: - "32" scriptarguments: id: - simple: 970fdfe19dfc52d209108f61af53808bea87d911d4e2dbfdeedc55fa2a3f7113 + simple: 82395fd5444851c0208bf7f1d184477cb60c70cc880e5891694842f51c964cbc separatecontext: false view: |- { @@ -1114,12 +1131,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "23": id: "23" - taskid: 511b42a8-3cd4-4fb5-85e7-4d44f1c50375 + taskid: f7ae0271-2fa7-49fd-817c-09a623fef140 type: title task: - id: 511b42a8-3cd4-4fb5-85e7-4d44f1c50375 + id: f7ae0271-2fa7-49fd-817c-09a623fef140 version: -1 name: Test Done type: title @@ -1141,12 +1159,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "24": id: "24" - taskid: a8b49b1a-0138-4214-84e2-86639d3904ad + taskid: 5f2b7488-5ae3-4b6e-84c0-87ebf35b33a1 type: regular task: - id: a8b49b1a-0138-4214-84e2-86639d3904ad + id: 5f2b7488-5ae3-4b6e-84c0-87ebf35b33a1 version: -1 name: DeleteContext script: DeleteContext @@ -1174,12 +1193,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "25": id: "25" - taskid: eca87b3f-dcbb-47c0-8a77-0131088888d1 + taskid: 372eef56-86c1-4042-8ca7-5aa22c0b8a34 type: regular task: - id: eca87b3f-dcbb-47c0-8a77-0131088888d1 + id: 372eef56-86c1-4042-8ca7-5aa22c0b8a34 version: -1 name: DeleteContext script: DeleteContext @@ -1207,12 +1227,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "26": id: "26" - taskid: 87c11859-a07d-462a-879c-9746d7eddd54 + taskid: 6b942210-7947-4eb5-8b77-f6e613186f7a type: regular task: - id: 87c11859-a07d-462a-879c-9746d7eddd54 + id: 6b942210-7947-4eb5-8b77-f6e613186f7a version: -1 name: DeleteContext script: DeleteContext @@ -1240,12 +1261,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "27": id: "27" - taskid: 24befdae-f67d-4ef7-8487-45d247f90953 + taskid: 38fe7e81-806a-4be9-8ba2-d18a57ce6f42 type: regular task: - id: 24befdae-f67d-4ef7-8487-45d247f90953 + id: 38fe7e81-806a-4be9-8ba2-d18a57ce6f42 version: -1 name: DeleteContext script: DeleteContext @@ -1273,12 +1295,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "28": id: "28" - taskid: 8f47a97c-39a0-4e11-875c-55623902ee34 + taskid: 4a4e0669-7376-4cc3-8248-f2c7503c25ce type: regular task: - id: 8f47a97c-39a0-4e11-875c-55623902ee34 + id: 4a4e0669-7376-4cc3-8248-f2c7503c25ce version: -1 name: DeleteContext script: DeleteContext @@ -1306,12 +1329,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "29": id: "29" - taskid: 60d5442e-0031-4957-8be3-7ae17f3991d8 + taskid: 289dcfdf-35ee-49f6-802b-ceb38df9ffe0 type: regular task: - id: 60d5442e-0031-4957-8be3-7ae17f3991d8 + id: 289dcfdf-35ee-49f6-802b-ceb38df9ffe0 version: -1 name: DeleteContext script: DeleteContext @@ -1339,12 +1363,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "30": id: "30" - taskid: 675a3120-a69f-4c2d-834e-63f041cf9792 + taskid: bf342b6c-62fd-460d-85b2-d03b6635d9a1 type: regular task: - id: 675a3120-a69f-4c2d-834e-63f041cf9792 + id: bf342b6c-62fd-460d-85b2-d03b6635d9a1 version: -1 name: DeleteContext script: DeleteContext @@ -1372,12 +1397,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "31": id: "31" - taskid: be50cbd3-f721-4f65-8795-9d272e4049bc + taskid: eeb0237c-2e9c-4244-86fe-63665b784558 type: regular task: - id: be50cbd3-f721-4f65-8795-9d272e4049bc + id: eeb0237c-2e9c-4244-86fe-63665b784558 version: -1 name: DeleteContext script: DeleteContext @@ -1405,12 +1431,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "32": id: "32" - taskid: a4039e2b-28d7-4b7f-88aa-66a07dda2c35 + taskid: 4dc97988-d296-459e-83e7-f8de334a96ae type: condition task: - id: a4039e2b-28d7-4b7f-88aa-66a07dda2c35 + id: 4dc97988-d296-459e-83e7-f8de334a96ae version: -1 name: Verify Outputs type: condition @@ -1454,12 +1481,13 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "33": id: "33" - taskid: 6db30c72-c554-48d7-8019-48a098c3952e + taskid: 50a20ab0-f080-4a07-8c1c-f8b4de707b29 type: regular task: - id: 6db30c72-c554-48d7-8019-48a098c3952e + id: 50a20ab0-f080-4a07-8c1c-f8b4de707b29 version: -1 name: DeleteContext script: DeleteContext @@ -1487,6 +1515,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" view: |- { "linkLabelsPosition": { diff --git a/Packs/CyberChef/Integrations/CyberChef/CyberChef.py b/Packs/CyberChef/Integrations/CyberChef/CyberChef.py index 865bb6313e0a..c2466fb93b81 100644 --- a/Packs/CyberChef/Integrations/CyberChef/CyberChef.py +++ b/Packs/CyberChef/Integrations/CyberChef/CyberChef.py @@ -1,4 +1,3 @@ -from typing import Optional import demistomock as demisto # noqa: F401 from CommonServerPython import * # noqa: F401 import json @@ -12,7 +11,8 @@ def build_params(data: dict) -> list[str]: params.append(f'{json.dumps(value)}') return params -def test_module(client: Optional[BaseClient], local_execution: bool): + +def test_module(client: BaseClient | None, local_execution: bool): data = {'input': 'One, two, three, four.', 'recipe': 'to decimal'} if not local_execution and client: @@ -30,7 +30,7 @@ def test_module(client: Optional[BaseClient], local_execution: bool): return 'Test failed: ' + str(result) -def run_command(client: Optional[BaseClient], data: dict, endpoint: str, local_execution: bool): +def run_command(client: BaseClient | None, data: dict, endpoint: str, local_execution: bool): if not local_execution and client: response = client._http_request('POST', endpoint, json_data=data) else: diff --git a/Packs/CyberChef/Integrations/CyberChef/CyberChef.yml b/Packs/CyberChef/Integrations/CyberChef/CyberChef.yml index 74ab43db5d66..5f908c0c372f 100644 --- a/Packs/CyberChef/Integrations/CyberChef/CyberChef.yml +++ b/Packs/CyberChef/Integrations/CyberChef/CyberChef.yml @@ -58,7 +58,7 @@ script: - contextPath: CyberChef.Magic description: Output of the Magic operation. type: string - dockerimage: demisto/cyberchef:1.0.0.104247 + dockerimage: demisto/cyberchef:1.0.0.114638 runonce: false script: '' subtype: python3 diff --git a/Packs/CyberChef/ReleaseNotes/1_0_8.md b/Packs/CyberChef/ReleaseNotes/1_0_8.md new file mode 100644 index 000000000000..24142f1df2c8 --- /dev/null +++ b/Packs/CyberChef/ReleaseNotes/1_0_8.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### CyberChef + +- Updated the Docker image to: *demisto/cyberchef:1.0.0.114638*. diff --git a/Packs/CyberChef/pack_metadata.json b/Packs/CyberChef/pack_metadata.json index c32ecdbc9624..480d9c6fd735 100644 --- a/Packs/CyberChef/pack_metadata.json +++ b/Packs/CyberChef/pack_metadata.json @@ -2,7 +2,7 @@ "name": "CyberChef", "description": "Integration with your CyberChef server or https://prod.apifor.io service for CyberChef.", "support": "community", - "currentVersion": "1.0.7", + "currentVersion": "1.0.8", "author": "Harri Ruuttila", "url": "", "email": "", diff --git a/Packs/DB2/Integrations/DB2/DB2.py b/Packs/DB2/Integrations/DB2/DB2.py index a9751530e8b5..6601f559126d 100644 --- a/Packs/DB2/Integrations/DB2/DB2.py +++ b/Packs/DB2/Integrations/DB2/DB2.py @@ -5,7 +5,8 @@ import re import traceback -from typing import Any, Callable, Dict, List, Tuple +from typing import Any +from collections.abc import Callable from urllib.parse import parse_qsl import ibm_db @@ -87,7 +88,7 @@ def __init__( self.connection = self._connect() @staticmethod - def _parse_connect_parameters(connect_parameters: str) -> Dict: + def _parse_connect_parameters(connect_parameters: str) -> dict: """ Parses a string of the form key1=value1&key2=value2 etc. into a dict with matching keys and values. @@ -100,7 +101,7 @@ def _parse_connect_parameters(connect_parameters: str) -> Dict: """ connect_parameters_tuple_list = parse_qsl(connect_parameters, keep_blank_values=True) - connect_parameters_dict = dict() + connect_parameters_dict = {} for key, value in connect_parameters_tuple_list: connect_parameters_dict[key] = value return connect_parameters_dict @@ -114,7 +115,7 @@ def create_url(self) -> str: string containing all of the required parameters """ - conn_string = ("DRIVER={0};DATABASE={1};HOSTNAME={2};PORT={3};PROTOCOL={4};UID={5};PWD={6};").format( + conn_string = ("DRIVER={};DATABASE={};HOSTNAME={};PORT={};PROTOCOL={};UID={};PWD={};").format( DRIVER_NAME, self.dbname, self.host, @@ -129,12 +130,12 @@ def create_url(self) -> str: return conn_string - def _options(self) -> Dict: + def _options(self) -> dict: """ Map connection options with connection parameters `ibm_db.OPTION` will be called for every option """ - options = dict() + options = {} for key, val in self.connect_parameters.items(): option: str = key.upper() @@ -215,7 +216,7 @@ def repl(x, bindvars=bindvars): return stmt - def execute_query(self, query: str, bind_vars: Any) -> Tuple[List, List]: + def execute_query(self, query: str, bind_vars: Any) -> tuple[list, list]: """ Execute query at DB2 Database via connection @@ -227,8 +228,8 @@ def execute_query(self, query: str, bind_vars: Any) -> Tuple[List, List]: Returns: Tuple[results(List), headers(List)] """ - results = list() - headers = list() + results = [] + headers = [] status = False stmt = self._prepare_statement(query, bind_vars) @@ -295,7 +296,7 @@ def bind_variables(names: str, values: str) -> Any: # assuming the order of values is correct if values_list and not names_list: - return [val for val in values_list] + return list(values_list) elif len(names_list) == len(values_list): return dict(zip(names_list, values_list)) else: @@ -305,7 +306,7 @@ def bind_variables(names: str, values: str) -> Any: """ COMMAND FUNCTIONS """ -def query_command(client: Client, args: Dict, *_) -> CommandResults: +def query_command(client: Client, args: dict, *_) -> CommandResults: """ Executes the db2 query with the connection that was configured in the Client @@ -386,7 +387,7 @@ def main(): # pragma: no cover use_persistent=use_persistent, ) - commands: Dict[str, Callable] = { + commands: dict[str, Callable] = { "test-module": test_module, "db2-query": query_command, } diff --git a/Packs/DB2/Integrations/DB2/DB2.yml b/Packs/DB2/Integrations/DB2/DB2.yml index 22fce5ada98e..91d09e0b8bc8 100644 --- a/Packs/DB2/Integrations/DB2/DB2.yml +++ b/Packs/DB2/Integrations/DB2/DB2.yml @@ -52,7 +52,7 @@ script: name: bind_variables_values description: Running a DB2 query command name: db2-query - dockerimage: demisto/ibm-db2:1.0.0.100241 + dockerimage: demisto/ibm-db2:1.0.0.114680 script: '' subtype: python3 type: python diff --git a/Packs/DB2/ReleaseNotes/1_0_2.md b/Packs/DB2/ReleaseNotes/1_0_2.md new file mode 100644 index 000000000000..429e6379bcac --- /dev/null +++ b/Packs/DB2/ReleaseNotes/1_0_2.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### DB2 + +- Updated the Docker image to: *demisto/ibm-db2:1.0.0.114680*. diff --git a/Packs/DB2/pack_metadata.json b/Packs/DB2/pack_metadata.json index 6f7265d1bf5b..d2c4ecdef408 100644 --- a/Packs/DB2/pack_metadata.json +++ b/Packs/DB2/pack_metadata.json @@ -2,7 +2,7 @@ "name": "DB2", "description": "This pack's purpose is to provide helpful commands to build a connectivity and run queries on IBM DB2 database.", "support": "community", - "currentVersion": "1.0.1", + "currentVersion": "1.0.2", "author": "Shubham Kaushik", "url": "", "email": "its.shubham.kaushik@gmail.com", diff --git a/Packs/Devo/Integrations/Devo_v2/Devo_v2.py b/Packs/Devo/Integrations/Devo_v2/Devo_v2.py index d363dc5d5c3b..24e5ed754e5f 100644 --- a/Packs/Devo/Integrations/Devo_v2/Devo_v2.py +++ b/Packs/Devo/Integrations/Devo_v2/Devo_v2.py @@ -12,7 +12,7 @@ import re import os import pandas as pd -from datetime import datetime +from datetime import datetime, UTC from devo.sender import Lookup, SenderConfigSSL, Sender from functools import partial @@ -179,7 +179,7 @@ def _to_unix(date, milliseconds=False): epoch = pd.to_datetime(date).timestamp() elif isinstance(date, pd.Timestamp | datetime): if date.tzinfo is None: - epoch = date.replace(tzinfo=timezone.utc).timestamp() + epoch = date.replace(tzinfo=UTC).timestamp() else: epoch = date.timestamp() elif isinstance(date, int | float): diff --git a/Packs/Devo/Integrations/Devo_v2/Devo_v2.yml b/Packs/Devo/Integrations/Devo_v2/Devo_v2.yml index 7c5d0a1b0e1b..51d733c2c0da 100644 --- a/Packs/Devo/Integrations/Devo_v2/Devo_v2.yml +++ b/Packs/Devo/Integrations/Devo_v2/Devo_v2.yml @@ -237,7 +237,7 @@ script: type: unknown description: Writes lookup table entry records to a specified Devo table. execution: true - dockerimage: demisto/devo:1.0.0.93142 + dockerimage: demisto/devo:1.0.0.113864 isfetch: true subtype: python3 tests: diff --git a/Packs/Devo/Integrations/Devo_v2/Devo_v2_test.py b/Packs/Devo/Integrations/Devo_v2/Devo_v2_test.py index d2964253c6c7..39d119385d1c 100644 --- a/Packs/Devo/Integrations/Devo_v2/Devo_v2_test.py +++ b/Packs/Devo/Integrations/Devo_v2/Devo_v2_test.py @@ -2,7 +2,7 @@ import time import copy from unittest.mock import MagicMock, patch -from datetime import datetime, timezone +from datetime import datetime, UTC import pytest import re from freezegun import freeze_time @@ -925,7 +925,7 @@ def test_to_unix_current_time(): def test_to_unix_datetime_object(): - dt = datetime(2024, 3, 23, 12, 0, 0, tzinfo=timezone.utc) # Ensure timezone is UTC + dt = datetime(2024, 3, 23, 12, 0, 0, tzinfo=UTC) # Ensure timezone is UTC unix_timestamp = _to_unix(dt) assert unix_timestamp == 1711195200 diff --git a/Packs/Devo/ReleaseNotes/1_3_3.md b/Packs/Devo/ReleaseNotes/1_3_3.md new file mode 100644 index 000000000000..ef957247ff8b --- /dev/null +++ b/Packs/Devo/ReleaseNotes/1_3_3.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Devo v2 + +- Updated the Docker image to: *demisto/devo:1.0.0.113864*. diff --git a/Packs/Devo/pack_metadata.json b/Packs/Devo/pack_metadata.json index 63d840912622..e1c98de72ba9 100644 --- a/Packs/Devo/pack_metadata.json +++ b/Packs/Devo/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Devo", "description": "Use the Devo integration to query Devo for alerts, lookup tables, and to write to lookup tables.", "support": "partner", - "currentVersion": "1.3.2", + "currentVersion": "1.3.3", "author": "Devo", "url": "https://www.devo.com", "email": "support@devo.com", diff --git a/Packs/DigitalShadows/Integrations/ReliaQuestGreyMatterDRPIncidents/ReliaQuestGreyMatterDRPIncidents.py b/Packs/DigitalShadows/Integrations/ReliaQuestGreyMatterDRPIncidents/ReliaQuestGreyMatterDRPIncidents.py index e42199a21e7f..6f6ca8e93200 100644 --- a/Packs/DigitalShadows/Integrations/ReliaQuestGreyMatterDRPIncidents/ReliaQuestGreyMatterDRPIncidents.py +++ b/Packs/DigitalShadows/Integrations/ReliaQuestGreyMatterDRPIncidents/ReliaQuestGreyMatterDRPIncidents.py @@ -579,7 +579,7 @@ def search_find(request_handler: Client, args): "tags": [], "types": [ "ACTORS", - "Bdemisto.info_POST", + "BLOG_POST", "CAMPAIGNS", "CHAT_MESSAGE", "CLIENT_INCIDENT", diff --git a/Packs/DigitalShadows/Integrations/ReliaQuestGreyMatterDRPIncidents/ReliaQuestGreyMatterDRPIncidents_image.png b/Packs/DigitalShadows/Integrations/ReliaQuestGreyMatterDRPIncidents/ReliaQuestGreyMatterDRPIncidents_image.png index defdd9cc5071..48cc9debbea6 100644 Binary files a/Packs/DigitalShadows/Integrations/ReliaQuestGreyMatterDRPIncidents/ReliaQuestGreyMatterDRPIncidents_image.png and b/Packs/DigitalShadows/Integrations/ReliaQuestGreyMatterDRPIncidents/ReliaQuestGreyMatterDRPIncidents_image.png differ diff --git a/Packs/DigitalShadows/ReleaseNotes/2_0_2.md b/Packs/DigitalShadows/ReleaseNotes/2_0_2.md new file mode 100644 index 000000000000..601fed003a1c --- /dev/null +++ b/Packs/DigitalShadows/ReleaseNotes/2_0_2.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### ReliaQuest GreyMatter DRP Incidents + +Fixed result type in ***ds-search*** command. diff --git a/Packs/DigitalShadows/pack_metadata.json b/Packs/DigitalShadows/pack_metadata.json index a00308e1ce2b..335e01f1b7a4 100644 --- a/Packs/DigitalShadows/pack_metadata.json +++ b/Packs/DigitalShadows/pack_metadata.json @@ -2,7 +2,7 @@ "name": "ReliaQuest GreyMatter DRP Incidents", "description": "ReliaQuest GreyMatter DRP monitors and manages an organization's digital risk across the open, deep, and dark web.", "support": "partner", - "currentVersion": "2.0.1", + "currentVersion": "2.0.2", "author": "ReliaQuest", "url": "https:// www.reliaquest.com/", "email": "drpsupport@reliaquest.com", diff --git a/Packs/EDL/Integrations/EDL/README.md b/Packs/EDL/Integrations/EDL/README.md index f2f55d5e1957..e2294178e742 100644 --- a/Packs/EDL/Integrations/EDL/README.md +++ b/Packs/EDL/Integrations/EDL/README.md @@ -39,11 +39,13 @@ To view logs concerning the creation of the indicator list and its current statu <~XSOAR_SAAS> `https://ext-/xsoar/instance/execute//log` + <~XSOAR_ON_PREM> `https://**/instance/execute/**/log` + <~XSIAM> -`https://edl-/xsoar/instance/execute//log` +`https://ext-/xsoar/instance/execute//log` ## Use Cases diff --git a/Packs/ExodusIntelligence/Integrations/ExodusVulnerabilityEnrichment/ExodusVulnerabilityEnrichment.yml b/Packs/ExodusIntelligence/Integrations/ExodusVulnerabilityEnrichment/ExodusVulnerabilityEnrichment.yml index 049304a13a29..3d95057d4885 100644 --- a/Packs/ExodusIntelligence/Integrations/ExodusVulnerabilityEnrichment/ExodusVulnerabilityEnrichment.yml +++ b/Packs/ExodusIntelligence/Integrations/ExodusVulnerabilityEnrichment/ExodusVulnerabilityEnrichment.yml @@ -123,7 +123,7 @@ script: - contextPath: ExodusVulnerabilityEnrichment.ResetDataStream.end_ts description: New date data stream is set to. type: String - dockerimage: demisto/exodusintelligence:1.0.0.91256 + dockerimage: demisto/exodusintelligence:1.0.0.113866 feed: true isFetchSamples: true runonce: true diff --git a/Packs/ExodusIntelligence/ReleaseNotes/1_0_2.md b/Packs/ExodusIntelligence/ReleaseNotes/1_0_2.md new file mode 100644 index 000000000000..5057e9aa2f92 --- /dev/null +++ b/Packs/ExodusIntelligence/ReleaseNotes/1_0_2.md @@ -0,0 +1,7 @@ + +#### Integrations + +##### Exodus Intelligence Vulnerabilities +- Updated the Docker image to: *demisto/exodusintelligence:1.0.0.113866*. + + diff --git a/Packs/ExodusIntelligence/pack_metadata.json b/Packs/ExodusIntelligence/pack_metadata.json index e517ca1ed53c..5cf5314c7d64 100644 --- a/Packs/ExodusIntelligence/pack_metadata.json +++ b/Packs/ExodusIntelligence/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Exodus Intelligence EVE Platform", "description": "Built on original research from some of the best reverse engineers in the world as well as cutting edge machine learning technology, [Exodus Intelligence’s EVE](https://vpx.exodusintel.com) platform provides deep intelligence about the latest vulnerabilities. This integration allows Cortex XSOAR users to add context regarding the nature of vulnerabilities and their likelihood to be exploited in the wild, identify platforms on which given vulnerabilities exist and have been verified to be exploitable, update incidents with specific mitigation guidance, and much more.", "support": "partner", - "currentVersion": "1.0.1", + "currentVersion": "1.0.2", "author": "Exodus Intelligence LLC", "url": "", "email": "eng@exodusintel.com", diff --git a/Packs/FeedBlocklist_de/ReleaseNotes/1_1_30.md b/Packs/FeedBlocklist_de/ReleaseNotes/1_1_30.md new file mode 100644 index 000000000000..a9dd6ac4a484 --- /dev/null +++ b/Packs/FeedBlocklist_de/ReleaseNotes/1_1_30.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Blocklist_de Feed + +Fixed an issue with reading the ETAG header from feed response. diff --git a/Packs/FeedBlocklist_de/pack_metadata.json b/Packs/FeedBlocklist_de/pack_metadata.json index 1b7af161c355..95f871518c7b 100644 --- a/Packs/FeedBlocklist_de/pack_metadata.json +++ b/Packs/FeedBlocklist_de/pack_metadata.json @@ -2,7 +2,7 @@ "name": "BlockList DE Feed", "description": "Indicators feed from BlockList DE", "support": "xsoar", - "currentVersion": "1.1.29", + "currentVersion": "1.1.30", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/FeedBruteForceBlocker/ReleaseNotes/1_1_28.md b/Packs/FeedBruteForceBlocker/ReleaseNotes/1_1_28.md new file mode 100644 index 000000000000..a8453bd9d90b --- /dev/null +++ b/Packs/FeedBruteForceBlocker/ReleaseNotes/1_1_28.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### BruteForceBlocker Feed + +Fixed an issue with reading the ETAG header from feed response. diff --git a/Packs/FeedBruteForceBlocker/pack_metadata.json b/Packs/FeedBruteForceBlocker/pack_metadata.json index 0c0a6bae59c8..ee5811018a73 100644 --- a/Packs/FeedBruteForceBlocker/pack_metadata.json +++ b/Packs/FeedBruteForceBlocker/pack_metadata.json @@ -2,7 +2,7 @@ "name": "BruteForce Feed", "description": "Indicators feed from BruteForceBlocker", "support": "xsoar", - "currentVersion": "1.1.27", + "currentVersion": "1.1.28", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/FeedCloudflare/ReleaseNotes/1_1_28.md b/Packs/FeedCloudflare/ReleaseNotes/1_1_28.md new file mode 100644 index 000000000000..472cc248fb6c --- /dev/null +++ b/Packs/FeedCloudflare/ReleaseNotes/1_1_28.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Cloudflare Feed + +Fixed an issue with reading the ETAG header from feed response. diff --git a/Packs/FeedCloudflare/pack_metadata.json b/Packs/FeedCloudflare/pack_metadata.json index 92bb6d276fdf..d7bc6ddcf7dd 100644 --- a/Packs/FeedCloudflare/pack_metadata.json +++ b/Packs/FeedCloudflare/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Cloudflare Feed", "description": "Indicators feed from Cloudflare", "support": "xsoar", - "currentVersion": "1.1.27", + "currentVersion": "1.1.28", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/FeedDShield/ReleaseNotes/1_1_32.md b/Packs/FeedDShield/ReleaseNotes/1_1_32.md new file mode 100644 index 000000000000..47df8d2994ab --- /dev/null +++ b/Packs/FeedDShield/ReleaseNotes/1_1_32.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### DShield Feed + +Fixed an issue with reading the ETAG header from feed response. diff --git a/Packs/FeedDShield/pack_metadata.json b/Packs/FeedDShield/pack_metadata.json index fcf377211905..1378d28a64c4 100644 --- a/Packs/FeedDShield/pack_metadata.json +++ b/Packs/FeedDShield/pack_metadata.json @@ -2,7 +2,7 @@ "name": "DShield Feed", "description": "Indicators feed from DShield", "support": "xsoar", - "currentVersion": "1.1.31", + "currentVersion": "1.1.32", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/FeedElasticsearch.py b/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/FeedElasticsearch.py index 5b757323c9f9..37e65d912e49 100644 --- a/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/FeedElasticsearch.py +++ b/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/FeedElasticsearch.py @@ -174,12 +174,12 @@ def test_command(client, feed_type, src_val, src_type, default_type, time_method def get_indicators_command(client, feed_type, src_val, src_type, default_type): """Implements es-get-indicators command""" now = datetime.now() - if FEED_TYPE_GENERIC in feed_type: + if FEED_TYPE_GENERIC in feed_type: # Generic Feed search = get_scan_generic_format(client, now) ioc_lst = get_generic_indicators(search, src_val, src_type, default_type, client.tags, client.tlp_color, client.enrichment_excluded) hr = tableToMarkdown('Indicators', ioc_lst, [src_val]) - else: + else: # Demisto Feed types # Insight is the name of the indicator object as it's saved into the database search = get_scan_insight_format(client, now, feed_type=feed_type) ioc_lst, ioc_enrch_lst = get_demisto_indicators(search, client.tags, client.tlp_color, client.enrichment_excluded) @@ -192,10 +192,13 @@ def get_indicators_command(client, feed_type, src_val, src_type, default_type): def get_generic_indicators(search, src_val, src_type, default_type, tags, tlp_color, enrichment_excluded): """Implements get indicators in generic format""" + limit = int(demisto.args().get('limit', FETCH_SIZE)) ioc_lst: list = [] - hit = search.execute() - hit_lst = extract_indicators_from_generic_hit(hit, src_val, src_type, default_type, tags, tlp_color, enrichment_excluded) - ioc_lst.extend(hit_lst) + for hit in search.scan(): + hit_lst = extract_indicators_from_generic_hit(hit, src_val, src_type, default_type, tags, tlp_color, enrichment_excluded) + ioc_lst.extend(hit_lst) + if len(ioc_lst) >= limit: + break return ioc_lst @@ -219,9 +222,11 @@ def update_last_fetch(client, ioc_lst): last_calculated_timestamp = None last_ids = [] for ioc in reversed(ioc_lst): - calculate_time = dateparser.parse(ioc.get(client.time_field)) + calculate_time: Optional[datetime] = '' # type: ignore + if time_val := ioc.get(client.time_field): + calculate_time = dateparser.parse(time_val) if not calculate_time: - demisto.info(f"ioc {ioc.get('name')} if missing {client.time_field}") + demisto.info(f"ioc {ioc.get('value')} is missing time_field: {client.time_field}") break calculate_timestamp = int(calculate_time.timestamp() * 1000) if not last_calculated_timestamp or calculate_timestamp >= last_calculated_timestamp: @@ -232,6 +237,9 @@ def update_last_fetch(client, ioc_lst): demisto.debug(f"FeedElasticSearch: {calculate_timestamp=}") break if last_calculated_timestamp is None: + # possible cases: + # 1. We didn't fetch any indicators in this cycle + # 2. This is a fetch of indicators from a generic feed type without a client.time_field last_calculated_timestamp = int(datetime.now().timestamp() * 1000) demisto.info(f"FeedElasticSearch: The length of the indicators of the last time: {len(last_ids)}") demisto.debug(f"FeedElasticSearch: The last ids which were fetched with the same last time: {last_ids}") @@ -246,18 +254,18 @@ def fetch_indicators_command(client, feed_type, src_val, src_type, default_type, now = datetime.now() ioc_lst: list = [] ioc_enrch_lst: list = [] - if FEED_TYPE_GENERIC not in feed_type: + if FEED_TYPE_GENERIC not in feed_type: # Demisto Feed types # Insight is the name of the indicator object as it's saved into the database - search = get_scan_insight_format(client, now, last_fetch_timestamp, feed_type) - for hit in search if client.time_field else search.scan: # if time field is not set we have to scan all + search = get_scan_insight_format(client, now, last_fetch_timestamp, feed_type, fetch_limit) + for hit in search: hit_lst, hit_enrch_lst = extract_indicators_from_insight_hit(hit, tags=client.tags, tlp_color=client.tlp_color, enrichment_excluded=client.enrichment_excluded) ioc_lst.extend(hit_lst) ioc_enrch_lst.extend(hit_enrch_lst) - else: + else: # Generic Feed type search = get_scan_generic_format(client, now, last_fetch_timestamp, fetch_limit) - for hit in search if client.time_field else search.scan: # if time field is not set we have to scan all + for hit in search if client.time_field else search.scan(): # if time field isn't set we have to scan all (in every cycle) ioc_lst.extend(extract_indicators_from_generic_hit(hit, src_val, src_type, default_type, client.tags, client.tlp_color, client.enrichment_excluded)) ioc_lst = list(filter(lambda ioc: ioc.get("id") not in prev_iocs_ids, ioc_lst)) @@ -373,7 +381,7 @@ def hit_to_indicator(hit, ioc_val_key='name', ioc_type_key=None, default_ioc_typ ioc_dict['rawJSON'] = dict(ioc_dict) if default_ioc_type: ioc_dict['type'] = default_ioc_type - elif ioc_type_key: + if ioc_type_key and ioc_dict.get(ioc_type_key): # in case the user didn't specify a field type, we keep the default type ioc_dict['type'] = ioc_dict.get(ioc_type_key) ioc_dict['fields'] = {} @@ -419,7 +427,7 @@ def main(): time_method = params.get('time_method') fetch_index = params.get('fetch_index') fetch_time = params.get('fetch_time', '3 days') - fetch_limit = arg_to_number(params.get('fetch_limit', 10000)) + fetch_limit = arg_to_number(params.get('fetch_limit', FETCH_LIMIT)) enrichment_excluded = params.get('enrichmentExcluded', False) if not fetch_limit or fetch_limit > 10_000: raise DemistoException(f"Fetch limit must be between 1-10,000, got {fetch_limit}") diff --git a/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/FeedElasticsearch.yml b/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/FeedElasticsearch.yml index 70cb83baf8a3..8b0868be40bd 100644 --- a/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/FeedElasticsearch.yml +++ b/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/FeedElasticsearch.yml @@ -63,6 +63,7 @@ configuration: required: false section: Collect - defaultvalue: '10000' + additionalinfo: The maximal number of indicators that could be fetched in a fetch cycle. display: Fetch Limit name: fetch_limit type: 0 @@ -144,21 +145,21 @@ configuration: required: false section: Collect advanced: true -- additionalinfo: Source field that contains the indicator value in the index +- additionalinfo: Source field that contains the indicator value in the index. Relevant for generic feed type only. display: Indicator Value Field name: src_val type: 0 required: false section: Collect advanced: true -- additionalinfo: Source field that contains the indicator type in the index +- additionalinfo: Source field that contains the indicator type in the index. Relevant for generic feed type only. display: Indicator Type Field name: src_type type: 0 required: false section: Collect advanced: true -- additionalinfo: Default indicator type used in case no "Indicator Type Field" was provided +- additionalinfo: Default indicator type used in case no "Indicator Type Field" was provided. Relevant for generic feed type only. display: Indicator Type name: default_type type: 0 @@ -183,7 +184,7 @@ configuration: - Timestamp-Milliseconds section: Collect advanced: true -- additionalinfo: Used for sorting and limiting data. If empty, results are not sorted. +- additionalinfo: Used for sorting and limiting data. If empty, results are not sorted. Relevant for generic feed type only. display: Index Time Field name: time_field type: 0 @@ -223,7 +224,7 @@ script: commands: - arguments: - defaultValue: '50' - description: The maximum number of indicators to fetch. The default is 50. + description: The maximum number of indicators to fetch. name: limit required: true description: Gets indicators available in the configured Elasticsearch database. @@ -236,7 +237,8 @@ script: type: python fromversion: 5.5.0 tests: -- No tests (auto formatted) +- Elasticsearch_Fetch_Custom_Indicators_Test +- Elasticsearch_Fetch_Demisto_Indicators_Test sectionOrder: - Connect - Collect \ No newline at end of file diff --git a/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/FeedElasticsearch_test.py b/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/FeedElasticsearch_test.py index 705af445deb3..55e6646a3a8e 100644 --- a/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/FeedElasticsearch_test.py +++ b/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/FeedElasticsearch_test.py @@ -179,6 +179,9 @@ def test_hit_to_indicator(): assert ioc['type'] == 'IP' assert ioc[CUSTOM_TYPE_KEY] == '' + ioc = esf.hit_to_indicator(MockHit(CUSTOM_HIT), CUSTOM_VAL_KEY, '', 'URL', ['tag1', 'tag2'], 'AMBER') + assert ioc['type'] == 'URL' + def test_hit_to_indicator_enrichment_excluded(): """ diff --git a/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/README.md b/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/README.md index 9e19202e455e..d186e589f12c 100644 --- a/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/README.md +++ b/Packs/FeedElasticsearch/Integrations/FeedElasticsearch/README.md @@ -23,20 +23,19 @@ Fetch indicators stored in an Elasticsearch database. | Feed Type | The Cortex XSOAR Feed contains system indicators saved in an Elasticsearch index. The Cortex XSOAR MT Shared Feed contains indicators shared by a tenant account in a multi-tenant environment. Generic Feed contains a feed in a format specified by the user | False | | Fetch indicators | | False | | First Fetch Time | Determine how far to look back for fetched indicators \(<number> <time unit>, e.g., 12 hours, 7 days\). | False | + | Fetch Limit | The maximal number of indicators that could be fetched in a fetch cycle. | False | | Indicator Reputation | Indicators from this integration instance will be marked with this reputation | False | | Source Reliability | Reliability of the source providing the intelligence data | True | | Traffic Light Protocol Color | The Traffic Light Protocol \(TLP\) designation to apply to indicators fetched from the feed | False | - | | | False | - | | | False | | Feed Fetch Interval | | False | | Tags | Supports CSV values. | False | | Bypass exclusion list | When selected, the exclusion list is ignored for indicators from this feed. This means that if an indicator from this feed is on the exclusion list, the indicator might still be added to the system. | False | - | Indicator Value Field | Source field that contains the indicator value in the index | False | - | Indicator Type Field | Source field that contains the indicator type in the index | False | - | Indicator Type | Default indicator type used in case no "Indicator Type Field" was provided | False | + | Indicator Value Field | Source field that contains the indicator value in the index. Relevant for generic feed type only. | False | + | Indicator Type Field | Source field that contains the indicator type in the index. Relevant for generic feed type only. | False | + | Indicator Type | Default indicator type used in case no "Indicator Type Field" was provided. Relevant for generic feed type only. | False | | Index from Which To Fetch Indicators | A comma-separated list of indexes. If empty, searches all indexes. | False | | Time Field Type | | False | - | Index Time Field | Used for sorting and limiting data. If empty, results are not sorted. | False | + | Index Time Field | Used for sorting and limiting data. If empty, results are not sorted. Relevant for generic feed type only. | False | | Query | Elasticsearch query to execute when fetching indicators from Elasticsearch | False | 4. Click **Test** to validate the URLs, token, and connection. @@ -59,7 +58,7 @@ Gets indicators available in the configured Elasticsearch database. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | -| limit | The maximum number of indicators to fetch. The default is 50. Default is 50. | Required | +| limit | The maximum number of indicators to fetch. Default is 50. | Required | #### Context Output diff --git a/Packs/FeedElasticsearch/ReleaseNotes/1_1_9.md b/Packs/FeedElasticsearch/ReleaseNotes/1_1_9.md new file mode 100644 index 000000000000..9baf0e6209f1 --- /dev/null +++ b/Packs/FeedElasticsearch/ReleaseNotes/1_1_9.md @@ -0,0 +1,7 @@ + +#### Integrations + +##### Elasticsearch Feed + +- Fixed an issue where indicators weren't fetched for Generic Feed Type. +- Documentation improvements. diff --git a/Packs/FeedElasticsearch/pack_metadata.json b/Packs/FeedElasticsearch/pack_metadata.json index cf314ce5e880..2863a5aa642e 100644 --- a/Packs/FeedElasticsearch/pack_metadata.json +++ b/Packs/FeedElasticsearch/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Elasticsearch Feed", "description": "Indicators feed from Elasticsearch database", "support": "xsoar", - "currentVersion": "1.1.8", + "currentVersion": "1.1.9", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/FeedFeodoTracker/ReleaseNotes/1_1_30.md b/Packs/FeedFeodoTracker/ReleaseNotes/1_1_30.md new file mode 100644 index 000000000000..fefa13494cab --- /dev/null +++ b/Packs/FeedFeodoTracker/ReleaseNotes/1_1_30.md @@ -0,0 +1,10 @@ + +#### Integrations + +##### Feodo Tracker Hashes Feed (Deprecated) + +Fixed an issue with reading the ETAG header from feed response. + +##### Feodo Tracker IP Blocklist Feed + +Fixed an issue with reading the ETAG header from feed response. \ No newline at end of file diff --git a/Packs/FeedFeodoTracker/pack_metadata.json b/Packs/FeedFeodoTracker/pack_metadata.json index 91a87794d58f..7b9f09349d61 100644 --- a/Packs/FeedFeodoTracker/pack_metadata.json +++ b/Packs/FeedFeodoTracker/pack_metadata.json @@ -2,7 +2,7 @@ "name": "FeodoTracker Feed", "description": "Indicators feed from FeodoTracker", "support": "xsoar", - "currentVersion": "1.1.29", + "currentVersion": "1.1.30", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/FeedMalwareDomainList/ReleaseNotes/1_1_10.md b/Packs/FeedMalwareDomainList/ReleaseNotes/1_1_10.md new file mode 100644 index 000000000000..a9365d69d51d --- /dev/null +++ b/Packs/FeedMalwareDomainList/ReleaseNotes/1_1_10.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Malware Domain List Active IPs Feed (Deprecated) + +Fixed an issue with reading the ETAG header from feed response. diff --git a/Packs/FeedMalwareDomainList/pack_metadata.json b/Packs/FeedMalwareDomainList/pack_metadata.json index 6869ae19d66b..608723122d9f 100644 --- a/Packs/FeedMalwareDomainList/pack_metadata.json +++ b/Packs/FeedMalwareDomainList/pack_metadata.json @@ -3,7 +3,7 @@ "description": "Deprecated. This feed is no longer supported. No available replacement.", "support": "xsoar", "hidden": true, - "currentVersion": "1.1.9", + "currentVersion": "1.1.10", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/FeedPlainText/ReleaseNotes/1_1_29.md b/Packs/FeedPlainText/ReleaseNotes/1_1_29.md new file mode 100644 index 000000000000..0583a26df14e --- /dev/null +++ b/Packs/FeedPlainText/ReleaseNotes/1_1_29.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Plain Text Feed + +Fixed an issue with reading the ETAG header from feed response. diff --git a/Packs/FeedPlainText/pack_metadata.json b/Packs/FeedPlainText/pack_metadata.json index 0a32d45cb88f..525d190b2f21 100644 --- a/Packs/FeedPlainText/pack_metadata.json +++ b/Packs/FeedPlainText/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Plain Text Feed", "description": "Fetches indicators from a plain text feed.", "support": "xsoar", - "currentVersion": "1.1.28", + "currentVersion": "1.1.29", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/FeedSpamhaus/ReleaseNotes/1_1_25.md b/Packs/FeedSpamhaus/ReleaseNotes/1_1_25.md new file mode 100644 index 000000000000..eebb3f61ed56 --- /dev/null +++ b/Packs/FeedSpamhaus/ReleaseNotes/1_1_25.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Spamhaus Feed + +Fixed an issue with reading the ETAG header from feed response. diff --git a/Packs/FeedSpamhaus/pack_metadata.json b/Packs/FeedSpamhaus/pack_metadata.json index b67aad5733a3..e705ecd91410 100644 --- a/Packs/FeedSpamhaus/pack_metadata.json +++ b/Packs/FeedSpamhaus/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Spamhaus Feed", "description": "The Spamhaus DROP (Don't Route Or Peer) lists are advisory \"drop all traffic\" lists, consisting of netblocks that are \"hijacked\" or leased by professional spam or cyber-crime operations (used for dissemination of malware, trojan downloaders, botnet controllers). The DROP lists are a tiny subset of the SBL, designed for use by firewalls and routing equipment to filter out the malicious traffic from these netblocks.", "support": "xsoar", - "currentVersion": "1.1.24", + "currentVersion": "1.1.25", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GCP-IAM/Integrations/GCPIAM/GCPIAM.yml b/Packs/GCP-IAM/Integrations/GCPIAM/GCPIAM.yml index da0ccbc7760b..df33bcad1789 100644 --- a/Packs/GCP-IAM/Integrations/GCPIAM/GCPIAM.yml +++ b/Packs/GCP-IAM/Integrations/GCPIAM/GCPIAM.yml @@ -1250,7 +1250,7 @@ script: description: Create a short-lived access token for a service account. The generated token will be exposed to the context menu and War Room, and can potentially be logged. execution: true name: gcp-iam-service-account-generate-access-token - dockerimage: demisto/google-api-py3:1.0.0.112317 + dockerimage: demisto/google-api-py3:1.0.0.114199 runonce: false script: '-' subtype: python3 diff --git a/Packs/GCP-IAM/ReleaseNotes/1_0_28.md b/Packs/GCP-IAM/ReleaseNotes/1_0_28.md new file mode 100644 index 000000000000..0e4bc8841159 --- /dev/null +++ b/Packs/GCP-IAM/ReleaseNotes/1_0_28.md @@ -0,0 +1,7 @@ + +#### Integrations + +##### GCP-IAM +- Updated the Docker image to: *demisto/google-api-py3:1.0.0.114199*. + + diff --git a/Packs/GCP-IAM/pack_metadata.json b/Packs/GCP-IAM/pack_metadata.json index e519a8a16a74..a2684801f0e8 100644 --- a/Packs/GCP-IAM/pack_metadata.json +++ b/Packs/GCP-IAM/pack_metadata.json @@ -2,7 +2,7 @@ "name": "GCP IAM", "description": "Manage identity and access control for Google Cloud Platform resources.", "support": "xsoar", - "currentVersion": "1.0.27", + "currentVersion": "1.0.28", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GSuiteAdmin/Integrations/GSuiteAdmin/GSuiteAdmin.yml b/Packs/GSuiteAdmin/Integrations/GSuiteAdmin/GSuiteAdmin.yml index 08aaad5f849c..95de2a0d37e3 100644 --- a/Packs/GSuiteAdmin/Integrations/GSuiteAdmin/GSuiteAdmin.yml +++ b/Packs/GSuiteAdmin/Integrations/GSuiteAdmin/GSuiteAdmin.yml @@ -2895,7 +2895,7 @@ script: name: policy_schema description: Delete multiple policy values that are applied to a specific group. All targets must have the same target format. That is to say that they must point to the same target resource and must have the same keys specified in additionalTargetKeyNames, though the values for those keys may be different. On failure the request will return the error details as part of the google.rpc.Status. name: gsuite-policy-groups-delete - dockerimage: demisto/googleapi-python3:1.0.0.112316 + dockerimage: demisto/googleapi-python3:1.0.0.113882 runonce: false script: '-' subtype: python3 diff --git a/Packs/GSuiteAdmin/ReleaseNotes/1_2_2.md b/Packs/GSuiteAdmin/ReleaseNotes/1_2_2.md new file mode 100644 index 000000000000..0d2bc4098fc6 --- /dev/null +++ b/Packs/GSuiteAdmin/ReleaseNotes/1_2_2.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Google Workspace Admin + +- Updated the Docker image to: *demisto/googleapi-python3:1.0.0.113882*. diff --git a/Packs/GSuiteAdmin/pack_metadata.json b/Packs/GSuiteAdmin/pack_metadata.json index 3b9867e801d5..4bb765c601b0 100644 --- a/Packs/GSuiteAdmin/pack_metadata.json +++ b/Packs/GSuiteAdmin/pack_metadata.json @@ -2,7 +2,7 @@ "name": "G Suite Admin", "description": "G Suite Admin integration with Cortex XSOAR. G Suite or Google Workspace Admin is an integration to perform an action on IT infrastructure, create users, update settings, and more administrative tasks.", "support": "xsoar", - "currentVersion": "1.2.1", + "currentVersion": "1.2.2", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GSuiteSecurityAlertCenter/Integrations/GSuiteSecurityAlertCenter/GSuiteSecurityAlertCenter.yml b/Packs/GSuiteSecurityAlertCenter/Integrations/GSuiteSecurityAlertCenter/GSuiteSecurityAlertCenter.yml index b33d63c7786c..951938a2c792 100644 --- a/Packs/GSuiteSecurityAlertCenter/Integrations/GSuiteSecurityAlertCenter/GSuiteSecurityAlertCenter.yml +++ b/Packs/GSuiteSecurityAlertCenter/Integrations/GSuiteSecurityAlertCenter/GSuiteSecurityAlertCenter.yml @@ -767,7 +767,7 @@ script: - contextPath: GSuiteSecurityAlert.Recover.failedAlerts.status description: Status of the failed alert recovery. type: String - dockerimage: demisto/googleapi-python3:1.0.0.112316 + dockerimage: demisto/googleapi-python3:1.0.0.113882 isfetch: true runonce: false script: '-' diff --git a/Packs/GSuiteSecurityAlertCenter/ReleaseNotes/1_1_45.md b/Packs/GSuiteSecurityAlertCenter/ReleaseNotes/1_1_45.md new file mode 100644 index 000000000000..3a046dd4047c --- /dev/null +++ b/Packs/GSuiteSecurityAlertCenter/ReleaseNotes/1_1_45.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### G Suite Security Alert Center + +- Updated the Docker image to: *demisto/googleapi-python3:1.0.0.113882*. diff --git a/Packs/GSuiteSecurityAlertCenter/pack_metadata.json b/Packs/GSuiteSecurityAlertCenter/pack_metadata.json index 7d9fb3859437..1d30ef96d1bf 100644 --- a/Packs/GSuiteSecurityAlertCenter/pack_metadata.json +++ b/Packs/GSuiteSecurityAlertCenter/pack_metadata.json @@ -2,7 +2,7 @@ "name": "G Suite Security Alert Center", "description": "Fetch alert types, delete or recover alerts, retrieve an alert's metadata, and create or view alert feedback.", "support": "xsoar", - "currentVersion": "1.1.44", + "currentVersion": "1.1.45", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/Gmail/Integrations/Gmail/Gmail.yml b/Packs/Gmail/Integrations/Gmail/Gmail.yml index 5332ad0de831..7f3234b8d8bb 100644 --- a/Packs/Gmail/Integrations/Gmail/Gmail.yml +++ b/Packs/Gmail/Integrations/Gmail/Gmail.yml @@ -1735,7 +1735,7 @@ script: - contextPath: Gmail.ForwardingAddress.verificationStatus description: Indicates whether this address has been verified and is usable for forwarding. type: String - dockerimage: demisto/google-api-py3:1.0.0.112317 + dockerimage: demisto/google-api-py3:1.0.0.114199 isfetch: true runonce: false script: '-' diff --git a/Packs/Gmail/ReleaseNotes/1_3_26.md b/Packs/Gmail/ReleaseNotes/1_3_26.md new file mode 100644 index 000000000000..a4a3ca379cca --- /dev/null +++ b/Packs/Gmail/ReleaseNotes/1_3_26.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Gmail + +- Updated the Docker image to: *demisto/google-api-py3:1.0.0.114199*. diff --git a/Packs/Gmail/pack_metadata.json b/Packs/Gmail/pack_metadata.json index 72d47b6366f7..835064004422 100644 --- a/Packs/Gmail/pack_metadata.json +++ b/Packs/Gmail/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Gmail", "description": "Gmail API and user management (This integration replaces the Gmail functionality in the GoogleApps API and G Suite integration).", "support": "xsoar", - "currentVersion": "1.3.25", + "currentVersion": "1.3.26", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GmailSingleUser/Integrations/GmailSingleUser/GmailSingleUser.yml b/Packs/GmailSingleUser/Integrations/GmailSingleUser/GmailSingleUser.yml index fbddb59231d4..76ee41551355 100644 --- a/Packs/GmailSingleUser/Integrations/GmailSingleUser/GmailSingleUser.yml +++ b/Packs/GmailSingleUser/Integrations/GmailSingleUser/GmailSingleUser.yml @@ -354,7 +354,7 @@ script: required: true description: Retrieves attachments from a sent Gmail message. name: gmail-get-attachments - dockerimage: demisto/google-api-py3:1.0.0.112317 + dockerimage: demisto/google-api-py3:1.0.0.114199 isfetch: true runonce: false script: '-' diff --git a/Packs/GmailSingleUser/ReleaseNotes/1_4_6.md b/Packs/GmailSingleUser/ReleaseNotes/1_4_6.md new file mode 100644 index 000000000000..ddc63e7edf50 --- /dev/null +++ b/Packs/GmailSingleUser/ReleaseNotes/1_4_6.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Gmail Single User + +- Updated the Docker image to: *demisto/google-api-py3:1.0.0.114199*. diff --git a/Packs/GmailSingleUser/pack_metadata.json b/Packs/GmailSingleUser/pack_metadata.json index 827a0efb5242..0d45b522653b 100644 --- a/Packs/GmailSingleUser/pack_metadata.json +++ b/Packs/GmailSingleUser/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Gmail Single User", "description": "Gmail API using OAuth 2.0.", "support": "xsoar", - "currentVersion": "1.4.5", + "currentVersion": "1.4.6", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GoogleCalendar/Integrations/GoogleCalendar/GoogleCalendar.yml b/Packs/GoogleCalendar/Integrations/GoogleCalendar/GoogleCalendar.yml index c1d73476c112..554447a51b35 100644 --- a/Packs/GoogleCalendar/Integrations/GoogleCalendar/GoogleCalendar.yml +++ b/Packs/GoogleCalendar/Integrations/GoogleCalendar/GoogleCalendar.yml @@ -173,7 +173,7 @@ script: - contextPath: GoogleCalendar.PageToken.Acl.nextSyncToken description: Token used at a later point in time to retrieve only the entries that have changed since this result was returned. type: String - dockerimage: demisto/googleapi-python3:1.0.0.112316 + dockerimage: demisto/googleapi-python3:1.0.0.113882 runonce: false script: '-' subtype: python3 diff --git a/Packs/GoogleCalendar/ReleaseNotes/1_1_47.md b/Packs/GoogleCalendar/ReleaseNotes/1_1_47.md new file mode 100644 index 000000000000..a39db00e7635 --- /dev/null +++ b/Packs/GoogleCalendar/ReleaseNotes/1_1_47.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Google Calendar + +- Updated the Docker image to: *demisto/googleapi-python3:1.0.0.113882*. diff --git a/Packs/GoogleCalendar/pack_metadata.json b/Packs/GoogleCalendar/pack_metadata.json index 8a220b4b1ab1..2314958aca11 100644 --- a/Packs/GoogleCalendar/pack_metadata.json +++ b/Packs/GoogleCalendar/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Google Calendar", "description": "Google Calendar integration with Cortex XSOAR.", "support": "xsoar", - "currentVersion": "1.1.46", + "currentVersion": "1.1.47", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GoogleCloudCompute/Integrations/GoogleCloudCompute/GoogleCloudCompute.yml b/Packs/GoogleCloudCompute/Integrations/GoogleCloudCompute/GoogleCloudCompute.yml index c6fa1a61ec1b..3c0c06e73212 100644 --- a/Packs/GoogleCloudCompute/Integrations/GoogleCloudCompute/GoogleCloudCompute.yml +++ b/Packs/GoogleCloudCompute/Integrations/GoogleCloudCompute/GoogleCloudCompute.yml @@ -8418,7 +8418,7 @@ script: - contextPath: GoogleCloudCompute.Instances.kind description: '] Type of the resource. Always compute#instance for instances.' type: string - dockerimage: demisto/googleapi-python3:1.0.0.112316 + dockerimage: demisto/googleapi-python3:1.0.0.113882 script: '' subtype: python3 type: python diff --git a/Packs/GoogleCloudCompute/ReleaseNotes/1_1_12.md b/Packs/GoogleCloudCompute/ReleaseNotes/1_1_12.md new file mode 100644 index 000000000000..51d74c5880f2 --- /dev/null +++ b/Packs/GoogleCloudCompute/ReleaseNotes/1_1_12.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Google Cloud Compute + +- Updated the Docker image to: *demisto/googleapi-python3:1.0.0.113882*. diff --git a/Packs/GoogleCloudCompute/pack_metadata.json b/Packs/GoogleCloudCompute/pack_metadata.json index 95a5e05383a2..c3298154b1fd 100644 --- a/Packs/GoogleCloudCompute/pack_metadata.json +++ b/Packs/GoogleCloudCompute/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Google Cloud Compute", "description": "Google Compute Engine delivers virtual machines running in Google's innovative data centers and worldwide fiber network. Compute Engine's tooling and workflow support enable scaling from single instances to global, load-balanced cloud computing.", "support": "xsoar", - "currentVersion": "1.1.11", + "currentVersion": "1.1.12", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GoogleCloudFunctions/Integrations/GoogleCloudFunctions/GoogleCloudFunctions.yml b/Packs/GoogleCloudFunctions/Integrations/GoogleCloudFunctions/GoogleCloudFunctions.yml index dfc68e0d6859..f01e95f847a5 100644 --- a/Packs/GoogleCloudFunctions/Integrations/GoogleCloudFunctions/GoogleCloudFunctions.yml +++ b/Packs/GoogleCloudFunctions/Integrations/GoogleCloudFunctions/GoogleCloudFunctions.yml @@ -114,7 +114,7 @@ script: - contextPath: GoogleCloudFunctions.Execution.error description: Either a system or user-function generated error. Set if the execution was not successful. type: String - dockerimage: demisto/google-api-py3:1.0.0.112317 + dockerimage: demisto/google-api-py3:1.0.0.114199 runonce: false script: '-' type: python diff --git a/Packs/GoogleCloudFunctions/ReleaseNotes/1_0_29.md b/Packs/GoogleCloudFunctions/ReleaseNotes/1_0_29.md new file mode 100644 index 000000000000..a07bd273d748 --- /dev/null +++ b/Packs/GoogleCloudFunctions/ReleaseNotes/1_0_29.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Google Cloud Functions + +- Updated the Docker image to: *demisto/google-api-py3:1.0.0.114199*. diff --git a/Packs/GoogleCloudFunctions/pack_metadata.json b/Packs/GoogleCloudFunctions/pack_metadata.json index 278d83683da6..1d6e36b6130c 100644 --- a/Packs/GoogleCloudFunctions/pack_metadata.json +++ b/Packs/GoogleCloudFunctions/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Google Cloud Functions", "description": "Google Cloud Functions", "support": "xsoar", - "currentVersion": "1.0.28", + "currentVersion": "1.0.29", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GoogleCloudLogging/Integrations/GoogleCloudLogging/GoogleCloudLogging.yml b/Packs/GoogleCloudLogging/Integrations/GoogleCloudLogging/GoogleCloudLogging.yml index b003e59108e1..082dc74b5b58 100644 --- a/Packs/GoogleCloudLogging/Integrations/GoogleCloudLogging/GoogleCloudLogging.yml +++ b/Packs/GoogleCloudLogging/Integrations/GoogleCloudLogging/GoogleCloudLogging.yml @@ -187,7 +187,7 @@ script: script: '-' type: python subtype: python3 - dockerimage: demisto/google-api-py3:1.0.0.112317 + dockerimage: demisto/google-api-py3:1.0.0.114199 fromversion: 6.8.0 tests: - No tests (auto formatted) diff --git a/Packs/GoogleCloudLogging/ReleaseNotes/1_0_15.md b/Packs/GoogleCloudLogging/ReleaseNotes/1_0_15.md new file mode 100644 index 000000000000..9435084daf07 --- /dev/null +++ b/Packs/GoogleCloudLogging/ReleaseNotes/1_0_15.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Google Cloud Logging + +- Updated the Docker image to: *demisto/google-api-py3:1.0.0.114199*. diff --git a/Packs/GoogleCloudLogging/pack_metadata.json b/Packs/GoogleCloudLogging/pack_metadata.json index fa8d08e23755..f119dcc183d7 100644 --- a/Packs/GoogleCloudLogging/pack_metadata.json +++ b/Packs/GoogleCloudLogging/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Google Cloud Logging", "description": "Google Cloud Logging is a managed logging solution provided by Google Cloud Platform (GCP) that allows users to collect, store, search, analyze, and monitor logs generated by GCP services, third-party applications, and custom applications running on GCP.", "support": "xsoar", - "currentVersion": "1.0.14", + "currentVersion": "1.0.15", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GoogleDocs/Integrations/GoogleDocs/GoogleDocs.yml b/Packs/GoogleDocs/Integrations/GoogleDocs/GoogleDocs.yml index b44ccb802437..7c59ee6310fd 100644 --- a/Packs/GoogleDocs/Integrations/GoogleDocs/GoogleDocs.yml +++ b/Packs/GoogleDocs/Integrations/GoogleDocs/GoogleDocs.yml @@ -81,7 +81,7 @@ script: - contextPath: GoogleDocs.DocumentId description: The document ID of the updated document. type: Unknown - dockerimage: demisto/googleapi-python3:1.0.0.112316 + dockerimage: demisto/googleapi-python3:1.0.0.113882 runonce: false script: '-' type: python diff --git a/Packs/GoogleDocs/ReleaseNotes/1_0_26.md b/Packs/GoogleDocs/ReleaseNotes/1_0_26.md new file mode 100644 index 000000000000..95e87b1ccfa2 --- /dev/null +++ b/Packs/GoogleDocs/ReleaseNotes/1_0_26.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Google Docs + +- Updated the Docker image to: *demisto/googleapi-python3:1.0.0.113882*. diff --git a/Packs/GoogleDocs/pack_metadata.json b/Packs/GoogleDocs/pack_metadata.json index 9d0532bad2d3..3537b1f52914 100644 --- a/Packs/GoogleDocs/pack_metadata.json +++ b/Packs/GoogleDocs/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Google Docs", "description": "Use the Google Docs integration to create and modify Google Docs documents.", "support": "xsoar", - "currentVersion": "1.0.25", + "currentVersion": "1.0.26", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GoogleDrive/Integrations/GoogleDrive/GoogleDrive.yml b/Packs/GoogleDrive/Integrations/GoogleDrive/GoogleDrive.yml index 473988e7af4a..d412697d9f26 100644 --- a/Packs/GoogleDrive/Integrations/GoogleDrive/GoogleDrive.yml +++ b/Packs/GoogleDrive/Integrations/GoogleDrive/GoogleDrive.yml @@ -3112,7 +3112,7 @@ script: - contextPath: GoogleDrive.File.Parents description: The IDs of the parent folders which contain the file. type: String - dockerimage: demisto/googleapi-python3:1.0.0.112316 + dockerimage: demisto/googleapi-python3:1.0.0.113882 isfetch: true runonce: false script: "-" diff --git a/Packs/GoogleDrive/ReleaseNotes/1_3_9.md b/Packs/GoogleDrive/ReleaseNotes/1_3_9.md new file mode 100644 index 000000000000..9508d3f85d09 --- /dev/null +++ b/Packs/GoogleDrive/ReleaseNotes/1_3_9.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Google Drive + +- Updated the Docker image to: *demisto/googleapi-python3:1.0.0.113882*. diff --git a/Packs/GoogleDrive/pack_metadata.json b/Packs/GoogleDrive/pack_metadata.json index e179bdf2ad10..340039e0ab23 100644 --- a/Packs/GoogleDrive/pack_metadata.json +++ b/Packs/GoogleDrive/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Google Drive", "description": "Google Drive allows users to store files on their servers, synchronize files across devices, and share files. This integration helps you to create a new drive, query past activity and view change logs performed by the users, as well as list drives and files, and manage their permissions.", "support": "xsoar", - "currentVersion": "1.3.8", + "currentVersion": "1.3.9", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GooglePubSub/Integrations/GooglePubSub/GooglePubSub.yml b/Packs/GooglePubSub/Integrations/GooglePubSub/GooglePubSub.yml index 516cf7b2db3d..ee395abad3c4 100644 --- a/Packs/GooglePubSub/Integrations/GooglePubSub/GooglePubSub.yml +++ b/Packs/GooglePubSub/Integrations/GooglePubSub/GooglePubSub.yml @@ -530,7 +530,7 @@ script: required: true description: Acknowledge previously pulled message or messages. name: gcp-pubsub-topic-ack-messages - dockerimage: demisto/googleapi-python3:1.0.0.112316 + dockerimage: demisto/googleapi-python3:1.0.0.113882 isfetch: true runonce: false script: '-' diff --git a/Packs/GooglePubSub/ReleaseNotes/1_1_2.md b/Packs/GooglePubSub/ReleaseNotes/1_1_2.md new file mode 100644 index 000000000000..0a5bf13cde54 --- /dev/null +++ b/Packs/GooglePubSub/ReleaseNotes/1_1_2.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Google Cloud Pub/Sub + +- Updated the Docker image to: *demisto/googleapi-python3:1.0.0.113882*. diff --git a/Packs/GooglePubSub/pack_metadata.json b/Packs/GooglePubSub/pack_metadata.json index f6e7d14b5c19..5493a38ae102 100644 --- a/Packs/GooglePubSub/pack_metadata.json +++ b/Packs/GooglePubSub/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Google Cloud Pub / Sub", "description": "Google Cloud Pub / Sub is a fully-managed real-time messaging service that allows you to send and receive messages between independent applications.", "support": "xsoar", - "currentVersion": "1.1.1", + "currentVersion": "1.1.2", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GoogleResourceManager/Integrations/GoogleResourceManager/GoogleResourceManager.yml b/Packs/GoogleResourceManager/Integrations/GoogleResourceManager/GoogleResourceManager.yml index cb906d19be18..528b72aa8608 100644 --- a/Packs/GoogleResourceManager/Integrations/GoogleResourceManager/GoogleResourceManager.yml +++ b/Packs/GoogleResourceManager/Integrations/GoogleResourceManager/GoogleResourceManager.yml @@ -397,7 +397,7 @@ script: - contextPath: GRM.Project.Parent.Type description: Type of the parent resource. type: String - dockerimage: demisto/googleapi-python3:1.0.0.112316 + dockerimage: demisto/googleapi-python3:1.0.0.113882 runonce: false script: '' type: python diff --git a/Packs/GoogleResourceManager/ReleaseNotes/1_0_7.md b/Packs/GoogleResourceManager/ReleaseNotes/1_0_7.md new file mode 100644 index 000000000000..8856a8e6fd42 --- /dev/null +++ b/Packs/GoogleResourceManager/ReleaseNotes/1_0_7.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Google Resource Manager + +- Updated the Docker image to: *demisto/googleapi-python3:1.0.0.113882*. diff --git a/Packs/GoogleResourceManager/pack_metadata.json b/Packs/GoogleResourceManager/pack_metadata.json index 3f5eb82bf03d..758b4519e988 100644 --- a/Packs/GoogleResourceManager/pack_metadata.json +++ b/Packs/GoogleResourceManager/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Google Resource Manager", "description": "Google Cloud Platform Resource Manager", "support": "xsoar", - "currentVersion": "1.0.6", + "currentVersion": "1.0.7", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GoogleSheets/Integrations/GoogleSheets/GoogleSheets.yml b/Packs/GoogleSheets/Integrations/GoogleSheets/GoogleSheets.yml index 040b72d1c30e..7dce3caa3252 100644 --- a/Packs/GoogleSheets/Integrations/GoogleSheets/GoogleSheets.yml +++ b/Packs/GoogleSheets/Integrations/GoogleSheets/GoogleSheets.yml @@ -665,7 +665,7 @@ script: - contextPath: GoogleSheets.Spreadsheet.updatedSpreadsheet.sheets.title description: Sheet title. type: String - dockerimage: demisto/googleapi-python3:1.0.0.112316 + dockerimage: demisto/googleapi-python3:1.0.0.113882 runonce: false script: "-" subtype: python3 diff --git a/Packs/GoogleSheets/ReleaseNotes/1_0_45.md b/Packs/GoogleSheets/ReleaseNotes/1_0_45.md new file mode 100644 index 000000000000..1a94b2c5a6c3 --- /dev/null +++ b/Packs/GoogleSheets/ReleaseNotes/1_0_45.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Google Sheets + +- Updated the Docker image to: *demisto/googleapi-python3:1.0.0.113882*. diff --git a/Packs/GoogleSheets/pack_metadata.json b/Packs/GoogleSheets/pack_metadata.json index 33f89bd9e85b..7a4fa4a9f152 100644 --- a/Packs/GoogleSheets/pack_metadata.json +++ b/Packs/GoogleSheets/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Google Sheets", "description": "The Google Sheets API is a RESTful interface that lets you read and modify a spreadsheet's data. The most common uses of this API include the following tasks- create spreadsheets, read and write spreadsheets cells, update spreadsheet formatting", "support": "xsoar", - "currentVersion": "1.0.44", + "currentVersion": "1.0.45", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GoogleVault/Integrations/GoogleVault/GoogleVault.yml b/Packs/GoogleVault/Integrations/GoogleVault/GoogleVault.yml index 84950e6f07a5..c2ca69006448 100644 --- a/Packs/GoogleVault/Integrations/GoogleVault/GoogleVault.yml +++ b/Packs/GoogleVault/Integrations/GoogleVault/GoogleVault.yml @@ -540,7 +540,7 @@ script: - contextPath: GoogleVault.Matter.Export.Results.To description: The address the message was sent to type: string - dockerimage: demisto/googleapi-python3:1.0.0.112316 + dockerimage: demisto/googleapi-python3:1.0.0.113882 runonce: false script: '-' subtype: python3 diff --git a/Packs/GoogleVault/ReleaseNotes/1_0_14.md b/Packs/GoogleVault/ReleaseNotes/1_0_14.md new file mode 100644 index 000000000000..417432d491c4 --- /dev/null +++ b/Packs/GoogleVault/ReleaseNotes/1_0_14.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Google Vault + +- Updated the Docker image to: *demisto/googleapi-python3:1.0.0.113882*. diff --git a/Packs/GoogleVault/pack_metadata.json b/Packs/GoogleVault/pack_metadata.json index 5f2bd593bfc8..e19fc84949a9 100644 --- a/Packs/GoogleVault/pack_metadata.json +++ b/Packs/GoogleVault/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Google Vault", "description": "Archiving and eDiscovery for G Suite.", "support": "xsoar", - "currentVersion": "1.0.13", + "currentVersion": "1.0.14", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/GsuiteAuditor/Integrations/GsuiteAuditor/GsuiteAuditor.yml b/Packs/GsuiteAuditor/Integrations/GsuiteAuditor/GsuiteAuditor.yml index ab0f72b786e4..4ad1bf5833d4 100644 --- a/Packs/GsuiteAuditor/Integrations/GsuiteAuditor/GsuiteAuditor.yml +++ b/Packs/GsuiteAuditor/Integrations/GsuiteAuditor/GsuiteAuditor.yml @@ -125,7 +125,7 @@ script: - contextPath: GSuite.PageToken.ActivitySearch.nextPageToken description: Token to specify the next page in the list. type: String - dockerimage: demisto/googleapi-python3:1.0.0.112316 + dockerimage: demisto/googleapi-python3:1.0.0.113882 runonce: false script: '-' subtype: python3 diff --git a/Packs/GsuiteAuditor/ReleaseNotes/1_0_24.md b/Packs/GsuiteAuditor/ReleaseNotes/1_0_24.md new file mode 100644 index 000000000000..7af0e928fbd3 --- /dev/null +++ b/Packs/GsuiteAuditor/ReleaseNotes/1_0_24.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### G Suite Auditor + +- Updated the Docker image to: *demisto/googleapi-python3:1.0.0.113882*. diff --git a/Packs/GsuiteAuditor/pack_metadata.json b/Packs/GsuiteAuditor/pack_metadata.json index 12555f0297ae..2bd415b585ff 100644 --- a/Packs/GsuiteAuditor/pack_metadata.json +++ b/Packs/GsuiteAuditor/pack_metadata.json @@ -2,7 +2,7 @@ "name": "GsuiteAuditor", "description": "G Suite Auditor integration with Cortex XSOAR. G Suite Auditor is an integration to recieve audit log data from G Suite services like drive,gmail and more. The integration uses Google Admin SDK", "support": "xsoar", - "currentVersion": "1.0.23", + "currentVersion": "1.0.24", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/HashiCorpVault.py b/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/HashiCorpVault.py index 8dfddc50cb3a..757081810882 100644 --- a/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/HashiCorpVault.py +++ b/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/HashiCorpVault.py @@ -31,6 +31,7 @@ def get_headers(): headers = { 'Content-Type': 'application/json', + 'X-Vault-Request': 'true' } if TOKEN: # pragma: no cover @@ -44,10 +45,10 @@ def get_headers(): def login(): # pragma: no cover if USE_APPROLE_AUTH_METHOD: - path = 'auth/approle/login' + path = 'auth/approle/login' # type: ignore body = { 'role_id': USERNAME, - 'secret_id': PASSWORD, + 'secret_id': PASSWORD } else: path = 'auth/userpass/login/' + USERNAME # type: ignore @@ -56,16 +57,18 @@ def login(): # pragma: no cover } url = urljoin(SERVER_URL, path) - res = requests.request('POST', url, headers=get_headers(), data=json.dumps(body), verify=VERIFY_SSL) + payload = json.dumps(body) + headers = get_headers() + res = requests.request("POST", url, headers=headers, data=payload, verify=VERIFY_SSL, allow_redirects=True) if (res.status_code < 200 or res.status_code >= 300) and res.status_code not in DEFAULT_STATUS_CODES: try: error_body = res.json() if 'errors' in error_body and isinstance(error_body['errors'], list): error_body = ';'.join(error_body['errors']) if len(error_body['errors']) > 0 else 'None' except Exception as ex: - demisto.error("Error in login (parsing error msg): {}".format(ex)) + demisto.error(f"Error in login (parsing error msg): {ex}") error_body = res.content - return_error('Login failed. Status code: {}, details: {}'.format(str(res.status_code), error_body)) + return_error(f'Login failed. Status code: {str(res.status_code)}, details: {error_body}') auth_res = res.json() if not auth_res or 'auth' not in auth_res or 'client_token' not in auth_res['auth']: @@ -88,9 +91,9 @@ def send_request(path, method='get', body=None, params=None, headers=None): if 'errors' in error_body and isinstance(error_body['errors'], list): error_body = ';'.join(error_body['errors']) if len(error_body['errors']) > 0 else 'None' except Exception as ex: - demisto.error("Error in send_request (parsing error msg): {}".format(ex)) + demisto.error(f"Error in send_request (parsing error msg): {ex}") error_body = res.content - return_error('Request failed. Status code: {}, details: {}'.format(str(res.status_code), error_body)) + return_error(f'Request failed. Status code: {str(res.status_code)}, details: {error_body}') if res.content: return res.json() return '' @@ -99,6 +102,64 @@ def send_request(path, method='get', body=None, params=None, headers=None): ''' FUNCTIONS ''' +def generate_role_secret_command(): + """ + Generate a secret ID for a specified AppRole in the authentication system. + Args: + args (dict): A dictionary containing the following keys: + - 'role_name' (required): The name of the AppRole for which the secret ID is generated. + - 'meta_data': Metadata associated with the secret ID. + - 'cidr_list': Comma-separated list of CIDR blocks from which requests using the secret ID are allowed. + - 'token_bound_cidrs': Comma-separated list of CIDR blocks to restrict tokens issued with this secret ID. + - 'num_uses': Number of times the secret ID can be used before it expires. + - 'ttl_seconds': Time duration in seconds for which the secret ID remains valid. + Returns: + CommandResults: The command results object containing the response from the Vault server as readable output. + """ + args = demisto.args() + role_name = args.get('role_name') + meta_data = args.get('meta_data') + cidr_list = argToList(args.get('cidr_list', '')) + token_bound_cidrs = argToList(args.get('token_bound_cidrs', '')) + num_uses = arg_to_number(args.get('num_uses', '')) + ttl_seconds = arg_to_number(args.get('ttl_seconds', '')) + + path = f'/auth/approle/role/{role_name}/secret-id' + body = { + "metadata": meta_data, + "cidr_list": cidr_list, + "token_bound_cidrs": token_bound_cidrs, + "ttl": ttl_seconds, + "num_uses": num_uses + } + body = remove_empty_elements(body) + + response = send_request(path=path, method='post', body=body) + return_results(CommandResults(readable_output=response)) + + +def get_role_id_command(): + """ + Retrieve the Role ID associated with a specified AppRole from the authentication system. + Args: + args (dict): A dictionary containing the following keys: + - 'role_name' (required): The name of the AppRole for which the Role ID is retrieved. + Returns: + CommandResults: The command results object containing the retrieved Role ID and role name as outputs. + """ + args = demisto.args() + role_name = args.get('role_name') + path = f'/auth/approle/role/{role_name}/role-id' + response = send_request(path=path, method='get', body={'role_name': role_name}) + if response: + role_id = response.get('data', {}).get('role_id', '') + + if not role_id: + raise DemistoException(f"Role ID not found for AppRole '{role_name}'. Please check the role name and try again.") + + return_results(CommandResults(outputs_prefix='HashiCorp.AppRole', outputs={"Id": role_id, "Name": role_name})) + + def list_secrets_engines_command(): # pragma: no cover res = list_secrets_engines() @@ -645,7 +706,7 @@ def get_kv1_secrets(engine_path, concat_username_to_cred_name=False): # pragma: secret_data = get_kv1_secret(engine_path, secret) for k, v in secret_data.get('data', {}).items(): if concat_username_to_cred_name: - name = '{0}_{1}'.format(secret, k) + name = f'{secret}_{k}' else: name = secret secrets.append({ @@ -670,15 +731,15 @@ def get_kv2_secrets(engine_path, concat_username_to_cred_name=False, folder=None return [] for secret in res['data'].get('keys', []): - if str(secret).endswith('/') and not secret.replace('/', '') == folder: - demisto.debug('Could not get secrets from path: {}'.format(secret)) + if str(secret).endswith('/') and secret.replace('/', '') != folder: + demisto.debug(f'Could not get secrets from path: {secret}') continue secret_data = get_kv2_secret(engine_path, secret, folder) secret_info = secret_data.get('data', {}).get('data', {}) for k in secret_data.get('data', {}).get('data', {}): if concat_username_to_cred_name: - name = '{0}_{1}'.format(secret, k) + name = f'{secret}_{k}' else: name = secret secrets.append({ @@ -717,7 +778,7 @@ def get_ch_secrets(engine_path, concat_username_to_cred_name=False): # pragma: secret_data = get_ch_secret(engine_path, secret) for k, v in secret_data.get('data', {}).items(): if concat_username_to_cred_name: - name = '{0}_{1}'.format(secret, k) + name = f'{secret}_{k}' else: name = secret secrets.append({ @@ -732,7 +793,7 @@ def get_ch_secrets(engine_path, concat_username_to_cred_name=False): # pragma: def get_aws_secrets(engine_path, concat_username_to_cred_name, aws_roles_list, aws_method): secrets = [] roles_list_url = engine_path + '/roles' - demisto.debug('roles_list_url: {}'.format(roles_list_url)) + demisto.debug(f'roles_list_url: {roles_list_url}') params = {'list': 'true'} res = send_request(roles_list_url, 'get', params=params) if not res or 'data' not in res: @@ -741,7 +802,7 @@ def get_aws_secrets(engine_path, concat_username_to_cred_name, aws_roles_list, a if aws_roles_list and role not in aws_roles_list: continue role_url = urljoin(engine_path, urljoin('/roles/', role)) - demisto.debug('role_url: {}'.format(role_url)) + demisto.debug(f'role_url: {role_url}') role_data = send_request(role_url, 'get') if not role_data or 'data' not in role_data: return [] @@ -758,7 +819,7 @@ def get_aws_secrets(engine_path, concat_username_to_cred_name, aws_roles_list, a method = 'GET' credential_type = 'creds' generate_credentials_url = urljoin(engine_path + '/', urljoin(credential_type, '/' + role)) - demisto.debug('generate_credentials_url: {}'.format(generate_credentials_url)) + demisto.debug(f'generate_credentials_url: {generate_credentials_url}') body = {} if 'role_arns' in role_data['data']: body['role_arns'] = role_data['data'].get('role_arns', []) @@ -770,7 +831,7 @@ def get_aws_secrets(engine_path, concat_username_to_cred_name, aws_roles_list, a if aws_credentials['data'].get('security_token'): secret_key = secret_key + '@@@' + aws_credentials["data"].get("security_token") if concat_username_to_cred_name: - role = '{0}_{1}'.format(role, access_key) + role = f'{role}_{access_key}' secrets.append({ 'user': access_key, 'password': secret_key, @@ -808,40 +869,46 @@ def get_ch_secret(engine_path, secret): ENGINE_CONFIGS = integration_context['configs'] try: - if demisto.command() == 'test-module': + command = demisto.command() + if command == 'test-module': demisto.results('ok') - elif demisto.command() == 'fetch-credentials': + elif command == 'fetch-credentials': fetch_credentials() - elif demisto.command() == 'hashicorp-list-secrets-engines': + elif command == 'hashicorp-list-secrets-engines': list_secrets_engines_command() - elif demisto.command() == 'hashicorp-list-secrets': + elif command == 'hashicorp-list-secrets': list_secrets_command() - elif demisto.command() == 'hashicorp-list-policies': + elif command == 'hashicorp-list-policies': list_policies_command() - elif demisto.command() == 'hashicorp-get-policy': + elif command == 'hashicorp-get-policy': get_policy_command() - elif demisto.command() == 'hashicorp-get-secret-metadata': + elif command == 'hashicorp-get-secret-metadata': get_secret_metadata_command() - elif demisto.command() == 'hashicorp-delete-secret': + elif command == 'hashicorp-delete-secret': delete_secret_command() - elif demisto.command() == 'hashicorp-undelete-secret': + elif command == 'hashicorp-undelete-secret': undelete_secret_command() - elif demisto.command() == 'hashicorp-destroy-secret': + elif command == 'hashicorp-destroy-secret': destroy_secret_command() - elif demisto.command() == 'hashicorp-disable-engine': + elif command == 'hashicorp-disable-engine': disable_engine_command() - elif demisto.command() == 'hashicorp-enable-engine': + elif command == 'hashicorp-enable-engine': enable_engine_command() - elif demisto.command() == 'hashicorp-seal-vault': + elif command == 'hashicorp-seal-vault': seal_vault_command() - elif demisto.command() == 'hashicorp-unseal-vault': + elif command == 'hashicorp-unseal-vault': unseal_vault_command() - elif demisto.command() == 'hashicorp-create-token': + elif command == 'hashicorp-create-token': create_token_command() - elif demisto.command() == 'hashicorp-configure-engine': + elif command == 'hashicorp-configure-engine': configure_engine_command() - elif demisto.command() == 'hashicorp-reset-configuration': + elif command == 'hashicorp-reset-configuration': reset_config_command() + elif command == 'hashicorp-generate-role-secret': + generate_role_secret_command() + elif command == 'hashicorp-get-role-id': + get_role_id_command() + except Exception as e: demisto.debug(f'An error occurred: {e}') return_error(f'An error occurred: {e}') diff --git a/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/HashiCorpVault.yml b/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/HashiCorpVault.yml index acc5d6d6e789..68a1ec18b8d6 100644 --- a/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/HashiCorpVault.yml +++ b/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/HashiCorpVault.yml @@ -338,7 +338,40 @@ script: description: Authentication lease duration in seconds, 0 if indefinitely. type: number description: Creates a new authentication token. - dockerimage: demisto/vendors-sdk:1.0.0.87491 + - name: hashicorp-generate-role-secret + arguments: + - name: role_name + required: true + description: The name of the AppRole. + - name: meta_data + description: Metadata to be tied to the SecretID. + - name: cidr_list + description: Comma separated string or list of CIDR blocks enforcing secret IDs to be used from specific set of IP addresses. + isArray: true + - name: token_bound_cidrs + description: Comma-separated string or list of CIDR blocks. + isArray: true + - name: num_uses + description: Number of times this SecretID can be used, after which the SecretID expires. A value of zero will allow unlimited uses. + type: number + - name: ttl_seconds + description: Duration in seconds after which this SecretID expires. A value of zero will allow the SecretID to not expire. + type: number + description: Generates and issues a new SecretID on an existing AppRole. + - name: hashicorp-get-role-id + arguments: + - name: role_name + required: true + description: The name of the AppRole. + outputs: + - contextPath: HashiCorp.AppRole.Id + description: AppRole ID. + type: string + - contextPath: HashiCorp.AppRole.Name + description: AppRole Name. + type: string + description: Retrieves the AppRole ID for a specified role. + dockerimage: demisto/vendors-sdk:1.0.0.114678 tests: - hashicorp_test fromversion: 5.0.0 diff --git a/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/HashiCorpVault_test.py b/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/HashiCorpVault_test.py index e290e942b37d..d29e5b897180 100644 --- a/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/HashiCorpVault_test.py +++ b/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/HashiCorpVault_test.py @@ -42,7 +42,7 @@ def test_get_aws_secrets(mocker): def test_get_headers(): - assert get_headers() == {'Content-Type': 'application/json'} + assert get_headers() == {'Content-Type': 'application/json', 'X-Vault-Request': 'true'} def test_list_secrets_engines(mocker): @@ -113,3 +113,86 @@ def test_seal_vault(mocker): def test_disable_engine(mocker): mocker.patch('HashiCorpVault.send_request', return_value={}) assert disable_engine('test') == {} + + +def test_generate_role_secret_command(mocker): + """ + Given: + A set of command arguments including role_name, meta_data, cidr_list, token_bound_cidrs, num_uses, and ttl_seconds. + + When: + Executing the generate_role_secret_command function to generate a secret ID for a given role. + + Then: + Verify that the send_request function is called with the correct path and body, and that the return_results function + is called with the expected result containing the secret_id. + """ + mock_demisto = mocker.patch('HashiCorpVault.demisto.args') + mock_return_results = mocker.patch('HashiCorpVault.return_results') + response = {'secret_id': '123'} + mock_send_request = mocker.patch('HashiCorpVault.send_request', return_value=response) + mock_demisto.return_value = { + 'role_name': 'test_role', + 'meta_data': 'test_metadata', + 'cidr_list': '', + 'token_bound_cidrs': '', + 'num_uses': '5', + 'ttl_seconds': '3600' + } + mock_send_request.return_value = {'secret_id': '123'} + + generate_role_secret_command() + + mock_send_request.assert_called_once_with( + path='/auth/approle/role/test_role/secret-id', + method='post', + body={ + "metadata": 'test_metadata', + "ttl": 3600, + "num_uses": 5 + } + ) + mock_return_results.assert_called_once() + result_call_args = mock_return_results.call_args[0][0] + assert 'secret_id' in result_call_args.readable_output + assert result_call_args.readable_output['secret_id'] == '123' + + +def test_get_role_id_command(mocker): + """ + Given: + A set of command arguments including role_name. + + When: + Executing the get_role_id_command function to retrieve the role ID for a given role. + + Then: + Verify that the send_request function is called with the correct path, method, and body, and that the return_results + function is called with the expected result containing the role_id. + """ + mock_demisto_args = mocker.patch('HashiCorpVault.demisto.args') + mock_return_results = mocker.patch('HashiCorpVault.return_results') + mock_send_request = mocker.patch('HashiCorpVault.send_request') + mock_demisto_args.return_value = { + 'role_name': 'test_role' + } + mock_send_request.return_value = { + 'data': { + 'role_id': '12345' + } + } + + expected_path = '/auth/approle/role/test_role/role-id' + expected_method = 'get' + expected_body = { + 'role_name': 'test_role' + } + expected_outputs = {'Id': '12345', 'Name': 'test_role'} + + get_role_id_command() + + mock_send_request.assert_called_once_with(path=expected_path, method=expected_method, body=expected_body) + mock_return_results.assert_called_once() + result_call_args = mock_return_results.call_args[0][0] + assert result_call_args.outputs == expected_outputs + assert result_call_args.outputs_prefix == 'HashiCorp.AppRole' diff --git a/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/README.md b/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/README.md index 277d4ed9f6cb..07a66716d74e 100644 --- a/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/README.md +++ b/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/README.md @@ -404,6 +404,67 @@ Create a new authentication token. #### Command example ```!hashicorp-create-token display_name=token explicit_max_ttl=3600 renewable=false``` + +### hashicorp-generate-role-secret +*** +Generates and issues a new SecretID on an existing AppRole. + +#### Base Command + +`hashicorp-generate-role-secret` +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| role_name | The name of the AppRole. | Required | +| meta_data | Metadata to be tied to the SecretID. | Optional | +| cidr_list | Comma separated string or list of CIDR blocks enforcing secret IDs to be used from specific set of IP addresses. | Optional | +| token_bound_cidrs | Comma-separated string or list of CIDR blocks. | Optional | +| num_uses | Number of times this SecretID can be used, after which the SecretID expires. A value of zero will allow unlimited uses. | Optional | +| ttl_seconds | Duration in seconds after which this SecretID expires. A value of zero will allow the SecretID to not expire. | Optional | + +#### Context Output +There is no context output for this command. +#### Command example +```!hashicorp-generate-role-secret role_name=my-role``` + +#### Human Readable Output +>SecretID:123 + + + +### hashicorp-get-role-id +*** +Retrieves the AppRole ID for a specified role. + + +#### Base Command + +`hashicorp-get-role-id` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| role_name | The name of the AppRole. | Required | + + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| HashiCorp.AppRole.Id | string | AppRole ID. | +| HashiCorp.AppRole.Name | string | AppRole Name. | + +#### Command example +```!hashicorp-get-role-id role_name=my-role``` + +#### Human Readable Output +|Id|Name| +|---|---| +|role_id|role_name| + + ## Additional Information - In order to fetch credentials from HashiCorp Vault, the relevant secrets engines must be configured with the integration so it can pull the data from them. To configure an engine with the integration, use the ***configure-engine*** command. - The default fetch rate for fetch-credentials is 10 minutes. This is configurable with the server parameter *vault.module.cache.expire* diff --git a/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/command_example.txt b/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/command_example.txt index 370449ab8856..fd22ba1bc07f 100644 --- a/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/command_example.txt +++ b/Packs/HashiCorp-Vault/Integrations/HashiCorpVault/command_example.txt @@ -12,4 +12,6 @@ !hashicorp-enable-engine path=secrets type=AWS !hashicorp-list-secrets-engines !hashicorp-seal-vault -!hashicorp-unseal-vault \ No newline at end of file +!hashicorp-unseal-vault +!hashicorp-get-role-id role_name=app-read-write +!hashicorp-generate-role-secret role_name=app-read-write \ No newline at end of file diff --git a/Packs/HashiCorp-Vault/ReleaseNotes/1_1_26.md b/Packs/HashiCorp-Vault/ReleaseNotes/1_1_26.md new file mode 100644 index 000000000000..411aaec6a3e3 --- /dev/null +++ b/Packs/HashiCorp-Vault/ReleaseNotes/1_1_26.md @@ -0,0 +1,10 @@ + +#### Integrations + +##### HashiCorp Vault +- Updated the Docker image to: *demisto/vendors-sdk:1.0.0.114678*. + +- Added the commands: + - ***hashicorp-generate-role-secret*** + - ***hashicorp-get-role-id*** + diff --git a/Packs/HashiCorp-Vault/pack_metadata.json b/Packs/HashiCorp-Vault/pack_metadata.json index 91709acb9e7f..4b2c8cc5eee3 100644 --- a/Packs/HashiCorp-Vault/pack_metadata.json +++ b/Packs/HashiCorp-Vault/pack_metadata.json @@ -2,7 +2,7 @@ "name": "HashiCorp Vault", "description": "Manage Secrets and Protect Sensitive Data through HashiCorp Vault. Ingest and normalize Vault Audit logs.", "support": "xsoar", - "currentVersion": "1.1.25", + "currentVersion": "1.1.26", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/IntegrationsAndIncidentsHealthCheck/ReleaseNotes/1_3_21.md b/Packs/IntegrationsAndIncidentsHealthCheck/ReleaseNotes/1_3_21.md new file mode 100644 index 000000000000..80909bf3755d --- /dev/null +++ b/Packs/IntegrationsAndIncidentsHealthCheck/ReleaseNotes/1_3_21.md @@ -0,0 +1,6 @@ + +#### Scripts + +##### RestartFailedTasks + +Fixed an issue where the **Restart Failed Tasks** script incorrectly reopened successful tasks that share the same task ID with failed tasks. \ No newline at end of file diff --git a/Packs/IntegrationsAndIncidentsHealthCheck/Scripts/RestartFailedTasks/RestartFailedTasks.py b/Packs/IntegrationsAndIncidentsHealthCheck/Scripts/RestartFailedTasks/RestartFailedTasks.py index 49264000db58..db8595d06f67 100644 --- a/Packs/IntegrationsAndIncidentsHealthCheck/Scripts/RestartFailedTasks/RestartFailedTasks.py +++ b/Packs/IntegrationsAndIncidentsHealthCheck/Scripts/RestartFailedTasks/RestartFailedTasks.py @@ -63,7 +63,7 @@ def restart_tasks(failed_tasks: list, sleep_time: int, group_size: int): task_id, incident_id, playbook_name, task_name =\ task['Task ID'], task['Incident ID'], task['Playbook Name'], task['Task Name'] demisto.info(f'Restarting task with id: {task_id} and incident id: {incident_id}') - demisto.executeCommand("taskReopen", {'id': task_id, 'incident_id': incident_id}) + demisto.executeCommand("taskReopen", {'id': task_id, 'incidentId': incident_id}) body = {'invId': incident_id, 'inTaskID': task_id} if is_xsoar_version_6_2: diff --git a/Packs/IntegrationsAndIncidentsHealthCheck/pack_metadata.json b/Packs/IntegrationsAndIncidentsHealthCheck/pack_metadata.json index c2a01f7e93d6..35d52d063fce 100644 --- a/Packs/IntegrationsAndIncidentsHealthCheck/pack_metadata.json +++ b/Packs/IntegrationsAndIncidentsHealthCheck/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Integrations & Incidents Health Check", "description": "Do you know which of your integrations or open incidents failed? With this content, you can view your failed integrations and open incidents", "support": "xsoar", - "currentVersion": "1.3.20", + "currentVersion": "1.3.21", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py index d35ae9ced33f..258d2a542fdf 100644 --- a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py +++ b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py @@ -158,8 +158,9 @@ def handle_errors(self, res: dict) -> None: DemistoException: If the response contains any errors. """ if "errors" in res: + demisto.debug(f"Erroneous response: {res}") errors = "\n".join([error.get("message") for error in res.get("errors", [])]) - raise DemistoException(errors) + raise DemistoException(errors, res=res) def graphql(self, query: str, variables: dict) -> dict: """ diff --git a/Packs/JamfProtect/ReleaseNotes/1_1_3.md b/Packs/JamfProtect/ReleaseNotes/1_1_3.md new file mode 100644 index 000000000000..3f2c5edf15cf --- /dev/null +++ b/Packs/JamfProtect/ReleaseNotes/1_1_3.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Jamf Protect Event Collector + +- Added logging of erroneous responses. \ No newline at end of file diff --git a/Packs/JamfProtect/pack_metadata.json b/Packs/JamfProtect/pack_metadata.json index 2b93c898255d..2cb6e7d03e92 100644 --- a/Packs/JamfProtect/pack_metadata.json +++ b/Packs/JamfProtect/pack_metadata.json @@ -2,7 +2,7 @@ "name": "JamfProtect", "description": "Apple Mobile and Mac endpoint protection", "support": "xsoar", - "currentVersion": "1.1.2", + "currentVersion": "1.1.3", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/LinuxEventsCollection/ParsingRules/LinuxEventsCollectionParsingRules/LinuxEventsCollectionParsingRules.xif b/Packs/LinuxEventsCollection/ParsingRules/LinuxEventsCollectionParsingRules/LinuxEventsCollectionParsingRules.xif index 2c0d2ff513e9..6b6fdd046df5 100644 --- a/Packs/LinuxEventsCollection/ParsingRules/LinuxEventsCollectionParsingRules/LinuxEventsCollectionParsingRules.xif +++ b/Packs/LinuxEventsCollection/ParsingRules/LinuxEventsCollectionParsingRules/LinuxEventsCollectionParsingRules.xif @@ -1,31 +1,21 @@ [INGEST:vendor="linux", product="linux", target_dataset="linux_linux_raw", no_hit=keep] -// Filter to apply the parsing rule only on logs ingested via syslog and not xdrc. -filter _raw_log ~= "\w{3}\s+\d{1,2}\s\d{2}:\d{2}:\d{2}" and _collector_type != "XDR Collector" -| alter -// Get the current year and timestamp. - tmp_get_current_year = arrayindex(regextract(to_string(_insert_time), "\d{4}"), 0), - tmp_get_timestamp = arrayindex(regextract(_raw_log, "\w{3}\s+\d{1,2}\s\d{2}:\d{2}:\d{2}"), 0) -| alter -// Unifies the year and timestamp as String. - tmp_timestamp1 = concat(tmp_get_current_year, " ", tmp_get_timestamp) -| alter -// Converts the full timestamp to datetime format (First option). - tmp_timestamp_format1 = parse_timestamp("%Y %b %d %H:%M:%S", tmp_timestamp1) -| alter -// Check the days difference between the current and extracted time. - tmp_timeDiff = timestamp_diff(tmp_timestamp_format1, current_time(), "MILLISECOND") -| alter -// If the number of days between extracted and current time is positive, reduce the current year by 1. - tmp_verify_year = if(tmp_timeDiff > 0, to_string(subtract(to_integer(tmp_get_current_year),1)),null) -| alter -// If the year was reduced by 1, unifies the reduced year and extracted timestamp as String. - tmp_timestamp2 = if(tmp_verify_year != null, concat(tmp_verify_year, " ", tmp_get_timestamp), null) -| alter -// Converts the full timestamp to datetime format (Second option). - tmp_timestamp_format2 = if(tmp_timestamp2 != null, parse_timestamp("%Y %b %d %H:%M:%S", tmp_timestamp2), null) -| alter - tmp_check_which_timestamp = coalesce(tmp_timestamp_format2, tmp_timestamp_format1, _insert_time) -| alter -// Check if the second option is null, if not, use the first option. - _time = tmp_check_which_timestamp -| fields -tmp_get_current_year, tmp_get_timestamp, tmp_timestamp1, tmp_timestamp_format1, tmp_timeDiff, tmp_verify_year, tmp_timestamp2, tmp_timestamp_format2, tmp_check_which_timestamp; \ No newline at end of file +// Filter applies to log records which contain a full RFC 3339 style timestamp with an explicit timezone offset or Zulu time suffix (UTC) +filter _raw_log ~= "\d{4}\-\d{2}\-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[+-]\d{2}:?\d{2}|Z)" +| alter tmp_timestamp = arrayindex(regextract(_raw_log, "\d{4}\-\d{2}\-\d{2}T\d{2}:\d{2}:\d{2}\S+"), 0) +| alter _time = if( + tmp_timestamp ~= "[+-]\d{4}", parse_timestamp("%FT%H:%M:%E*S%z", tmp_timestamp), // timezone offset without a separating colon, e.g., 2024-10-28T14:30:55+0300 + tmp_timestamp ~= "[+-]\d{2}:\d{2}", parse_timestamp("%FT%H:%M:%E*S%Ez", tmp_timestamp), // RFC 3339 compatible timestamp offset, e.g., 2024-10-28T14:30:55+03:00 + parse_timestamp("%FT%H:%M:%E*SZ", tmp_timestamp)) // RFC 3339 compatible timestamp with zulu time notation, e.g., 2024-10-28T14:30:55Z +| fields - tmp*; + +/* Filter applies to RFC 3164 style syslog records (logs timestamp does not contain an explicit timezone nor year), which are ingested via the Broker VM syslog applet + Log records which are ingested via the XDR Filebeat collector or excluded since their timestamp assignment is handled in the backend within the XDRC based on the Filebeat @timestamp entity. */ +filter _collector_type != "XDR Collector" and _raw_log ~= "\w{3}\s+\d{1,2}\s\d{2}:\d{2}:\d{2}" and _raw_log !~= "\d{4}\-\d{2}\-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[+-]\d{2}:?\d{2}|Z)" +| alter // construct timestamp basted on log timestamp and current year, assuming timestamp is given in UTC + tmp_current_year = format_timestamp("%Y", _insert_time), + tmp_rfc_3164_timestamp = arrayindex(regextract(_raw_log, "\w{3}\s+\d{1,2}\s\d{2}:\d{2}:\d{2}"), 0) // RFC 3164 compatible timestamp, e.g., Oct 28 14:30:55 +| alter tmp_current_year_timestamp = parse_timestamp("%Y %b %e %H:%M:%S", concat(tmp_current_year, " ", tmp_rfc_3164_timestamp), "UTC") +| alter _time = if( // validate the evaluated timestamp with current year is not in the future due to year transition during ingestion. If so, fallback to previous year. + timestamp_diff(tmp_current_year_timestamp, current_time(), "MILLISECOND") <= 0, tmp_current_year_timestamp, // current (ingestion time) year + parse_timestamp("%Y %b %e %H:%M:%S", concat(to_string(subtract(to_integer(tmp_current_year), 1)), " ", tmp_rfc_3164_timestamp), "UTC")) // previous year +| fields - tmp*; \ No newline at end of file diff --git a/Packs/LinuxEventsCollection/README.md b/Packs/LinuxEventsCollection/README.md index bcc9590ebaf9..730533a162db 100644 --- a/Packs/LinuxEventsCollection/README.md +++ b/Packs/LinuxEventsCollection/README.md @@ -1,52 +1,80 @@ # Linux Events Collection -This pack includes XSIAM content. -## Collect Events from Vendor +## Collector Configuration -In order to use the collector, you can use one of the following options to collect events from the vendor: +Use one of the following options to collect Linux events into Cortex XSIAM: + - [Broker VM Syslog Applet](#broker-vm) + - [Filebeat XDRC (XDR Collector)](#xdrc-xdr-collector) -- [Linux Events Collection](#linux-events-collection) - - [Collect Events from Vendor](#collect-events-from-vendor) - - [Broker VM](#broker-vm) - - [XDRC (XDR Collector)](#xdrc-xdr-collector) - -In either option, you will need to configure the vendor and product for this specific collector. +After the Cortex XSIAM collector starts ingesting logs from the Linux servers, you can query the logs under the linux_linux_raw dataset. ### Broker VM -You will need to use the information described [here](https://docs-cortex.paloaltonetworks.com/r/Cortex-XDR/Cortex-XDR-Pro-Administrator-Guide/Configure-the-Broker-VM).\ -You can configure the specific vendor and product for this instance. +#### Prerequisites -1. Navigate to **Settings** -> **Configuration** -> **Data Broker** -> **Broker VMs**. -2. Right-click, and select **Syslog Collector** -> **Configure**. -3. When configuring the Syslog Collector, set: - - vendor as linux - - product as linux +You need to set and configure a Broker VM. For more information, see [Broker VM](https://docs-cortex.paloaltonetworks.com/r/Cortex-XSIAM/Cortex-XSIAM-Documentation/Broker-VM). -* Pay attention: Timestamp parsing is configured for **mmm dd HH:MM:SS** format in UTC timezone. - This can be done by running the following command on the relevant Linux server: - `sudo timedatectl set-timezone UTC` +#### Configuration Steps +1. Navigate to **Settings** → **Configuration** → **Data Broker** → **Broker VMs**. +2. Go to the **APPS** column under the **Brokers** tab and add the **Syslog** app for the relevant broker instance. If the Syslog app already exists, hover over it and click **Configure**. +3. Click **Add New**. +4. When configuring the Syslog Collector, set the following parameters: + | Parameter | Value + | :--- | :--- + | `Vendor` | **linux**. + | `Product` | **linux**. + ### XDRC (XDR Collector) -You will need to use the information described [here](https://docs.paloaltonetworks.com/cortex/cortex-xdr/cortex-xdr-pro-admin/cortex-xdr-collectors/xdr-collector-datasets#id7f0fcd4d-b019-4959-a43a-40b03db8a8b2).\ -You can configure the vendor and product by replacing [vendor]\_[product]\_raw with linux_linux_raw -When configuring an XDR collector profile, you should use a yml that will be used, among other things, to configure the vendor and product. This example demonstrates how to set it, specifically for the Ubuntu Linux product: - -``` -filebeat.inputs: -- type: filestream - enabled: true - paths: - - /var/log/syslog - - /var/log/auth.log - - /var/log/messages - - /var/log/secure - processors: - - add_fields: - fields: - vendor: linux - product: linux -``` - -**Please note**: The above configuration uses the default location of the logs. In case your linux saves the logs under a different location, you would need to change it in the yaml (under the `paths` field). +#### Configuration Steps + +Follow the steps bellow for configuring an [XDR Collector](https://docs-cortex.paloaltonetworks.com/r/Cortex-XSIAM/Cortex-XSIAM-Documentation/Manage-XDR-Collectors): +1. Create an XDR Collector installation package as described [here](https://docs-cortex.paloaltonetworks.com/r/Cortex-XSIAM/Cortex-XSIAM-Documentation/Create-an-XDR-Collector-installation-package). +2. Install the XDR Collector installation package for Linux on the requested Linux servers as described [here](https://docs-cortex.paloaltonetworks.com/r/Cortex-XSIAM/Cortex-XSIAM-Documentation/Install-the-XDR-Collector-installation-package-for-Linux). +3. Configure an [XDR Collector Filebeat profile](https://docs-cortex.paloaltonetworks.com/r/Cortex-XSIAM/Cortex-XSIAM-Documentation/XDR-Collector-profiles) for the requested linux servers as described [here](https://docs-cortex.paloaltonetworks.com/r/Cortex-XSIAM/Cortex-XSIAM-Documentation/Add-an-XDR-Collector-profile-for-Linux). + - When configuring the Filebeat YAML configuration file, use the *LinuxEventCollection* template as a reference: + ![LinuxEventCollection Filebeat Template](https://raw.githubusercontent.com/demisto/content/435111554ddbc4b737b48688314aa466e4a4b8a2/Packs/LinuxEventsCollection/doc_files/LinuxFilebeatTemplate.png) + - Customize the *[paths](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-filestream.html#filestream-input-paths)* parameter in accordance to the requested log files for collection: + ```yaml + filebeat.inputs: + - type: filestream + enabled: true + paths: # customize paths as necessary + - /var/log/syslog + - /var/log/auth.log + - /var/log/messages + - /var/log/secure + processors: + - add_fields: + fields: + vendor: linux + product: linux + ``` +4. Apply the configured Filebeat profile to the requested target Linux servers by attaching it to a policy as described [here](https://docs-cortex.paloaltonetworks.com/r/Cortex-XSIAM/Cortex-XSIAM-Documentation/Apply-profiles-to-collection-machine-policies). + + +#### Supported Timestamp formats +##### Broker VM Syslog +- [RFC 3164](https://datatracker.ietf.org/doc/html/rfc3164#section-4.1.2) compatible timestamps, in UTC, for example: *`Oct 8 19:44:40`*. + **Note**: + You can run the following command on the relevant Linux servers to configure their timezone to UTC: + ```bash + sudo timedatectl set-timezone UTC + ``` +- [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) compatible like timestamps. + **Examples**: + - *`2024-10-28T14:30:55Z`* + - *`2024-10-28T14:30:55-0300`* + - *`2024-10-28T14:30:55.123+02:00`* + + +##### Filebeat XDR Collector +- [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339) compatible like timestamps. +**Examples**: + - *`2024-10-28T14:30:55Z`* + - *`2024-10-28T14:30:55-0300`* + - *`2024-10-28T14:30:55.123+02:00`* + +**Note**: +Event logs collected via Filebeat with timestamp formats other than those listed above are assigned the agent collection time. \ No newline at end of file diff --git a/Packs/LinuxEventsCollection/ReleaseNotes/1_0_10.md b/Packs/LinuxEventsCollection/ReleaseNotes/1_0_10.md new file mode 100644 index 000000000000..77a570bb5faa --- /dev/null +++ b/Packs/LinuxEventsCollection/ReleaseNotes/1_0_10.md @@ -0,0 +1,7 @@ + +#### Parsing Rules + +##### Linux Events Collection Parsing Rule + +- Improved implementation of the existing parsing rule. +- Added support for [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) compatible timestamps, such as *`2024-10-28T14:30:55+0300`*, *`2024-10-28T14:30:55.123-03:00`* and *`2024-10-28T14:30:55.123Z`*, in addition to the already supported [RFC 3164](https://datatracker.ietf.org/doc/html/rfc3164) compatible timestamps. diff --git a/Packs/LinuxEventsCollection/doc_files/LinuxFilebeatTemplate.png b/Packs/LinuxEventsCollection/doc_files/LinuxFilebeatTemplate.png new file mode 100644 index 000000000000..766f1e53b217 Binary files /dev/null and b/Packs/LinuxEventsCollection/doc_files/LinuxFilebeatTemplate.png differ diff --git a/Packs/LinuxEventsCollection/pack_metadata.json b/Packs/LinuxEventsCollection/pack_metadata.json index 47868b5096ef..4250756bf9e3 100644 --- a/Packs/LinuxEventsCollection/pack_metadata.json +++ b/Packs/LinuxEventsCollection/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Linux Events Collection", "description": "Linux is an operating system for servers, desktops, cloud, and IoTs", "support": "xsoar", - "currentVersion": "1.0.9", + "currentVersion": "1.0.10", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/MajorBreachesInvestigationandResponse/.pack-ignore b/Packs/MajorBreachesInvestigationandResponse/.pack-ignore index 764bb59c31e1..0a7ebfe60adf 100644 --- a/Packs/MajorBreachesInvestigationandResponse/.pack-ignore +++ b/Packs/MajorBreachesInvestigationandResponse/.pack-ignore @@ -80,3 +80,5 @@ ignore=GR107 [file:playbook-CVE-2021-22893_-_Pulse_Connect_Secure_RCE.yml] ignore=GR107 +[file:1_6_39.md] +ignore=RN113,RN114 \ No newline at end of file diff --git a/Packs/MajorBreachesInvestigationandResponse/ReleaseNotes/1_6_39.md b/Packs/MajorBreachesInvestigationandResponse/ReleaseNotes/1_6_39.md new file mode 100644 index 000000000000..0861bd24f015 --- /dev/null +++ b/Packs/MajorBreachesInvestigationandResponse/ReleaseNotes/1_6_39.md @@ -0,0 +1,6 @@ +#### Packs +##### CVE-2024-47575 - FortiManager Authentication Bypass +- New pack which handles CVE-2024-47575 - FortiManager Authentication Bypass vulnerability + + This pack can be installed by checking the box when updating the Rapid Breach Response pack (optional dependency) or by installing it directly via + our Marketplace. \ No newline at end of file diff --git a/Packs/MajorBreachesInvestigationandResponse/pack_metadata.json b/Packs/MajorBreachesInvestigationandResponse/pack_metadata.json index f539513dcb11..2c9c35f00e25 100644 --- a/Packs/MajorBreachesInvestigationandResponse/pack_metadata.json +++ b/Packs/MajorBreachesInvestigationandResponse/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Rapid Breach Response", "description": "This content Pack helps you collect, investigate, and remediate incidents related to major breaches.", "support": "xsoar", - "currentVersion": "1.6.38", + "currentVersion": "1.6.39", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", @@ -113,6 +113,10 @@ "IvantiCriticalVulnerabilities": { "mandatory": false, "display_name": "Ivanti Critical Vulnerabilities" + }, + "CVE_2024_47575": { + "mandatory": false, + "display_name": "CVE-2024-47575 - FortiManager Authentication Bypass" } }, "marketplaces": [ diff --git a/Packs/MalwareInvestigationAndResponse/Playbooks/playbook-Malware_Investigation_and_Response_Incident_Handler.yml b/Packs/MalwareInvestigationAndResponse/Playbooks/playbook-Malware_Investigation_and_Response_Incident_Handler.yml index ce81bb76df63..f360d8ee7c53 100644 --- a/Packs/MalwareInvestigationAndResponse/Playbooks/playbook-Malware_Investigation_and_Response_Incident_Handler.yml +++ b/Packs/MalwareInvestigationAndResponse/Playbooks/playbook-Malware_Investigation_and_Response_Incident_Handler.yml @@ -731,7 +731,7 @@ tasks: task: id: bd8a46f7-b83d-496c-839f-e4205505c5fb version: -1 - name: Strat Triage SLA Timer + name: Start Triage SLA Timer description: commands.local.cmd.start.timer type: title iscommand: false diff --git a/Packs/MalwareInvestigationAndResponse/ReleaseNotes/2_0_13.md b/Packs/MalwareInvestigationAndResponse/ReleaseNotes/2_0_13.md new file mode 100644 index 000000000000..17127ea5aa2d --- /dev/null +++ b/Packs/MalwareInvestigationAndResponse/ReleaseNotes/2_0_13.md @@ -0,0 +1,6 @@ + +#### Playbooks + +##### Malware Investigation & Response Incident Handler + +Documentation and metadata improvements. diff --git a/Packs/MalwareInvestigationAndResponse/pack_metadata.json b/Packs/MalwareInvestigationAndResponse/pack_metadata.json index 618dcc93deb9..c903849d3ff6 100644 --- a/Packs/MalwareInvestigationAndResponse/pack_metadata.json +++ b/Packs/MalwareInvestigationAndResponse/pack_metadata.json @@ -5,7 +5,7 @@ "videos": [ "https://www.youtube.com/watch?v=DtGIefyoTao" ], - "currentVersion": "2.0.12", + "currentVersion": "2.0.13", "serverMinVersion": "6.5.0", "author": "Cortex XSOAR", "hidden": false, diff --git a/Packs/Microsoft365Defender/Integrations/Microsoft365Defender/Microsoft365Defender.yml b/Packs/Microsoft365Defender/Integrations/Microsoft365Defender/Microsoft365Defender.yml index 7426bb3f125a..52aaddfefe49 100644 --- a/Packs/Microsoft365Defender/Integrations/Microsoft365Defender/Microsoft365Defender.yml +++ b/Packs/Microsoft365Defender/Integrations/Microsoft365Defender/Microsoft365Defender.yml @@ -382,7 +382,7 @@ script: type: string - contextPath: Microsoft365Defender.Incident.alerts description: List of alerts relevant for the incidents. - dockerimage: demisto/crypto:1.0.0.111961 + dockerimage: demisto/crypto:1.0.0.114611 isfetch: true script: '' subtype: python3 diff --git a/Packs/Microsoft365Defender/ReleaseNotes/4_5_34.md b/Packs/Microsoft365Defender/ReleaseNotes/4_5_34.md new file mode 100644 index 000000000000..eef471b13830 --- /dev/null +++ b/Packs/Microsoft365Defender/ReleaseNotes/4_5_34.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Microsoft 365 Defender + +- Updated the Docker image to: *demisto/crypto:1.0.0.114611*. diff --git a/Packs/Microsoft365Defender/pack_metadata.json b/Packs/Microsoft365Defender/pack_metadata.json index 3d5e6a0f6650..61aa517e66e1 100644 --- a/Packs/Microsoft365Defender/pack_metadata.json +++ b/Packs/Microsoft365Defender/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Microsoft 365 Defender", "description": "Microsoft Defender XDR (formerly Microsoft 365 Defender) is a unified pre- and post-breach enterprise defense suite that natively coordinates detection, prevention, investigation, and response across endpoints, identities, email, and applications to provide integrated protection against sophisticated attacks.", "support": "xsoar", - "currentVersion": "4.5.33", + "currentVersion": "4.5.34", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/MicrosoftDefenderAdvancedThreatProtection/Integrations/MicrosoftDefenderAdvancedThreatProtection/MicrosoftDefenderAdvancedThreatProtection.yml b/Packs/MicrosoftDefenderAdvancedThreatProtection/Integrations/MicrosoftDefenderAdvancedThreatProtection/MicrosoftDefenderAdvancedThreatProtection.yml index 92263723ec8d..a38b1c751d5a 100644 --- a/Packs/MicrosoftDefenderAdvancedThreatProtection/Integrations/MicrosoftDefenderAdvancedThreatProtection/MicrosoftDefenderAdvancedThreatProtection.yml +++ b/Packs/MicrosoftDefenderAdvancedThreatProtection/Integrations/MicrosoftDefenderAdvancedThreatProtection/MicrosoftDefenderAdvancedThreatProtection.yml @@ -332,6 +332,7 @@ script: deprecated: true description: Tests connectivity to Microsoft Defender for Endpoint. name: microsoft-atp-test + polling: true - arguments: - description: A comma-separated list of machine IDs to be used for isolation. e.g., 0a3250e0693a109f1affc9217be9459028aa8426,0a3250e0693a109f1affc9217be9459028aa8424. isArray: true @@ -391,6 +392,7 @@ script: description: 'The type of the file identifier. Possible values: "SHA1" ,"SHA256", and "MD5".' type: String execution: true + polling: true - arguments: - description: A comma-separated list of machine IDs to be used to stop the isolation. e.g., 0a3250e0693a109f1affc9217be9459028aa8426,0a3250e0693a109f1affc9217be9459028aa8424. isArray: true @@ -441,6 +443,7 @@ script: - contextPath: MicrosoftATP.MachineAction.RelatedFileInfo.FileIdentifierType description: 'The type of the file identifier. Possible values: "SHA1" ,"SHA256", and "MD5".' type: String + polling: true - arguments: - description: A comma-separated list of computer DNS name. isArray: true @@ -529,6 +532,7 @@ script: - contextPath: MicrosoftATP.Machine.MachineTags description: Set of machine tags. type: String + polling: true - arguments: - description: A comma-separated list of file SHA1 hashes to get the related machines. isArray: true @@ -597,6 +601,7 @@ script: - contextPath: MicrosoftATP.FileMachine.File description: The machine related file hash. type: String + polling: true - arguments: - description: A comma-separated list of machine IDs used to get the machine details, e.g., 0a3250e0693a109f1affc9217be9459028aa8426,0a3250e0693a109f1affc9217be9459028aa8424. isArray: true @@ -675,6 +680,7 @@ script: - contextPath: MicrosoftATP.Machine.NetworkInterfaces.Status description: Status for the network interface (e.g. Up, Down). type: String + polling: true - arguments: - description: A comma-separated list of machine IDs to run the scan on. name: machine_id @@ -732,6 +738,7 @@ script: - contextPath: MicrosoftATP.MachineAction.RelatedFileInfo.FileIdentifierType description: 'The type of the file identifier. Possible values: "SHA1" ,"SHA256", and "MD5".' type: String + polling: true - arguments: - description: Alert severity. name: severity @@ -854,6 +861,7 @@ script: - contextPath: MicrosoftATP.Alert.RBACGroupName description: The device RBAC group name. type: String + polling: true - arguments: - description: Alert ID to update. name: alert_id @@ -975,6 +983,7 @@ script: - contextPath: MicrosoftATP.Alert.Comments.CreatedTime description: The alert comment created time date. type: Date + polling: true - arguments: - description: The query to run. Must be passed if query_batch argument is not provided. name: query @@ -1014,6 +1023,7 @@ script: - contextPath: MicrosoftATP.Hunt.Result description: The query results. type: String + polling: true - arguments: - description: ID of the machine on which the event was identified. name: machine_id @@ -1159,6 +1169,7 @@ script: - contextPath: MicrosoftATP.Alert.Comments.CreatedTime description: The alert comment created time date. type: Date + polling: true - arguments: - description: ID of the alert. name: id @@ -1208,6 +1219,7 @@ script: - contextPath: MicrosoftATP.AlertUser.AlertID description: The alert ID. type: String + polling: true - arguments: - description: ID of the alert. name: id @@ -1275,6 +1287,7 @@ script: - contextPath: MicrosoftATP.AlertFile.Files.Md5 description: The MD5 hash of the file. type: String + polling: true - arguments: - description: ID of the alert. name: id @@ -1297,6 +1310,7 @@ script: - contextPath: MicrosoftATP.AlertIP.AlertID description: The alert ID. type: String + polling: true - arguments: - description: ID of the alert. name: id @@ -1320,6 +1334,7 @@ script: - contextPath: MicrosoftATP.AlertDomain.AlertID description: The alert ID. type: Unknown + polling: true - arguments: - description: ID of the action. name: id @@ -1399,6 +1414,7 @@ script: - contextPath: MicrosoftATP.MachineAction.RelatedFileInfo.FileIdentifierType description: 'The file identifier type. Possible values: "SHA1" ,"SHA256", and "MD5".' type: String + polling: true - arguments: - description: The machine ID. name: machine_id @@ -1448,6 +1464,7 @@ script: - contextPath: MicrosoftATP.MachineAction.RelatedFileInfo.FileIdentifierType description: 'The file identifier type. Possible values: "SHA1" ,"SHA256", and "MD5".' type: String + polling: true - arguments: - description: machine action ID. name: action_id @@ -1461,6 +1478,7 @@ script: - contextPath: MicrosoftATP.InvestigationURI.Link description: The investigation package URI. type: String + polling: true - arguments: - description: The machine ID. name: machine_id @@ -1509,6 +1527,7 @@ script: - contextPath: MicrosoftATP.MachineAction.RelatedFileInfo.FileIdentifierType description: 'The file identifier type. Possible values: "SHA1" ,"SHA256", and "MD5".' type: String + polling: true - arguments: - description: The machine ID. name: machine_id @@ -1559,6 +1578,7 @@ script: - contextPath: MicrosoftATP.MachineAction.RelatedFileInfo.FileIdentifierType description: 'The file identifier type. Possible values: "SHA1" ,"SHA256", and "MD5".' type: String + polling: true - arguments: - description: The machine ID. When providing multiple values, each value is checked for the same hash. name: machine_id @@ -1615,6 +1635,7 @@ script: - contextPath: MicrosoftATP.MachineAction.RelatedFileInfo.FileIdentifierType description: 'The file identifier type. Possible values: "SHA1" ,"SHA256", and "MD5".' type: String + polling: true - arguments: - description: ID can be the investigation ID or the investigation triggering alert ID. name: id @@ -1659,6 +1680,7 @@ script: - contextPath: MicrosoftATP.Investigation.TriggeringAlertID description: The alert ID that triggered the investigation. type: String + polling: true - arguments: - description: The machine's ID. name: machine_id @@ -1702,6 +1724,7 @@ script: - contextPath: MicrosoftATP.Investigation.TriggeringAlertID description: The alert ID that triggered the investigation. type: String + polling: true - arguments: - description: The domain address. name: domain @@ -1724,6 +1747,7 @@ script: - contextPath: MicrosoftATP.DomainStatistics.Statistics.OrgLastSeen description: The last date and time the domain was in the organization. type: Date + polling: true - arguments: - description: The domain address. name: domain @@ -1812,6 +1836,7 @@ script: - contextPath: MicrosoftATP.DomainAlert.Alerts.Comments.CreatedTime description: The alert comment created time date. type: Date + polling: true - arguments: - description: The domain address. name: domain @@ -1879,6 +1904,7 @@ script: - contextPath: MicrosoftATP.DomainMachine.Machines.MachineTags description: Set of machine tags. type: String + polling: true - arguments: - description: File SHA1 hash to get statistics on. name: file_hash @@ -1913,6 +1939,7 @@ script: - contextPath: MicrosoftATP.FileStatistics.Statistics.TopFileNames description: The file's top names. type: String + polling: true - arguments: - description: File SHA1 hash to get statistics on. name: file_hash @@ -2001,6 +2028,7 @@ script: - contextPath: MicrosoftATP.FileAlert.Alerts.Comments.CreatedTime description: The alert comment created time date. type: Date + polling: true - arguments: - description: The IP address. name: ip @@ -2023,6 +2051,7 @@ script: - contextPath: MicrosoftATP.IPStatistics.Statistics.OrgLastSeen description: The last date and time the IP was in the organization. type: Date + polling: true - arguments: - description: |- The IP address. @@ -2112,6 +2141,7 @@ script: - contextPath: MicrosoftATP.IPAlert.Alerts.Comments.CreatedTime description: The alert comment created time date. type: Date + polling: true - arguments: - description: |- The user ID. Note that the ID is not the full UPN, but only the username. @@ -2202,6 +2232,7 @@ script: - contextPath: MicrosoftATP.UserAlert.Alerts.Comments.CreatedTime description: The alert comment created time date. type: Date + polling: true - arguments: - description: |- The user ID. Note that the ID is not the full UPN, but only the username. @@ -2271,6 +2302,7 @@ script: - contextPath: MicrosoftATP.UserMachine.Machines.MachineTags description: Set of machine tags. type: String + polling: true - arguments: - description: The machine ID. name: machine_id @@ -2345,6 +2377,7 @@ script: - contextPath: MicrosoftATP.Machine.MachineTags description: Set of machine tags. type: String + polling: true - arguments: - description: The maximum number of indicators to return. name: limit @@ -2533,6 +2566,7 @@ script: - contextPath: URL.Data description: The URL. type: String + polling: true - arguments: - description: The ID of the indicator to get. name: indicator_id @@ -2719,6 +2753,7 @@ script: - contextPath: URL.Data description: The URL. type: String + polling: true - arguments: - auto: PREDEFINED description: The action to apply if the indicator is matched from within the targetProduct security tool. @@ -2974,6 +3009,7 @@ script: - contextPath: File.Path description: The path where the file is located. type: String + polling: true - arguments: - description: The action to apply if the indicator is matched from within the targetProduct security tool. name: action @@ -3224,6 +3260,7 @@ script: - contextPath: URL.Data description: The URL. type: String + polling: true - arguments: - description: The ID of the indicator to update. name: indicator_id @@ -3424,6 +3461,7 @@ script: - contextPath: URL.Data description: The URL. type: String + polling: true - arguments: - description: The ID of the indicator to delete. name: indicator_id @@ -3434,6 +3472,7 @@ script: description: Deprecated. Use the microsoft-atp-sc-indicator-delete command instead. Deletes the specified indicator. name: microsoft-atp-indicator-delete deprecated: true + polling: true - arguments: - description: The value of the indicator to update. name: indicator_value @@ -3584,6 +3623,7 @@ script: - contextPath: DBotScore.Score description: The actual score. type: Number + polling: true - arguments: - description: The value of the indicator to update. name: indicator_value @@ -3734,6 +3774,7 @@ script: - contextPath: DBotScore.Score description: The actual score. type: Number + polling: true - arguments: - description: The ID of the indicator to delete. The ID can be retrieved by running the microsoft-atp-sc-indicator-list command. name: indicator_id @@ -3743,6 +3784,7 @@ script: deprecated: true description: Deletes the specified indicator. name: microsoft-atp-sc-indicator-delete + polling: true - arguments: - description: The maximum number of indicators to return. name: limit @@ -3863,6 +3905,7 @@ script: - contextPath: DBotScore.Score description: The actual score. type: Number + polling: true - arguments: - description: The ID of the indicator to get. The ID can be retrieved by running the microsoft-atp-sc-indicator-list command. name: indicator_id @@ -3967,6 +4010,7 @@ script: - contextPath: DBotScore.Score description: The actual score. type: Number + polling: true - arguments: - description: Software ID. Use the !microsoft-atp-list-software command to get the ID. name: id @@ -4283,6 +4327,7 @@ script: - contextPath: MicrosoftATP.CveMachine.CVE description: The given CVE IDs related to this machine. type: Unknown + polling: true - arguments: - description: A comma-separated list of file hashes (SHA1 or SHA256) used for getting the file information. isArray: true @@ -4358,6 +4403,7 @@ script: - contextPath: File.Size description: The file size. type: Number + polling: true - name: endpoint description: Gets machines that have communicated with Microsoft Defender for Endpoint cloud. At least one of the following arguments is required - IP, hostname, or ID. Otherwise, an error appears. arguments: @@ -4468,6 +4514,7 @@ script: - contextPath: MicrosoftATP.Machine.AgentVersion description: The machine Agent version. type: String + polling: true - name: microsoft-atp-indicator-batch-update description: Updates a batch of indicators. If an indicator does not exist, a new indicator is created. arguments: @@ -4490,6 +4537,7 @@ script: - contextPath: MicrosoftATP.Indicators.IsFailed description: Whether the update failed. type: Boolean + polling: true - name: microsoft-atp-get-alert-by-id description: 'Retrieves a specific alert by the given alert ID.' arguments: @@ -4594,6 +4642,7 @@ script: - contextPath: MicrosoftATP.Alert.RBACGroupName description: The device RBAC group name. type: String + polling: true - name: microsoft-atp-live-response-get-file description: 'Collects a file from a device. Note: Backslashes in the path must be escaped.' arguments: @@ -4954,6 +5003,7 @@ script: - contextPath: MicrosoftATP.HuntLateralMovementEvidence.Result.management_connection description: The query results for management_connection query_purpose. type: String + polling: true - arguments: - description: When you select a “query_purpose” argument, a designated query template is used. "scheduled_job" - Did the process create any scheduled jobs? "registry_entry" - Did it write to the registry? Requires also the process_cmd argument to be provided. "startup_folder_changes" - Was anything added to the startup folder? "new_service_created" - Was a new service created? "service_updated" - Was an existing service edited? "file_replaced" - Was a file replaced in program files? "new_user" - Was a new user created (on the local machine)? "new_group" - Was a new group created? "group_user_change" - Was a user added to a group (on the local machine)? "local_firewall_change" - Was there a change to the local FW rules? "host_file_change" - Whether there was a change to the hosts file or not. name: query_purpose @@ -5052,6 +5102,7 @@ script: - contextPath: MicrosoftATP.HuntPersistenceEvidence.Result.host_file_change description: The query results for host_file_change query_purpose. type: String + polling: true - arguments: - description: Device name to look for. name: device_name @@ -5101,6 +5152,7 @@ script: - contextPath: MicrosoftATP.HuntFileOrigin.Result description: The query results. type: String + polling: true - arguments: - description: When you select a “query_purpose” argument, a designated query template is used. "parent_process" - Parent process. "grandparent_process" - Grandparent process. "process_details" - Process hash, path, signature details. "beaconing_evidence" - Does the process appear to be beaconing? "powershell_execution_unsigned_files" - Has the file executed PowerShell? Query without specifying processes. No additional arguments are required. "process_excecution_powershell" - Whether there the file executed PowerShell or not. name: query_purpose @@ -5177,6 +5229,7 @@ script: - contextPath: MicrosoftATP.HuntProcessDetails.Result.process_excecution_powershell description: The query results for process_excecution_powershell query_purpose. type: String + polling: true - name: microsoft-atp-advanced-hunting-network-connections description: Detects network connections. When you select a “query_purpose” argument, a designated query template is used. arguments: @@ -5241,6 +5294,7 @@ script: - contextPath: MicrosoftATP.HuntNetworkConnections.Result.encoded_commands description: The query results for encoded_commands query_purpose. type: String + polling: true - name: microsoft-atp-advanced-hunting-privilege-escalation description: Detects evidence of privilege escalation. arguments: @@ -5315,6 +5369,7 @@ script: - contextPath: MicrosoftATP.HuntTampering.Result description: The query results. type: String + polling: true - arguments: - description: When you select a “query_purpose” argument, a designated query template is used. "file_deleted" - Did the file delete itself? "event_log_cleared" - Was the event log cleared? Requires at least one of device arguments (device_name/device_id). "compromised_information" - Information on a compromised user and its activities. Requires only username argument. "connected_devices" - All connected devices by compromised user. Requires only username argument. "action_types" - All action types created by a user on each machine. Requires only username argument. "common_files" - Most common files associated with a user. Requires only username argument. name: query_purpose @@ -5394,6 +5449,7 @@ script: - contextPath: MicrosoftATP.HuntCoverUp.Result.common_files description: The query results for common_files query_purpose. type: String + polling: true - arguments: - default: true description: A machine ID used for getting logged on users. @@ -5432,6 +5488,7 @@ script: - contextPath: MicrosoftATP.MachineUser.MachineID description: The machine ID. type: String + polling: true - arguments: - description: A machine ID used for getting machine related alerts. name: machine_id @@ -5473,6 +5530,7 @@ script: - contextPath: MicrosoftATP.MachineAlerts.MachineID description: The alerts machine ID. type: String + polling: true - arguments: - description: The machine ID. Can be retrieved by running the 'microsoft-atp-get-machines' command. name: machine_id @@ -5558,6 +5616,7 @@ script: - contextPath: MicrosoftATP.OffboardMachine.troubleshootInfo description: Troubleshooting information. type: String + polling: true - description: Generate the login url used for Authorization code flow. name: microsoft-atp-generate-login-url arguments: [] @@ -5565,7 +5624,7 @@ script: execution: false name: microsoft-atp-auth-reset arguments: [] - dockerimage: demisto/crypto:1.0.0.111961 + dockerimage: demisto/crypto:1.0.0.114611 isfetch: true runonce: false script: '-' diff --git a/Packs/MicrosoftDefenderAdvancedThreatProtection/ReleaseNotes/1_16_40.md b/Packs/MicrosoftDefenderAdvancedThreatProtection/ReleaseNotes/1_16_40.md new file mode 100644 index 000000000000..a2e9195924df --- /dev/null +++ b/Packs/MicrosoftDefenderAdvancedThreatProtection/ReleaseNotes/1_16_40.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Microsoft Defender for Endpoint + +- Updated the Docker image to: *demisto/crypto:1.0.0.114611*. diff --git a/Packs/MicrosoftDefenderAdvancedThreatProtection/ReleaseNotes/1_16_41.md b/Packs/MicrosoftDefenderAdvancedThreatProtection/ReleaseNotes/1_16_41.md new file mode 100644 index 000000000000..949e9effa07e --- /dev/null +++ b/Packs/MicrosoftDefenderAdvancedThreatProtection/ReleaseNotes/1_16_41.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Microsoft Defender for Endpoint + +- Fixed an issue when reaching API rate limit, where the retry later mechanism failed to run for all commands. diff --git a/Packs/MicrosoftDefenderAdvancedThreatProtection/pack_metadata.json b/Packs/MicrosoftDefenderAdvancedThreatProtection/pack_metadata.json index 56c167a79a73..ebe260c8c720 100644 --- a/Packs/MicrosoftDefenderAdvancedThreatProtection/pack_metadata.json +++ b/Packs/MicrosoftDefenderAdvancedThreatProtection/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Microsoft Defender for Endpoint", "description": "Microsoft Defender for Endpoint (previously Microsoft Defender Advanced Threat Protection (ATP)) is a unified platform for preventative protection, post-breach detection, automated investigation, and response.", "support": "xsoar", - "currentVersion": "1.16.39", + "currentVersion": "1.16.41", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/MicrosoftExchangeOnPremise/Integrations/EWSv2/EWSv2.py b/Packs/MicrosoftExchangeOnPremise/Integrations/EWSv2/EWSv2.py index dacba5e75b9e..0b0e6dcbf5f5 100644 --- a/Packs/MicrosoftExchangeOnPremise/Integrations/EWSv2/EWSv2.py +++ b/Packs/MicrosoftExchangeOnPremise/Integrations/EWSv2/EWSv2.py @@ -682,6 +682,11 @@ def get_payload(self): class SearchMailboxes(EWSService): + + def __init__(self, protocol, limit): + self.limit = limit + super().__init__(protocol) + SERVICE_NAME = 'SearchMailboxes' element_container_name = f'{{{MNS}}}SearchMailboxesResult/{{{TNS}}}Items' @@ -732,6 +737,7 @@ def get_mailbox_search_scope(mailbox_id): element = create_element('m:%s' % self.SERVICE_NAME) add_xml_child(element, "m:SearchQueries", mailbox_query_element) add_xml_child(element, "m:ResultType", "PreviewOnly") + add_xml_child(element, "m:PageSize", str(self.limit)) return element @@ -805,8 +811,27 @@ def get_searchable_mailboxes(protocol): # pragma: no cover def search_mailboxes(protocol, filter, limit=100, mailbox_search_scope=None, email_addresses=None): # pragma: no cover + """ + Search mailboxes for items matching the given filter. + + Args: + protocol (Protocol): The EWS protocol object. + filter (str): The search filter to apply. + limit (int): The maximum number of results to return. Default value is 100. + mailbox_search_scope (str or list, optional): The mailbox search scope. Defaults to None. + email_addresses (str, optional): Comma-separated list of email addresses to search. Defaults to None. + + Returns: + dict: A dictionary containing the search results. + + Raises: + Exception: If both mailbox_search_scope and email_addresses are provided, or if no searchable mailboxes are found. + """ mailbox_ids = [] - limit = int(limit) + limit_argument = arg_to_number(limit) + if not limit_argument: + raise DemistoException(f"Invalid limit value: {limit}. Please provide a valid integer.") + if mailbox_search_scope is not None and email_addresses is not None: raise Exception("Use one of the arguments - mailbox-search-scope or email-addresses, not both") if email_addresses: @@ -825,8 +850,7 @@ def search_mailboxes(protocol, filter, limit=100, mailbox_search_scope=None, ema mailboxes = [x for x in entry[ENTRY_CONTEXT]['EWS.Mailboxes'] if MAILBOX_ID in list(x.keys())] mailbox_ids = [x[MAILBOX_ID] for x in mailboxes] # type: ignore try: - search_results = SearchMailboxes(protocol=protocol).call(filter, mailbox_ids) - search_results = search_results[:limit] + search_results = SearchMailboxes(protocol=protocol, limit=limit_argument).call(filter, mailbox_ids) except TransportError as e: if "ItemCount>0<" in str(e): return "No results for search query: " + filter diff --git a/Packs/MicrosoftExchangeOnPremise/Integrations/EWSv2/EWSv2.yml b/Packs/MicrosoftExchangeOnPremise/Integrations/EWSv2/EWSv2.yml index da3ad5b398d3..a604b775cb7b 100644 --- a/Packs/MicrosoftExchangeOnPremise/Integrations/EWSv2/EWSv2.yml +++ b/Packs/MicrosoftExchangeOnPremise/Integrations/EWSv2/EWSv2.yml @@ -245,8 +245,8 @@ script: - description: The mailbox IDs to search. If empty, all mailboxes are searched. isArray: true name: mailbox-search-scope - - defaultValue: '250' - description: Maximum number of results to return. + - defaultValue: '100' + description: Maximum number of results to return. Default is 100. This maximum limit can vary based on the EWS server configuration, but a safe recommendation for this argument's upper value is 1000. name: limit - description: CSV list or array of email addresses. isArray: true diff --git a/Packs/MicrosoftExchangeOnPremise/ReleaseNotes/2_1_13.md b/Packs/MicrosoftExchangeOnPremise/ReleaseNotes/2_1_13.md new file mode 100644 index 000000000000..23f5ea7ab911 --- /dev/null +++ b/Packs/MicrosoftExchangeOnPremise/ReleaseNotes/2_1_13.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### EWS v2 + +- Fixed an issue in ***ews-search-mailboxes*** command where the *limit* argument was capped at 100 results. The command now correctly retrieves the specified number of results according to *limit*, allowing to return more than 100 items when available. diff --git a/Packs/MicrosoftExchangeOnPremise/pack_metadata.json b/Packs/MicrosoftExchangeOnPremise/pack_metadata.json index c2442c9970f4..ef928a8af076 100644 --- a/Packs/MicrosoftExchangeOnPremise/pack_metadata.json +++ b/Packs/MicrosoftExchangeOnPremise/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Microsoft Exchange On-Premise", "description": "Exchange Web Services", "support": "xsoar", - "currentVersion": "2.1.12", + "currentVersion": "2.1.13", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/MicrosoftExchangeOnline/Integrations/SecurityAndComplianceV2/README.md b/Packs/MicrosoftExchangeOnline/Integrations/SecurityAndComplianceV2/README.md index 826599036ee1..c8b8eee013a3 100644 --- a/Packs/MicrosoftExchangeOnline/Integrations/SecurityAndComplianceV2/README.md +++ b/Packs/MicrosoftExchangeOnline/Integrations/SecurityAndComplianceV2/README.md @@ -37,7 +37,7 @@ To set up the integration and register the application in Azure, follow these st - Under **Manage**, select **API permissions** > **Add a permission**. - Select **APIs my organization uses**. - Search for "Office 365 Exchange Online". - - Select **Application permissions** and search for `Exchange.ManageAsApp`. + - Select **Delegated permissions** and search for `Exchange.Manage`. - Check the box and click **Add permissions**. - Ensure the permissions are granted by selecting **Grant admin consent for [Your Organization]**. diff --git a/Packs/MicrosoftExchangeOnline/Integrations/SecurityAndComplianceV2/SecurityAndComplianceV2_description.md b/Packs/MicrosoftExchangeOnline/Integrations/SecurityAndComplianceV2/SecurityAndComplianceV2_description.md index 5c95307696c0..33c77887a9a4 100644 --- a/Packs/MicrosoftExchangeOnline/Integrations/SecurityAndComplianceV2/SecurityAndComplianceV2_description.md +++ b/Packs/MicrosoftExchangeOnline/Integrations/SecurityAndComplianceV2/SecurityAndComplianceV2_description.md @@ -16,7 +16,7 @@ Supported authentication methods: ### Overview In response to Microsoft's deprecation of the App ID, the following changes to app registration in Azure are required: -1. Add the `Exchange.ManageAsApp` application permissions. +1. Add the `Exchange.Manage` delegated permissions. 2. Enable "Allow public client flows" in the authentication section. 3. Add an app secret to the app registration. @@ -38,8 +38,8 @@ In response to Microsoft's deprecation of the App ID, the following changes to a - Click on **Add a permission**. - Select **APIs my organization uses**. - Type "Office" in the search bar and select **Office 365 Exchange Online**. - - Choose **Application permissions**. - - Search for `Exchange.ManageAsApp` and check the corresponding box. + - Choose **Delegated permissions**. + - Search for `Exchange.Manage` and check the corresponding box. - Click on **Add permissions**. - Ensure the permissions are granted for your organization by selecting **Grant admin consent for [Your Organization]** and confirming the action. diff --git a/Packs/MicrosoftExchangeOnline/ReleaseNotes/1_5_11.md b/Packs/MicrosoftExchangeOnline/ReleaseNotes/1_5_11.md new file mode 100644 index 000000000000..79e9e05e73f9 --- /dev/null +++ b/Packs/MicrosoftExchangeOnline/ReleaseNotes/1_5_11.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### O365 - Security And Compliance - Content Search v2 + +Updated the documentation to include the required *Exchange.Manage* delegated permission for proper functionality. \ No newline at end of file diff --git a/Packs/MicrosoftExchangeOnline/pack_metadata.json b/Packs/MicrosoftExchangeOnline/pack_metadata.json index bbd1a15dcd48..5e0641d2279b 100644 --- a/Packs/MicrosoftExchangeOnline/pack_metadata.json +++ b/Packs/MicrosoftExchangeOnline/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Microsoft Exchange Online", "description": "Exchange Online and Office 365 (mail)", "support": "xsoar", - "currentVersion": "1.5.10", + "currentVersion": "1.5.11", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/MicrosoftGraphMail/Integrations/MicrosoftGraphListener/MicrosoftGraphListener_test.py b/Packs/MicrosoftGraphMail/Integrations/MicrosoftGraphListener/MicrosoftGraphListener_test.py index 6687c55062fa..95fb4dd601bf 100644 --- a/Packs/MicrosoftGraphMail/Integrations/MicrosoftGraphListener/MicrosoftGraphListener_test.py +++ b/Packs/MicrosoftGraphMail/Integrations/MicrosoftGraphListener/MicrosoftGraphListener_test.py @@ -733,7 +733,8 @@ def test_get_attachment(client): with open('test_data/mail_with_attachment.txt') as mail_json: user_id = 'ex@example.com' raw_response = json.load(mail_json) - res = GraphMailUtils.item_result_creator(raw_response, user_id) + args = {} + res = GraphMailUtils.item_result_creator(raw_response, user_id, args, client) assert isinstance(res, CommandResults) output = res.to_context().get('EntryContext', {}) assert output.get(output_prefix).get('ID') == 'exampleID' @@ -789,8 +790,9 @@ def test_get_attachment_unsupported_type(client): from MicrosoftGraphListener import GraphMailUtils with open('test_data/mail_with_unsupported_attachment.txt') as mail_json: user_id = 'ex@example.com' + args = {} raw_response = json.load(mail_json) - res = GraphMailUtils.item_result_creator(raw_response, user_id) + res = GraphMailUtils.item_result_creator(raw_response, user_id, args, client) assert isinstance(res, CommandResults) output = res.to_context().get('HumanReadable', '') assert 'Integration does not support attachments from type #microsoft.graph.contact' in output diff --git a/Packs/MicrosoftGraphMail/Integrations/MicrosoftGraphMail/MicrosoftGraphMail.yml b/Packs/MicrosoftGraphMail/Integrations/MicrosoftGraphMail/MicrosoftGraphMail.yml index 60a362688326..533ebe1ba9d9 100644 --- a/Packs/MicrosoftGraphMail/Integrations/MicrosoftGraphMail/MicrosoftGraphMail.yml +++ b/Packs/MicrosoftGraphMail/Integrations/MicrosoftGraphMail/MicrosoftGraphMail.yml @@ -455,6 +455,8 @@ script: name: folder_id - description: The ID of the attachment. In case not supplied, the command will return all the attachments. name: attachment_id + - description: Setting this argument to 'true' will return message attachments of type 'microsoft.graph.message' (also known as 'Outlook item' or '.eml') as downloadable files. Default value is 'false'. Default behavior is to return 'microsoft.graph.message' attachments inside a command result. + name: should_download_message_attachment - deprecated: true description: flag for rate limit retry. name: ran_once_flag diff --git a/Packs/MicrosoftGraphMail/Integrations/MicrosoftGraphMail/MicrosoftGraphMail_test.py b/Packs/MicrosoftGraphMail/Integrations/MicrosoftGraphMail/MicrosoftGraphMail_test.py index 44aa567ee821..936e6e0a559a 100644 --- a/Packs/MicrosoftGraphMail/Integrations/MicrosoftGraphMail/MicrosoftGraphMail_test.py +++ b/Packs/MicrosoftGraphMail/Integrations/MicrosoftGraphMail/MicrosoftGraphMail_test.py @@ -2,11 +2,11 @@ import pytest import requests_mock +from MicrosoftGraphMail import * +import demistomock as demisto from CommonServerPython import * -from MicrosoftGraphMail import * from MicrosoftApiModule import MicrosoftClient -import demistomock as demisto class MockedResponse: @@ -636,29 +636,60 @@ def test_build_message(): @pytest.mark.parametrize('client', [oproxy_client(), self_deployed_client()]) -def test_get_attachment(client): +def test_get_attachment_as_command_result(client): """ Given: - raw response returned from get_attachment_command When: - response type is itemAttachment and 'item_result_creator' is called + - The 'should_download_message_attachment' command argument value is False (by default) Then: - Validate that the message object created successfully + - GraphMailUtils.item_result_creator function should return a command result """ output_prefix = 'MSGraphMail(val.ID && val.ID == obj.ID)' with open('test_data/mail_with_attachment') as mail_json: user_id = 'ex@example.com' raw_response = json.load(mail_json) - res = GraphMailUtils.item_result_creator(raw_response, user_id) + args = {} + res = GraphMailUtils.item_result_creator(raw_response, user_id, args, client) assert isinstance(res, CommandResults) output = res.to_context().get('EntryContext', {}) assert output.get(output_prefix).get('ID') == 'exampleID' assert output.get(output_prefix).get('Subject') == 'Test it' +@pytest.mark.parametrize('client', [oproxy_client(), self_deployed_client()]) +def test_get_attachment_as_file_result(mocker, client): + """ + Given: + - raw response returned from get_attachment_command + + When: + - response type is itemAttachment and 'item_result_creator' is called. + - The 'should_download_message_attachment' command argument is True + + Then: + - Validate that the message object created successfully + - GraphMailUtils.item_result_creator function should return a command result + + """ + + mocker.patch.object(MsGraphMailBaseClient, '_get_attachment_mime', return_value='raw data') + with open('test_data/mail_with_attachment') as mail_json: + user_id = 'ex@example.com' + args = {'message_id': 'example_message_id', 'attachment_id': 'example_attachment_id', + 'should_download_message_attachment': True} + raw_response = json.load(mail_json) + res = GraphMailUtils.item_result_creator(raw_response, user_id, args, client) + assert isinstance(res, dict) + assert res['File'] == 'Test_it.eml' + assert res['FileID'] + + @pytest.mark.parametrize('client', [oproxy_client(), self_deployed_client()]) def test_get_attachments_without_attachment_id(mocker, client): """ @@ -709,15 +740,16 @@ def test_get_attachment_unsupported_type(client): with open('test_data/mail_with_unsupported_attachment') as mail_json: user_id = 'ex@example.com' raw_response = json.load(mail_json) - res = GraphMailUtils.item_result_creator(raw_response, user_id) + args = {} + res = GraphMailUtils.item_result_creator(raw_response, user_id, args, client) assert isinstance(res, CommandResults) output = res.to_context().get('HumanReadable', '') assert 'Integration does not support attachments from type #microsoft.graph.contact' in output -@pytest.mark.parametrize('function_name, attachment_type', [('file_result_creator', 'fileAttachment'), - ('item_result_creator', 'itemAttachment')]) -def test_create_attachment(mocker, function_name, attachment_type): +@pytest.mark.parametrize('function_name, attachment_type, client', [('file_result_creator', 'fileAttachment', oproxy_client()), + ('item_result_creator', 'itemAttachment', oproxy_client())]) +def test_create_attachment(mocker, function_name, attachment_type, client): """ Given: - raw response returned from api: @@ -734,7 +766,8 @@ def test_create_attachment(mocker, function_name, attachment_type): mocker.patch(f'MicrosoftGraphMail.GraphMailUtils.{function_name}', return_value=function_name) raw_response = {'@odata.type': f'#microsoft.graph.{attachment_type}'} user_id = 'ex@example.com' - called_function = GraphMailUtils.create_attachment(raw_response, user_id) + args = {} + called_function = GraphMailUtils.create_attachment(raw_response, user_id, args, client) assert called_function == function_name @@ -1384,9 +1417,10 @@ def test_test_module_command_with_managed_identities(mocker, requests_mock, clie Then: - Ensure the output are as expected. """ - from MicrosoftGraphMail import main, MANAGED_IDENTITIES_TOKEN_URL, Resources import re + from MicrosoftGraphMail import MANAGED_IDENTITIES_TOKEN_URL, Resources, main + mock_token = {'access_token': 'test_token', 'expires_in': '86400'} get_mock = requests_mock.get(MANAGED_IDENTITIES_TOKEN_URL, json=mock_token) requests_mock.get(re.compile(f'^{Resources.graph}.*'), json={}) diff --git a/Packs/MicrosoftGraphMail/ReleaseNotes/1_6_18.md b/Packs/MicrosoftGraphMail/ReleaseNotes/1_6_18.md new file mode 100644 index 000000000000..090d5b4150a0 --- /dev/null +++ b/Packs/MicrosoftGraphMail/ReleaseNotes/1_6_18.md @@ -0,0 +1,10 @@ + +#### Integrations + +##### O365 Outlook Mail (Using Graph API) + +Added a command argument *should_download_message_attachment* to the ***msgraph-mail-get-attachment*** command, which allows returning email attachments of type "Outlook item" and ".eml" as downloadable files. + +##### Microsoft Graph Mail Single User + +Added a command argument *should_download_message_attachment* to the ***msgraph-mail-get-attachment*** command, which allows returning email attachments of type "Outlook item" and ".eml" as downloadable files. diff --git a/Packs/MicrosoftGraphMail/pack_metadata.json b/Packs/MicrosoftGraphMail/pack_metadata.json index 0133eb8e98e0..c4d832ef31c6 100644 --- a/Packs/MicrosoftGraphMail/pack_metadata.json +++ b/Packs/MicrosoftGraphMail/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Microsoft Graph Mail", "description": "Microsoft Graph lets your app get authorized access to a user's Outlook mail data in a personal or organization account.", "support": "xsoar", - "currentVersion": "1.6.17", + "currentVersion": "1.6.18", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/MicrosoftGraphUser/Integrations/MicrosoftGraphUser/MicrosoftGraphUser.yml b/Packs/MicrosoftGraphUser/Integrations/MicrosoftGraphUser/MicrosoftGraphUser.yml index d67146dc1774..1d888a603c26 100644 --- a/Packs/MicrosoftGraphUser/Integrations/MicrosoftGraphUser/MicrosoftGraphUser.yml +++ b/Packs/MicrosoftGraphUser/Integrations/MicrosoftGraphUser/MicrosoftGraphUser.yml @@ -634,7 +634,7 @@ script: - description: Run this command if for some reason you need to rerun the authentication process. name: msgraph-user-auth-reset arguments: [] - dockerimage: demisto/crypto:1.0.0.111961 + dockerimage: demisto/crypto:1.0.0.114611 runonce: false script: '-' subtype: python3 diff --git a/Packs/MicrosoftGraphUser/ReleaseNotes/1_5_40.md b/Packs/MicrosoftGraphUser/ReleaseNotes/1_5_40.md new file mode 100644 index 000000000000..b866da896203 --- /dev/null +++ b/Packs/MicrosoftGraphUser/ReleaseNotes/1_5_40.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Azure Active Directory Users + +- Updated the Docker image to: *demisto/crypto:1.0.0.114611*. diff --git a/Packs/MicrosoftGraphUser/pack_metadata.json b/Packs/MicrosoftGraphUser/pack_metadata.json index f67f89617750..8518986c291a 100644 --- a/Packs/MicrosoftGraphUser/pack_metadata.json +++ b/Packs/MicrosoftGraphUser/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Microsoft Graph User", "description": "Use the Microsoft Graph integration to connect to and interact with user objects on Microsoft Platforms.", "support": "xsoar", - "currentVersion": "1.5.39", + "currentVersion": "1.5.40", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/Netmiko/Integrations/Netmiko/Netmiko.yml b/Packs/Netmiko/Integrations/Netmiko/Netmiko.yml index 9f94fdd14982..ac5daecc550d 100644 --- a/Packs/Netmiko/Integrations/Netmiko/Netmiko.yml +++ b/Packs/Netmiko/Integrations/Netmiko/Netmiko.yml @@ -461,7 +461,7 @@ script: - contextPath: Netmiko.Output description: The results of the command. type: string - dockerimage: demisto/netmiko:1.0.0.113064 + dockerimage: demisto/netmiko:1.0.0.114712 script: "" subtype: python3 type: python diff --git a/Packs/Netmiko/ReleaseNotes/1_0_17.md b/Packs/Netmiko/ReleaseNotes/1_0_17.md new file mode 100644 index 000000000000..179561bc84bf --- /dev/null +++ b/Packs/Netmiko/ReleaseNotes/1_0_17.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Netmiko + +- Updated the Docker image to: *demisto/netmiko:1.0.0.114712*. diff --git a/Packs/Netmiko/pack_metadata.json b/Packs/Netmiko/pack_metadata.json index 613d68eeff33..e8ae3b0891b4 100644 --- a/Packs/Netmiko/pack_metadata.json +++ b/Packs/Netmiko/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Netmiko", "description": "The Netmiko pack uses the Netmiko/Paramiko libraries to execute commands via SSH on platforms supported by these python modules.", "support": "xsoar", - "currentVersion": "1.0.16", + "currentVersion": "1.0.17", "author": "Josh Levine", "url": "", "email": "", diff --git a/Packs/Okta/Integrations/Okta_v2/Okta_v2.py b/Packs/Okta/Integrations/Okta_v2/Okta_v2.py index 5520723a18be..bb50b8c68be8 100644 --- a/Packs/Okta/Integrations/Okta_v2/Okta_v2.py +++ b/Packs/Okta/Integrations/Okta_v2/Okta_v2.py @@ -1432,6 +1432,7 @@ def main(): scopes=OAUTH_TOKEN_SCOPES, private_key=params.get('private_key'), jwt_algorithm=JWTAlgorithm(params['jwt_algorithm']) if params.get('jwt_algorithm') else None, + key_id=params.get('key_id', None), ) if command in commands: diff --git a/Packs/Okta/Integrations/Okta_v2/Okta_v2.yml b/Packs/Okta/Integrations/Okta_v2/Okta_v2.yml index c85c23010816..4384db9122be 100644 --- a/Packs/Okta/Integrations/Okta_v2/Okta_v2.yml +++ b/Packs/Okta/Integrations/Okta_v2/Okta_v2.yml @@ -56,6 +56,12 @@ configuration: - ES384 - ES512 defaultvalue: RS256 +- display: Key ID + name: key_id + type: 0 + section: Connect + required: false + additionalinfo: Required and used if more than one key is used for signing JWT tokens. - display: Trust any certificate (not secure) name: insecure type: 8 diff --git a/Packs/Okta/Integrations/Okta_v2/README.md b/Packs/Okta/Integrations/Okta_v2/README.md index 077af0ccf200..f72e29ab59ef 100644 --- a/Packs/Okta/Integrations/Okta_v2/README.md +++ b/Packs/Okta/Integrations/Okta_v2/README.md @@ -9,6 +9,8 @@ Integration with Okta's cloud-based identity management service. #### Notes - API tokens have the same permissions as the user who creates them, and if the permissions of a user change, so do the permissions of the API token. +- If more than one certificate is assigned to the application, the Key ID parameter is required to specify which + certificate to use for signing the JWT token. For more information, see the '[Create an API token](https://developer.okta.com/docs/guides/create-an-api-token/main/)' official documentation article. @@ -53,16 +55,17 @@ For more information, see the '[Implement OAuth for Okta](https://developer.okta 2. Search for Okta v2. 3. Click **Add instance** to create and configure a new integration instance. - | **Parameter** | **Description** | **Required** | - | --- | --- | --- | - | Okta URL (https://<domain>.okta.com) | | True | - | API Token | | False | - | Use OAuth 2.0 Authentication | See detailed instructions on the 'Help' tab. | False | - | Client ID | Required and used if OAuth 2.0 is used for authentication. See detailed instructions on the 'Help' tab. | False | - | Private Key | In PEM format. Required and used if OAuth 2.0 is used for authentication. See detailed instructions on the 'Help' tab. | False | - | JWT Signing Algorithm | Algorithm to sign generated JWT tokens with. Doesn't affect integration's functionality. Required and used if OAuth 2.0 is used for authentication. See detailed instructions on the 'Help' tab. | False | - | Trust any certificate (not secure) | | False | - | Use system proxy settings | | False | + | **Parameter** | **Description** | **Required** | + |--------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------| + | Okta URL (https://<domain>.okta.com) | | True | + | API Token | | False | + | Use OAuth 2.0 Authentication | See detailed instructions on the 'Help' tab. | False | + | Client ID | Required and used if OAuth 2.0 is used for authentication. See detailed instructions on the 'Help' tab. | False | + | Private Key | In PEM format. Required and used if OAuth 2.0 is used for authentication. See detailed instructions on the 'Help' tab. | False | + | JWT Signing Algorithm | Algorithm to sign generated JWT tokens with. Doesn't affect integration's functionality. Required and used if OAuth 2.0 is used for authentication. See detailed instructions on the 'Help' tab. | False | + | Key ID | Required and used if more than one key is used for signing JWT tokens. | False | + | Trust any certificate (not secure) | | False | + | Use system proxy settings | | False | 4. Click **Test** to validate the URLs, token, and connection. diff --git a/Packs/Okta/ReleaseNotes/3_3_4.md b/Packs/Okta/ReleaseNotes/3_3_4.md new file mode 100644 index 000000000000..a1155afc12fc --- /dev/null +++ b/Packs/Okta/ReleaseNotes/3_3_4.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Okta v2 + +- Added the Key ID parameter for environments configured with multiple authentication keys. diff --git a/Packs/Okta/pack_metadata.json b/Packs/Okta/pack_metadata.json index a957ca6b55ae..28b7792daa0b 100644 --- a/Packs/Okta/pack_metadata.json +++ b/Packs/Okta/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Okta", "description": "Integration with Okta's cloud-based identity management service.", "support": "xsoar", - "currentVersion": "3.3.3", + "currentVersion": "3.3.4", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/Palo_Alto_Networks_WildFire/Playbooks/WildFire_-_Detonate_file_v2.yml b/Packs/Palo_Alto_Networks_WildFire/Playbooks/WildFire_-_Detonate_file_v2.yml index 937c088f45b9..862b6ec51521 100644 --- a/Packs/Palo_Alto_Networks_WildFire/Playbooks/WildFire_-_Detonate_file_v2.yml +++ b/Packs/Palo_Alto_Networks_WildFire/Playbooks/WildFire_-_Detonate_file_v2.yml @@ -440,13 +440,13 @@ inputs: playbookInputQuery: - key: Interval value: - simple: "1" + simple: "60" required: false description: The duration for executing the polling (in seconds). playbookInputQuery: - key: Timeout value: - simple: "8" + simple: "480" required: false description: The duration after which to stop polling and to resume the playbook. (in seconds) playbookInputQuery: diff --git a/Packs/Palo_Alto_Networks_WildFire/ReleaseNotes/2_1_51.md b/Packs/Palo_Alto_Networks_WildFire/ReleaseNotes/2_1_51.md new file mode 100644 index 000000000000..8b0b7b1d6cdb --- /dev/null +++ b/Packs/Palo_Alto_Networks_WildFire/ReleaseNotes/2_1_51.md @@ -0,0 +1,6 @@ + +#### Playbooks + +##### WildFire - Detonate file v2 + +- Changed the default values of the playbook inputs *Interval*, *Timeout* from minutes to equivalent seconds. diff --git a/Packs/Palo_Alto_Networks_WildFire/pack_metadata.json b/Packs/Palo_Alto_Networks_WildFire/pack_metadata.json index 299579d72fe0..f0eee6d1090c 100644 --- a/Packs/Palo_Alto_Networks_WildFire/pack_metadata.json +++ b/Packs/Palo_Alto_Networks_WildFire/pack_metadata.json @@ -2,7 +2,7 @@ "name": "WildFire by Palo Alto Networks", "description": "Perform malware dynamic analysis", "support": "xsoar", - "currentVersion": "2.1.50", + "currentVersion": "2.1.51", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/PrismaAccess/Integrations/PrismaAccess/PrismaAccess.py b/Packs/PrismaAccess/Integrations/PrismaAccess/PrismaAccess.py index 1c0b28e7f3b4..ec2f2fc336c4 100644 --- a/Packs/PrismaAccess/Integrations/PrismaAccess/PrismaAccess.py +++ b/Packs/PrismaAccess/Integrations/PrismaAccess/PrismaAccess.py @@ -3,7 +3,7 @@ import json import sys from base64 import b64encode -from typing import Any, Dict +from typing import Any import requests @@ -49,7 +49,7 @@ def panos_connect(net_connect: Netmiko = None): def panos_ssh(cmd: str, net_connect: Netmiko = None): - result_cmd = str() + result_cmd = '' if sshConfigured: """ Run any command @@ -93,7 +93,7 @@ def prisma_access_cli_command(): def prisma_access_query(): query = demisto.args().get('query') - cmd = 'debug plugins cloud_services gpcs query {}'.format(query) + cmd = f'debug plugins cloud_services gpcs query {query}' sshRes = panos_ssh(cmd) jsonStartPos = sshRes.find('{"@status') if jsonStartPos < 0: @@ -113,7 +113,7 @@ def prisma_access_query(): def prisma_access_active_users(): limit = demisto.args().get('limit', 20) - cmd = 'debug plugins cloud_services gpcs query querystring limit={} action getGPaaSActiveUsers'.format(limit) + cmd = f'debug plugins cloud_services gpcs query querystring limit={limit} action getGPaaSActiveUsers' sshRes = panos_ssh(cmd) jsonStartPos = sshRes.find('{"@status') if jsonStartPos < 0: @@ -220,8 +220,8 @@ class PAN_OS_Not_Found(Exception): """ PAN-OS Error. """ -def http_request(uri: str, method: str, headers: Dict = {}, - body: Dict = {}, params: Dict = {}, files=None) -> Any: +def http_request(uri: str, method: str, headers: dict = {}, + body: dict = {}, params: dict = {}, files=None) -> Any: """ Makes an API call with the given arguments """ @@ -392,19 +392,19 @@ def device_group_test(): @logger -def prisma_access_logout_user(computer: str, domain: str, user: str, tenant: str) -> Dict[str, str]: +def prisma_access_logout_user(computer: str, domain: str, user: str, tenant: str) -> dict[str, str]: if apiConfigured: xmlComputer = '%s' % b64encode(computer.encode('utf8')).decode('utf8') if computer else '' b64User = (b64encode(user.encode('utf8'))).decode('utf8') cmd = '' if domain: cmd = ''' - %s%s%s - ''' % (xmlComputer, domain, b64User) + {}{}{} + '''.format(xmlComputer, domain, b64User) else: cmd = ''' - %s%s - ''' % (xmlComputer, b64User) + {}{} + '''.format(xmlComputer, b64User) if tenant: tenant_entry = f"" diff --git a/Packs/PrismaAccess/Integrations/PrismaAccess/PrismaAccess.yml b/Packs/PrismaAccess/Integrations/PrismaAccess/PrismaAccess.yml index 3fba607d0ddc..1679275e2c3d 100644 --- a/Packs/PrismaAccess/Integrations/PrismaAccess/PrismaAccess.yml +++ b/Packs/PrismaAccess/Integrations/PrismaAccess/PrismaAccess.yml @@ -99,7 +99,7 @@ script: description: Active Users on Prisma Access description: Query currently active users. deprecated: true - dockerimage: demisto/netmiko:1.0.0.113064 + dockerimage: demisto/netmiko:1.0.0.114712 subtype: python3 fromversion: 5.0.0 tests: diff --git a/Packs/PrismaAccess/ReleaseNotes/2_1_10.md b/Packs/PrismaAccess/ReleaseNotes/2_1_10.md new file mode 100644 index 000000000000..dab99866cc10 --- /dev/null +++ b/Packs/PrismaAccess/ReleaseNotes/2_1_10.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Prisma Access + +- Updated the Docker image to: *demisto/netmiko:1.0.0.114712*. diff --git a/Packs/PrismaAccess/pack_metadata.json b/Packs/PrismaAccess/pack_metadata.json index e4eb0bc5777a..88c2b1b6c5db 100644 --- a/Packs/PrismaAccess/pack_metadata.json +++ b/Packs/PrismaAccess/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Palo Alto Networks - Strata Cloud Manager", "description": "Integrate with Palo Alto Networks Prisma SASE to query activity and take actions.", "support": "xsoar", - "currentVersion": "2.1.9", + "currentVersion": "2.1.10", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/PrismaCloud/Integrations/PrismaCloudV2/PrismaCloudV2.py b/Packs/PrismaCloud/Integrations/PrismaCloudV2/PrismaCloudV2.py index 13f36d01b428..0c1893c866a1 100644 --- a/Packs/PrismaCloud/Integrations/PrismaCloudV2/PrismaCloudV2.py +++ b/Packs/PrismaCloud/Integrations/PrismaCloudV2/PrismaCloudV2.py @@ -286,7 +286,7 @@ def config_search_request(self, time_range: Dict[str, Any], query: str, limit: O 'sort': [{'direction': sort_direction, 'field': sort_field}], 'timeRange': time_range, 'withResourceJson': include_resource_json, - 'HeuristicSearch': 'true' + 'heuristicSearch': 'true' }) return self._http_request('POST', 'search/config', json_data=data) diff --git a/Packs/PrismaCloud/Integrations/PrismaCloudV2/PrismaCloudV2_test.py b/Packs/PrismaCloud/Integrations/PrismaCloudV2/PrismaCloudV2_test.py index a271de511475..a19a5864b7cd 100644 --- a/Packs/PrismaCloud/Integrations/PrismaCloudV2/PrismaCloudV2_test.py +++ b/Packs/PrismaCloud/Integrations/PrismaCloudV2/PrismaCloudV2_test.py @@ -253,7 +253,7 @@ def test_config_search_command(mocker, prisma_cloud_v2_client): 'sort': [{'direction': 'desc', 'field': 'insertTs'}], 'timeRange': {'type': 'to_now', 'value': 'epoch'}, 'withResourceJson': 'true', - 'HeuristicSearch': 'true' + 'heuristicSearch': 'true' }) diff --git a/Packs/PrismaCloud/ReleaseNotes/4_3_14.md b/Packs/PrismaCloud/ReleaseNotes/4_3_14.md new file mode 100644 index 000000000000..84ea47045f49 --- /dev/null +++ b/Packs/PrismaCloud/ReleaseNotes/4_3_14.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Prisma Cloud v2 + +Fixed an issue where the ***prisma-cloud-config-search*** command occasionally failed due to intermittent timeouts. diff --git a/Packs/PrismaCloud/pack_metadata.json b/Packs/PrismaCloud/pack_metadata.json index 92096d84d6cb..f2cea4bb541f 100644 --- a/Packs/PrismaCloud/pack_metadata.json +++ b/Packs/PrismaCloud/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Prisma Cloud by Palo Alto Networks", "description": "Automate and unify security incident response across your cloud environments, while still giving a degree of control to dedicated cloud teams.", "support": "xsoar", - "currentVersion": "4.3.13", + "currentVersion": "4.3.14", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/ProofpointEmailSecurity/Integrations/ProofpointEmailSecurityEventCollector/ProofpointEmailSecurityEventCollector.py b/Packs/ProofpointEmailSecurity/Integrations/ProofpointEmailSecurityEventCollector/ProofpointEmailSecurityEventCollector.py index 18e8eece6413..a40fbcdf6401 100644 --- a/Packs/ProofpointEmailSecurity/Integrations/ProofpointEmailSecurityEventCollector/ProofpointEmailSecurityEventCollector.py +++ b/Packs/ProofpointEmailSecurity/Integrations/ProofpointEmailSecurityEventCollector/ProofpointEmailSecurityEventCollector.py @@ -1,5 +1,9 @@ -from contextlib import contextmanager +from contextlib import ExitStack, contextmanager from enum import Enum +from functools import partial +import threading + +from websockets import Data from CommonServerPython import * # noqa: F401 from websockets.sync.client import connect from websockets.sync.connection import Connection @@ -16,11 +20,48 @@ FETCH_INTERVAL_IN_SECONDS = 60 FETCH_SLEEP = 5 +SERVER_IDLE_TIMEOUT = 300 class EventType(str, Enum): - MESSAGE = "message" - MAILLOG = "maillog" + MESSAGE = 'message' + MAILLOG = 'maillog' + AUDIT = 'audit' + + +class EventConnection: + def __init__(self, event_type: EventType, connection: Connection, fetch_interval: int = FETCH_INTERVAL_IN_SECONDS, + idle_timeout: int = SERVER_IDLE_TIMEOUT - 20): + self.event_type = event_type + self.connection = connection + self.lock = threading.Lock() + self.idle_timeout = idle_timeout + self.fetch_interval = fetch_interval + + def recv(self, timeout: float | None = None) -> Data: + """ + Receive the next message from the connection + + Args: + timeout (float): Block until timeout seconds have elapsed or a message is received. If None, waits indefinitely. + If timeout passes, raises TimeoutError + + Returns: + Data: Next event received from the connection + """ + with self.lock: + event = self.connection.recv(timeout=timeout) + return event + + def heartbeat(self): + """ + Heartbeat thread function to periodically send keep-alives to the server. + For the sake of simplicity and error prevention, keep-alives are sent regardless of the actual connection activity. + """ + while True: + with self.lock: + self.connection.pong() + time.sleep(self.idle_timeout) def is_interval_passed(fetch_start_time: datetime, fetch_interval: int) -> bool: @@ -38,8 +79,22 @@ def is_interval_passed(fetch_start_time: datetime, fetch_interval: int) -> bool: @contextmanager def websocket_connections( - host: str, cluster_id: str, api_key: str, since_time: str | None = None, to_time: str | None = None -): + host: str, cluster_id: str, api_key: str, since_time: str | None = None, to_time: str | None = None, + fetch_interval: int = FETCH_INTERVAL_IN_SECONDS): + """ + Create a connection for every type of event. + + Args: + host (str): host URL for the websocket connection. + cluster_id (str): Proofpoint cluster ID to connect to. + api_key (str): Proofpoint API key. + since_time (str): Start time to fetch events from. + to_time (str): End time for fetch, leave empty for real-time streaming. + fetch_interval (int): Time between fetch iterations, used for estimating message receive times for idle heartbeat. + + Yields: + list[EventConnection]: List containing an eventConnection for every event type + """ demisto.info( f"Starting websocket connection to {host} with cluster id: {cluster_id}, sinceTime: {since_time}, toTime: {to_time}") url = URL @@ -47,30 +102,33 @@ def websocket_connections( since_time = datetime.utcnow().isoformat() if to_time: url += f"&toTime={to_time}" + url = partial(url.format, host=host, cluster_id=cluster_id, time=since_time) extra_headers = {"Authorization": f"Bearer {api_key}"} - with connect( - url.format(host=host, cluster_id=cluster_id, type=EventType.MESSAGE.value, time=since_time), - additional_headers=extra_headers, - ) as message_connection, connect( - url.format(host=host, cluster_id=cluster_id, type=EventType.MAILLOG.value, time=since_time), - additional_headers=extra_headers, - ) as maillog_connection: - yield message_connection, maillog_connection + with ExitStack() as stack: # Keep connection contexts for clean up + connections = [EventConnection( + event_type=event_type, + connection=stack.enter_context(connect(url(type=event_type.value), additional_headers=extra_headers)), + fetch_interval=fetch_interval, + ) for event_type in EventType] -def fetch_events(event_type: EventType, connection: Connection, fetch_interval: int, recv_timeout: int = 10) -> list[dict]: + yield connections + + +def fetch_events(connection: EventConnection, fetch_interval: int, recv_timeout: int = 10) -> list[dict]: """ - This function fetches events from the websocket connection for the given event type, for the given fetch interval + This function fetches events from the given connection, for the given fetch interval Args: - event_type (EventType): The event type to fetch (MAILLOG, MESSAGE) - connection (Connection): the websocket connection to the event type - fetch_interval (int): the interval of events to fetch, in seconds + connection (EventConnection): the connection to the event type + fetch_interval (int): Total time to keep fetching before stopping recv_timeout (int): The timeout for the receive function in the socket connection Returns: list[dict]: A list of events """ + event_type = connection.event_type + demisto.debug(f'Starting to fetch events of type {event_type.value}') events: list[dict] = [] event_ids = set() fetch_start_time = datetime.utcnow() @@ -106,43 +164,66 @@ def test_module(host: str, cluster_id: str, api_key: str): fetch_interval = 2 recv_timeout = 2 try: - with websocket_connections(host, cluster_id, api_key) as (message_connection, maillog_connection): - fetch_events(EventType.MESSAGE, message_connection, fetch_interval, recv_timeout) - fetch_events(EventType.MAILLOG, maillog_connection, fetch_interval, recv_timeout) + with websocket_connections(host, cluster_id, api_key) as connections: + for connection in connections: + fetch_events(connection, fetch_interval, recv_timeout) return "ok" except InvalidStatus as e: if e.response.status_code == 401: return_error("Authentication failed. Please check the Cluster ID and API key.") -def perform_long_running_loop(message_connection: Connection, maillog_connection: Connection, fetch_interval: int): - message_events = fetch_events(EventType.MESSAGE, message_connection, fetch_interval) - maillog_events = fetch_events(EventType.MAILLOG, maillog_connection, fetch_interval) - # Send the events to the XSIAM, with events from the context - integration_context = demisto.getIntegrationContext() - message_events_from_context = integration_context.get("message_events", []) - message_maillog_from_context = integration_context.get("maillog_events", []) +def perform_long_running_loop(connections: list[EventConnection], fetch_interval: int): + """ + Long running loop iteration function. Fetches events from each connection and sends them to XSIAM. - message_events.extend(message_events_from_context) - maillog_events.extend(message_maillog_from_context) - demisto.info(f"Adding {len(message_events)} Message Events, and {len(maillog_events)} MailLog Events to XSIAM") + Args: + connections (list[EventConnection]): List of connection objects to fetch events from. + fetch_interval (int): Fetch time per cycle allocated for each event type in seconds. + """ + integration_context = demisto.getIntegrationContext() + events_to_send = [] + for connection in connections: + events = fetch_events(connection, fetch_interval) + events.extend(integration_context.get(connection.event_type.value, [])) + integration_context[connection.event_type.value] = events # update events in context in case of fail + demisto.debug(f'Adding {len(events)} {connection.event_type.value} Events to XSIAM') + events_to_send.extend(events) + # Send the events to the XSIAM, with events from the context try: - send_events_to_xsiam(message_events + maillog_events, vendor=VENDOR, product=PRODUCT) + send_events_to_xsiam(events_to_send, vendor=VENDOR, product=PRODUCT) # clear the context after sending the events demisto.setIntegrationContext({}) except DemistoException: - demisto.error(f"Failed to send events to XSOAR. Error: {traceback.format_exc()}") + demisto.error(f"Failed to send events to XSIAM. Error: {traceback.format_exc()}") # save the events to the context so we can send them again in the next execution - demisto.setIntegrationContext({"message_events": message_events, "maillog_events": maillog_events}) + demisto.setIntegrationContext(integration_context) def long_running_execution_command(host: str, cluster_id: str, api_key: str, fetch_interval: int): - fetch_interval = max(1, fetch_interval // len(EventType)) - with websocket_connections(host, cluster_id, api_key) as (message_connection, maillog_connection): + """ + Performs the long running execution loop. + Opens a connection to Proofpoints for every event type and fetches events in a loop. + Heartbeat threads are opened for every connection to send keepalives if the connection is idle for too long. + + Args: + host (str): host URL for the websocket connection. + cluster_id (str): Proofpoint cluster ID to connect to. + api_key (str): Proofpoint API key. + fetch_interval (int): Total time allocated per fetch cycle. + """ + with websocket_connections(host, cluster_id, api_key, fetch_interval=fetch_interval) as connections: demisto.info("Connected to websocket") + fetch_interval = max(1, fetch_interval // len(EventType)) # Divide the fetch interval equally among all event types + + # The Proofpoint server will close connections if they are idle for 5 minutes + # Setting up heartbeat daemon threads to send keep-alives if needed + for connection in connections: + threading.Thread(target=connection.heartbeat, daemon=True).start() + while True: - perform_long_running_loop(message_connection, maillog_connection, fetch_interval) + perform_long_running_loop(connections, fetch_interval) # sleep for a bit to not throttle the CPU time.sleep(FETCH_SLEEP) diff --git a/Packs/ProofpointEmailSecurity/Integrations/ProofpointEmailSecurityEventCollector/ProofpointEmailSecurityEventCollector_test.py b/Packs/ProofpointEmailSecurity/Integrations/ProofpointEmailSecurityEventCollector/ProofpointEmailSecurityEventCollector_test.py index 6ab0b8cdbfc1..53c77fdc559f 100644 --- a/Packs/ProofpointEmailSecurity/Integrations/ProofpointEmailSecurityEventCollector/ProofpointEmailSecurityEventCollector_test.py +++ b/Packs/ProofpointEmailSecurity/Integrations/ProofpointEmailSecurityEventCollector/ProofpointEmailSecurityEventCollector_test.py @@ -1,3 +1,4 @@ +from contextlib import ExitStack, contextmanager import uuid import pytest from ProofpointEmailSecurityEventCollector import ( @@ -10,7 +11,9 @@ websocket_connections, perform_long_running_loop, DemistoException, - Connection + Connection, + EventConnection, + long_running_execution_command, ) import ProofpointEmailSecurityEventCollector from freezegun import freeze_time @@ -37,7 +40,7 @@ def connection(): return MockConnection() -class MockConnection: +class MockConnection(Connection): def __init__( self, ): @@ -45,6 +48,8 @@ def __init__( self.id = uuid.uuid4() self.events = EVENTS self.index = 0 + self.pongs = 0 + self.create_time = datetime.now() def recv(self, timeout): global CURRENT_TIME @@ -58,6 +63,9 @@ def recv(self, timeout): self.index += 1 return json.dumps(event) + def pong(self): + self.pongs += 1 + def test_fetch_events(mocker, connection): """ @@ -75,9 +83,10 @@ def test_fetch_events(mocker, connection): # We set fetch_interval to 7 to get this first two events (as we "wait" 4 seconds between each event) fetch_interval = 7 + event_connection = EventConnection(event_type=EventType.MESSAGE, connection=connection) mocker.patch.object(ProofpointEmailSecurityEventCollector, "is_interval_passed", side_effect=is_interval_passed) debug_logs = mocker.patch.object(demisto, "debug") - events = fetch_events(event_type=EventType.MESSAGE, connection=connection, fetch_interval=fetch_interval) + events = fetch_events(connection=event_connection, fetch_interval=fetch_interval) assert len(events) == 2 assert events[0]["message"] == "Test message 1" @@ -87,19 +96,19 @@ def test_fetch_events(mocker, connection): assert events[1]["_time"] == "2023-08-14T11:24:12.147573+00:00" assert events[1]["event_type"] == "message" - assert debug_logs.call_args_list[0][0][0] == "Fetched 2 events of type message" - assert debug_logs.call_args_list[1][0][0] == "The fetched events ids are: 1, 2" + debug_logs.assert_any_call("Fetched 2 events of type message") + debug_logs.assert_any_call("The fetched events ids are: 1, 2") # Now we want to freeze the time, so we will get the next interval with freeze_time(CURRENT_TIME): debug_logs = mocker.patch.object(demisto, "debug") - events = fetch_events(event_type=EventType.MESSAGE, connection=connection, fetch_interval=fetch_interval) + events = fetch_events(connection=event_connection, fetch_interval=fetch_interval) assert len(events) == 1 assert events[0]["message"] == "Test message 3" assert events[0]["_time"] == "2023-08-12T13:24:11.147573+00:00" assert events[0]["event_type"] == "message" - assert debug_logs.call_args_list[0][0][0] == "Fetched 1 events of type message" - assert debug_logs.call_args_list[1][0][0] == "The fetched events ids are: 3" + debug_logs.assert_any_call("Fetched 1 events of type message") + debug_logs.assert_any_call("The fetched events ids are: 3") @freeze_time("2023-08-16T13:24:12.147573+0100") @@ -118,38 +127,29 @@ def test_connects_to_websocket(mocker): connect_mock = mocker.patch.object(ProofpointEmailSecurityEventCollector, "connect") # Call the websocket_connections function without since_time and to_time - with websocket_connections("wss://host", "cluster_id", "api_key") as (message_connection, maillog_connection): + with websocket_connections("wss://host", "cluster_id", "api_key"): pass - assert connect_mock.call_count == 2 - assert ( - connect_mock.call_args_list[0][0][0] - == "wss://host/v1/stream?cid=cluster_id&type=message&sinceTime=2023-08-16T12:24:12.147573" - ) - assert ( - connect_mock.call_args_list[1][0][0] - == "wss://host/v1/stream?cid=cluster_id&type=maillog&sinceTime=2023-08-16T12:24:12.147573" - ) - assert connect_mock.call_args_list[0][1]["additional_headers"]["Authorization"] == "Bearer api_key" - assert connect_mock.call_args_list[1][1]["additional_headers"]["Authorization"] == "Bearer api_key" + assert connect_mock.call_count == len(EventType) + for event_type in EventType: + connect_mock.assert_any_call( + f'wss://host/v1/stream?cid=cluster_id&type={event_type.value}&sinceTime=2023-08-16T12:24:12.147573', + additional_headers={'Authorization': 'Bearer api_key'} + ) connect_mock = mocker.patch.object(ProofpointEmailSecurityEventCollector, "connect") # Call the websocket_connections function with since_time and to_time - with websocket_connections( - "wss://host", "cluster_id", "api_key", since_time="2023-08-14T12:24:12.147573", to_time="2023-08-16T12:24:12.147573" - ) as (message_connection, maillog_connection): + with websocket_connections("wss://host", "cluster_id", "api_key", since_time="2023-08-14T12:24:12.147573", + to_time="2023-08-16T12:24:12.147573"): pass - assert connect_mock.call_count == 2 - assert ( - connect_mock.call_args_list[0][0][0] - == "wss://host/v1/stream?cid=cluster_id&type=message&sinceTime=2023-08-14T12:24:12.147573&toTime=2023-08-16T12:24:12.147573" # noqa: E501 - ) - assert ( - connect_mock.call_args_list[1][0][0] - == "wss://host/v1/stream?cid=cluster_id&type=maillog&sinceTime=2023-08-14T12:24:12.147573&toTime=2023-08-16T12:24:12.147573" # noqa: E501 - ) + assert connect_mock.call_count == len(EventType) + for event_type in EventType: + connect_mock.assert_any_call( + f'wss://host/v1/stream?cid=cluster_id&type={event_type.value}&sinceTime=2023-08-14T12:24:12.147573&toTime=2023-08-16T12:24:12.147573', + additional_headers={'Authorization': 'Bearer api_key'} + ) def test_handle_failures_of_send_events(mocker, capfd): @@ -163,8 +163,8 @@ def test_handle_failures_of_send_events(mocker, capfd): Then: - Add the failing events to the context, and try again in the next run. """ - def fetch_events_mock(event_type: EventType, connection: Connection, fetch_interval: int): - if event_type == EventType.MESSAGE: + def fetch_events_mock(connection: EventConnection, fetch_interval: int): + if connection.event_type == EventType.MESSAGE: return EVENTS[:2] return EVENTS[2:] @@ -174,17 +174,59 @@ def sends_events_to_xsiam_mock(events, **kwargs): mocker.patch.object(ProofpointEmailSecurityEventCollector, "fetch_events", side_effect=fetch_events_mock) mocker.patch.object(ProofpointEmailSecurityEventCollector, "send_events_to_xsiam", side_effect=sends_events_to_xsiam_mock) with capfd.disabled(): - perform_long_running_loop(MockConnection(), MockConnection(), 60) + perform_long_running_loop([EventConnection(EventType.MESSAGE, MockConnection()), + EventConnection(EventType.MAILLOG, MockConnection())], 60) context = demisto.getIntegrationContext() - assert context["message_events"] == EVENTS[:2] - assert context["maillog_events"] == EVENTS[2:] + assert context[EventType.MESSAGE] == EVENTS[:2] + assert context[EventType.MAILLOG] == EVENTS[2:] second_try_send_events_mock = mocker.patch.object(ProofpointEmailSecurityEventCollector, "send_events_to_xsiam") with capfd.disabled(): - perform_long_running_loop(MockConnection(), MockConnection(), 60) + perform_long_running_loop([EventConnection(EventType.MESSAGE, MockConnection()), + EventConnection(EventType.MAILLOG, MockConnection())], 60) context = demisto.getIntegrationContext() # check the the context is cleared assert not context # check that the events failed events were sent to xsiam for event in EVENTS: assert event in second_try_send_events_mock.call_args_list[0][0][0] + + +def test_heartbeat(mocker, connection): + """ + Given: + - A connection object with scarce messages + + When: + - The long running execution loop runs + + Then: + - Periodic keep-alive messages (pongs) are sent to the websocket connection to prevent it from closing. + + """ + idle_timeout = 3 + + @contextmanager + def mock_websocket_connections(host, cluster_id, api_key, since_time=None, to_time=None, fetch_interval=60): + with ExitStack(): + yield [EventConnection(EventType.AUDIT, connection, fetch_interval, idle_timeout)] + + def mock_perform_long_running_loop(connections, interval): + # This mock will raise exceptions to stop the long running loop + # StopIteration exception marks success + connection = connections[0].connection + if connection.pongs: + raise StopIteration(f'Sent {connections[0].connection.pongs} pongs') + if datetime.now() > connection.create_time + timedelta(seconds=idle_timeout + 2): + # Heartbeat should've been sent already + raise TimeoutError(f'No heartbeat sent within {idle_timeout} seconds') + + mocker.patch.object(ProofpointEmailSecurityEventCollector, 'websocket_connections', + side_effect=mock_websocket_connections) + mocker.patch.object(ProofpointEmailSecurityEventCollector, 'perform_long_running_loop', + side_effect=mock_perform_long_running_loop) + + with pytest.raises(StopIteration): + long_running_execution_command('host', 'cid', 'key', 60) + + assert connection.pongs > 0 diff --git a/Packs/ProofpointEmailSecurity/README.md b/Packs/ProofpointEmailSecurity/README.md index 4607311b0631..6132063664db 100644 --- a/Packs/ProofpointEmailSecurity/README.md +++ b/Packs/ProofpointEmailSecurity/README.md @@ -7,5 +7,6 @@ Proofpoint Email Protection is the industry-leading email gateway, which can be This pack gathers and structures logs of the types listed below: 1. Maillog 2. Message +3. Audit \ No newline at end of file diff --git a/Packs/ProofpointEmailSecurity/ReleaseNotes/1_0_4.md b/Packs/ProofpointEmailSecurity/ReleaseNotes/1_0_4.md new file mode 100644 index 000000000000..ae72049a5810 --- /dev/null +++ b/Packs/ProofpointEmailSecurity/ReleaseNotes/1_0_4.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Proofpoint Email Security Event Collector + +- Added support for audit event collection. diff --git a/Packs/ProofpointEmailSecurity/pack_metadata.json b/Packs/ProofpointEmailSecurity/pack_metadata.json index 4075ec4d3a71..eabd00c6c7c9 100644 --- a/Packs/ProofpointEmailSecurity/pack_metadata.json +++ b/Packs/ProofpointEmailSecurity/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Proofpoint Email Security", "description": "Proofpoint Email Security pack provides visibility into email security threats and protects your organization from phishing, malware, and compliance risks.", "support": "xsoar", - "currentVersion": "1.0.3", + "currentVersion": "1.0.4", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/QRCodeReader/ReleaseNotes/1_0_7.md b/Packs/QRCodeReader/ReleaseNotes/1_0_7.md new file mode 100644 index 000000000000..9af9d04854f1 --- /dev/null +++ b/Packs/QRCodeReader/ReleaseNotes/1_0_7.md @@ -0,0 +1,6 @@ + +#### Scripts + +##### qrcodereader + +- Updated the Docker image to: *demisto/opencv:1.0.0.114711*. diff --git a/Packs/QRCodeReader/Scripts/Qrcodereader/Qrcodereader.yml b/Packs/QRCodeReader/Scripts/Qrcodereader/Qrcodereader.yml index 6829d6cb9ae2..723c46a07aa0 100644 --- a/Packs/QRCodeReader/Scripts/Qrcodereader/Qrcodereader.yml +++ b/Packs/QRCodeReader/Scripts/Qrcodereader/Qrcodereader.yml @@ -9,7 +9,7 @@ commonfields: contentitemexportablefields: contentitemfields: fromServerVersion: "" -dockerimage: demisto/opencv:1.0.0.82635 +dockerimage: demisto/opencv:1.0.0.114711 enabled: true name: qrcodereader outputs: diff --git a/Packs/QRCodeReader/pack_metadata.json b/Packs/QRCodeReader/pack_metadata.json index 7cc3f74c1e2d..2db1b5014242 100644 --- a/Packs/QRCodeReader/pack_metadata.json +++ b/Packs/QRCodeReader/pack_metadata.json @@ -2,7 +2,7 @@ "name": "QR Code Reader", "description": "Pack contains an integration with api.qrserver.com to read QR codes from uploaded image files.", "support": "community", - "currentVersion": "1.0.6", + "currentVersion": "1.0.7", "author": "vibhuabharadwaj", "url": "", "email": "", diff --git a/Packs/QRadar/Playbooks/playbook-QRadar_Generic.yml b/Packs/QRadar/Playbooks/playbook-QRadar_Generic.yml index 708a6ee7e1d2..2b2ce9643329 100644 --- a/Packs/QRadar/Playbooks/playbook-QRadar_Generic.yml +++ b/Packs/QRadar/Playbooks/playbook-QRadar_Generic.yml @@ -3,10 +3,7 @@ version: -1 contentitemexportablefields: contentitemfields: {} name: QRadar Generic -description: The QRadar Generic playbook is executed for the QRadar Generic incident - type. It performs all the common parts of the investigation, including - notifying the SOC, enriching data for indicators and users, calculating severity, - assigning incidents, and notifying the SIEM admin about false positives. +description: The QRadar Generic playbook is executed for the QRadar Generic incident type. It performs all the common parts of the investigation, including notifying the SOC, enriching data for indicators and users, calculating severity, assigning incidents, and notifying the SIEM admin about false positives. starttaskid: "0" tasks: "0": @@ -36,6 +33,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "1": id: "1" taskid: a04c8331-e7c5-4107-8605-b6ee82d4639d @@ -53,9 +53,6 @@ tasks: - "2" "yes": - "3" - scriptarguments: - left: {} - right: {} separatecontext: false conditions: - label: "yes" @@ -82,6 +79,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "2": id: "2" taskid: c74d18c6-9939-4701-828f-149cddba2b8d @@ -112,6 +112,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "3": id: "3" taskid: aca20665-33d5-4e20-866b-0b8f73cd90fc @@ -140,6 +143,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "7": id: "7" taskid: e3efbacf-f8e3-4291-8ab7-459037ce9a64 @@ -167,17 +173,19 @@ tasks: timertriggers: [] ignoreworker: false message: - to: null - subject: null - body: null + to: + subject: + body: methods: [] format: "" - bcc: null - cc: null + bcc: + cc: timings: retriescount: 2 retriesinterval: 360 completeafterreplies: 1 + completeafterv2: false + completeaftersla: false form: questions: - id: "0" @@ -201,6 +209,9 @@ tasks: totalanswers: 0 skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "8": id: "8" taskid: 4b1a5788-3cef-4857-8023-dcd01dfa8793 @@ -236,6 +247,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "9": id: "9" taskid: 354e53b0-0132-44d6-895e-0f6e0a248cd9 @@ -244,8 +258,7 @@ tasks: id: 354e53b0-0132-44d6-895e-0f6e0a248cd9 version: -1 name: Extract indicators from incident - description: Extracts all indicators from the incident and enriches the indicators - by using the reputation command defined for each indicator type. + description: Extracts all indicators from the incident and enriches the indicators by using the reputation command defined for each indicator type. script: Builtin|||extractIndicators type: regular iscommand: true @@ -271,6 +284,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "12": id: "12" taskid: de6f9320-320d-4bd6-820f-b612a7a0c2c7 @@ -296,6 +312,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "13": id: "13" taskid: fd2276ce-b8ca-43f2-8d91-1ad091484e27 @@ -364,6 +383,9 @@ tasks: ignoreworker: false skipunavailable: true quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "14": id: "14" taskid: 1b3aae31-8d82-401d-87cf-d0148d0b278b @@ -372,10 +394,10 @@ tasks: id: 1b3aae31-8d82-401d-87cf-d0148d0b278b version: -1 name: Was this a true positive? + description: "" type: condition iscommand: false brand: "" - description: '' nexttasks: False Positive: - "29" @@ -393,22 +415,27 @@ tasks: timertriggers: [] ignoreworker: false message: - to: null - subject: null - body: null + to: + subject: + body: methods: [] format: "" - bcc: null - cc: null + bcc: + cc: timings: retriescount: 2 retriesinterval: 360 completeafterreplies: 1 + completeafterv2: false + completeaftersla: false replyOptions: - "Yes" - "No" skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "15": id: "15" taskid: ff1b9850-ef10-4d42-80e3-39b72d8d01f8 @@ -445,6 +472,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "16": id: "16" taskid: b419c44d-1762-4553-8493-f9d7606af7bc @@ -453,10 +483,10 @@ tasks: id: b419c44d-1762-4553-8493-f9d7606af7bc version: -1 name: Use Calculate Severity? + description: "" type: condition iscommand: false brand: "" - description: '' nexttasks: '#default#': - "2" @@ -486,6 +516,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "17": id: "17" taskid: 670d8449-b528-465d-8b3f-6e22cda63229 @@ -494,10 +527,10 @@ tasks: id: 670d8449-b528-465d-8b3f-6e22cda63229 version: -1 name: Was the SOC email address provided? + description: "" type: condition iscommand: false brand: "" - description: '' nexttasks: '#default#': - "8" @@ -524,6 +557,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "18": id: "18" taskid: 355b3075-9035-4285-82b0-c4d63679b10c @@ -532,10 +568,10 @@ tasks: id: 355b3075-9035-4285-82b0-c4d63679b10c version: -1 name: Was the SIEM admin email address provided? + description: "" type: condition iscommand: false brand: "" - description: '' nexttasks: '#default#': - "15" @@ -562,6 +598,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "19": id: "19" taskid: 0c7b3033-c209-4a87-8ef5-63fbd907f68d @@ -597,6 +636,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "20": id: "20" taskid: 381f98db-b60a-4514-89d8-959cd9189cb3 @@ -625,6 +667,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "22": id: "22" taskid: 4dfa75fe-917f-4eed-894a-3f2dfda362fc @@ -636,8 +681,7 @@ tasks: type: collection iscommand: false brand: "" - description: 'Provide data to adjust the rule in order to avoid similar false - positives in the future.' + description: 'Provide data to adjust the rule in order to avoid similar false positives in the future.' nexttasks: '#none#': - "18" @@ -653,17 +697,19 @@ tasks: timertriggers: [] ignoreworker: false message: - to: null - subject: null - body: null + to: + subject: + body: methods: [] format: "" - bcc: null - cc: null + bcc: + cc: timings: retriescount: 2 retriesinterval: 360 completeafterreplies: 1 + completeafterv2: false + completeaftersla: false form: questions: - id: "0" @@ -737,6 +783,9 @@ tasks: totalanswers: 0 skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "25": id: "25" taskid: 8873fc30-eabd-4137-8f78-8ba80684a2a0 @@ -745,9 +794,7 @@ tasks: id: 8873fc30-eabd-4137-8f78-8ba80684a2a0 version: -1 name: Determine incident severity according to offense info - description: Sets the incident severity according to the FieldToSetSeverityFrom - and ScaleToSetSeverityFrom playbook inputs, which specify the relevant offense - field and the scale for the severity translation. + description: Sets the incident severity according to the FieldToSetSeverityFrom and ScaleToSetSeverityFrom playbook inputs, which specify the relevant offense field and the scale for the severity translation. script: Builtin|||setIncident type: regular iscommand: true @@ -782,6 +829,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "28": id: "28" taskid: 226309cb-824c-486f-8b8a-f977f03bba67 @@ -810,6 +860,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "29": id: "29" taskid: d8d79caa-94a4-4f02-8bda-d306a1357b34 @@ -842,6 +895,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "30": id: "30" taskid: 88147dfd-8093-46f6-8a63-5ef810b03328 @@ -871,6 +927,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "31": id: "31" taskid: e02854a2-f41b-444b-8953-067035e160ca @@ -900,6 +959,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "32": id: "32" taskid: b6008b80-dc3e-4381-8c5f-5ead8aa3debe @@ -929,6 +991,9 @@ tasks: ignoreworker: false skipunavailable: false quietmode: 0 + continueonerrortype: "" + isoversize: false + isautoswitchedtoquietmode: false "33": id: "33" taskid: 9a80f6b4-18be-413a-8397-794a919efa0b @@ -937,10 +1002,10 @@ tasks: id: 9a80f6b4-18be-413a-8397-794a919efa0b version: -1 name: Use custom severity? + description: "" type: condition iscommand: false brand: "" - description: '' nexttasks: '#default#': - "34" @@ -972,6 +1037,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "34": id: "34" taskid: 359cb86e-fb0e-4a4c-8291-edef6d443ee2 @@ -980,10 +1046,10 @@ tasks: id: 359cb86e-fb0e-4a4c-8291-edef6d443ee2 version: -1 name: Run additional searches? + description: "" type: condition iscommand: false brand: "" - description: '' nexttasks: '#default#': - "1" @@ -1034,13 +1100,7 @@ tasks: id: bb27c52d-e30b-491a-80a8-c20fb7f914dd version: -1 name: QRadar - Get Offense Logs - description: "Works for QRadar integrations versions 2 and 3, v1 is deprecated.\n\nNote: - For QRadar v2 and v3 you can use the integration to fetch the events - according to the limit defined in the instance settings. Using this playbook you can define - you can define an additional search to query a larger number of logs.\n\nDefault playbook - inputs use the QRadar incident fields such as idoffense, starttime. These - fields can be replaced, but need to point to relevant offense ID and starttime - fields. " + description: "Works for QRadar integrations versions 2 and 3, v1 is deprecated.\n\nNote: For QRadar v2 and v3 you can use the integration to fetch the events according to the limit defined in the instance settings. Using this playbook you can define you can define an additional search to query a larger number of logs.\n\nDefault playbook inputs use the QRadar incident fields such as idoffense, starttime. These fields can be replaced, but need to point to relevant offense ID and starttime fields. " playbookName: QRadar - Get Offense Logs type: playbook iscommand: false @@ -1083,6 +1143,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "37": id: "37" taskid: 379235d9-c4b9-46c1-81f8-ceac15a2b23a @@ -1134,6 +1195,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "38": id: "38" taskid: 78b79c26-5204-4982-8530-8cc48542474d @@ -1170,6 +1232,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "39": id: "39" taskid: 57166b79-05fa-43af-8d85-fa6e622371ca @@ -1178,10 +1241,10 @@ tasks: id: 57166b79-05fa-43af-8d85-fa6e622371ca version: -1 name: Is Indicator exclusion allowed in XSOAR? + description: "" type: condition iscommand: false brand: "" - description: '' nexttasks: '#default#': - "42" @@ -1213,6 +1276,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "41": id: "41" taskid: 511e4e6a-ea30-4ca6-8249-d1a11fc267b3 @@ -1222,9 +1286,9 @@ tasks: version: -1 name: Any indicators to exclude? type: condition + description: "" iscommand: false brand: "" - description: '' nexttasks: '#default#': - "42" @@ -1260,6 +1324,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "42": id: "42" taskid: f6ca219f-b710-403c-8d4b-c9dbc86b607c @@ -1290,6 +1355,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "43": id: "43" taskid: f5ef5d8f-37c9-4fe1-8021-f1f49e9cad32 @@ -1324,6 +1390,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "44": id: "44" taskid: 1d1b35bd-3d25-4ffa-839e-b2b4f647bd2c @@ -1332,8 +1399,7 @@ tasks: id: 1d1b35bd-3d25-4ffa-839e-b2b4f647bd2c version: -1 name: Select indicators to exclude - description: Provide data to adjust the rule in order to avoid similar false - positives in the future. + description: Provide data to adjust the rule in order to avoid similar false positives in the future. type: collection iscommand: false brand: "" @@ -1352,17 +1418,19 @@ tasks: timertriggers: [] ignoreworker: false message: - to: null - subject: null - body: null + to: + subject: + body: methods: [] format: "" - bcc: null - cc: null + bcc: + cc: timings: retriescount: 2 retriesinterval: 360 completeafterreplies: 1 + completeafterv2: false + completeaftersla: false form: questions: - id: "0" @@ -1422,6 +1490,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "45": id: "45" taskid: 19cfa6ac-e92f-4950-8a66-e38083737378 @@ -1430,8 +1499,7 @@ tasks: id: 19cfa6ac-e92f-4950-8a66-e38083737378 version: -1 name: Provide closing reason and tag indicators - description: Provide data to adjust the rule in order to avoid similar false - positives in the future. + description: Provide data to adjust the rule in order to avoid similar false positives in the future. type: collection iscommand: false brand: "" @@ -1450,17 +1518,19 @@ tasks: timertriggers: [] ignoreworker: false message: - to: null - subject: null - body: null + to: + subject: + body: methods: [] format: "" - bcc: null - cc: null + bcc: + cc: timings: retriescount: 2 retriesinterval: 360 completeafterreplies: 1 + completeafterv2: false + completeaftersla: false form: questions: - id: "0" @@ -1534,6 +1604,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "50": id: "50" taskid: eacc95db-5005-477b-88d5-ecc5947beccb @@ -1568,6 +1639,7 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "52": id: "52" taskid: bb2db2a5-aa9b-403c-828b-b89904706e34 @@ -1681,12 +1753,14 @@ tasks: methods: - email format: "" - bcc: null - cc: null + bcc: + cc: timings: retriescount: 2 retriesinterval: 360 completeafterreplies: 1 + completeafterv2: false + completeaftersla: false form: questions: - id: "0" @@ -1732,19 +1806,20 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false + continueonerrortype: "" "53": id: "53" - taskid: d9fdb2bc-7484-4ef5-8522-cfdc1865745a + taskid: 2bbee7bc-a5b9-4c8a-81ff-6a165827f860 type: playbook task: - id: d9fdb2bc-7484-4ef5-8522-cfdc1865745a + id: 2bbee7bc-a5b9-4c8a-81ff-6a165827f860 version: -1 name: Entity Enrichment - Generic v3 playbookName: Entity Enrichment - Generic v3 type: playbook iscommand: false brand: "" - description: '' + description: 'Enrich entities using one or more integrations.' nexttasks: '#none#': - "16" @@ -1805,10 +1880,26 @@ tasks: - operator: uniq Username: complex: - root: Account - accessor: Username + root: QRadar.Username transformers: + - operator: SetIfEmpty + args: + applyIfEmpty: {} + defaultValue: + value: + simple: Account.Username + iscontext: true - operator: uniq + filters: + - - operator: isNotEmpty + left: + value: + simple: QRadar.Username + iscontext: true + URLSSLVerification: + simple: "False" + UseReputationCommand: + simple: "False" separatecontext: true continueonerrortype: "" loop: @@ -1830,7 +1921,6 @@ tasks: quietmode: 0 isoversize: false isautoswitchedtoquietmode: false -system: true view: |- { "linkLabelsPosition": { @@ -1854,52 +1944,47 @@ inputs: simple: "true" required: false description: Determines whether to enrich all indicators in the incident. - playbookInputQuery: null + playbookInputQuery: - key: OnCall value: simple: "false" required: false description: Set to true to assign only the user that is currently on shift. Requires Cortex XSOAR v5.5 or later. - playbookInputQuery: null + playbookInputQuery: - key: SocEmailAddress value: {} required: false description: The SOC team's email address. - playbookInputQuery: null + playbookInputQuery: - key: SocMailSubject value: simple: 'XSOAR Summary report, ID - ' required: false description: The subject of the email to send to the SOC. - playbookInputQuery: null + playbookInputQuery: - key: SiemAdminEmailAddress value: {} required: false description: The SIEM admin's email address. - playbookInputQuery: null + playbookInputQuery: - key: UseCalculateSeverity value: simple: "true" required: false - description: Determines whether to use the Calculate Severity playbook to calculate - the incident severity. If the playbook isn't used, the severity - is determined by the QRadar magnitude value. - playbookInputQuery: null + description: Determines whether to use the Calculate Severity playbook to calculate the incident severity. If the playbook isn't used, the severity is determined by the QRadar magnitude value. + playbookInputQuery: - key: SiemAdminMailSubject value: simple: 'Adjustment/Exclusion for offense ' required: false description: The subject of the email to send to the SIEM admin. - playbookInputQuery: null + playbookInputQuery: - key: UseCustomSeveritySettings value: simple: "false" required: false - description: Determines whether to use the default mapping in the QRadar - generic mapper to set the XSOAR incident severity, or set the severity using the - FieldToSetSeverityFrom and ScaleToSetSeverityFrom playbook inputs. Any value other than false is considered as true - and causes the playbook inputs to be used. - playbookInputQuery: null + description: Determines whether to use the default mapping in the QRadar generic mapper to set the XSOAR incident severity, or set the severity using the FieldToSetSeverityFrom and ScaleToSetSeverityFrom playbook inputs. Any value other than false is considered as true and causes the playbook inputs to be used. + playbookInputQuery: - key: FieldToSetSeverityFrom value: complex: @@ -1908,71 +1993,51 @@ inputs: required: false description: | Specifies the field to use for calculating the incident severity, for example the severity field. - playbookInputQuery: null + playbookInputQuery: - key: ScaleToSetSeverityFrom value: simple: 1,1,1,2,2,2,2,3,3,3 required: false - description: "The range of values of FieldToSetSeverityFrom is 1-10. The XSOAR incident - severity field value range is 0-4 where\n0 - Informational\n1 - Low\n2 - Medium\n3 - - High\n4 - Critical\n\nThe scale translates the value of FieldToSetSeverityFrom - to a valid incident severity value. The default scale is 1,1,1,2,2,2,2,3,3,3 \nThis - means that values 1-3 of FieldToSetSeverityFrom are - translated to low severity (positions 1-3 in the scale), values 4-7 are - translated to medium severity (positions 4-7 in the scale) and values 8-10 are - translated to high severity (positions 8-10 in the scale)." - playbookInputQuery: null + description: "The range of values of FieldToSetSeverityFrom is 1-10. The XSOAR incident severity field value range is 0-4 where\n0 - Informational\n1 - Low\n2 - Medium\n3 - High\n4 - Critical\n\nThe scale translates the value of FieldToSetSeverityFrom to a valid incident severity value. The default scale is 1,1,1,2,2,2,2,3,3,3 \nThis means that values 1-3 of FieldToSetSeverityFrom are translated to low severity (positions 1-3 in the scale), values 4-7 are translated to medium severity (positions 4-7 in the scale) and values 8-10 are translated to high severity (positions 8-10 in the scale)." + playbookInputQuery: - key: RunAdditionalSeach value: simple: "true" required: false - description: By default the incident fetches the events defined in the integration - instance settings (default is 20 events). To fetch - additional events, change this setting to true. - playbookInputQuery: null + description: By default the incident fetches the events defined in the integration instance settings (default is 20 events). To fetch additional events, change this setting to true. + playbookInputQuery: - key: MaxLogsCount value: simple: "50" required: false - description: 'Maximum number of log entires to query from QRadar. - Used for the QRadar - Get Offense Logs subplaybook.' - playbookInputQuery: null + description: 'Maximum number of log entires to query from QRadar. Used for the QRadar - Get Offense Logs subplaybook.' + playbookInputQuery: - key: GetOnlyCREEvents value: simple: All required: false description: | If this value is "OnlyCRE", get only events made by CRE. Values can be "OnlyCRE", "OnlyNotCRE", "All". Used for the QRadar - Get Offense Logs subplaybook. - playbookInputQuery: null + playbookInputQuery: - key: Fields value: - simple: QIDNAME(qid), LOGSOURCENAME(logsourceid), CATEGORYNAME(highlevelcategory), - CATEGORYNAME(category), PROTOCOLNAME(protocolid), sourceip, sourceport, destinationip, - destinationport, QIDDESCRIPTION(qid), username, PROTOCOLNAME(protocolid), RULENAME("creEventList"), - sourcegeographiclocation, sourceMAC, sourcev6, destinationgeographiclocation, - destinationv6, LOGSOURCETYPENAME(devicetype), credibility, severity, magnitude, - eventcount, eventDirection, postNatDestinationIP, postNatDestinationPort, postNatSourceIP, - postNatSourcePort, preNatDestinationPort, preNatSourceIP, preNatSourcePort, - UTF8(payload), starttime, devicetime + simple: QIDNAME(qid), LOGSOURCENAME(logsourceid), CATEGORYNAME(highlevelcategory), CATEGORYNAME(category), PROTOCOLNAME(protocolid), sourceip, sourceport, destinationip, destinationport, QIDDESCRIPTION(qid), username, PROTOCOLNAME(protocolid), RULENAME("creEventList"), sourcegeographiclocation, sourceMAC, sourcev6, destinationgeographiclocation, destinationv6, LOGSOURCETYPENAME(devicetype), credibility, severity, magnitude, eventcount, eventDirection, postNatDestinationIP, postNatDestinationPort, postNatSourceIP, postNatSourcePort, preNatDestinationPort, preNatSourceIP, preNatSourcePort, UTF8(payload), starttime, devicetime required: false description: | A comma-separated list of extra fields to get from each event. You can use different fields or rename the existing fields. Used for the QRadar - Get Offense Logs subplaybook. - playbookInputQuery: null + playbookInputQuery: - key: IndicatorTag value: simple: block required: false - description: The tag to provide for true positive indicators, for example to use - the indicators in an EDL (External Dynamic List). - playbookInputQuery: null + description: The tag to provide for true positive indicators, for example to use the indicators in an EDL (External Dynamic List). + playbookInputQuery: - key: ExcludeIndicatorsInXSOAR value: simple: "false" required: false - description: If this value is not false, add indicators - to the XSOAR exclude list. The excluded indicators won't be created - in XSOAR anymore. - playbookInputQuery: null + description: If this value is not false, add indicators to the XSOAR exclude list. The excluded indicators won't be created in XSOAR anymore. + playbookInputQuery: outputs: [] tests: - No test diff --git a/Packs/QRadar/ReleaseNotes/2_5_6.md b/Packs/QRadar/ReleaseNotes/2_5_6.md new file mode 100644 index 000000000000..87d9711512a1 --- /dev/null +++ b/Packs/QRadar/ReleaseNotes/2_5_6.md @@ -0,0 +1,6 @@ + +#### Playbooks + +##### QRadar Generic + +- Fixed an issue where the username involved in the QRadar offense was not enriched. diff --git a/Packs/QRadar/pack_metadata.json b/Packs/QRadar/pack_metadata.json index 5e42574f2c9e..81c56f500950 100644 --- a/Packs/QRadar/pack_metadata.json +++ b/Packs/QRadar/pack_metadata.json @@ -2,7 +2,7 @@ "name": "IBM QRadar", "description": "Fetch offenses as incidents and search QRadar", "support": "xsoar", - "currentVersion": "2.5.5", + "currentVersion": "2.5.6", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/RemoteAccess/Integrations/RemoteAccessv2/RemoteAccessv2.py b/Packs/RemoteAccess/Integrations/RemoteAccessv2/RemoteAccessv2.py index 0c4cadef9009..7347147b8ec2 100644 --- a/Packs/RemoteAccess/Integrations/RemoteAccessv2/RemoteAccessv2.py +++ b/Packs/RemoteAccess/Integrations/RemoteAccessv2/RemoteAccessv2.py @@ -262,7 +262,12 @@ def copy_to_command(ssh_client: SSHClient, args: Dict[str, Any]) -> CommandResul # Create all folders to destination_path in the remote machine if destination_dir: - execute_shell_command(ssh_client, args={'cmd': f'mkdir -p {destination_dir}'}) + try: + execute_shell_command(ssh_client, args={'cmd': f'mkdir -p {destination_dir}'}) + except Exception as e: + # ignore the error of creating the dir, as sometime is already exist and the error are due to permission + # otherwise the next operation will fail. + demisto.debug(f'Ignoring the error: {str(e)}, occurred when run the command: mkdir -p {destination_dir}') perform_copy_command(ssh_client, file_path, destination_path, copy_to_remote=True, socket_timeout=timeout) return CommandResults(readable_output=f'### The file corresponding to entry ID: {entry_id} was copied to remote' diff --git a/Packs/RemoteAccess/Integrations/RemoteAccessv2/RemoteAccessv2.yml b/Packs/RemoteAccess/Integrations/RemoteAccessv2/RemoteAccessv2.yml index c6f2e8bd541b..a16caec7c07c 100644 --- a/Packs/RemoteAccess/Integrations/RemoteAccessv2/RemoteAccessv2.yml +++ b/Packs/RemoteAccess/Integrations/RemoteAccessv2/RemoteAccessv2.yml @@ -149,7 +149,7 @@ script: - contextPath: File.Type description: The file type, as determined by libmagic (same as displayed in file entries). type: String - dockerimage: demisto/netmiko:1.0.0.113064 + dockerimage: demisto/netmiko:1.0.0.114712 runonce: false script: '-' subtype: python3 diff --git a/Packs/RemoteAccess/Integrations/RemoteAccessv2/RemoteAccessv2_test.py b/Packs/RemoteAccess/Integrations/RemoteAccessv2/RemoteAccessv2_test.py index 5e8df85b8ca9..1f220d184522 100644 --- a/Packs/RemoteAccess/Integrations/RemoteAccessv2/RemoteAccessv2_test.py +++ b/Packs/RemoteAccess/Integrations/RemoteAccessv2/RemoteAccessv2_test.py @@ -1,4 +1,3 @@ -import io import json import pytest @@ -9,7 +8,7 @@ def util_load_json(path): - with io.open(path, mode='r', encoding='utf-8') as f: + with open(path, encoding='utf-8') as f: return json.loads(f.read()) @@ -183,6 +182,31 @@ def test_copy_to_command_valid(mocker): assert results.readable_output == '### The file corresponding to entry ID: 456 was copied to remote host.' +def test_copy_to_command_failed_to_mkdir(mocker): + """ + Given: + - Cortex XSOAR arguments + + When: + - Calling the copy-to command but failing to run the mkdir. + + Then: + - Ensure the error info printed to debug but the command finished successfully. + """ + from RemoteAccessv2 import copy_to_command + from paramiko import SSHClient + mock_client: SSHClient = SSHClient() + mocker.patch.object(demisto, 'getFilePath', return_value={'path': 'test', 'name': 'file-name.txt'}) + mocker.patch.object(demisto, 'debug') + mocker.patch('RemoteAccessv2.perform_copy_command', return_value='') + mocker.patch('RemoteAccessv2.execute_shell_command', side_effect=Exception('permission error')) + + results: CommandResults = copy_to_command(mock_client, {'entry': 123, 'entry_id': 456, 'dest-dir': 'test_dir'}) + + assert 'permission error, occurred when run the command: mkdir -p test_dir' in demisto.debug.call_args[0][0] + assert results.readable_output == '### The file corresponding to entry ID: 456 was copied to remote host.' + + def test_copy_to_command_invalid_entry_id(mocker): """ Given: diff --git a/Packs/RemoteAccess/ReleaseNotes/1_0_35.md b/Packs/RemoteAccess/ReleaseNotes/1_0_35.md new file mode 100644 index 000000000000..110a11b811ee --- /dev/null +++ b/Packs/RemoteAccess/ReleaseNotes/1_0_35.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### RemoteAccess v2 + +- Fixed an issue where the command ***copy-to*** failed in case of missing permission to create the destination dir. The command will now succeed when missing this permission if the folder already exists. diff --git a/Packs/RemoteAccess/ReleaseNotes/1_0_36.md b/Packs/RemoteAccess/ReleaseNotes/1_0_36.md new file mode 100644 index 000000000000..ae52a0c1e015 --- /dev/null +++ b/Packs/RemoteAccess/ReleaseNotes/1_0_36.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### RemoteAccess v2 + +- Updated the Docker image to: *demisto/netmiko:1.0.0.114712*. diff --git a/Packs/RemoteAccess/pack_metadata.json b/Packs/RemoteAccess/pack_metadata.json index 7c9f01d4a79e..993f24f28c00 100644 --- a/Packs/RemoteAccess/pack_metadata.json +++ b/Packs/RemoteAccess/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Remote Access", "description": "Transfer files and execute commands via SSH on remote machines.", "support": "xsoar", - "currentVersion": "1.0.34", + "currentVersion": "1.0.36", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/ServiceNow/Integrations/ServiceNowv2/README.md b/Packs/ServiceNow/Integrations/ServiceNowv2/README.md index ce4809f13fd8..fa9045e9c361 100644 --- a/Packs/ServiceNow/Integrations/ServiceNowv2/README.md +++ b/Packs/ServiceNow/Integrations/ServiceNowv2/README.md @@ -2537,6 +2537,28 @@ Generic call to ServiceNow api >Request for GET method is successful +### servicenow-get-ticket-attachments + +*** +Retrieve file attachments from tickets. + +#### Base Command + +`servicenow-get-ticket-attachments` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| sys_id | sys_id of the ticket containing the file. | Required | + +#### Context Output + +There is no context output for this command. + +#### Human Readable Output + +>Successfully retrieved attachments for ticket with sys id 111 ### Troubleshooting The following are tips for handling issues with mirroring incidents between ServiceNow and Cortex XSOAR. diff --git a/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2.py b/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2.py index 65b114b0a416..0a52bccd277a 100644 --- a/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2.py +++ b/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2.py @@ -1502,6 +1502,24 @@ def delete_attachment_command(client: Client, args: dict) -> tuple[str, dict, di raise DemistoException("Error: No record found. Record doesn't exist or ACL restricts the record retrieval.") +def get_attachment_command(client: Client, args: dict) -> list | CommandResults: + """Retreives attachment from a ticket. + + Args: + client: Client object with request. + args: Usually demisto.args() + + Returns: + Command results and file results. + """ + sys_id = str(args.get('sys_id', '')) + + result = client.get_ticket_attachment_entries(sys_id) + if result: + return [CommandResults(readable_output=f'Successfully retrieved attachments for ticket with sys id {sys_id}.'), result] + return CommandResults(readable_output=f'Ticket with sys id {sys_id} has no attachments to retrieve.') + + def add_tag_command(client: Client, args: dict) -> tuple[str, dict, dict, bool]: """Add tag to a ticket. @@ -2699,11 +2717,13 @@ def is_new_incident(ticket_id: str) -> bool: Returns: bool: Whether its a new incident in XSOAR. """ - last_fetched_ids = get_integration_context().get("last_fetched_incident_ids") or [] + int_context = get_integration_context() + last_fetched_ids = int_context.get("last_fetched_incident_ids") or [] demisto.debug(f"ServiceNowV2 - Last fetched incident ids are: {last_fetched_ids}") if ticket_id_in_last_fetch := ticket_id in last_fetched_ids: last_fetched_ids.remove(ticket_id) - set_integration_context({"last_fetched_incident_ids": last_fetched_ids}) + int_context["last_fetched_incident_ids"] = last_fetched_ids + set_integration_context(int_context) return ticket_id_in_last_fetch @@ -3339,6 +3359,8 @@ def main(): return_results(get_tasks_for_co_command(client, demisto.args())) elif demisto.command() == 'servicenow-get-ticket-notes': return_results(get_ticket_notes_command(client, args, params)) + elif demisto.command() == 'servicenow-get-ticket-attachments': + return_results(get_attachment_command(client, args)) elif command in commands: md_, ec_, raw_response, ignore_auto_extract = commands[command](client, args) return_outputs(md_, ec_, raw_response, ignore_auto_extract=ignore_auto_extract) diff --git a/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2.yml b/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2.yml index b910b20f94e1..fc080a0309ad 100644 --- a/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2.yml +++ b/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2.yml @@ -1630,7 +1630,13 @@ script: - contextPath: ServiceNow.Generic.Response description: Generic response to servicenow api. type: string - dockerimage: demisto/python3:3.11.9.103066 + - arguments: + - description: sys_id of the ticket containing the attachment. + name: sys_id + required: true + description: Retrieves attachments from a ticket. + name: servicenow-get-ticket-attachments + dockerimage: demisto/python3:3.11.10.113941 isfetch: true ismappable: true isremotesyncin: true diff --git a/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2_description.md b/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2_description.md index eda8d9cccf05..f2c742f61ebe 100644 --- a/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2_description.md +++ b/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2_description.md @@ -37,4 +37,4 @@ the look back to a number that is greater than the previous value, then in the i If the integration was already set with look back > 0, and the look-back is not being increased at any point of time, then those incident duplications would not occur. --- -[View Integration Documentation](https://xsoar.pan.dev/docs/reference/integrations/service-now-v2) +[View Integration Documentation](https://xsoar.pan.dev/docs/reference/integrations/service-now-v2) \ No newline at end of file diff --git a/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2_test.py b/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2_test.py index 224a76c1974b..6e42fd1cf0a3 100644 --- a/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2_test.py +++ b/Packs/ServiceNow/Integrations/ServiceNowv2/ServiceNowv2_test.py @@ -1,4 +1,5 @@ import re +from unittest.mock import MagicMock from pytest_mock import MockerFixture from requests_mock import MockerCore @@ -19,7 +20,8 @@ ServiceNowClient, oauth_test_module, login_command, get_modified_remote_data_command, \ get_ticket_fields, check_assigned_to_field, generic_api_call_command, get_closure_case, get_timezone_offset, \ converts_close_code_or_state_to_close_reason, split_notes, DATE_FORMAT, convert_to_notes_result, DATE_FORMAT_OPTIONS, \ - format_incidents_response_with_display_values, get_entries_for_notes, is_time_field, delete_attachment_command + format_incidents_response_with_display_values, get_entries_for_notes, is_time_field, delete_attachment_command, \ + get_attachment_command, is_new_incident from ServiceNowv2 import test_module as module from test_data.response_constants import RESPONSE_TICKET, RESPONSE_MULTIPLE_TICKET, RESPONSE_UPDATE_TICKET, \ RESPONSE_UPDATE_TICKET_SC_REQ, RESPONSE_CREATE_TICKET, RESPONSE_CREATE_TICKET_WITH_OUT_JSON, RESPONSE_QUERY_TICKETS, \ @@ -2474,3 +2476,75 @@ def test_is_time_field(input_string, expected): It should return True if string contains valid datetime, False otherwise """ assert is_time_field(input_string) is expected + + +def test_get_attachment_command_success(): + client = MagicMock() + args = {'sys_id': '12345'} + mock_attachments = [ + {'file_name': 'file1.txt', 'content': 'file1 content'}, + {'file_name': 'file2.txt', 'content': 'file2 content'} + ] + client.get_ticket_attachment_entries = MagicMock(return_value=mock_attachments) + result = get_attachment_command(client, args) + client.get_ticket_attachment_entries.assert_called_once_with('12345') + assert isinstance(result, list) + assert isinstance(result[0], CommandResults) + assert result[0].readable_output == 'Successfully retrieved attachments for ticket with sys id 12345.' + assert result[1] == mock_attachments + + +def test_get_attachment_command_missing_sys_id(): + client = MagicMock() + args = {'sys_id': '12345'} + mock_attachments = [] + client.get_ticket_attachment_entries = MagicMock(return_value=mock_attachments) + result = get_attachment_command(client, args) + client.get_ticket_attachment_entries.assert_called_once_with('12345') + assert isinstance(result, CommandResults) + assert result.readable_output == 'Ticket with sys id 12345 has no attachments to retrieve.' + + +def test_incident_id_in_last_fetched_updates_correctly(mocker): + """ + Given: + Ticket ID to remove + When: + is_new_incident is called + Then: + It should remove the id without modifying the existing integration context keys + """ + mocker.patch.object(ServiceNowv2, 'get_integration_context', + return_value={"access_token": "token", "last_fetched_incident_ids": ['ABC123', 'XYZ789']}) + res = mocker.patch.object(ServiceNowv2, 'set_integration_context') + + # Executing the function with the incident id to be checked + is_new_incident("XYZ789") + + # Setup verification context with wrapper to cover the whole integration context if necessary + expected_context = {"access_token": "token", "last_fetched_incident_ids": ['ABC123']} + + # Verifying that set_integration_context was called with the correct new context + res.assert_called_once_with(expected_context) + + +def test_incident_id_not_in_last_fetched(mocker): + """ + Given: + Ticket ID that should not be removed + When: + is_new_incident is called + Then: + It should not modify the integration context + """ + # Mock the get_integration_context to return some incident IDs which does not include the tested ID + mocker.patch.object(ServiceNowv2, 'get_integration_context', + return_value={"access_token": "token", "last_fetched_incident_ids": ['ABC123', 'XYZ789']}) + # Mock the set_integration_context to check it is not called + res = mocker.patch.object(ServiceNowv2, 'set_integration_context') + + # Executing the function with an incident id that is not in the context's list + is_new_incident("DEF456") + + # Assert that set_integration_context was never called because no incident ID was removed + res.assert_not_called() diff --git a/Packs/ServiceNow/ReleaseNotes/2_6_10.md b/Packs/ServiceNow/ReleaseNotes/2_6_10.md new file mode 100644 index 000000000000..1096fb620b01 --- /dev/null +++ b/Packs/ServiceNow/ReleaseNotes/2_6_10.md @@ -0,0 +1,6 @@ + +#### Scripts + +##### ServiceNowAddComment + +- Updated the Docker image to: *demisto/python3:3.11.10.113941*. diff --git a/Packs/ServiceNow/ReleaseNotes/2_6_11.md b/Packs/ServiceNow/ReleaseNotes/2_6_11.md new file mode 100644 index 000000000000..56f58f5a8636 --- /dev/null +++ b/Packs/ServiceNow/ReleaseNotes/2_6_11.md @@ -0,0 +1,8 @@ + +#### Integrations + +##### ServiceNow v2 + +- Updated the docker image to: *demisto/python3:3.11.10.113941*. + +- Added the ***servicenow-get-attachments*** command, which retrieves attachments from tickets. diff --git a/Packs/ServiceNow/ReleaseNotes/2_6_12.md b/Packs/ServiceNow/ReleaseNotes/2_6_12.md new file mode 100644 index 000000000000..6cb3f3eda803 --- /dev/null +++ b/Packs/ServiceNow/ReleaseNotes/2_6_12.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### ServiceNow v2 + +- Fixed an issue where in some cases the access token could not be retrieved. diff --git a/Packs/ServiceNow/Scripts/ServiceNowAddComment/ServiceNowAddComment.yml b/Packs/ServiceNow/Scripts/ServiceNowAddComment/ServiceNowAddComment.yml index 7afd1994e20e..8b4efc63dbbf 100644 --- a/Packs/ServiceNow/Scripts/ServiceNowAddComment/ServiceNowAddComment.yml +++ b/Packs/ServiceNow/Scripts/ServiceNowAddComment/ServiceNowAddComment.yml @@ -25,7 +25,7 @@ contentitemexportablefields: dependson: must: - '|||servicenow-add-comment' -dockerimage: demisto/python3:3.10.14.90585 +dockerimage: demisto/python3:3.11.10.113941 enabled: true name: ServiceNowAddComment runas: DBotWeakRole diff --git a/Packs/ServiceNow/pack_metadata.json b/Packs/ServiceNow/pack_metadata.json index dc2ddcd0cd9d..b98630aa7917 100644 --- a/Packs/ServiceNow/pack_metadata.json +++ b/Packs/ServiceNow/pack_metadata.json @@ -2,7 +2,7 @@ "name": "ServiceNow", "description": "Use The ServiceNow IT Service Management (ITSM) solution to modernize the way you manage and deliver services to your users.", "support": "xsoar", - "currentVersion": "2.6.9", + "currentVersion": "2.6.12", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/SimpleSFTP/Integrations/SimpleSFTP/SimpleSFTP.py b/Packs/SimpleSFTP/Integrations/SimpleSFTP/SimpleSFTP.py index b94f5c554c3c..215a0f84e4a6 100644 --- a/Packs/SimpleSFTP/Integrations/SimpleSFTP/SimpleSFTP.py +++ b/Packs/SimpleSFTP/Integrations/SimpleSFTP/SimpleSFTP.py @@ -67,7 +67,7 @@ def main(): file_path = demisto.args()["file_path"] sftp.get(file_path, "/tmp/" + file_path[file_path.rindex("/") + 1:]) # type: ignore sftp.close() # type: ignore - with open("/tmp/" + file_path[file_path.rindex("/") + 1:], "r") as f: + with open("/tmp/" + file_path[file_path.rindex("/") + 1:]) as f: data = f.read() if demisto.args()["return_file"] == "True": demisto.results( diff --git a/Packs/SimpleSFTP/Integrations/SimpleSFTP/SimpleSFTP.yml b/Packs/SimpleSFTP/Integrations/SimpleSFTP/SimpleSFTP.yml index 0b01eec1812f..d15d4347ee5b 100644 --- a/Packs/SimpleSFTP/Integrations/SimpleSFTP/SimpleSFTP.yml +++ b/Packs/SimpleSFTP/Integrations/SimpleSFTP/SimpleSFTP.yml @@ -56,7 +56,7 @@ script: name: file_entry_id required: true description: Upload a file to a path on the SFTP Server - dockerimage: demisto/netmiko:1.0.0.100251 + dockerimage: demisto/netmiko:1.0.0.114712 subtype: python3 fromversion: 6.2.0 tests: diff --git a/Packs/SimpleSFTP/ReleaseNotes/1_2_2.md b/Packs/SimpleSFTP/ReleaseNotes/1_2_2.md new file mode 100644 index 000000000000..d21d4bcdcece --- /dev/null +++ b/Packs/SimpleSFTP/ReleaseNotes/1_2_2.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Simple SFTP + +- Updated the Docker image to: *demisto/netmiko:1.0.0.114712*. diff --git a/Packs/SimpleSFTP/pack_metadata.json b/Packs/SimpleSFTP/pack_metadata.json index 0b89fd5b12b8..ec5d0db574df 100644 --- a/Packs/SimpleSFTP/pack_metadata.json +++ b/Packs/SimpleSFTP/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Simple SFTP", "description": "Simple SFTP Integration to copy files from SFTP Server using paramiko.", "support": "community", - "currentVersion": "1.2.1", + "currentVersion": "1.2.2", "author": "Rahul Vijaydev, Vibhu A Bharadwaj", "url": "", "email": "", diff --git a/Packs/Slack/Integrations/SlackV3/README.md b/Packs/Slack/Integrations/SlackV3/README.md index 9cf286a53b96..0b2702ce09a3 100644 --- a/Packs/Slack/Integrations/SlackV3/README.md +++ b/Packs/Slack/Integrations/SlackV3/README.md @@ -283,16 +283,30 @@ There is no context output for this command. Sends a file to a user, channel, or group. If not specified, the file is sent to the mirrored investigation channel (if the channel exists). -**Note:** Command slack-send-file isn't available for newly created apps (from May 8, 2024) and will get an error in case of use, due to changes from the Slack API side. - #### Base Command `slack-send-file` +#### Permissions + +Permission scopes required for this command: + +| **Token Type** | **Scope** | +| --- | --- | +| Granular bot | files:write | +| User | files:write files:write:user | +| Legacy bot | bot | + +The full list of Slack API scopes can be accessed [here](https://api.slack.com/scopes). + +#### Limitations + +There are no known limitations for this command. + #### Input | **Argument Name** | **Description** | **Required** | -|-------------------|-----------------------------------------------------------------------------------------------------|--------------| +| --- | --- | --- | | file | The ID of the file entry to send. | Required | | to | The user to whom to send the file. Can be the username or the email address. | Optional | | group | The name of the Slack group (private channel) to which to send the file. | Optional | diff --git a/Packs/Slack/Integrations/SlackV3/SlackV3.py b/Packs/Slack/Integrations/SlackV3/SlackV3.py index 879f803c8a0e..b20868ca92f9 100644 --- a/Packs/Slack/Integrations/SlackV3/SlackV3.py +++ b/Packs/Slack/Integrations/SlackV3/SlackV3.py @@ -9,6 +9,7 @@ import aiohttp import slack_sdk from urllib.parse import urlparse +from typing import TypedDict, Literal, get_args from slack_sdk.errors import SlackApiError from slack_sdk.socket_mode.aiohttp import SocketModeClient @@ -20,6 +21,7 @@ ''' CONSTANTS ''' +ALLOWED_HTTP_VERBS = Literal['POST', 'GET'] SEVERITY_DICT = { 'Unknown': 0, 'Low': 1, @@ -55,6 +57,15 @@ PROFILING_DUMP_ROWS_LIMIT = 20 MAX_SAMPLES = 10 + +class FileUploadParams(TypedDict): + filename: str + file: str # file path + initial_comment: Optional[str] + channel: str # channel ID + thread_ts: Optional[str] # thread ID + + ''' GLOBALS ''' USER_TOKEN: str @@ -458,21 +469,53 @@ def set_name_and_icon(body: dict, method: str): body['icon_url'] = BOT_ICON_URL -def send_slack_request_sync(client: slack_sdk.WebClient, method: str, http_verb: str = 'POST', file_: str = '', - body: dict = None) -> SlackResponse: +def validate_slack_request_args( + http_verb: str, + method: Optional[str], + file_upload_params: Optional[FileUploadParams], +) -> None: + """ + Performs basic pre-validation on the Slack request arguments + + Args: + http_verb: The HTTP method to use. + method: The Slack web API method to use (not relevant when file_upload_params are specified). + file_upload_params: An instance of FileUploadParams (for uploading using the file-upload APIs). + + Raises: + ValueError: If neither method nor file_upload_params are specified, or if an invalid http_verb is used. + """ + if not method and not file_upload_params: + # empty method is only allowed when uploading a file + raise ValueError('Either a Slack web API method or file_upload_params need to specified') + + allowed_http_verb_values: tuple = get_args(ALLOWED_HTTP_VERBS) + if http_verb not in allowed_http_verb_values: + raise ValueError(f'Invalid http_verb: {http_verb}. Allowed values: {", ".join(allowed_http_verb_values)}.') + + +def send_slack_request_sync( + client: slack_sdk.WebClient, + method: str = '', # irrelevant when file_upload_params are specified + http_verb: ALLOWED_HTTP_VERBS = 'POST', + body: Optional[dict] = None, + file_upload_params: Optional[FileUploadParams] = None, +) -> SlackResponse: """ Sends a request to slack API while handling rate limit errors. Args: - client: The slack client. - method: The method to use. + client: The Synchronous Slack client. + method: The Slack web API method to use (irrelevant when file_upload_params are specified). http_verb: The HTTP method to use. - file_: A file path to send. body: The request body. + file_upload_params: An instance of FileUploadParams (for uploading using the file-upload APIs). Returns: - The slack API response. + The Slack API response. """ + validate_slack_request_args(http_verb=http_verb, method=method, file_upload_params=file_upload_params) + if body is None: body = {} @@ -481,11 +524,12 @@ def send_slack_request_sync(client: slack_sdk.WebClient, method: str, http_verb: while True: try: demisto.debug(f'Sending slack {method} (sync). Body is: {str(body)}') - if http_verb == 'POST': - if file_: - response = client.api_call(method, files={"file": file_}, data=body) - else: - response = client.api_call(method, json=body) + if file_upload_params: + # When file_upload_params provided, use three-stage `file_upload_v2` wrapper method in Slack's SDK client + # https://tools.slack.dev/python-slack-sdk/web/#uploading-files + response = client.files_upload_v2(**file_upload_params) + elif http_verb == 'POST': + response = client.api_call(method, json=body) else: response = client.api_call(method, http_verb='GET', params=body) except SlackApiError as api_error: @@ -504,21 +548,28 @@ def send_slack_request_sync(client: slack_sdk.WebClient, method: str, http_verb: return response # type: ignore -async def send_slack_request_async(client: AsyncWebClient, method: str, http_verb: str = 'POST', file_: str = '', - body: dict = None) -> SlackResponse: +async def send_slack_request_async( + client: AsyncWebClient, + method: str = '', # irrelevant when file_upload_params are specified + http_verb: ALLOWED_HTTP_VERBS = 'POST', + body: Optional[dict] = None, + file_upload_params: Optional[FileUploadParams] = None, +) -> SlackResponse: """ Sends an async request to slack API while handling rate limit errors. Args: - client: The slack client. - method: The method to use. + client: The Asynchronous Slack client. + method: The Slack web API method to use (irrelevant when file_upload_params are specified). http_verb: The HTTP method to use. - file_: A file path to send. body: The request body. + file_upload_params: An instance of FileUploadParams (for uploading using the file upload APIs). Returns: - The slack API response. + The Slack API response. """ + validate_slack_request_args(http_verb=http_verb, method=method, file_upload_params=file_upload_params) + if body is None: body = {} @@ -527,13 +578,14 @@ async def send_slack_request_async(client: AsyncWebClient, method: str, http_ver while True: try: demisto.debug(f'Sending slack {method} (async). Body is: {str(body)}') - if http_verb == 'POST': - if file_: - response = await client.api_call(method, files={"file": file_}, data=body) # type: ignore - else: - response = await client.api_call(method, json=body) # type: ignore + if file_upload_params: + # When file_upload_params provided, use three-stage `file_upload_v2` wrapper method in Slack's SDK client + # https://tools.slack.dev/python-slack-sdk/web/#uploading-files + response = await client.files_upload_v2(**file_upload_params) + elif http_verb == 'POST': + response = await client.api_call(method, json=body) else: - response = await client.api_call(method, http_verb='GET', params=body) # type: ignore + response = await client.api_call(method, http_verb='GET', params=body) except SlackApiError as api_error: demisto.debug(f'Got rate limit error (async). Body is: {str(body)}\n{api_error}') response = api_error.response @@ -1978,6 +2030,39 @@ def save_entitlement(entitlement, thread, reply, expiry, default_response): set_to_integration_context_with_retries({'questions': questions}, OBJECTS_TO_KEYS, SYNC_CONTEXT) +SEND_FILE_ERROR_EXPLANATIONS = { + 'access_denied': 'Access to a resource specified in the request is denied.', + 'channel_not_found': 'The value passed for channel_id was invalid.', + 'file_not_found': 'Could not find the file from the upload ticket.', + 'file_update_failed': 'Failure occurred when attempting to update the file.', + 'invalid_channel': 'The channel could not be found or the channel specified is invalid.', + 'posting_to_channel_denied': 'The user is not authorized to post to the target channel(s).', + 'account_inactive': 'The authentication token is for a deleted user or workspace when using a bot token.', + 'deprecated_endpoint': 'The endpoint has been deprecated.', + 'ekm_access_denied': 'Administrators have suspended the ability to post a message.', + 'enterprise_is_restricted': 'The method cannot be called from an Enterprise.', + 'invalid_auth': 'The provided token is invalid or the request originates from a disallowed IP address.', + 'method_deprecated': 'The method has been deprecated.', + 'missing_scope': 'The token used is not granted the specific scope permissions required to complete this request.', + 'not_allowed_token_type': 'The token type used in this request is not allowed.', + 'not_authed': 'No authentication token provided.', + 'not_in_channel': 'The user or bot used is not in the target channel(s). Ensure they are invited to the channel(s).', + 'no_permission': 'The workspace token used in this request does not have the permissions necessary to complete the request.', + 'org_login_required': 'The workspace is undergoing an enterprise migration and is temporarily unavailable.', + 'token_expired': 'The authentication token has expired.', + 'token_revoked': 'The authentication token is for a deleted user or workspace or the app has been removed.', + 'two_factor_setup_required': 'Two factor setup is required.', + 'team_access_not_granted': 'The token used is not granted the specific workspace access required to complete this request.', + 'accesslimited': 'Access to this method is limited on the current network.', + 'fatal_error': 'The Slack server could not complete this operation(s).', + 'internal_error': 'The Slack server could not complete this operation(s), likely due to a transient issue on our end.', + 'ratelimited': 'The request has been rate limited.', + 'request_timeout': 'Data was either missing or truncated for the POST request.', + 'service_unavailable': 'The Slack service is temporarily unavailable.', + 'team_added_to_org': 'The Slack workspace is currently undergoing migration to an Enterprise Organization.' +} + + def slack_send_file(_channel: str | None = None, _channel_id: str = '', _entry_id: str | None = None, _comment: str = ""): """ Sends a file to slack @@ -2005,15 +2090,21 @@ def slack_send_file(_channel: str | None = None, _channel_id: str = '', _entry_i 'name': file_path['name'], 'comment': comment } + + error_message = f'Failed to send file: {file_path["name"]} to Slack.' try: response = slack_send_request(to, channel, group, thread_id=thread_id, file_dict=file_dict, channel_id=channel_id) if response: - demisto.results('File sent to Slack successfully.') + return_results(CommandResults(readable_output='File sent to Slack successfully.')) else: - demisto.results('Could not send the file to Slack.') + raise DemistoException(message=error_message) except SlackApiError as e: - if 'method_deprecated' in str(e): - raise DemistoException('Command slack-send-file isn\'t available for newly created apps (from May 8, 2024).') + demisto.debug(f'{error_message} {e}') + if error_code := e.response.get('error'): + error_explanation = SEND_FILE_ERROR_EXPLANATIONS.get(error_code, error_code.replace('_', ' ').capitalize()) + error_message += f' {error_explanation}' + + raise DemistoException(message=error_message) def handle_tags_in_message_sync(message: str) -> str: @@ -2167,19 +2258,16 @@ def send_file_to_destinations(destinations: list, file_dict: dict, thread_id: st The Slack send response. """ response: Optional[SlackResponse] = None - body = { - 'filename': file_dict['name'] - } - - if 'comment' in file_dict: - body['initial_comment'] = file_dict['comment'] for destination in destinations: - body['channels'] = destination - if thread_id: - body['thread_ts'] = thread_id - - response = send_slack_request_sync(CLIENT, 'files.upload', file_=file_dict['path'], body=body) + file_upload_params = FileUploadParams( + filename=file_dict['name'], + file=file_dict['path'], + initial_comment=file_dict.get('comment'), + channel=destination, + thread_ts=thread_id, + ) + response = send_slack_request_sync(CLIENT, file_upload_params=file_upload_params) return response diff --git a/Packs/Slack/Integrations/SlackV3/SlackV3.yml b/Packs/Slack/Integrations/SlackV3/SlackV3.yml index 099bb5c6c01e..66512de5a407 100644 --- a/Packs/Slack/Integrations/SlackV3/SlackV3.yml +++ b/Packs/Slack/Integrations/SlackV3/SlackV3.yml @@ -308,7 +308,7 @@ script: name: threadID - description: A comment to add to the file. name: comment - description: 'Sends a file to a user, channel, or group. If not specified, the file is sent to the mirrored investigation channel (if the channel exists). Newly created apps (from the beginning of May 8, 2024) will be unable to use "slack_send_file" and will get an error in case of use, due to changes from the Slack API side.' + description: 'Sends a file to a user, channel, or group. If not specified, the file is sent to the mirrored investigation channel (if the channel exists).' name: slack-send-file - arguments: - description: The channel name. If not specified, the topic of the mirrored investigation channel is set (if the channel exists). diff --git a/Packs/Slack/Integrations/SlackV3/SlackV3_test.py b/Packs/Slack/Integrations/SlackV3/SlackV3_test.py index e78d6f2dfc1b..c8953886d85f 100644 --- a/Packs/Slack/Integrations/SlackV3/SlackV3_test.py +++ b/Packs/Slack/Integrations/SlackV3/SlackV3_test.py @@ -2840,10 +2840,8 @@ def test_slack_send_with_mirrored_file(mocker): """ Given: - mirror entry which is basically a file - When: - running send-notification triggered from mirroring - Then: - Validate that the file is sent successfully """ @@ -2871,7 +2869,7 @@ def test_slack_send_with_mirrored_file(mocker): SlackV3.slack_send() assert slack_send_request.call_args_list[0].kwargs["file_dict"] assert slack_send_request.call_args_list[0].kwargs["channel_id"] == "1234" - assert demisto_results.call_args_list[0][0][0] == 'File sent to Slack successfully.' + assert demisto_results.call_args[0][0]['HumanReadable'] == 'File sent to Slack successfully.' def test_send_request_with_entitlement_blocks(mocker): @@ -3291,26 +3289,55 @@ def test_send_message_to_destinations(mocker): assert args['body']['text'] -def test_send_file_to_destinations(mocker): +def test_send_file_to_destinations_request_args(mocker): + """ + This mocks SlackV3.send_slack_request_sync while the other test mocks slack_sdk.WebClient.files_upload_v2 + Given: + - A file to send to a specific Slack channel + When: + - Calling the send_slack_request_sync function + Then: + - Assert the function is called once and the correct arguments are sent to the function + """ import SlackV3 # Set - - link = 'https://www.eizelulz.com:8443/#/WarRoom/727' - mocker.patch.object(demisto, 'investigation', return_value={'type': 1}) - mocker.patch.object(demisto, 'demistoUrls', return_value={'warRoom': link}) - mocker.patch.object(demisto, 'getIntegrationContext', side_effect=get_integration_context) mocker.patch.object(SlackV3, 'send_slack_request_sync') # Arrange SlackV3.send_file_to_destinations(['channel'], {'name': 'name', 'path': 'yo'}, None) - - args = SlackV3.send_slack_request_sync.call_args[1] + request_args = SlackV3.send_slack_request_sync.call_args[1] # Assert assert SlackV3.send_slack_request_sync.call_count == 1 - assert 'http_verb' not in args - assert args['file_'] == 'yo' - assert args['body']['filename'] == 'name' + assert 'http_verb' not in request_args + assert request_args['file_upload_params']['file'] == 'yo' + assert request_args['file_upload_params']['filename'] == 'name' + + +def test_send_file_to_destinations_sdk_client_args(mocker): + """ + This mocks slack_sdk.WebClient.files_upload_v2 while the other test mocks SlackV3.send_slack_request_sync + Given: + - A file to send to a specifc thread in a channel + When: + - Calling the files_upload_v2 'wrapper' method in the slack_sdk.WebClient class + Then: + - Assert correct arguments are sent to the method + """ + from SlackV3 import send_file_to_destinations + # Set + mocker.patch.object(slack_sdk.WebClient, 'files_upload_v2') + + # Arrange + send_file_to_destinations(['channel'], {'name': 'name', 'path': 'yo'}, 'thread') + sdk_args = slack_sdk.WebClient.files_upload_v2.call_args[1] + + # Assert + assert sdk_args['file'] == 'yo' + assert sdk_args['filename'] == 'name' + assert sdk_args['initial_comment'] is None + assert sdk_args['channel'] == 'channel' + assert sdk_args['thread_ts'] == 'thread' def test_send_message_retry(mocker): @@ -3506,7 +3533,7 @@ def test_send_file_no_args_investigation(mocker): # Assert assert SlackV3.slack_send_request.call_count == 1 - assert success_results[0] == 'File sent to Slack successfully.' + assert success_results[0]['HumanReadable'] == 'File sent to Slack successfully.' assert send_args[0][1] == 'incident-681' assert send_args[1]['file_dict'] == { @@ -5232,29 +5259,37 @@ def test_get_war_room_url_with_xsiam_from_alert_war_room(self, mocker): assert get_war_room_url(url) == expected_war_room_url -def test_send_file_deprecated_endpoint(mocker, requests_mock): +def test_send_file_api_exception(mocker): """ Given: - - Slack client of newaly created app (May 8,2024). + - A mocked, faulty Slack API response. When: - - calling the slack_send_file + - Calling the slack_send_file function. Then: - - assert readable exception is raised. + - Assert readable exception is raised. """ from SlackV3 import slack_send_file # Set - mocker.patch.object(demisto, 'args', return_value={}) - mocker.patch.object(demisto, 'investigation', return_value={'id': '999'}) - mocker.patch.object(demisto, 'getIntegrationContext', side_effect=get_integration_context) - mocker.patch.object(demisto, 'setIntegrationContext', side_effect=set_integration_context) mocker.patch('SlackV3.slack_send_request', side_effect=SlackApiError('The request to the Slack API failed. (url: https://slack.com/api/files.upload)', {'ok': False, 'error': 'method_deprecated'})) - # Check that function_A raises DemistoException + # Check that function raises DemistoException with pytest.raises(DemistoException) as e: - slack_send_file(['channel'], - {'name': "test", 'path': 'path'}, - demisto.getIntegrationContext(), - '1' - ) - assert str(e.value) == 'Command slack-send-file isn\'t available for newly created apps (from May 8, 2024).' + slack_send_file('channel', _entry_id='123', _comment='Here is a file!') + assert str(e.value) == 'Failed to send file: test.txt to Slack. The method has been deprecated.' + + +def test_validate_slack_request_args(): + """ + Given: + - Invalid Slack API request arguments. + When: + - Calling the validate_slack_request_args function. + Then: + - Assert ValueError is raised. + """ + from SlackV3 import validate_slack_request_args + + with pytest.raises(ValueError) as e: + validate_slack_request_args(http_verb='HI', method='chat.postMessage', file_upload_params=None) + assert str(e.value) == 'Invalid http_verb: HI. Allowed values: POST, GET.' diff --git a/Packs/Slack/ReleaseNotes/3_5_0.md b/Packs/Slack/ReleaseNotes/3_5_0.md new file mode 100644 index 000000000000..5a66b3c908b6 --- /dev/null +++ b/Packs/Slack/ReleaseNotes/3_5_0.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Slack v3 + +Updated the ***slack-send-file*** command to be compatible with all apps - including newly created apps from May 8, 2024. diff --git a/Packs/Slack/pack_metadata.json b/Packs/Slack/pack_metadata.json index 58de936d3330..501300032409 100644 --- a/Packs/Slack/pack_metadata.json +++ b/Packs/Slack/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Slack", "description": "Interact with Slack API - collect logs, send messages and notifications to your Slack team.", "support": "xsoar", - "currentVersion": "3.4.19", + "currentVersion": "3.5.0", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/SophosCentral/README.md b/Packs/SophosCentral/README.md index 496eeb5f8636..2674381e5e96 100644 --- a/Packs/SophosCentral/README.md +++ b/Packs/SophosCentral/README.md @@ -1,3 +1,3 @@ # content-sophos-central -Note: Support for this pack moved to the partner on September, 9, 2021. Please contact the partner directly via the support link on the right. \ No newline at end of file +Sophos Central is a cloud-based management platform for Sophos' cybersecurity solutions, designed to provide centralized control and real-time visibility over various security products. Organizations use it to manage a wide range of security services, including endpoint, mobile, email, web, and firewall protection, all from a single interface. \ No newline at end of file diff --git a/Packs/SuspiciousDomainHunting/ReleaseNotes/1_0_6.md b/Packs/SuspiciousDomainHunting/ReleaseNotes/1_0_6.md new file mode 100644 index 000000000000..d5d00630296c --- /dev/null +++ b/Packs/SuspiciousDomainHunting/ReleaseNotes/1_0_6.md @@ -0,0 +1,9 @@ + +#### Scripts + +##### HtmlDifflabDynamic + +- Updated the Docker image to: *demisto/ssdeep:1.0.0.114703*. +##### HtmlDifflibCheck + +- Updated the Docker image to: *demisto/ssdeep:1.0.0.114703*. diff --git a/Packs/SuspiciousDomainHunting/Scripts/HtmlDifflabDynamic/HtmlDifflabDynamic.yml b/Packs/SuspiciousDomainHunting/Scripts/HtmlDifflabDynamic/HtmlDifflabDynamic.yml index 1642a2193c3f..dec7755e8a06 100644 --- a/Packs/SuspiciousDomainHunting/Scripts/HtmlDifflabDynamic/HtmlDifflabDynamic.yml +++ b/Packs/SuspiciousDomainHunting/Scripts/HtmlDifflabDynamic/HtmlDifflabDynamic.yml @@ -20,7 +20,7 @@ outputs: scripttarget: 0 subtype: python3 runonce: false -dockerimage: demisto/ssdeep:1.0.0.93570 +dockerimage: demisto/ssdeep:1.0.0.114703 runas: DBotWeakRole engineinfo: {} tests: diff --git a/Packs/SuspiciousDomainHunting/Scripts/HtmlDifflibCheck/HtmlDifflibCheck.yml b/Packs/SuspiciousDomainHunting/Scripts/HtmlDifflibCheck/HtmlDifflibCheck.yml index 6e68ea419c55..f7d5bd687694 100644 --- a/Packs/SuspiciousDomainHunting/Scripts/HtmlDifflibCheck/HtmlDifflibCheck.yml +++ b/Packs/SuspiciousDomainHunting/Scripts/HtmlDifflibCheck/HtmlDifflibCheck.yml @@ -19,7 +19,7 @@ outputs: scripttarget: 0 subtype: python3 runonce: false -dockerimage: demisto/ssdeep:1.0.0.93570 +dockerimage: demisto/ssdeep:1.0.0.114703 runas: DBotWeakRole engineinfo: {} fromversion: 6.10.0 diff --git a/Packs/SuspiciousDomainHunting/pack_metadata.json b/Packs/SuspiciousDomainHunting/pack_metadata.json index 70adfba0dcdf..7119bf52fcc0 100644 --- a/Packs/SuspiciousDomainHunting/pack_metadata.json +++ b/Packs/SuspiciousDomainHunting/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Suspicious Domain Hunting", "description": "This pack provides all the necessary tools for the Suspicious Domain Hunting use case. It uses the CertStream integration to ingest new SSL certificates and alert for type-squatting domains with SSL certificate, these alerts are then analyzed and mitigated.", "support": "community", - "currentVersion": "1.0.5", + "currentVersion": "1.0.6", "author": "Cortex XSOAR", "url": "https://live.paloaltonetworks.com/t5/cortex-xsoar-discussions/bd-p/Cortex_XSOAR_Discussions", "email": "", diff --git a/Packs/Tanium/Integrations/Tanium_v2/Tanium_v2.py b/Packs/Tanium/Integrations/Tanium_v2/Tanium_v2.py index ca8a3e0d2ecc..cc53d8e888ee 100644 --- a/Packs/Tanium/Integrations/Tanium_v2/Tanium_v2.py +++ b/Packs/Tanium/Integrations/Tanium_v2/Tanium_v2.py @@ -372,7 +372,7 @@ def get_question_item(self, question): 'QueryText': question.get('query_text') } - saved_question_id = question.get('saved_question').get('id') + saved_question_id = (question.get('saved_question') or {}).get('id') if saved_question_id: item['SavedQuestionId'] = saved_question_id diff --git a/Packs/Tanium/ReleaseNotes/1_0_34.md b/Packs/Tanium/ReleaseNotes/1_0_34.md new file mode 100644 index 000000000000..62dcde4dbaec --- /dev/null +++ b/Packs/Tanium/ReleaseNotes/1_0_34.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Tanium v2 + +Fixed an issue where the **tn-get-question-metadata** command was raising an error when the saved_question field was empty. diff --git a/Packs/Tanium/pack_metadata.json b/Packs/Tanium/pack_metadata.json index 8f556ebef784..84d126ad701c 100644 --- a/Packs/Tanium/pack_metadata.json +++ b/Packs/Tanium/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Tanium", "description": "Tanium endpoint security and systems management", "support": "xsoar", - "currentVersion": "1.0.33", + "currentVersion": "1.0.34", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/UnifiVideoNVR/Integrations/UnifiVideo/UnifiVideo.py b/Packs/UnifiVideoNVR/Integrations/UnifiVideo/UnifiVideo.py index 69b5e365cf9b..128ede81e880 100644 --- a/Packs/UnifiVideoNVR/Integrations/UnifiVideo/UnifiVideo.py +++ b/Packs/UnifiVideoNVR/Integrations/UnifiVideo/UnifiVideo.py @@ -37,7 +37,7 @@ if demisto.command() == 'unifivideo-get-snapshot': camera_name = args.get('camera_name') - output = bytes() + output = b'' uva = UnifiVideoAPI(api_key=api_key, addr=address, port=port, schema=schema, verify_cert=verify_cert) uva.get_camera(camera_name).snapshot("/tmp/snapshot.png") f = open("/tmp/snapshot.png", "rb") @@ -140,7 +140,7 @@ try: file_result = demisto.getFilePath(entry_id) except Exception as ex: - return_error("Failed to load file entry with entryid: {}. Error: {}".format(entry_id, ex)) + return_error(f"Failed to load file entry with entryid: {entry_id}. Error: {ex}") video_path = file_result.get("path") # pylint: disable=E1101 vc = cv2.VideoCapture(video_path) # pylint: disable=E1101 diff --git a/Packs/UnifiVideoNVR/Integrations/UnifiVideo/UnifiVideo.yml b/Packs/UnifiVideoNVR/Integrations/UnifiVideo/UnifiVideo.yml index 2b0c6752c5a8..37d28329f7c9 100644 --- a/Packs/UnifiVideoNVR/Integrations/UnifiVideo/UnifiVideo.yml +++ b/Packs/UnifiVideoNVR/Integrations/UnifiVideo/UnifiVideo.yml @@ -139,7 +139,7 @@ script: required: true description: Gets the frame snapshot that has triggered the motion event. name: unifivideo-get-recording-motion-snapshot - dockerimage: demisto/unifi-video:1.0.0.98233 + dockerimage: demisto/unifi-video:1.0.0.114769 isfetch: true runonce: true script: '-' diff --git a/Packs/UnifiVideoNVR/ReleaseNotes/1_0_3.md b/Packs/UnifiVideoNVR/ReleaseNotes/1_0_3.md new file mode 100644 index 000000000000..e87937302d30 --- /dev/null +++ b/Packs/UnifiVideoNVR/ReleaseNotes/1_0_3.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### UnifiVideo + +- Updated the Docker image to: *demisto/unifi-video:1.0.0.114769*. diff --git a/Packs/UnifiVideoNVR/pack_metadata.json b/Packs/UnifiVideoNVR/pack_metadata.json index e459c0a36a1b..4e6feebe0aac 100644 --- a/Packs/UnifiVideoNVR/pack_metadata.json +++ b/Packs/UnifiVideoNVR/pack_metadata.json @@ -2,7 +2,7 @@ "name": "UnifiVideo NVR", "description": "This integration connects to UnifiVideo by Ubiquity Networks, which fetches motion events as incidents, allowing you to take video recordings and snapshots", "support": "community", - "currentVersion": "1.0.2", + "currentVersion": "1.0.3", "author": "Maciej Drobniuch", "url": "drobniuch.pl", "email": "maciej@drobniuch.pl", diff --git a/Packs/UrlScan/CONTRIBUTORS.json b/Packs/UrlScan/CONTRIBUTORS.json new file mode 100644 index 000000000000..f2a846970131 --- /dev/null +++ b/Packs/UrlScan/CONTRIBUTORS.json @@ -0,0 +1,3 @@ +[ + "Ryan McVicar" +] diff --git a/Packs/UrlScan/Integrations/UrlScan/README.md b/Packs/UrlScan/Integrations/UrlScan/README.md index 6cc6add9a2e0..24110ae90da8 100644 --- a/Packs/UrlScan/Integrations/UrlScan/README.md +++ b/Packs/UrlScan/Integrations/UrlScan/README.md @@ -12,6 +12,7 @@
  • API Key (needed only for submitting URLs for scanning)
  • Scan Visibility: Determines the visibility level of the scan. This will override the 'public submissions' setting.
  • Source Reliability. Reliability of the source providing the intelligence data. (The default value is C - Fairly reliable)
  • +
  • Scan Country. Specify which country the scan should be performed from. If you omit this value, urlscan will try to do automatic country detection based on the TLD of the URL, GeoIP information of the server and of the user.
  • Trust any certificate (not secure)
  • Use system proxy settings
  • diff --git a/Packs/UrlScan/Integrations/UrlScan/UrlScan.py b/Packs/UrlScan/Integrations/UrlScan/UrlScan.py index 849699d52300..4c379491f209 100644 --- a/Packs/UrlScan/Integrations/UrlScan/UrlScan.py +++ b/Packs/UrlScan/Integrations/UrlScan/UrlScan.py @@ -45,7 +45,7 @@ class Client: def __init__(self, api_key='', user_agent='', scan_visibility=None, threshold=None, use_ssl=False, - reliability=DBotScoreReliability.C): + reliability=DBotScoreReliability.C, country=None): self.base_url = 'https://urlscan.io/' self.base_api_url = 'https://urlscan.io/api/v1/' self.api_key = api_key @@ -54,6 +54,7 @@ def __init__(self, api_key='', user_agent='', scan_visibility=None, threshold=No self.scan_visibility = scan_visibility self.use_ssl = use_ssl self.reliability = reliability + self.country = country '''HELPER FUNCTIONS''' @@ -252,6 +253,9 @@ def urlscan_submit_url(client, url): elif demisto.params().get('useragent'): submission_dict['customagent'] = demisto.params().get('useragent') + if client.country: + submission_dict['country'] = client.country.split(' ')[0] + sub_json = json.dumps(submission_dict) retries = int(demisto.args().get('retries', 0)) r, metric, rate_limit_reset_after = http_request(client, 'POST', 'scan/', sub_json, retries) @@ -829,6 +833,7 @@ def main(): use_ssl = not params.get('insecure', False) reliability = params.get('integrationReliability') reliability = reliability if reliability else DBotScoreReliability.C + country = params.get('country', '') if DBotScoreReliability.is_valid_type(reliability): reliability = DBotScoreReliability.get_dbot_score_reliability_from_str(reliability) @@ -843,7 +848,8 @@ def main(): scan_visibility=scan_visibility, threshold=threshold, use_ssl=use_ssl, - reliability=reliability + reliability=reliability, + country=country ) demisto.debug(f'Command being called is {demisto.command()}') diff --git a/Packs/UrlScan/Integrations/UrlScan/UrlScan.yml b/Packs/UrlScan/Integrations/UrlScan/UrlScan.yml index 5cce39eca6eb..bef1826d5895 100644 --- a/Packs/UrlScan/Integrations/UrlScan/UrlScan.yml +++ b/Packs/UrlScan/Integrations/UrlScan/UrlScan.yml @@ -38,6 +38,35 @@ configuration: required: true type: 15 section: Collect +- additionalinfo: Specify which country the scan should be performed + display: Scan Country + name: country + options: + - "AT - Austria" + - "AU - Australia" + - "CA - Canada" + - "CH - Switzerland" + - "DE - Germany" + - "DK - Denmark" + - "ES - Spain" + - "FI - Finland" + - "FR - France" + - "GB - United Kingdom" + - "IL - Israel" + - "IS - Iceland" + - "IT - Italy" + - "JP - Japan" + - "NL - Netherlands" + - "NO - Norway" + - "NZ - New Zealand" + - "PL - Poland" + - "PT - Portugal" + - "SE - Sweden" + - "SG - Singapore" + - "US - United States" + required: false + type: 15 + section: Collect - defaultvalue: '1' display: URL Threshold. Minimum number of positive results from urlscan.io to consider the URL malicious. name: url_threshold @@ -464,4 +493,4 @@ script: dockerimage: demisto/python3:3.10.14.99865 fromversion: 5.0.0 tests: -- urlscan_malicious_Test +- urlscan_malicious_Test \ No newline at end of file diff --git a/Packs/UrlScan/ReleaseNotes/1_2_15.md b/Packs/UrlScan/ReleaseNotes/1_2_15.md new file mode 100644 index 000000000000..b48abd2fc4c9 --- /dev/null +++ b/Packs/UrlScan/ReleaseNotes/1_2_15.md @@ -0,0 +1,5 @@ + +#### Integrations + +##### urlscan.io +Added support for the *country* integration parameter, which enables you to choose what country to originate scans from. \ No newline at end of file diff --git a/Packs/UrlScan/pack_metadata.json b/Packs/UrlScan/pack_metadata.json index 9040a7ac7196..a33d3dd3cbc1 100644 --- a/Packs/UrlScan/pack_metadata.json +++ b/Packs/UrlScan/pack_metadata.json @@ -2,7 +2,7 @@ "name": "URLScan.io", "description": "urlscan.io Web Threat Intelligence", "support": "partner", - "currentVersion": "1.2.14", + "currentVersion": "1.2.15", "author": "urlscan GmbH", "url": "https://urlscan.io", "email": "support@urlscan.io", diff --git a/Packs/VaronisSaaS/Integrations/VaronisSaaS/VaronisSaaS_light.svg b/Packs/VaronisSaaS/Integrations/VaronisSaaS/VaronisSaaS_light.svg index a2da7ccc02b5..41c7b8a9b77a 100644 --- a/Packs/VaronisSaaS/Integrations/VaronisSaaS/VaronisSaaS_light.svg +++ b/Packs/VaronisSaaS/Integrations/VaronisSaaS/VaronisSaaS_light.svg @@ -1,20 +1,78 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/Packs/VaronisSaaS/ReleaseNotes/1_0_7.md b/Packs/VaronisSaaS/ReleaseNotes/1_0_7.md new file mode 100644 index 000000000000..d4e6cae8ce3a --- /dev/null +++ b/Packs/VaronisSaaS/ReleaseNotes/1_0_7.md @@ -0,0 +1,3 @@ +#### Integrations +##### Varonis SaaS +- Updated a Varonis log image. diff --git a/Packs/VaronisSaaS/pack_metadata.json b/Packs/VaronisSaaS/pack_metadata.json index 1782e20347b7..22e51b83c69f 100644 --- a/Packs/VaronisSaaS/pack_metadata.json +++ b/Packs/VaronisSaaS/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Varonis SaaS", "description": "Streamline alerts, events and related forensic information from Varonis SaaS", "support": "partner", - "currentVersion": "1.0.6", + "currentVersion": "1.0.7", "author": "Varonis", "url": "https://www.varonis.com/support", "email": "", diff --git a/Packs/WALLIXBastion/Integrations/WAB/README.md b/Packs/WALLIXBastion/Integrations/WAB/README.md index af9d1b5995db..4be256dc48dd 100644 --- a/Packs/WALLIXBastion/Integrations/WAB/README.md +++ b/Packs/WALLIXBastion/Integrations/WAB/README.md @@ -12,7 +12,7 @@ This integration was integrated and tested with version 12 of WALLIX Bastion. | Server URL (e.g. localhost) | True | | API Auth User | True | | API Auth Key or user password | False | - | Password authentication mode (false if you provided an API key) | False | + | Password authentication mode (set false if you provided an API key) | False | | Trust any certificate (not secure) | False | | Use system proxy settings | False | | API version to use. Leave the field empty to use the latest API version available. | False | @@ -28,7 +28,7 @@ After you successfully execute a command, a DBot message appears in the War Room ### wab-add-session-target-to-target-group *** -Add a target account to a target group. +Add a target account to a target group #### Base Command @@ -54,7 +54,7 @@ There is no context output for this command. ### wab-add-password-target-to-target-group *** -Add a password checkout account to a target group. +Add a password checkout account to a target group #### Base Command @@ -78,7 +78,8 @@ There is no context output for this command. ### wab-add-restriction-to-target-group *** -Add a restriction to a target group. +Add a restriction in a targetgroup +category: Target Group Restrictions. #### Base Command @@ -88,10 +89,37 @@ Add a restriction to a target group. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | -| group_id | The group id or name to edit. | Required | -| action | the restriction type: 'kill' or 'notify'. | Required | +| group_id | A target group id or name. | Required | +| action | The restriction type. Possible values are: kill, notify. | Required | | rules | the restriction rules. | Required | -| subprotocol | the restriction subprotocol: SSH_SHELL_SESSION, SSH_REMOTE_COMMAND, SSH_SCP_UP, SSH_SCP_DOWN, SFTP_SESSION, RLOGIN, TELNET, RDP. | Required | +| subprotocol | The restriction subprotocol. Possible values are: SSH_SHELL_SESSION, SSH_REMOTE_COMMAND, SSH_SCP_UP, SSH_SCP_DOWN, SFTP_SESSION, RLOGIN, TELNET, RDP. | Required | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_restriction_in_targetgroup.id | String | id of the created object. | + +### wab-add-timeframe-period + +*** +Add a period to a timeframe +category: Timeframes. + +#### Base Command + +`wab-add-timeframe-period` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| timeframe_id | The timeframe id or name to edit. | Required | +| start_date | The period start date. Must respect the format "yyyy-mm-dd". | Required | +| end_date | The period end date. Must respect the format "yyyy-mm-dd". | Required | +| start_time | The period start time. Must respect the format "hh:mm". | Required | +| end_time | The period end time. Must respect the format "hh:mm". | Required | +| week_days | The period week days.
    Comma-separated list (use [] for an empty list).
    Possible values: monday,tuesday,wednesday,thursday,friday,saturday,sunday. | Required | #### Context Output @@ -100,7 +128,8 @@ There is no context output for this command. ### wab-get-account-references *** -Get account references. +Get account references +category: Account References #### Base Command @@ -135,7 +164,8 @@ Get account references. ### wab-get-account-reference *** -Get account reference. +Get account reference +category: Account References #### Base Command @@ -164,10 +194,35 @@ Get account reference. | WAB.account_reference_get.devices.error_date | String | The date/time since which the status is "error", or null if the status is not "error". | | WAB.account_reference_get.devices.error_description | String | The description of the error, of null if the status is not "error". | +### wab-change-password-or-ssh-key-of-account + +*** +Change password or SSH key of an account and propagate changes on the target host. If the body is empty, an automatic password change is performed: the password or the SSH key are changed to a newly generated value, according to the password change policy on the domain. Note: the password change must be enabled on the domain, with a plugin that will be used to change the password on the target host +category: Account Change Password + +#### Base Command + +`wab-change-password-or-ssh-key-of-account` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| account_id | The account id. | Required | +| credential_type | 'password' to change the password or 'ssh_key' to change the SSH key. Possible values are: password, ssh_key. | Required | +| changePasswordOrSshKeyOfAccount_password | The new password. | Optional | +| changePasswordOrSshKeyOfAccount_private_key | The new SSH private key. | Optional | +| changePasswordOrSshKeyOfAccount_passphrase | The passphrase for the SSH private key (only for an encrypted private key). If provided, it must be between 4 and 1024 characters long. | Optional | + +#### Context Output + +There is no context output for this command. + ### wab-get-all-accounts *** -Get all accounts. +Get all accounts +category: Accounts #### Base Command @@ -180,7 +235,7 @@ Get all accounts. | account_type | The account type: "global" for only global domain accounts, "device" for only device accounts, "application" for only application accounts. By default accounts of any type are returned. Cannot be used if an account_name and/or device/application is specified. | Optional | | application | The name of the application whose accounts must be returned. Cannot be used if an account_name and/or an account_type/device is specified. | Optional | | device | The name of the device whose accounts must be returned. Cannot be used if an account_name and/or an application is specified. | Optional | -| passwords | Return credentials (passwords and SSH keys) as-is without replacing content by stars. Note: this requires the Password Manager license, the flag "Credential recovery" in the profile of the user logged on the API and the "Credential recovery" option must be enabled in REST API configuration. | Optional | +| passwords | Return credentials (passwords and SSH keys) as-is without replacing content by stars. Note: this requires the Password Manager license, the flag "Credential recovery" in the profile of the user logged on the API and the "Credential recovery" option must be enabled in REST API configuration. Possible values are: true, false. | Optional | | key_format | Format of the returned SSH public key of the account. Accepted values are 'openssh' (default value) and 'ssh.com'. | Optional | | q | Searches for a resource matching parameters. | Optional | | sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'account_name'. | Optional | @@ -235,7 +290,8 @@ Get all accounts. ### wab-get-one-account *** -Get one account. +Get one account +category: Accounts #### Base Command @@ -249,7 +305,7 @@ Get one account. | account_type | The account type: "global" for only global domain accounts, "device" for only device accounts, "application" for only application accounts. By default accounts of any type are returned. Cannot be used if an account_name and/or device/application is specified. | Optional | | application | The name of the application whose accounts must be returned. Cannot be used if an account_name and/or an account_type/device is specified. | Optional | | device | The name of the device whose accounts must be returned. Cannot be used if an account_name and/or an application is specified. | Optional | -| passwords | Return credentials (passwords and SSH keys) as-is without replacing content by stars. Note: this requires the Password Manager license, the flag "Credential recovery" in the profile of the user logged on the API and the "Credential recovery" option must be enabled in REST API configuration. | Optional | +| passwords | Return credentials (passwords and SSH keys) as-is without replacing content by stars. Note: this requires the Password Manager license, the flag "Credential recovery" in the profile of the user logged on the API and the "Credential recovery" option must be enabled in REST API configuration. Possible values are: true, false. | Optional | | key_format | Format of the returned SSH public key of the account. Accepted values are 'openssh' (default value) and 'ssh.com'. | Optional | | fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | @@ -300,7 +356,8 @@ Get one account. ### wab-delete-account *** -Delete an account. +Delete an account +category: Accounts #### Base Command @@ -319,7 +376,8 @@ There is no context output for this command. ### wab-get-application-accounts *** -Get the application accounts. +Get the application accounts +category: Application Accounts #### Base Command @@ -371,7 +429,8 @@ Get the application accounts. ### wab-add-account-to-local-domain-of-application *** -Add an account to a local domain of an application. +Add an account to a local domain of an application +category: Application Accounts #### Base Command @@ -386,19 +445,22 @@ Add an account to a local domain of an application. | app_account_post_account_name | The account name. /:*?"<>\|@ and space are forbidden. | Required | | app_account_post_account_login | The account login. | Required | | app_account_post_description | The account description. | Optional | -| app_account_post_auto_change_password | Automatically change the password. It is enabled by default on a new account. | Optional | +| app_account_post_auto_change_password | Automatically change the password. It is enabled by default on a new account. Possible values are: true, false. | Optional | | app_account_post_checkout_policy | The account checkout policy. | Required | | app_account_post_certificate_validity | The validity duration of the signed ssh public key in the case a Certificate Authority is defined for the account's domain. | Optional | -| app_account_post_can_edit_certificate_validity | True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. | Optional | +| app_account_post_can_edit_certificate_validity | True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. Possible values are: true, false. | Optional | #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_account_to_local_domain_of_application.id | String | id of the created object. | ### wab-get-application-account *** -Get the application account. +Get the application account +category: Application Accounts #### Base Command @@ -447,7 +509,8 @@ Get the application account. ### wab-edit-account-on-local-domain-of-application *** -Edit an account on a local domain of an application. +Edit an account on a local domain of an application +category: Application Accounts #### Base Command @@ -460,15 +523,15 @@ Edit an account on a local domain of an application. | application_id | The application id or name. | Required | | domain_id | The local domain id or name. | Required | | account_id | The account id or name to edit. | Required | -| force | The default value is false. When it is set to true the values of the credentials and services, if they are supplied, are replaced, otherwise the values are added to the existing ones. | Optional | +| force | The default value is false. When it is set to true the values of the credentials and services, if they are supplied, are replaced, otherwise the values are added to the existing ones. Possible values are: true, false. | Optional | | app_account_put_account_name | The account name. /:*?"<>\|@ and space are forbidden. | Optional | | app_account_put_account_login | The account login. | Optional | | app_account_put_description | The account description. | Optional | -| app_account_put_auto_change_password | Automatically change the password. It is enabled by default on a new account. | Optional | +| app_account_put_auto_change_password | Automatically change the password. It is enabled by default on a new account. Possible values are: true, false. | Optional | | app_account_put_checkout_policy | The account checkout policy. | Optional | | app_account_put_certificate_validity | The validity duration of the signed ssh public key in the case a Certificate Authority is defined for the account's domain. | Optional | -| app_account_put_can_edit_certificate_validity | True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. | Optional | -| app_account_put_onboard_status | Onboarding status of the account. | Optional | +| app_account_put_can_edit_certificate_validity | True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. Possible values are: true, false. | Optional | +| app_account_put_onboard_status | Onboarding status of the account. Possible values are: onboarded, to_onboard, hide, manual. | Optional | #### Context Output @@ -477,7 +540,8 @@ There is no context output for this command. ### wab-delete-account-from-local-domain-of-application *** -Delete an account from a local domain of an application. +Delete an account from a local domain of an application +category: Application Accounts #### Base Command @@ -495,10 +559,80 @@ Delete an account from a local domain of an application. There is no context output for this command. +### wab-get-local-domains-data-for-application + +*** +Get local domains data for a given application +category: Application Local Domains + +#### Base Command + +`wab-get-local-domains-data-for-application` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| application_id | The application id or name. | Required | +| q | Searches for a resource matching parameters. | Optional | +| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'domain_name'. | Optional | +| offset | The index of first item to retrieve (starts and defaults to 0). | Optional | +| limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.localdomain_app_get.id | String | The domain id. Usable in the "q" parameter. | +| WAB.localdomain_app_get.domain_name | String | The domain name. /:\*?"<>|@ are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.localdomain_app_get.description | String | The domain description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.localdomain_app_get.enable_password_change | Boolean | Enable the change of password on this domain. | +| WAB.localdomain_app_get.admin_account | String | The administrator account used to change passwords on this domain \(format: "account_name"\). | +| WAB.localdomain_app_get.password_change_policy | String | The name of password change policy for this domain. | +| WAB.localdomain_app_get.password_change_plugin | String | The name of plugin used to change passwords on this domain. | +| WAB.localdomain_app_get.ca_private_key | String | The ssh private key of the signing authority for the ssh keys for accounts in the domain. Special values are allowed to automatically generate SSH key: "generate:RSA_1024", "generate:RSA_2048", "generate:RSA_4096", "generate:RSA_8192", "generate:DSA_1024", "generate:ECDSA_256", "generate:ECDSA_384", "generate:ECDSA_521", "generate:ED25519". | +| WAB.localdomain_app_get.ca_public_key | String | The ssh public key of the signing authority for the ssh keys for accounts in the domain. | +| WAB.localdomain_app_get.url | String | The API URL to the resource. | + +### wab-get-local-domain-data-for-application + +*** +Get local domain data for a given application +category: Application Local Domains + +#### Base Command + +`wab-get-local-domain-data-for-application` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| application_id | The application id or name. | Required | +| domain_id | The local domain id or name. | Required | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.localdomain_app_get.id | String | The domain id. Usable in the "q" parameter. | +| WAB.localdomain_app_get.domain_name | String | The domain name. /:\*?"<>|@ are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.localdomain_app_get.description | String | The domain description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.localdomain_app_get.enable_password_change | Boolean | Enable the change of password on this domain. | +| WAB.localdomain_app_get.admin_account | String | The administrator account used to change passwords on this domain \(format: "account_name"\). | +| WAB.localdomain_app_get.password_change_policy | String | The name of password change policy for this domain. | +| WAB.localdomain_app_get.password_change_plugin | String | The name of plugin used to change passwords on this domain. | +| WAB.localdomain_app_get.ca_private_key | String | The ssh private key of the signing authority for the ssh keys for accounts in the domain. Special values are allowed to automatically generate SSH key: "generate:RSA_1024", "generate:RSA_2048", "generate:RSA_4096", "generate:RSA_8192", "generate:DSA_1024", "generate:ECDSA_256", "generate:ECDSA_384", "generate:ECDSA_521", "generate:ED25519". | +| WAB.localdomain_app_get.ca_public_key | String | The ssh public key of the signing authority for the ssh keys for accounts in the domain. | +| WAB.localdomain_app_get.url | String | The API URL to the resource. | + ### wab-get-applications *** -Get the applications. +Get the applications +category: Applications #### Base Command @@ -534,7 +668,6 @@ Get the applications. | WAB.application_get.local_domains.ca_private_key | String | The ssh private key of the signing authority for the ssh keys for accounts in the domain. Special values are allowed to automatically generate SSH key: "generate:RSA_1024", "generate:RSA_2048", "generate:RSA_4096", "generate:RSA_8192", "generate:DSA_1024", "generate:ECDSA_256", "generate:ECDSA_384", "generate:ECDSA_521", "generate:ED25519". | | WAB.application_get.local_domains.ca_public_key | String | The ssh public key of the signing authority for the ssh keys for accounts in the domain. | | WAB.application_get.local_domains.url | String | The API URL to the resource. | -| WAB.application_get.tags.id | String | The tag id. | | WAB.application_get.tags.key | String | The tag key. Must not start or end with a space. | | WAB.application_get.tags.value | String | The tag value. Must not start or end with a space. | | WAB.application_get.connection_policy | String | The connection policy name. Usable in the "q" parameter. | @@ -543,7 +676,8 @@ Get the applications. ### wab-get-application *** -Get the application. +Get the application +category: Applications #### Base Command @@ -576,7 +710,6 @@ Get the application. | WAB.application_get.local_domains.ca_private_key | String | The ssh private key of the signing authority for the ssh keys for accounts in the domain. Special values are allowed to automatically generate SSH key: "generate:RSA_1024", "generate:RSA_2048", "generate:RSA_4096", "generate:RSA_8192", "generate:DSA_1024", "generate:ECDSA_256", "generate:ECDSA_384", "generate:ECDSA_521", "generate:ED25519". | | WAB.application_get.local_domains.ca_public_key | String | The ssh public key of the signing authority for the ssh keys for accounts in the domain. | | WAB.application_get.local_domains.url | String | The API URL to the resource. | -| WAB.application_get.tags.id | String | The tag id. | | WAB.application_get.tags.key | String | The tag key. Must not start or end with a space. | | WAB.application_get.tags.value | String | The tag value. Must not start or end with a space. | | WAB.application_get.connection_policy | String | The connection policy name. Usable in the "q" parameter. | @@ -585,7 +718,8 @@ Get the application. ### wab-edit-application *** -Edit an application. +Edit an application +category: Applications #### Base Command @@ -596,12 +730,12 @@ Edit an application. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | | application_id | The application id or name to edit. | Required | -| force | The default value is false. When it is set to true the values of the global_domains and tags are replaced, otherwise the values are added to the existing ones. | Optional | +| force | The default value is false. When it is set to true the values of the global_domains and tags are replaced, otherwise the values are added to the existing ones. Possible values are: true, false. | Optional | | application_put_application_name | The application name. \/:*?"<>\| and space are forbidden. | Optional | | application_put_description | The application description. | Optional | | application_put_parameters | The application parameters. | Optional | +| application_put_global_domains | The global domains names.
    Comma-separated list (use [] for an empty list). | Optional | | application_put_connection_policy | The connection policy name. | Optional | -| application_put__meters | deprecated: use application_put_parameters instead. | Optional | #### Context Output @@ -610,7 +744,8 @@ There is no context output for this command. ### wab-delete-application *** -Delete an application. +Delete an application +category: Applications #### Base Command @@ -629,7 +764,8 @@ There is no context output for this command. ### wab-get-approvals *** -Get the approvals. +Get the approvals +category: Approvals #### Base Command @@ -680,7 +816,8 @@ Get the approvals. ### wab-get-approvals-for-all-approvers *** -Get the approvals for a given approver. +Get the approvals for a given approver +category: Approvals Assignments #### Base Command @@ -730,7 +867,8 @@ Get the approvals for a given approver. ### wab-reply-to-approval-request *** -Reply to an approval request (approve/reject it). Note: you can answer to an approval request only if you are in approvers groups of authorization. +Reply to an approval request (approve/reject it). Note: you can answer to an approval request only if you are in approvers groups of authorization +category: Approvals Assignments #### Base Command @@ -744,18 +882,21 @@ Reply to an approval request (approve/reject it). Note: you can answer to an app | approval_assignment_post_comment | The approval comment. | Required | | approval_assignment_post_duration | The allowed time range to connect (in minutes). | Optional | | approval_assignment_post_timeout | Timeout to initiate the first connection (in minutes). After that, the approval will be automatically closed. 0: no timeout. | Optional | -| approval_assignment_post_approved | Approve/reject the request. | Required | -| approval_assignment_post_is_active | The approval is active. | Optional | -| approval_assignment_post_status | The approval status. | Optional | +| approval_assignment_post_approved | Approve/reject the request. Possible values are: true, false. | Required | +| approval_assignment_post_is_active | The approval is active. Possible values are: true, false. | Optional | +| approval_assignment_post_status | The approval status. Possible values are: accepted, cancelled, closed, none, pending, rejected. | Optional | #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.reply_to_approval_request.id | String | id of the created object. | ### wab-get-approvals-for-approver *** -Get the approvals for a given approver. +Get the approvals for a given approver +category: Approvals Assignments #### Base Command @@ -806,7 +947,8 @@ Get the approvals for a given approver. ### wab-cancel-accepted-approval *** -Cancel an accepted approval. Note: you can cancel an approval only if you are in approvers groups of authorization and the end date is still not reached. +Cancel an accepted approval. Note: you can cancel an approval only if you are in approvers groups of authorization and the end date is still not reached +category: Approvals Assignments #### Base Command @@ -821,12 +963,15 @@ Cancel an accepted approval. Note: you can cancel an approval only if you are in #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.cancel_accepted_approval.id | String | id of the created object. | ### wab-notify-approvers-linked-to-approval-assignment *** -Notify approvers linked to an approval request by sending them an email. +Notify approvers linked to an approval request by sending them an email +category: Approvals Assignments #### Base Command @@ -848,7 +993,8 @@ Notify approvers linked to an approval request by sending them an email. ### wab-get-approval-request-pending-for-user *** -Get the approval request pending for this user (by default the user logged on the REST API), or the approval request with the given id. +Get the approval request pending for this user (by default the user logged on the REST API), or the approval request with the given id +category: Approvals Requests #### Base Command @@ -900,7 +1046,8 @@ Get the approval request pending for this user (by default the user logged on th ### wab-make-new-approval-request-to-access-target *** -Make a new approval request to access a target. Note: depending on the authorization settings, the fields "ticket" and "comment" may be required. +Make a new approval request to access a target. Note: depending on the authorization settings, the fields "ticket" and "comment" may be required +category: Approvals Requests #### Base Command @@ -931,7 +1078,8 @@ Make a new approval request to access a target. Note: depending on the authoriza ### wab-cancel-approval-request *** -Cancel an approval request. +Cancel an approval request +category: Approvals Requests #### Base Command @@ -945,12 +1093,15 @@ Cancel an approval request. #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.cancel_approval_request.id | String | id of the created object. | ### wab-notify-approvers-linked-to-approval-request *** -Notify approvers linked to an approval request by sending them an email. +Notify approvers linked to an approval request by sending them an email +category: Approvals Requests #### Base Command @@ -972,7 +1123,8 @@ Notify approvers linked to an approval request by sending them an email. ### wab-check-if-approval-is-required-for-target *** -Check if an approval is required for this target (optionally for a given date in future). +Check if an approval is required for this target (optionally for a given date in future) +category: Approvals Requests Target #### Base Command @@ -994,10 +1146,163 @@ Check if an approval is required for this target (optionally for a given date in | WAB.approval_request_target_get.message | String | A message with detail about the access to the target. | | WAB.approval_request_target_get.id | String | The approval id if an approval request is already pending for this target. | +### wab-get-mappings-of-domain + +*** +Get the mappings of a domain +category: Auth Domain Mappings + +#### Base Command + +`wab-get-mappings-of-domain` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| domain_id | A domain id or name to retrieve. | Required | +| q | Searches for a resource matching parameters. | Optional | +| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'user_group'. | Optional | +| offset | The index of first item to retrieve (starts and defaults to 0). | Optional | +| limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.authdomain_mapping_get.id | String | The mapping id. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.authdomain_mapping_get.domain | String | The name of the domain for which the mapping is defined. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.authdomain_mapping_get.user_group | String | The name of the Bastion users group. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.authdomain_mapping_get.external_group | String | The name of the external group \(LDAP/AD: Distinguished Name, Azure AD: name or ID\), "\*" means fallback mapping. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.authdomain_mapping_get.url | String | The API URL to the resource. | + +### wab-add-mapping-in-domain + +*** +Add a mapping in a domain and set mapping fallback. If the field "external_group" is set to "*", it is used as the fallback mapping, which allows mapping of users in the domain that do not belong to the external_group to be mapped to the user_group by default +category: Auth Domain Mappings + +#### Base Command + +`wab-add-mapping-in-domain` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| domain_id | A domain id or name. | Required | +| authdomain_mapping_post_domain | The name of the domain for which the mapping is defined. | Optional | +| authdomain_mapping_post_user_group | The name of the Bastion users group. | Required | +| authdomain_mapping_post_external_group | The name of the external group (LDAP/AD: Distinguished Name, Azure AD: name or ID), "*" means fallback mapping. | Required | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_mapping_in_domain.id | String | id of the created object. | + +### wab-edit-mappings-of-domain + +*** +Edit mappings of a domain +category: Auth Domain Mappings + +#### Base Command + +`wab-edit-mappings-of-domain` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| domain_id | A domain id or name. | Required | +| authdomain_mapping_put_domain | The name of the domain for which the mapping is defined. | Optional | +| authdomain_mapping_put_user_group | The name of the Bastion users group. | Required | +| authdomain_mapping_put_external_group | The name of the external group (LDAP/AD: Distinguished Name, Azure AD: name or ID), "*" means fallback mapping. | Required | + +#### Context Output + +There is no context output for this command. + +### wab-get-mapping-of-domain + +*** +Get the mapping of a domain +category: Auth Domain Mappings + +#### Base Command + +`wab-get-mapping-of-domain` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| domain_id | A domain id or name to retrieve. | Required | +| mapping_id | A mapping id to retrieve. If specified, only this mapping information will be retrieved. | Required | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.authdomain_mapping_get.id | String | The mapping id. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.authdomain_mapping_get.domain | String | The name of the domain for which the mapping is defined. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.authdomain_mapping_get.user_group | String | The name of the Bastion users group. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.authdomain_mapping_get.external_group | String | The name of the external group \(LDAP/AD: Distinguished Name, Azure AD: name or ID\), "\*" means fallback mapping. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.authdomain_mapping_get.url | String | The API URL to the resource. | + +### wab-edit-mapping-of-domain + +*** +Edit a mapping of a domain +category: Auth Domain Mappings + +#### Base Command + +`wab-edit-mapping-of-domain` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| domain_id | A domain id or name. | Required | +| mapping_id | A mapping id to edit. | Required | +| authdomain_mapping_put_domain | The name of the domain for which the mapping is defined. | Optional | +| authdomain_mapping_put_user_group | The name of the Bastion users group. | Required | +| authdomain_mapping_put_external_group | The name of the external group (LDAP/AD: Distinguished Name, Azure AD: name or ID), "*" means fallback mapping. | Required | + +#### Context Output + +There is no context output for this command. + +### wab-delete-mapping-of-domain + +*** +Delete the mapping of the given domain +category: Auth Domain Mappings + +#### Base Command + +`wab-delete-mapping-of-domain` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| domain_id | A domain id or name. | Required | +| mapping_id | A mapping id. | Required | + +#### Context Output + +There is no context output for this command. + ### wab-get-auth-domains *** -Get the auth domains. +Get the auth domains +category: Auth Domains #### Base Command @@ -1036,7 +1341,8 @@ Get the auth domains. ### wab-get-auth-domain *** -Get the auth domain. +Get the auth domain +category: Auth Domains #### Base Command @@ -1072,7 +1378,8 @@ Get the auth domain. ### wab-get-authentications *** -Get the authentications. +Get the authentications +category: Authentications #### Base Command @@ -1108,7 +1415,8 @@ Get the authentications. ### wab-get-authentication *** -Get the authentication. +Get the authentication +category: Authentications #### Base Command @@ -1141,7 +1449,8 @@ Get the authentication. ### wab-get-authorizations *** -Get the authorizations. +Get the authorizations +category: Authorizations #### Base Command @@ -1188,7 +1497,8 @@ Get the authorizations. ### wab-add-authorization *** -Add an authorization. +Add an authorization +category: Authorizations #### Base Command @@ -1202,32 +1512,35 @@ Add an authorization. | authorization_post_target_group | The target group. | Required | | authorization_post_authorization_name | The authorization name. \ /:*?"<>\|@& and space are forbidden. | Required | | authorization_post_description | The authorization description. | Optional | -| authorization_post_subprotocols | The authorization subprotocols. It is mandatory if "authorize_sessions" is enabled (default). | Optional | -| authorization_post_is_critical | Define if it's critical. | Optional | -| authorization_post_is_recorded | Define if it's recorded. | Optional | -| authorization_post_authorize_password_retrieval | Authorize password retrieval. Enabled by default. | Optional | -| authorization_post_authorize_sessions | Authorize sessions via proxies. Enabled by default. | Optional | -| authorization_post_approval_required | Approval is required to connect to targets. | Optional | -| authorization_post_has_comment | Comment is allowed in approval. | Optional | -| authorization_post_mandatory_comment | Comment is mandatory in approval. | Optional | -| authorization_post_has_ticket | Ticket is allowed in approval. | Optional | -| authorization_post_mandatory_ticket | Ticket is mandatory in approval. | Optional | -| authorization_post_approvers | The approvers user groups. | Optional | +| authorization_post_subprotocols | The authorization subprotocols. It is mandatory if "authorize_sessions" is enabled (default).
    Comma-separated list (use [] for an empty list). | Optional | +| authorization_post_is_critical | Define if it's critical. Possible values are: true, false. | Optional | +| authorization_post_is_recorded | Define if it's recorded. Possible values are: true, false. | Optional | +| authorization_post_authorize_password_retrieval | Authorize password retrieval. Enabled by default. Possible values are: true, false. | Optional | +| authorization_post_authorize_sessions | Authorize sessions via proxies. Enabled by default. Possible values are: true, false. | Optional | +| authorization_post_approval_required | Approval is required to connect to targets. Possible values are: true, false. | Optional | +| authorization_post_has_comment | Comment is allowed in approval. Possible values are: true, false. | Optional | +| authorization_post_mandatory_comment | Comment is mandatory in approval. Possible values are: true, false. | Optional | +| authorization_post_has_ticket | Ticket is allowed in approval. Possible values are: true, false. | Optional | +| authorization_post_mandatory_ticket | Ticket is mandatory in approval. Possible values are: true, false. | Optional | +| authorization_post_approvers | The approvers user groups.
    Comma-separated list (use [] for an empty list). | Optional | | authorization_post_active_quorum | The quorum for active periods (-1: approval workflow with automatic approval, 0: no approval workflow (direct connection), > 0: quorum to reach). | Optional | | authorization_post_inactive_quorum | The quorum for inactive periods (-1: approval workflow with automatic approval, 0: no connection allowed, > 0: quorum to reach). | Optional | -| authorization_post_single_connection | Limit to one single connection during the approval period (i.e. if the user disconnects, he will not be allowed to start a new session during the original requested time). | Optional | +| authorization_post_single_connection | Limit to one single connection during the approval period (i.e. if the user disconnects, he will not be allowed to start a new session during the original requested time). Possible values are: true, false. | Optional | | authorization_post_approval_timeout | Set a timeout in minutes after which the approval will be automatically closed if no connection has been initiated (i.e. the user won't be able to connect). 0: no timeout. | Optional | -| authorization_post_authorize_session_sharing | Enable Session Sharing. | Optional | -| authorization_post_session_sharing_mode | The Session Sharing Mode. | Optional | +| authorization_post_authorize_session_sharing | Enable Session Sharing. Possible values are: true, false. | Optional | +| authorization_post_session_sharing_mode | The Session Sharing Mode. Possible values are: view_only, view_control. | Optional | #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_authorization.id | String | id of the created object. | ### wab-get-authorization *** -Get the authorization. +Get the authorization +category: Authorizations #### Base Command @@ -1271,7 +1584,8 @@ Get the authorization. ### wab-edit-authorization *** -Edit an authorization. +Edit an authorization +category: Authorizations #### Base Command @@ -1282,26 +1596,26 @@ Edit an authorization. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | | authorization_id | The authorization id or name to edit. | Required | -| force | The default value is false. When it is set to true the values of subprotocols and approvers are replaced otherwise the values are added to the existing ones. | Optional | +| force | The default value is false. When it is set to true the values of subprotocols and approvers are replaced otherwise the values are added to the existing ones. Possible values are: true, false. | Optional | | authorization_put_authorization_name | The authorization name. \ /:*?"<>\|@& and space are forbidden. | Optional | | authorization_put_description | The authorization description. | Optional | -| authorization_put_subprotocols | The authorization subprotocols. It is mandatory if "authorize_sessions" is enabled (default). | Optional | -| authorization_put_is_critical | Define if it's critical. | Optional | -| authorization_put_is_recorded | Define if it's recorded. | Optional | -| authorization_put_authorize_password_retrieval | Authorize password retrieval. Enabled by default. | Optional | -| authorization_put_authorize_sessions | Authorize sessions via proxies. Enabled by default. | Optional | -| authorization_put_approval_required | Approval is required to connect to targets. | Optional | -| authorization_put_has_comment | Comment is allowed in approval. | Optional | -| authorization_put_mandatory_comment | Comment is mandatory in approval. | Optional | -| authorization_put_has_ticket | Ticket is allowed in approval. | Optional | -| authorization_put_mandatory_ticket | Ticket is mandatory in approval. | Optional | -| authorization_put_approvers | The approvers user groups. | Optional | +| authorization_put_subprotocols | The authorization subprotocols. It is mandatory if "authorize_sessions" is enabled (default).
    Comma-separated list (use [] for an empty list). | Optional | +| authorization_put_is_critical | Define if it's critical. Possible values are: true, false. | Optional | +| authorization_put_is_recorded | Define if it's recorded. Possible values are: true, false. | Optional | +| authorization_put_authorize_password_retrieval | Authorize password retrieval. Enabled by default. Possible values are: true, false. | Optional | +| authorization_put_authorize_sessions | Authorize sessions via proxies. Enabled by default. Possible values are: true, false. | Optional | +| authorization_put_approval_required | Approval is required to connect to targets. Possible values are: true, false. | Optional | +| authorization_put_has_comment | Comment is allowed in approval. Possible values are: true, false. | Optional | +| authorization_put_mandatory_comment | Comment is mandatory in approval. Possible values are: true, false. | Optional | +| authorization_put_has_ticket | Ticket is allowed in approval. Possible values are: true, false. | Optional | +| authorization_put_mandatory_ticket | Ticket is mandatory in approval. Possible values are: true, false. | Optional | +| authorization_put_approvers | The approvers user groups.
    Comma-separated list (use [] for an empty list). | Optional | | authorization_put_active_quorum | The quorum for active periods (-1: approval workflow with automatic approval, 0: no approval workflow (direct connection), > 0: quorum to reach). | Optional | | authorization_put_inactive_quorum | The quorum for inactive periods (-1: approval workflow with automatic approval, 0: no connection allowed, > 0: quorum to reach). | Optional | -| authorization_put_single_connection | Limit to one single connection during the approval period (i.e. if the user disconnects, he will not be allowed to start a new session during the original requested time). | Optional | +| authorization_put_single_connection | Limit to one single connection during the approval period (i.e. if the user disconnects, he will not be allowed to start a new session during the original requested time). Possible values are: true, false. | Optional | | authorization_put_approval_timeout | Set a timeout in minutes after which the approval will be automatically closed if no connection has been initiated (i.e. the user won't be able to connect). 0: no timeout. | Optional | -| authorization_put_authorize_session_sharing | Enable Session Sharing. | Optional | -| authorization_put_session_sharing_mode | The Session Sharing Mode. | Optional | +| authorization_put_authorize_session_sharing | Enable Session Sharing. Possible values are: true, false. | Optional | +| authorization_put_session_sharing_mode | The Session Sharing Mode. Possible values are: view_only, view_control. | Optional | #### Context Output @@ -1310,7 +1624,8 @@ There is no context output for this command. ### wab-delete-authorization *** -Delete an authorization. +Delete an authorization +category: Authorizations #### Base Command @@ -1329,7 +1644,8 @@ There is no context output for this command. ### wab-get-checkout-policies *** -Get the checkout policies. +Get the checkout policies +category: Checkout Policies #### Base Command @@ -1362,7 +1678,8 @@ Get the checkout policies. ### wab-get-checkout-policy *** -Get the checkout policy. +Get the checkout policy +category: Checkout Policies #### Base Command @@ -1389,10 +1706,72 @@ Get the checkout policy. | WAB.checkoutpolicy_get.change_credentials_at_checkin | Boolean | Change credentials at check-in. Usable in the "q" parameter. Usable in the "sort" parameter. | | WAB.checkoutpolicy_get.url | String | The API URL to the resource. | +### wab-get-clusters + +*** +Get the clusters +category: Clusters + +#### Base Command + +`wab-get-clusters` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| q | Searches for a resource matching parameters. | Optional | +| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'cluster_name'. | Optional | +| offset | The index of first item to retrieve (starts and defaults to 0). | Optional | +| limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.cluster_get.id | String | The cluster id. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.cluster_get.cluster_name | String | The cluster name. \\/:\*?"<>| and space are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.cluster_get.description | String | The cluster description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.cluster_get.accounts | String | The cluster targets. The targets must exist in the Bastion. | +| WAB.cluster_get.account_mappings | String | The cluster targets with account mapping. The targets must exist in the Bastion. | +| WAB.cluster_get.interactive_logins | String | The cluster targets with interactive login. The targets must exist in the Bastion. | +| WAB.cluster_get.url | String | The API URL to the resource. | + +### wab-get-cluster + +*** +Get the cluster +category: Clusters + +#### Base Command + +`wab-get-cluster` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| cluster_id | A cluster id or name. If specified, only this cluster is returned. | Required | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.cluster_get.id | String | The cluster id. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.cluster_get.cluster_name | String | The cluster name. \\/:\*?"<>| and space are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.cluster_get.description | String | The cluster description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.cluster_get.accounts | String | The cluster targets. The targets must exist in the Bastion. | +| WAB.cluster_get.account_mappings | String | The cluster targets with account mapping. The targets must exist in the Bastion. | +| WAB.cluster_get.interactive_logins | String | The cluster targets with interactive login. The targets must exist in the Bastion. | +| WAB.cluster_get.url | String | The API URL to the resource. | + ### wab-getx509-configuration-infos *** -Get the X509 configuration infos. +Get the X509 configuration infos +category: Config X509 #### Base Command @@ -1415,7 +1794,8 @@ There are no input arguments for this command. ### wab-uploadx509-configuration *** -Upload X509 configuration. +Upload X509 configuration +category: Config X509 #### Base Command @@ -1428,16 +1808,19 @@ Upload X509 configuration. | config_x509_post_ca_certificate | Certificate Authority's certificate (*.cert file in PEM format).If there's several certificate to be added, they've to be concatenated and supplied to this field, as one string. | Optional | | config_x509_post_server_public_key | Server public key (*.cert file in PEM format). | Optional | | config_x509_post_server_private_key | Server private key (*.key file in PEM format). | Optional | -| config_x509_post_enable | Enable X509 or not (true = enabled, false = disabled). | Optional | +| config_x509_post_enable | Enable X509 or not (true = enabled, false = disabled). Possible values are: true, false. | Optional | #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.uploadx509_configuration.id | String | id of the created object. | ### wab-updatex509-configuration *** -Update X509 Configuration. +Update X509 Configuration +category: Config X509 #### Base Command @@ -1450,7 +1833,7 @@ Update X509 Configuration. | config_x509_put_ca_certificate | Certificate Authority's certificate (*.cert file in PEM format).If there's several certificate to be added, they've to be concatenated and supplied to this field, as one string. | Optional | | config_x509_put_server_public_key | Server public key (*.cert file in PEM format). | Optional | | config_x509_put_server_private_key | Server private key (*.key file in PEM format). | Optional | -| config_x509_put_enable | Enable X509 or not (true = enabled, false = disabled). | Optional | +| config_x509_put_enable | Enable X509 or not (true = enabled, false = disabled). Possible values are: true, false. | Optional | #### Context Output @@ -1459,7 +1842,8 @@ There is no context output for this command. ### wab-resetx509-configuration *** -Reset X509 configuration. +Reset X509 configuration +category: Config X509 #### Base Command @@ -1476,7 +1860,8 @@ There is no context output for this command. ### wab-get-current-serial-configuration-number-of-bastion *** -Get current serial configuration number of the Bastion. This number can be used to know if the Bastion configuration was changed. +Get current serial configuration number of the Bastion. This number can be used to know if the Bastion configuration was changed +category: Configuration Number #### Base Command @@ -1492,24 +1877,22 @@ There are no input arguments for this command. | --- | --- | --- | | WAB.confignumber_get.configuration_number | Number | The current serial configuration number of the WALLIX Bastion. | -### wab-get-all-accounts-on-device-local-domain +### wab-get-connection-policies *** -Get all accounts on a device local domain. +Get the connection policies +category: Connection Policies #### Base Command -`wab-get-all-accounts-on-device-local-domain` +`wab-get-connection-policies` #### Input | **Argument Name** | **Description** | **Required** | | --- | --- | --- | -| device_id | The device id or name. | Required | -| domain_id | The local domain id or name. | Required | -| key_format | Format of the returned SSH public key of the account. Accepted values are 'openssh' (default value) and 'ssh.com'. | Optional | | q | Searches for a resource matching parameters. | Optional | -| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'account_name'. | Optional | +| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'connection_policy_name'. | Optional | | offset | The index of first item to retrieve (starts and defaults to 0). | Optional | | limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | | fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | @@ -1518,16 +1901,152 @@ Get all accounts on a device local domain. | **Path** | **Type** | **Description** | | --- | --- | --- | -| WAB.device_account_get.id | String | The account id. Usable in the "q" parameter. Usable in the "sort" parameter. | -| WAB.device_account_get.account_name | String | The account name. /:\*?"<>|@ and space are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. | -| WAB.device_account_get.account_login | String | The account login. Usable in the "q" parameter. Usable in the "sort" parameter. | -| WAB.device_account_get.description | String | The account description. Usable in the "q" parameter. Usable in the "sort" parameter. | -| WAB.device_account_get.credentials.id | String | The credential id. | -| WAB.device_account_get.credentials.type | String | The credential type. | -| WAB.device_account_get.credentials.password | String | The account password. | -| WAB.device_account_get.credentials.private_key | String | The account private key. Special values are allowed to automatically generate SSH key: "generate:RSA_1024", "generate:RSA_2048", "generate:RSA_4096", "generate:RSA_8192", "generate:DSA_1024", "generate:ECDSA_256", "generate:ECDSA_384", "generate:ECDSA_521", "generate:ED25519". | -| WAB.device_account_get.credentials.passphrase | String | The passphrase for the private key \(only for an encrypted private key\). If provided, it must be between 4 and 1024 characters long. | -| WAB.device_account_get.credentials.public_key | String | The account public key. | +| WAB.connectionpolicy_get.id | String | The connection policy id. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.connectionpolicy_get.connection_policy_name | String | The connection policy name. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.connectionpolicy_get.type | String | The connection policy type. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.connectionpolicy_get.description | String | The connection policy description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.connectionpolicy_get.protocol | String | The connection policy protocol. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.connectionpolicy_get.is_default | Boolean | True if the connection policy is a default one. | +| WAB.connectionpolicy_get.url | String | The API URL to the resource. | + +### wab-add-connection-policy + +*** +Add a connection policy +category: Connection Policies + +#### Base Command + +`wab-add-connection-policy` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| connectionpolicy_post_connection_policy_name | The connection policy name. | Required | +| connectionpolicy_post_type | The connection policy type. Possible values are: RAWTCPIP, RDP, RLOGIN, SSH, TELNET, VNC. | Required | +| connectionpolicy_post_description | The connection policy description. | Optional | +| connectionpolicy_post_protocol | The connection policy protocol. Possible values are: RAWTCPIP, RDP, RLOGIN, SSH, TELNET, VNC. | Required | +| connectionpolicy_post_authentication_methods | The allowed authentication methods.
    Comma-separated list (use [] for an empty list).
    Possible values: KERBEROS_FORWARDING,PASSWORD_INTERACTIVE,PASSWORD_MAPPING,PASSWORD_VAULT,PUBKEY_AGENT_FORWARDING,PUBKEY_VAULT. | Optional | +| options | Options for the connection policy, formatted in json. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_connection_policy.id | String | id of the created object. | + +### wab-get-connection-policy + +*** +Get the connection policy +category: Connection Policies + +#### Base Command + +`wab-get-connection-policy` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| connection_policy_id | A connection policy id or name. If specified, only this connection policy is returned. | Required | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.connectionpolicy_get.id | String | The connection policy id. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.connectionpolicy_get.connection_policy_name | String | The connection policy name. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.connectionpolicy_get.type | String | The connection policy type. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.connectionpolicy_get.description | String | The connection policy description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.connectionpolicy_get.protocol | String | The connection policy protocol. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.connectionpolicy_get.is_default | Boolean | True if the connection policy is a default one. | +| WAB.connectionpolicy_get.url | String | The API URL to the resource. | + +### wab-edit-connection-policy + +*** +Edit a connection policy +category: Connection Policies + +#### Base Command + +`wab-edit-connection-policy` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| connection_policy_id | A connection policy id or name to edit. | Required | +| force | The default value is false. When it is set to true the values of the authentication_methods are replaced, otherwise the values are added to the existing ones. Possible values are: true, false. | Optional | +| connectionpolicy_put_connection_policy_name | The connection policy name. | Optional | +| connectionpolicy_put_description | The connection policy description. | Optional | +| connectionpolicy_put_authentication_methods | The allowed authentication methods.
    Comma-separated list (use [] for an empty list).
    Possible values: KERBEROS_FORWARDING,PASSWORD_INTERACTIVE,PASSWORD_MAPPING,PASSWORD_VAULT,PUBKEY_AGENT_FORWARDING,PUBKEY_VAULT. | Optional | +| options | Options for the connection policy, formatted in json. | Optional | + +#### Context Output + +There is no context output for this command. + +### wab-delete-connection-policy + +*** +Delete a connection policy. Note: it is not possible to delete the default Bastion connection policies +category: Connection Policies + +#### Base Command + +`wab-delete-connection-policy` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| connection_policy_id | The connection policy id or name to delete. | Required | + +#### Context Output + +There is no context output for this command. + +### wab-get-all-accounts-on-device-local-domain + +*** +Get all accounts on a device local domain +category: Device Accounts + +#### Base Command + +`wab-get-all-accounts-on-device-local-domain` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| device_id | The device id or name. | Required | +| domain_id | The local domain id or name. | Required | +| key_format | Format of the returned SSH public key of the account. Accepted values are 'openssh' (default value) and 'ssh.com'. | Optional | +| q | Searches for a resource matching parameters. | Optional | +| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'account_name'. | Optional | +| offset | The index of first item to retrieve (starts and defaults to 0). | Optional | +| limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.device_account_get.id | String | The account id. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.device_account_get.account_name | String | The account name. /:\*?"<>|@ and space are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.device_account_get.account_login | String | The account login. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.device_account_get.description | String | The account description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.device_account_get.credentials.id | String | The credential id. | +| WAB.device_account_get.credentials.type | String | The credential type. | +| WAB.device_account_get.credentials.password | String | The account password. | +| WAB.device_account_get.credentials.private_key | String | The account private key. Special values are allowed to automatically generate SSH key: "generate:RSA_1024", "generate:RSA_2048", "generate:RSA_4096", "generate:RSA_8192", "generate:DSA_1024", "generate:ECDSA_256", "generate:ECDSA_384", "generate:ECDSA_521", "generate:ED25519". | +| WAB.device_account_get.credentials.passphrase | String | The passphrase for the private key \(only for an encrypted private key\). If provided, it must be between 4 and 1024 characters long. | +| WAB.device_account_get.credentials.public_key | String | The account public key. | | WAB.device_account_get.credentials.key_type | String | The key type. | | WAB.device_account_get.credentials.key_len | Number | The key length. | | WAB.device_account_get.credentials.key_id | String | The key identity: random value used for revocation. | @@ -1557,7 +2076,8 @@ Get all accounts on a device local domain. ### wab-add-account-to-local-domain-on-device *** -Add an account to a local domain on a device. +Add an account to a local domain on a device +category: Device Accounts #### Base Command @@ -1572,21 +2092,24 @@ Add an account to a local domain on a device. | device_account_post_account_name | The account name. /:*?"<>\|@ and space are forbidden. | Required | | device_account_post_account_login | The account login. | Required | | device_account_post_description | The account description. | Optional | -| device_account_post_auto_change_password | Automatically change the password. It is enabled by default on a new account. | Optional | -| device_account_post_auto_change_ssh_key | Automatically change the ssh key. It is enabled by default on a new account. | Optional | +| device_account_post_auto_change_password | Automatically change the password. It is enabled by default on a new account. Possible values are: true, false. | Optional | +| device_account_post_auto_change_ssh_key | Automatically change the ssh key. It is enabled by default on a new account. Possible values are: true, false. | Optional | | device_account_post_checkout_policy | The account checkout policy. | Required | | device_account_post_certificate_validity | The validity duration of the signed ssh public key in the case a Certificate Authority is defined for the account's domain. | Optional | -| device_account_post_can_edit_certificate_validity | True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. | Optional | -| device_account_post_services | The account services. | Optional | +| device_account_post_can_edit_certificate_validity | True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. Possible values are: true, false. | Optional | +| device_account_post_services | The account services.
    Comma-separated list (use [] for an empty list). | Optional | #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_account_to_local_domain_on_device.id | String | id of the created object. | ### wab-get-one-account-on-device-local-domain *** -Get one account on a device local domain. +Get one account on a device local domain +category: Device Accounts #### Base Command @@ -1645,7 +2168,8 @@ Get one account on a device local domain. ### wab-edit-account-on-local-domain-of-device *** -Edit an account on a local domain of a device. +Edit an account on a local domain of a device +category: Device Accounts #### Base Command @@ -1658,17 +2182,17 @@ Edit an account on a local domain of a device. | device_id | The device id or name. | Required | | domain_id | The local domain id or name. | Required | | account_id | The account id or name to edit. | Required | -| force | The default value is false. When it is set to true the values of the credentials and services, if they are supplied, are replaced, otherwise the values are added to the existing ones. | Optional | +| force | The default value is false. When it is set to true the values of the credentials and services, if they are supplied, are replaced, otherwise the values are added to the existing ones. Possible values are: true, false. | Optional | | device_account_put_account_name | The account name. /:*?"<>\|@ and space are forbidden. | Optional | | device_account_put_account_login | The account login. | Optional | | device_account_put_description | The account description. | Optional | -| device_account_put_auto_change_password | Automatically change the password. It is enabled by default on a new account. | Optional | -| device_account_put_auto_change_ssh_key | Automatically change the ssh key. It is enabled by default on a new account. | Optional | +| device_account_put_auto_change_password | Automatically change the password. It is enabled by default on a new account. Possible values are: true, false. | Optional | +| device_account_put_auto_change_ssh_key | Automatically change the ssh key. It is enabled by default on a new account. Possible values are: true, false. | Optional | | device_account_put_checkout_policy | The account checkout policy. | Optional | | device_account_put_certificate_validity | The validity duration of the signed ssh public key in the case a Certificate Authority is defined for the account's domain. | Optional | -| device_account_put_can_edit_certificate_validity | True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. | Optional | -| device_account_put_onboard_status | Onboarding status of the account. | Optional | -| device_account_put_services | The account services. | Optional | +| device_account_put_can_edit_certificate_validity | True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. Possible values are: true, false. | Optional | +| device_account_put_onboard_status | Onboarding status of the account. Possible values are: onboarded, to_onboard, hide, manual. | Optional | +| device_account_put_services | The account services.
    Comma-separated list (use [] for an empty list). | Optional | #### Context Output @@ -1677,7 +2201,8 @@ There is no context output for this command. ### wab-delete-account-from-local-domain-of-device *** -Delete an account from a local domain of a device. +Delete an account from a local domain of a device +category: Device Accounts #### Base Command @@ -1698,7 +2223,8 @@ There is no context output for this command. ### wab-get-certificates-on-device *** -Get the certificates on a device. +Get the certificates on a device +category: Device Certificates #### Base Command @@ -1730,7 +2256,8 @@ Get the certificates on a device. ### wab-get-certificate-on-device *** -Get the certificate on a device. +Get the certificate on a device +category: Device Certificates #### Base Command @@ -1765,7 +2292,8 @@ Get the certificate on a device. ### wab-revoke-certificate-of-device *** -Revoke a certificate of a device. +Revoke a certificate of a device +category: Device Certificates #### Base Command @@ -1784,10 +2312,80 @@ Revoke a certificate of a device. There is no context output for this command. +### wab-get-local-domains-of-device + +*** +Get the local domains of a device +category: Device Local Domains + +#### Base Command + +`wab-get-local-domains-of-device` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| device_id | The device id or name. | Required | +| q | Searches for a resource matching parameters. | Optional | +| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'domain_name'. | Optional | +| offset | The index of first item to retrieve (starts and defaults to 0). | Optional | +| limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.localdomain_get.id | String | The domain id. Usable in the "q" parameter. | +| WAB.localdomain_get.domain_name | String | The domain name. /:\*?"<>|@ are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.localdomain_get.description | String | The domain description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.localdomain_get.enable_password_change | Boolean | Enable the change of password on this domain. | +| WAB.localdomain_get.admin_account | String | The administrator account used to change passwords on this domain \(format: "account_name"\). | +| WAB.localdomain_get.password_change_policy | String | The name of password change policy for this domain. | +| WAB.localdomain_get.password_change_plugin | String | The name of plugin used to change passwords on this domain. | +| WAB.localdomain_get.ca_private_key | String | The ssh private key of the signing authority for the ssh keys for accounts in the domain. Special values are allowed to automatically generate SSH key: "generate:RSA_1024", "generate:RSA_2048", "generate:RSA_4096", "generate:RSA_8192", "generate:DSA_1024", "generate:ECDSA_256", "generate:ECDSA_384", "generate:ECDSA_521", "generate:ED25519". | +| WAB.localdomain_get.ca_public_key | String | The ssh public key of the signing authority for the ssh keys for accounts in the domain. | +| WAB.localdomain_get.url | String | The API URL to the resource. | + +### wab-get-local-domain-of-device + +*** +Get the local domain of a device +category: Device Local Domains + +#### Base Command + +`wab-get-local-domain-of-device` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| device_id | The device id or name. | Required | +| domain_id | The local domain id or name. | Required | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.localdomain_get.id | String | The domain id. Usable in the "q" parameter. | +| WAB.localdomain_get.domain_name | String | The domain name. /:\*?"<>|@ are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.localdomain_get.description | String | The domain description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.localdomain_get.enable_password_change | Boolean | Enable the change of password on this domain. | +| WAB.localdomain_get.admin_account | String | The administrator account used to change passwords on this domain \(format: "account_name"\). | +| WAB.localdomain_get.password_change_policy | String | The name of password change policy for this domain. | +| WAB.localdomain_get.password_change_plugin | String | The name of plugin used to change passwords on this domain. | +| WAB.localdomain_get.ca_private_key | String | The ssh private key of the signing authority for the ssh keys for accounts in the domain. Special values are allowed to automatically generate SSH key: "generate:RSA_1024", "generate:RSA_2048", "generate:RSA_4096", "generate:RSA_8192", "generate:DSA_1024", "generate:ECDSA_256", "generate:ECDSA_384", "generate:ECDSA_521", "generate:ED25519". | +| WAB.localdomain_get.ca_public_key | String | The ssh public key of the signing authority for the ssh keys for accounts in the domain. | +| WAB.localdomain_get.url | String | The API URL to the resource. | + ### wab-get-services-of-device *** -Get the services of a device. +Get the services of a device +category: Device Services #### Base Command @@ -1819,7 +2417,8 @@ Get the services of a device. ### wab-add-service-in-device *** -Add a service in a device. +Add a service in a device +category: Device Services #### Base Command @@ -1832,20 +2431,24 @@ Add a service in a device. | device_id | The device id or name. | Required | | service_post_id | The service id. Usable in the "sort" parameter. | Optional | | service_post_service_name | The service name. Must start with a letter; only letters, digits and -_ are allowed. Usable in the "sort" parameter. / The service name. Must start with a letter; only letters, digits and -_ are allowed. Usable in the "q" parameter. Usable in the "sort" parameter. | Required | -| service_post_protocol | The protocol. Usable in the "sort" parameter. / The protocol. Usable in the "q" parameter. Usable in the "sort" parameter. | Required | +| service_post_protocol | The protocol. Usable in the "sort" parameter. / The protocol. Usable in the "q" parameter. Usable in the "sort" parameter. Possible values are: RAWTCPIP, RDP, RLOGIN, SSH, TELNET, VNC. | Required | | service_post_port | The port number. Usable in the "sort" parameter. / The port number. Usable in the "q" parameter. Usable in the "sort" parameter. | Required | -| service_post_subprotocols | The sub protocols. | Required | +| service_post_subprotocols | The sub protocols.
    Comma-separated list (use [] for an empty list).
    Possible values: RDP_AUDIO_INPUT,RDP_AUDIO_OUTPUT,RDP_CLIPBOARD_DOWN,RDP_CLIPBOARD_FILE,RDP_CLIPBOARD_UP,RDP_COM_PORT,RDP_DRIVE,RDP_PRINTER,RDP_SMARTCARD,SFTP_SESSION,SSH_AUTH_AGENT,SSH_DIRECT_TCPIP,SSH_DIRECT_UNIXSOCK,SSH_REMOTE_COMMAND,SSH_REVERSE_TCPIP,SSH_REVERSE_UNIXSOCK,SSH_SCP_DOWN,SSH_SCP_UP,SSH_SHELL_SESSION,SSH_X11. | Optional | | service_post_connection_policy | The connection policy name. Usable in the "q" parameter. Usable in the "sort" parameter. | Required | -| service_post_global_domains | The global domains names. | Optional | +| service_post_global_domains | The global domains names.
    Comma-separated list (use [] for an empty list). | Optional | +| service_post_seamless_connection | The seamless connection. Possible values are: true, false. | Optional | #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_service_in_device.id | String | id of the created object. | ### wab-get-service-of-device *** -Get the service of a device. +Get the service of a device +category: Device Services #### Base Command @@ -1874,7 +2477,8 @@ Get the service of a device. ### wab-edit-service-of-device *** -Edit a service of a device. +Edit a service of a device +category: Device Services #### Base Command @@ -1886,10 +2490,12 @@ Edit a service of a device. | --- | --- | --- | | device_id | The device id or name. | Required | | service_id | The service id or name to edit. | Required | -| force | The default value is false. When it is set to true the values of the subprotocols, global_domains and additional_interfaces are replaced, otherwise the values are added to the existing ones. | Optional | +| force | The default value is false. When it is set to true the values of the subprotocols, global_domains and additional_interfaces are replaced, otherwise the values are added to the existing ones. Possible values are: true, false. | Optional | | service_put_port | The port number. | Optional | +| service_put_subprotocols | The sub protocols.
    Comma-separated list (use [] for an empty list).
    Possible values: RDP_AUDIO_INPUT,RDP_AUDIO_OUTPUT,RDP_CLIPBOARD_DOWN,RDP_CLIPBOARD_FILE,RDP_CLIPBOARD_UP,RDP_COM_PORT,RDP_DRIVE,RDP_PRINTER,RDP_SMARTCARD,SFTP_SESSION,SSH_AUTH_AGENT,SSH_DIRECT_TCPIP,SSH_DIRECT_UNIXSOCK,SSH_REMOTE_COMMAND,SSH_REVERSE_TCPIP,SSH_REVERSE_UNIXSOCK,SSH_SCP_DOWN,SSH_SCP_UP,SSH_SHELL_SESSION,SSH_X11. | Optional | | service_put_connection_policy | The connection policy name. | Optional | -| service_put_global_domains | The global domains names. | Optional | +| service_put_global_domains | The global domains names.
    Comma-separated list (use [] for an empty list). | Optional | +| service_put_seamless_connection | The seamless connection. Possible values are: true, false. | Optional | #### Context Output @@ -1898,7 +2504,8 @@ There is no context output for this command. ### wab-delete-service-from-device *** -Delete a service from a device. +Delete a service from a device +category: Device Services #### Base Command @@ -1918,7 +2525,8 @@ There is no context output for this command. ### wab-get-devices *** -Get the devices. +Get the devices +category: Devices #### Base Command @@ -1961,7 +2569,6 @@ Get the devices. | WAB.device_get.services.connection_policy | String | The connection policy name. Usable in the "q" parameter. Usable in the "sort" parameter. | | WAB.device_get.services.global_domains | String | The global domains names. | | WAB.device_get.services.url | String | The API URL to the resource. | -| WAB.device_get.tags.id | String | The tag id. | | WAB.device_get.tags.key | String | The tag key. Must not start or end with a space. | | WAB.device_get.tags.value | String | The tag value. Must not start or end with a space. | | WAB.device_get.onboard_status | String | Onboarding status of the device Usable in the "q" parameter. Usable in the "sort" parameter. | @@ -1982,7 +2589,8 @@ Get the devices. ### wab-add-device *** -Add a device. +Add a device +category: Devices #### Base Command @@ -1999,12 +2607,15 @@ Add a device. #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_device.id | String | id of the created object. | ### wab-get-device *** -Get the device. +Get the device +category: Devices #### Base Command @@ -2044,7 +2655,6 @@ Get the device. | WAB.device_get.services.connection_policy | String | The connection policy name. Usable in the "q" parameter. Usable in the "sort" parameter. | | WAB.device_get.services.global_domains | String | The global domains names. | | WAB.device_get.services.url | String | The API URL to the resource. | -| WAB.device_get.tags.id | String | The tag id. | | WAB.device_get.tags.key | String | The tag key. Must not start or end with a space. | | WAB.device_get.tags.value | String | The tag value. Must not start or end with a space. | | WAB.device_get.onboard_status | String | Onboarding status of the device Usable in the "q" parameter. Usable in the "sort" parameter. | @@ -2065,7 +2675,8 @@ Get the device. ### wab-edit-device *** -Edit a device. +Edit a device +category: Devices #### Base Command @@ -2076,12 +2687,12 @@ Edit a device. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | | device_id | The device id or name to edit. | Required | -| force | The default value is false. When it is set to true the values of the tags are replaced, otherwise the values are added to the existing ones. | Optional | +| force | The default value is false. When it is set to true the values of the tags are replaced, otherwise the values are added to the existing ones. Possible values are: true, false. | Optional | | device_put_device_name | The device name. \ /:*?"<>\|@ and space are forbidden. | Optional | | device_put_description | The device description. | Optional | | device_put_alias | The device alias. \ /:*?"<>\|@ and space are forbidden. | Optional | | device_put_host | The device host address. | Optional | -| device_put_onboard_status | Onboarding status of the device. | Optional | +| device_put_onboard_status | Onboarding status of the device. Possible values are: onboarded, to_onboard, hide, manual. | Optional | #### Context Output @@ -2090,7 +2701,8 @@ There is no context output for this command. ### wab-delete-device *** -Delete a device. +Delete a device +category: Devices #### Base Command @@ -2109,7 +2721,8 @@ There is no context output for this command. ### wab-get-accounts-of-global-domain *** -Get the accounts of a global domain. +Get the accounts of a global domain +category: Domain Accounts #### Base Command @@ -2168,7 +2781,8 @@ Get the accounts of a global domain. ### wab-add-account-in-global-domain *** -Add an account in a global domain. +Add an account in a global domain +category: Domain Accounts #### Base Command @@ -2182,21 +2796,24 @@ Add an account in a global domain. | domain_account_post_account_name | The account name. /:*?"<>\|@ and space are forbidden. | Required | | domain_account_post_account_login | The account login. | Required | | domain_account_post_description | The account description. | Optional | -| domain_account_post_auto_change_password | Automatically change the password. It is enabled by default on a new account. | Optional | -| domain_account_post_auto_change_ssh_key | Automatically change the ssh key. It is enabled by default on a new account. | Optional | +| domain_account_post_auto_change_password | Automatically change the password. It is enabled by default on a new account. Possible values are: true, false. | Optional | +| domain_account_post_auto_change_ssh_key | Automatically change the ssh key. It is enabled by default on a new account. Possible values are: true, false. | Optional | | domain_account_post_checkout_policy | The account checkout policy. | Required | | domain_account_post_certificate_validity | The validity duration of the signed ssh public key in the case a Certificate Authority is defined for the account's domain. | Optional | -| domain_account_post_can_edit_certificate_validity | True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. | Optional | -| domain_account_post_resources | The account resources. | Optional | +| domain_account_post_can_edit_certificate_validity | True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. Possible values are: true, false. | Optional | +| domain_account_post_resources | The account resources.
    Comma-separated list (use [] for an empty list). | Optional | #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_account_in_global_domain.id | String | id of the created object. | ### wab-get-account-of-global-domain *** -Get the account of a global domain. +Get the account of a global domain +category: Domain Accounts #### Base Command @@ -2253,7 +2870,8 @@ Get the account of a global domain. ### wab-edit-account-in-global-domain *** -Edit an account in a global domain. +Edit an account in a global domain +category: Domain Accounts #### Base Command @@ -2265,17 +2883,17 @@ Edit an account in a global domain. | --- | --- | --- | | domain_id | The global domain id or name. | Required | | account_id | The account id or name to edit. | Required | -| force | The default value is false. When it is set to true the values of the credentials and services, if they are supplied, are replaced, otherwise the values are added to the existing ones. | Optional | +| force | The default value is false. When it is set to true the values of the credentials and services, if they are supplied, are replaced, otherwise the values are added to the existing ones. Possible values are: true, false. | Optional | | domain_account_put_account_name | The account name. /:*?"<>\|@ and space are forbidden. | Optional | | domain_account_put_account_login | The account login. | Optional | | domain_account_put_description | The account description. | Optional | -| domain_account_put_auto_change_password | Automatically change the password. It is enabled by default on a new account. | Optional | -| domain_account_put_auto_change_ssh_key | Automatically change the ssh key. It is enabled by default on a new account. | Optional | +| domain_account_put_auto_change_password | Automatically change the password. It is enabled by default on a new account. Possible values are: true, false. | Optional | +| domain_account_put_auto_change_ssh_key | Automatically change the ssh key. It is enabled by default on a new account. Possible values are: true, false. | Optional | | domain_account_put_checkout_policy | The account checkout policy. | Optional | | domain_account_put_certificate_validity | The validity duration of the signed ssh public key in the case a Certificate Authority is defined for the account's domain. | Optional | -| domain_account_put_can_edit_certificate_validity | True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. | Optional | -| domain_account_put_onboard_status | Onboarding status of the account. | Optional | -| domain_account_put_resources | The account resources. | Optional | +| domain_account_put_can_edit_certificate_validity | True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. Possible values are: true, false. | Optional | +| domain_account_put_onboard_status | Onboarding status of the account. Possible values are: onboarded, to_onboard, hide, manual. | Optional | +| domain_account_put_resources | The account resources.
    Comma-separated list (use [] for an empty list). | Optional | #### Context Output @@ -2284,7 +2902,8 @@ There is no context output for this command. ### wab-delete-account-from-global-domain *** -Delete an account from a global domain. +Delete an account from a global domain +category: Domain Accounts #### Base Command @@ -2304,7 +2923,8 @@ There is no context output for this command. ### wab-delete-resource-from-global-domain-account *** -delete a resource from the global domain account. +delete a resource from the global domain account +category: Domain Accounts #### Base Command @@ -2325,7 +2945,8 @@ There is no context output for this command. ### wab-get-global-domains *** -Get the global domains. +Get the global domains +category: Domains #### Base Command @@ -2365,7 +2986,8 @@ Get the global domains. ### wab-get-global-domain *** -Get the global domain. +Get the global domain +category: Domains #### Base Command @@ -2399,10 +3021,40 @@ Get the global domain. | WAB.domain_get.is_editable | Boolean | True if the domain is editable by the user who made the query. This might be slow to compute for a domain with many accounts if the user has limitations. | | WAB.domain_get.url | String | The API URL to the resource. | +### wab-get-external-authentication-group-mappings + +*** +Get the external authentication group mappings +category: Ldap Mappings + +#### Base Command + +`wab-get-external-authentication-group-mappings` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_by | Group the result-set by one property. Can take one of the values 'user_group' or 'domain'. | Optional | +| q | Searches for a resource matching parameters. Used only if "group_by" is not set. | Optional | +| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'domain,user_group'. Used only if "group_by" is not set. | Optional | +| offset | The index of first item to retrieve (starts and defaults to 0). Used only if "group_by" is not set. | Optional | +| limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. Used only if "group_by" is not set. | Optional | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.authmappings_get.domain | String | The name of the domain for which the mapping is defined. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.authmappings_get.user_group | String | The name of the Bastion users group. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.authmappings_get.external_group | String | The name of the external group \(LDAP/AD: Distinguished Name, Azure AD: name or ID\), "\*" means fallback mapping. Usable in the "q" parameter. Usable in the "sort" parameter. | + ### wab-get-ldap-users-of-domain *** -Get the LDAP users of a given domain. +Get the LDAP users of a given domain +category: Ldap Users #### Base Command @@ -2413,7 +3065,7 @@ Get the LDAP users of a given domain. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | | domain | A LDAP domain name. All users in this domain are returned. | Required | -| last_connection | If set to true, the date of last connection is returned for each user returned. Be careful: this can slow down the request if a lot of users are returned. | Optional | +| last_connection | If set to true, the date of last connection is returned for each user returned. Be careful: this can slow down the request if a lot of users are returned. Possible values are: true, false. | Optional | | q | Searches for a resource matching parameters. | Optional | | offset | The index of first item to retrieve (starts and defaults to 0). | Optional | | limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | @@ -2438,7 +3090,8 @@ Get the LDAP users of a given domain. ### wab-get-ldap-user-of-domain *** -Get the LDAP user of a given domain. +Get the LDAP user of a given domain +category: Ldap Users #### Base Command @@ -2450,7 +3103,7 @@ Get the LDAP user of a given domain. | --- | --- | --- | | domain | A LDAP domain name. All users in this domain are returned. | Required | | user_name | A user name. If specified, only this user is returned. | Required | -| last_connection | If set to true, the date of last connection is returned for each user returned. Be careful: this can slow down the request if a lot of users are returned. | Optional | +| last_connection | If set to true, the date of last connection is returned for each user returned. Be careful: this can slow down the request if a lot of users are returned. Possible values are: true, false. | Optional | | fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | #### Context Output @@ -2472,7 +3125,8 @@ Get the LDAP user of a given domain. ### wab-get-information-about-wallix-bastion-license *** -Get information about the WALLIX Bastion license. +Get information about the WALLIX Bastion license +category: License Info #### Base Command @@ -2524,7 +3178,8 @@ There are no input arguments for this command. ### wab-post-logsiem *** -Write a message in /var/log/wabaudit.log and send it to the SIEM (if configured). +Write a message in /var/log/wabaudit.log and send it to the SIEM (if configured) +category: Log Siem #### Base Command @@ -2539,12 +3194,15 @@ Write a message in /var/log/wabaudit.log and send it to the SIEM (if configured) #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.post_logsiem.id | String | id of the created object. | ### wab-get-notifications *** -Get the notifications. +Get the notifications +category: Notifications #### Base Command @@ -2576,7 +3234,8 @@ Get the notifications. ### wab-add-notification *** -Add a notification. +Add a notification +category: Notifications #### Base Command @@ -2588,20 +3247,23 @@ Add a notification. | --- | --- | --- | | notification_post_notification_name | The notification name. | Required | | notification_post_description | The notification description. | Optional | -| notification_post_enabled | Notification is enabled. | Required | -| notification_post_type | Notification type. | Required | +| notification_post_enabled | Notification is enabled. Possible values are: true, false. | Required | +| notification_post_type | Notification type. Possible values are: email. | Required | | notification_post_destination | Destination for notification; for the type "email", this is a list of recipient emails separated by ";". | Required | -| notification_post_language | The notification language (in email). | Required | -| notification_post_events | The list of events that will trigger a notification. | Optional | +| notification_post_language | The notification language (in email). Possible values are: de, en, es, fr, ru. | Required | +| notification_post_events | The list of events that will trigger a notification.
    Comma-separated list (use [] for an empty list).
    Possible values: cx_equipment,daily_reporting,external_storage_full,filesystem_full,integrity_error,licence_notifications,new_fingerprint,password_expired,pattern_found,primary_cx_failed,raid_error,rdp_outcxn_found,rdp_pattern_found,rdp_process_found,secondary_cx_failed,sessionlog_purge,watchdog_notifications,wrong_fingerprint. | Optional | #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_notification.id | String | id of the created object. | ### wab-get-notification *** -Get the notification. +Get the notification +category: Notifications #### Base Command @@ -2630,7 +3292,8 @@ Get the notification. ### wab-edit-notification *** -Edit a notification. +Edit a notification +category: Notifications #### Base Command @@ -2641,14 +3304,14 @@ Edit a notification. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | | notification_id | The notification id or name to edit. | Required | -| force | The default value is false. When it is set to true the values of the events are replaced, otherwise the values are added to the existing ones. | Optional | +| force | The default value is false. When it is set to true the values of the events are replaced, otherwise the values are added to the existing ones. Possible values are: true, false. | Optional | | notification_put_notification_name | The notification name. | Optional | | notification_put_description | The notification description. | Optional | -| notification_put_enabled | Notification is enabled. | Optional | -| notification_put_type | Notification type. | Optional | +| notification_put_enabled | Notification is enabled. Possible values are: true, false. | Optional | +| notification_put_type | Notification type. Possible values are: email. | Optional | | notification_put_destination | Destination for notification; for the type "email", this is a list of recipient emails separated by ";". | Optional | -| notification_put_language | The notification language (in email). | Optional | -| notification_put_events | The list of events that will trigger a notification. | Optional | +| notification_put_language | The notification language (in email). Possible values are: de, en, es, fr, ru. | Optional | +| notification_put_events | The list of events that will trigger a notification.
    Comma-separated list (use [] for an empty list).
    Possible values: cx_equipment,daily_reporting,external_storage_full,filesystem_full,integrity_error,licence_notifications,new_fingerprint,password_expired,pattern_found,primary_cx_failed,raid_error,rdp_outcxn_found,rdp_pattern_found,rdp_process_found,secondary_cx_failed,sessionlog_purge,watchdog_notifications,wrong_fingerprint. | Optional | #### Context Output @@ -2657,7 +3320,8 @@ There is no context output for this command. ### wab-delete-notification *** -Delete a notification. +Delete a notification +category: Notifications #### Base Command @@ -2676,7 +3340,8 @@ There is no context output for this command. ### wab-get-object-to-onboard *** -Get object to onboard, by type (either devices with their linked accounts or global accounts alone). +Get object to onboard, by type (either devices with their linked accounts or global accounts alone) +category: Onboarding Objects #### Base Command @@ -2715,136 +3380,393 @@ Get object to onboard, by type (either devices with their linked accounts or glo | WAB.onboarding_objects_get.last_seen.end | String | Scan job end timestamp. | | WAB.onboarding_objects_get.url | String | The API URL to the resource. | -### wab-get-profiles +### wab-get-password-change-policies *** -Get the profiles. +Get the password change policies +category: Password Change Policies #### Base Command -`wab-get-profiles` +`wab-get-password-change-policies` #### Input | **Argument Name** | **Description** | **Required** | | --- | --- | --- | | q | Searches for a resource matching parameters. | Optional | -| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'profile_name'. | Optional | +| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'password_change_policy_name'. | Optional | | offset | The index of first item to retrieve (starts and defaults to 0). | Optional | | limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | -| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | #### Context Output | **Path** | **Type** | **Description** | | --- | --- | --- | -| WAB.profile_get.id | String | The profile id. Usable in the "q" parameter. Usable in the "sort" parameter. | -| WAB.profile_get.profile_name | String | The profile name. Usable in the "q" parameter. Usable in the "sort" parameter. | -| WAB.profile_get.editable | Boolean | Profile is editable. Usable in the "q" parameter. Usable in the "sort" parameter. | -| WAB.profile_get.description | String | The target group description. Usable in the "q" parameter. Usable in the "sort" parameter. | -| WAB.profile_get.gui_features.wab_audit | String | wab audit. | -| WAB.profile_get.gui_features.system_audit | String | system audit. | -| WAB.profile_get.gui_features.users | String | users. | -| WAB.profile_get.gui_features.user_groups | String | user groups. | -| WAB.profile_get.gui_features.devices | String | devices. | -| WAB.profile_get.gui_features.target_groups | String | target groups. | -| WAB.profile_get.gui_features.authorizations | String | authorizations. | -| WAB.profile_get.gui_features.profiles | String | profiles. | -| WAB.profile_get.gui_features.wab_settings | String | wab settings. | -| WAB.profile_get.gui_features.system_settings | String | system settings. | -| WAB.profile_get.gui_features.backup | String | backup. | -| WAB.profile_get.gui_features.approval | String | approval. | -| WAB.profile_get.gui_features.credential_recovery | String | credential recovery. | -| WAB.profile_get.gui_transmission.system_audit | String | system audit. | -| WAB.profile_get.gui_transmission.users | String | users. | -| WAB.profile_get.gui_transmission.user_groups | String | user groups. | -| WAB.profile_get.gui_transmission.devices | String | devices. | -| WAB.profile_get.gui_transmission.target_groups | String | target groups. | -| WAB.profile_get.gui_transmission.authorizations | String | authorizations. | -| WAB.profile_get.gui_transmission.profiles | String | profiles. | -| WAB.profile_get.gui_transmission.wab_settings | String | wab settings. | -| WAB.profile_get.gui_transmission.system_settings | String | system settings. | -| WAB.profile_get.gui_transmission.backup | String | backup. | -| WAB.profile_get.gui_transmission.approval | String | approval. | -| WAB.profile_get.gui_transmission.credential_recovery | String | credential recovery. | -| WAB.profile_get.ip_limitation | String | The profile ip limitation. Format is an IPv4 address, subnet or host name, for example: 192.168.1.10/24 Usable in the "q" parameter. Usable in the "sort" parameter. | -| WAB.profile_get.target_access | Boolean | Target access. | -| WAB.profile_get.dashboards | String | Ordered list of dashboards names. Usable in the "q" parameter. | -| WAB.profile_get.url | String | The API URL to the resource. | -| WAB.profile_get.gui_features.dashboards | String | deprecated: unused field. | - -### wab-get-profile +| WAB.passwordchangepolicy_get.id | String | The password change policy id. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.password_change_policy_name | String | The password change policy name. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.description | String | The password change policy description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.password_length | Number | Number of chars in password. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.special_chars | Number | The minimum number of special chars in password \(0 = no minimum, null = no special chars at all\). Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.lower_chars | Number | The minimum number of lower case chars in password \(0 = no minimum, null = no lower case chars at all\). Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.upper_chars | Number | The minimum number of upper case chars in password \(0 = no minimum, null = no upper case chars at all\). Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.digit_chars | Number | The minimum number of digit chars in password \(0 = no minimum, null = no digit chars at all\). Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.exclude_chars | String | Characters to exclude in password. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.ssh_key_type | String | The SSH key type. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.ssh_key_size | Number | The SSH key size \(in bits\). Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.change_period | String | +The period to change password. + +String value must be a valid cron syntax \(e.g. '\\\* \\\* \\\* \\\* \\\*'\). + +Aliases are allowed: + +@hourly → 0 \\\* \\\* \\\* \\\* +@daily → 0 0 \\\* \\\* \\\* +@weekly → 0 0 \\\* \\\* 0 +@monthly → 0 0 1 \\\* \\\* +@yearly → 0 0 1 1 \\\* + +Note: An empty string \(or null\) will deactivate the change password schedule. +Moreover, @reboot is not allowed. + Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.url | String | The API URL to the resource. | + +### wab-add-password-change-policy *** -Get the profile. +Add a password change policy. Note: at least password or SSH options must be given in the policy (and both can be used at same time) +category: Password Change Policies #### Base Command -`wab-get-profile` +`wab-add-password-change-policy` #### Input | **Argument Name** | **Description** | **Required** | | --- | --- | --- | -| profile_id | A profile id or name. If specified, only this profile is returned. | Required | -| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | +| passwordchangepolicy_post_password_change_policy_name | The password change policy name. | Required | +| passwordchangepolicy_post_description | The password change policy description. | Optional | +| passwordchangepolicy_post_password_length | Number of chars in password. (enter null for null value). | Optional | +| passwordchangepolicy_post_special_chars | The minimum number of special chars in password (0 = no minimum, null = no special chars at all). (enter null for null value). | Optional | +| passwordchangepolicy_post_lower_chars | The minimum number of lower case chars in password (0 = no minimum, null = no lower case chars at all). (enter null for null value). | Optional | +| passwordchangepolicy_post_upper_chars | The minimum number of upper case chars in password (0 = no minimum, null = no upper case chars at all). (enter null for null value). | Optional | +| passwordchangepolicy_post_digit_chars | The minimum number of digit chars in password (0 = no minimum, null = no digit chars at all). (enter null for null value). | Optional | +| passwordchangepolicy_post_exclude_chars | Characters to exclude in password. (enter null for null value). | Optional | +| passwordchangepolicy_post_ssh_key_type | The SSH key type. (enter null for null value). | Optional | +| passwordchangepolicy_post_ssh_key_size | The SSH key size (in bits). (enter null for null value). | Optional | +| passwordchangepolicy_post_change_period |
    The period to change password.

    String value must be a valid cron syntax (e.g. '\* \* \* \* \*').

    Aliases are allowed:

    @hourly → 0 \* \* \* \*
    @daily → 0 0 \* \* \*
    @weekly → 0 0 \* \* 0
    @monthly → 0 0 1 \* \*
    @yearly → 0 0 1 1 \*

    Note: An empty string (or null) will deactivate the change password schedule.
    Moreover, @reboot is not allowed.
    (enter null for null value). | Optional | #### Context Output | **Path** | **Type** | **Description** | | --- | --- | --- | -| WAB.profile_get.id | String | The profile id. Usable in the "q" parameter. Usable in the "sort" parameter. | -| WAB.profile_get.profile_name | String | The profile name. Usable in the "q" parameter. Usable in the "sort" parameter. | -| WAB.profile_get.editable | Boolean | Profile is editable. Usable in the "q" parameter. Usable in the "sort" parameter. | -| WAB.profile_get.description | String | The target group description. Usable in the "q" parameter. Usable in the "sort" parameter. | -| WAB.profile_get.gui_features.wab_audit | String | wab audit. | -| WAB.profile_get.gui_features.system_audit | String | system audit. | -| WAB.profile_get.gui_features.users | String | users. | -| WAB.profile_get.gui_features.user_groups | String | user groups. | -| WAB.profile_get.gui_features.devices | String | devices. | -| WAB.profile_get.gui_features.target_groups | String | target groups. | -| WAB.profile_get.gui_features.authorizations | String | authorizations. | -| WAB.profile_get.gui_features.profiles | String | profiles. | -| WAB.profile_get.gui_features.wab_settings | String | wab settings. | -| WAB.profile_get.gui_features.system_settings | String | system settings. | -| WAB.profile_get.gui_features.backup | String | backup. | -| WAB.profile_get.gui_features.approval | String | approval. | -| WAB.profile_get.gui_features.credential_recovery | String | credential recovery. | -| WAB.profile_get.gui_transmission.system_audit | String | system audit. | -| WAB.profile_get.gui_transmission.users | String | users. | -| WAB.profile_get.gui_transmission.user_groups | String | user groups. | -| WAB.profile_get.gui_transmission.devices | String | devices. | -| WAB.profile_get.gui_transmission.target_groups | String | target groups. | -| WAB.profile_get.gui_transmission.authorizations | String | authorizations. | -| WAB.profile_get.gui_transmission.profiles | String | profiles. | -| WAB.profile_get.gui_transmission.wab_settings | String | wab settings. | -| WAB.profile_get.gui_transmission.system_settings | String | system settings. | -| WAB.profile_get.gui_transmission.backup | String | backup. | -| WAB.profile_get.gui_transmission.approval | String | approval. | -| WAB.profile_get.gui_transmission.credential_recovery | String | credential recovery. | -| WAB.profile_get.ip_limitation | String | The profile ip limitation. Format is an IPv4 address, subnet or host name, for example: 192.168.1.10/24 Usable in the "q" parameter. Usable in the "sort" parameter. | -| WAB.profile_get.target_access | Boolean | Target access. | -| WAB.profile_get.dashboards | String | Ordered list of dashboards names. Usable in the "q" parameter. | -| WAB.profile_get.url | String | The API URL to the resource. | -| WAB.profile_get.gui_features.dashboards | String | deprecated: unused field. | +| WAB.add_password_change_policy.id | String | id of the created object. | -### wab-get-scanjobs +### wab-get-password-change-policy *** -Get the scanjobs. +Get the password change policy +category: Password Change Policies #### Base Command -`wab-get-scanjobs` +`wab-get-password-change-policy` #### Input | **Argument Name** | **Description** | **Required** | | --- | --- | --- | -| q | Searches for a resource matching parameters. | Optional | -| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'scan_name'. | Optional | -| offset | The index of first item to retrieve (starts and defaults to 0). | Optional | -| limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | +| policy_id | A password change policy id or name. If specified, only this password change policy is returned. | Required | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.passwordchangepolicy_get.id | String | The password change policy id. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.password_change_policy_name | String | The password change policy name. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.description | String | The password change policy description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.password_length | Number | Number of chars in password. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.special_chars | Number | The minimum number of special chars in password \(0 = no minimum, null = no special chars at all\). Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.lower_chars | Number | The minimum number of lower case chars in password \(0 = no minimum, null = no lower case chars at all\). Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.upper_chars | Number | The minimum number of upper case chars in password \(0 = no minimum, null = no upper case chars at all\). Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.digit_chars | Number | The minimum number of digit chars in password \(0 = no minimum, null = no digit chars at all\). Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.exclude_chars | String | Characters to exclude in password. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.ssh_key_type | String | The SSH key type. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.ssh_key_size | Number | The SSH key size \(in bits\). Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.change_period | String | +The period to change password. + +String value must be a valid cron syntax \(e.g. '\\\* \\\* \\\* \\\* \\\*'\). + +Aliases are allowed: + +@hourly → 0 \\\* \\\* \\\* \\\* +@daily → 0 0 \\\* \\\* \\\* +@weekly → 0 0 \\\* \\\* 0 +@monthly → 0 0 1 \\\* \\\* +@yearly → 0 0 1 1 \\\* + +Note: An empty string \(or null\) will deactivate the change password schedule. +Moreover, @reboot is not allowed. + Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.passwordchangepolicy_get.url | String | The API URL to the resource. | + +### wab-edit-password-change-policy + +*** +Edit a password change policy +category: Password Change Policies + +#### Base Command + +`wab-edit-password-change-policy` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| policy_id | The password change policy id or name to edit. | Required | +| passwordchangepolicy_put_password_change_policy_name | The password change policy name. | Optional | +| passwordchangepolicy_put_description | The password change policy description. | Optional | +| passwordchangepolicy_put_password_length | Number of chars in password. (enter null for null value). | Optional | +| passwordchangepolicy_put_special_chars | The minimum number of special chars in password (0 = no minimum, null = no special chars at all). (enter null for null value). | Optional | +| passwordchangepolicy_put_lower_chars | The minimum number of lower case chars in password (0 = no minimum, null = no lower case chars at all). (enter null for null value). | Optional | +| passwordchangepolicy_put_upper_chars | The minimum number of upper case chars in password (0 = no minimum, null = no upper case chars at all). (enter null for null value). | Optional | +| passwordchangepolicy_put_digit_chars | The minimum number of digit chars in password (0 = no minimum, null = no digit chars at all). (enter null for null value). | Optional | +| passwordchangepolicy_put_exclude_chars | Characters to exclude in password. (enter null for null value). | Optional | +| passwordchangepolicy_put_ssh_key_type | The SSH key type. (enter null for null value). | Optional | +| passwordchangepolicy_put_ssh_key_size | The SSH key size (in bits). (enter null for null value). | Optional | +| passwordchangepolicy_put_change_period |
    The period to change password.

    String value must be a valid cron syntax (e.g. '\* \* \* \* \*').

    Aliases are allowed:

    @hourly → 0 \* \* \* \*
    @daily → 0 0 \* \* \*
    @weekly → 0 0 \* \* 0
    @monthly → 0 0 1 \* \*
    @yearly → 0 0 1 1 \*

    Note: An empty string (or null) will deactivate the change password schedule.
    Moreover, @reboot is not allowed.
    (enter null for null value). | Optional | + +#### Context Output + +There is no context output for this command. + +### wab-delete-password-change-policy + +*** +Delete a password change policy +category: Password Change Policies + +#### Base Command + +`wab-delete-password-change-policy` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| policy_id | The password change policy id or name to delete. | Required | + +#### Context Output + +There is no context output for this command. + +### wab-get-passwordrights + +*** +Get current user's or the user 'user_name' password rights on accounts (for checkout/checkin) +category: Password Rights + +#### Base Command + +`wab-get-passwordrights` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| count | The default value is false. When it is set to true, the headers x-total-count and x-filtered-count are returned. Possible values are: true, false. | Optional | +| q | Only a simple string to search is allowed in this resource (for example: 'q=windows'). The search is performed on the following fields only: account, account_description, device, device_alias, device_description, application, application_description, domain, domain_description, authorization, authorization_description. | Optional | +| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'account,domain,device,application'. | Optional | +| offset | The index of first item to retrieve (starts and defaults to 0). | Optional | +| limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.passwordrights_get.type | String | The account type. | +| WAB.passwordrights_get.target | String | The complete target identifier which can be used in resource /targetpasswords \(format: "account_name@global_domain_name"\). / The complete target identifier which can be used in resource /targetpasswords \(example: "account@domain@device"\). / The complete target identifier which can be used in resource /targetpasswords \(format: "account_name@local_domain_name@application_name"\). | +| WAB.passwordrights_get.account | String | The account name. Usable in the "sort" parameter. | +| WAB.passwordrights_get.account_description | String | The account description. Usable in the "sort" parameter. | +| WAB.passwordrights_get.domain | String | The global domain name. Usable in the "sort" parameter. / The local domain name on device. Usable in the "sort" parameter. / The local domain name on application. Usable in the "sort" parameter. | +| WAB.passwordrights_get.domain_description | String | The domain description. Usable in the "sort" parameter. | +| WAB.passwordrights_get.domain_vault | Boolean | The domain accounts are stored on an external vault. Usable in the "sort" parameter. | +| WAB.passwordrights_get.authorization_approval | Boolean | True if an approval workflow is defined in the authorization, otherwise False. Usable in the "sort" parameter. | +| WAB.passwordrights_get.authorization | String | The authorization name. Usable in the "sort" parameter. | +| WAB.passwordrights_get.authorization_description | String | The authorization description. Usable in the "sort" parameter. | +| WAB.passwordrights_get.right_fingerprint | String | The fingerprint of the right \(hash of authorization and target uid\). | + +### wab-get-passwordrights-user-name + +*** +Get current user's or the user 'user_name' password rights on accounts (for checkout/checkin) +category: Password Rights + +#### Base Command + +`wab-get-passwordrights-user-name` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| user_name | If specified, the user_name password rights is returned. | Required | +| count | The default value is false. When it is set to true, the headers x-total-count and x-filtered-count are returned. Possible values are: true, false. | Optional | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.passwordrights_get.type | String | The account type. | +| WAB.passwordrights_get.target | String | The complete target identifier which can be used in resource /targetpasswords \(format: "account_name@global_domain_name"\). / The complete target identifier which can be used in resource /targetpasswords \(example: "account@domain@device"\). / The complete target identifier which can be used in resource /targetpasswords \(format: "account_name@local_domain_name@application_name"\). | +| WAB.passwordrights_get.account | String | The account name. Usable in the "sort" parameter. | +| WAB.passwordrights_get.account_description | String | The account description. Usable in the "sort" parameter. | +| WAB.passwordrights_get.domain | String | The global domain name. Usable in the "sort" parameter. / The local domain name on device. Usable in the "sort" parameter. / The local domain name on application. Usable in the "sort" parameter. | +| WAB.passwordrights_get.domain_description | String | The domain description. Usable in the "sort" parameter. | +| WAB.passwordrights_get.domain_vault | Boolean | The domain accounts are stored on an external vault. Usable in the "sort" parameter. | +| WAB.passwordrights_get.authorization_approval | Boolean | True if an approval workflow is defined in the authorization, otherwise False. Usable in the "sort" parameter. | +| WAB.passwordrights_get.authorization | String | The authorization name. Usable in the "sort" parameter. | +| WAB.passwordrights_get.authorization_description | String | The authorization description. Usable in the "sort" parameter. | +| WAB.passwordrights_get.right_fingerprint | String | The fingerprint of the right \(hash of authorization and target uid\). | +| WAB.passwordrights_get.user_name | String | the user_name. | + +### wab-get-profiles + +*** +Get the profiles +category: Profiles + +#### Base Command + +`wab-get-profiles` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| q | Searches for a resource matching parameters. | Optional | +| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'profile_name'. | Optional | +| offset | The index of first item to retrieve (starts and defaults to 0). | Optional | +| limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.profile_get.id | String | The profile id. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.profile_get.profile_name | String | The profile name. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.profile_get.editable | Boolean | Profile is editable. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.profile_get.description | String | The target group description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.profile_get.gui_features.wab_audit | String | wab audit. | +| WAB.profile_get.gui_features.system_audit | String | system audit. | +| WAB.profile_get.gui_features.users | String | users. | +| WAB.profile_get.gui_features.user_groups | String | user groups. | +| WAB.profile_get.gui_features.devices | String | devices. | +| WAB.profile_get.gui_features.target_groups | String | target groups. | +| WAB.profile_get.gui_features.authorizations | String | authorizations. | +| WAB.profile_get.gui_features.profiles | String | profiles. | +| WAB.profile_get.gui_features.wab_settings | String | wab settings. | +| WAB.profile_get.gui_features.system_settings | String | system settings. | +| WAB.profile_get.gui_features.backup | String | backup. | +| WAB.profile_get.gui_features.approval | String | approval. | +| WAB.profile_get.gui_features.credential_recovery | String | credential recovery. | +| WAB.profile_get.gui_transmission.system_audit | String | system audit. | +| WAB.profile_get.gui_transmission.users | String | users. | +| WAB.profile_get.gui_transmission.user_groups | String | user groups. | +| WAB.profile_get.gui_transmission.devices | String | devices. | +| WAB.profile_get.gui_transmission.target_groups | String | target groups. | +| WAB.profile_get.gui_transmission.authorizations | String | authorizations. | +| WAB.profile_get.gui_transmission.profiles | String | profiles. | +| WAB.profile_get.gui_transmission.wab_settings | String | wab settings. | +| WAB.profile_get.gui_transmission.system_settings | String | system settings. | +| WAB.profile_get.gui_transmission.backup | String | backup. | +| WAB.profile_get.gui_transmission.approval | String | approval. | +| WAB.profile_get.gui_transmission.credential_recovery | String | credential recovery. | +| WAB.profile_get.ip_limitation | String | The profile ip limitation. Format is an IPv4 address, subnet or host name, for example: 192.168.1.10/24 Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.profile_get.target_access | Boolean | Target access. | +| WAB.profile_get.dashboards | String | Ordered list of dashboards names. Usable in the "q" parameter. | +| WAB.profile_get.url | String | The API URL to the resource. | + +### wab-get-profile + +*** +Get the profile +category: Profiles + +#### Base Command + +`wab-get-profile` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| profile_id | A profile id or name. If specified, only this profile is returned. | Required | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.profile_get.id | String | The profile id. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.profile_get.profile_name | String | The profile name. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.profile_get.editable | Boolean | Profile is editable. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.profile_get.description | String | The target group description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.profile_get.gui_features.wab_audit | String | wab audit. | +| WAB.profile_get.gui_features.system_audit | String | system audit. | +| WAB.profile_get.gui_features.users | String | users. | +| WAB.profile_get.gui_features.user_groups | String | user groups. | +| WAB.profile_get.gui_features.devices | String | devices. | +| WAB.profile_get.gui_features.target_groups | String | target groups. | +| WAB.profile_get.gui_features.authorizations | String | authorizations. | +| WAB.profile_get.gui_features.profiles | String | profiles. | +| WAB.profile_get.gui_features.wab_settings | String | wab settings. | +| WAB.profile_get.gui_features.system_settings | String | system settings. | +| WAB.profile_get.gui_features.backup | String | backup. | +| WAB.profile_get.gui_features.approval | String | approval. | +| WAB.profile_get.gui_features.credential_recovery | String | credential recovery. | +| WAB.profile_get.gui_transmission.system_audit | String | system audit. | +| WAB.profile_get.gui_transmission.users | String | users. | +| WAB.profile_get.gui_transmission.user_groups | String | user groups. | +| WAB.profile_get.gui_transmission.devices | String | devices. | +| WAB.profile_get.gui_transmission.target_groups | String | target groups. | +| WAB.profile_get.gui_transmission.authorizations | String | authorizations. | +| WAB.profile_get.gui_transmission.profiles | String | profiles. | +| WAB.profile_get.gui_transmission.wab_settings | String | wab settings. | +| WAB.profile_get.gui_transmission.system_settings | String | system settings. | +| WAB.profile_get.gui_transmission.backup | String | backup. | +| WAB.profile_get.gui_transmission.approval | String | approval. | +| WAB.profile_get.gui_transmission.credential_recovery | String | credential recovery. | +| WAB.profile_get.ip_limitation | String | The profile ip limitation. Format is an IPv4 address, subnet or host name, for example: 192.168.1.10/24 Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.profile_get.target_access | Boolean | Target access. | +| WAB.profile_get.dashboards | String | Ordered list of dashboards names. Usable in the "q" parameter. | +| WAB.profile_get.url | String | The API URL to the resource. | + +### wab-get-scanjobs + +*** +Get the scanjobs +category: Scan Jobs + +#### Base Command + +`wab-get-scanjobs` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| q | Searches for a resource matching parameters. | Optional | +| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'scan_name'. | Optional | +| offset | The index of first item to retrieve (starts and defaults to 0). | Optional | +| limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | | fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | #### Context Output @@ -2861,7 +3783,8 @@ Get the scanjobs. ### wab-start-scan-job-manually *** -Start a scan job manually. +Start a scan job manually +category: Scan Jobs #### Base Command @@ -2875,12 +3798,15 @@ Start a scan job manually. #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.start_scan_job_manually.id | String | id of the created object. | ### wab-get-scanjob *** -Get the scanjob. +Get the scanjob +category: Scan Jobs #### Base Command @@ -2907,7 +3833,8 @@ Get the scanjob. ### wab-cancel-scan-job *** -Cancel a scan job. +Cancel a scan job +category: Scan Jobs #### Base Command @@ -2926,7 +3853,8 @@ There is no context output for this command. ### wab-get-scans *** -Get the scans. +Get the scans +category: Scans #### Base Command @@ -2962,7 +3890,8 @@ Get the scans. ### wab-get-scan *** -Get the scan. +Get the scan +category: Scans #### Base Command @@ -2992,10 +3921,63 @@ Get the scan. | WAB.scan_get.type | String | Scan type Usable in the "q" parameter. Usable in the "sort" parameter. | | WAB.scan_get.url | String | The API URL to the resource. | +### wab-edit-scan + +*** +Edit a scan +category: Scans + +#### Base Command + +`wab-edit-scan` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| scan_id | The scan id or name to edit. | Required | +| scan_put_name | Scan name. | Optional | +| scan_put_active | State of the job schedule. Possible values are: true, false. | Optional | +| scan_put_periodicity | Periodicity of the scan, in cron notation. | Optional | +| scan_put_description | Description of the scan. | Optional | +| scan_put_emails | Emails to notify when a job is finished.
    Comma-separated list (use [] for an empty list). | Optional | +| scan_put_subnets | List of subnets to scan.
    Comma-separated list (use [] for an empty list). | Optional | +| scan_put_banner_regex | Regexes to mach on SSH banner.
    Comma-separated list (use [] for an empty list). | Optional | +| scan_put_scan_for_accounts | Scan for accounts on discovered devices. Possible values are: true, false. | Optional | +| scan_put_master_accounts | The master accounts used to log and the devices empty if scan_for_accounts is false.
    Comma-separated list (use [] for an empty list). | Optional | +| scan_put_search_filter | Active Directory search filter. | Optional | +| scan_put_dn_list | List of Distinguished Names to search.
    Comma-separated list (use [] for an empty list). | Optional | +| scan_put_devices | The devices to scan.
    Comma-separated list (use [] for an empty list). | Optional | + +#### Context Output + +There is no context output for this command. + +### wab-delete-scan + +*** +Delete a scan +category: Scans + +#### Base Command + +`wab-delete-scan` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| scan_id | The scan id or name to delete. | Required | + +#### Context Output + +There is no context output for this command. + ### wab-get-sessionrights *** -Get current user's or the user 'user_name' session rights (connections via proxies). +Get current user's or the user 'user_name' session rights (connections via proxies) +category: Session Rights #### Base Command @@ -3005,8 +3987,8 @@ Get current user's or the user 'user_name' session rights (connections via proxi | **Argument Name** | **Description** | **Required** | | --- | --- | --- | -| count | The default value is false. When set to true, the headers x-total-count and x-filtered-count are returned. | Optional | -| last_connection | The default value is false. When set to true, the last connection date is returned for each authorizations. | Optional | +| count | The default value is false. When set to true, the headers x-total-count and x-filtered-count are returned. Possible values are: true, false. | Optional | +| last_connection | The default value is false. When set to true, the last connection date is returned for each authorizations. Possible values are: true, false. | Optional | | q | Only a simple string to search is allowed in this resource (for exemple: 'q=windows'). The search is performed on the following fields only: account, account_description, device, device_alias, device_description, application, application_description, service_protocol, domain, domain_description, authorization, authorization_description. | Optional | | sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'account,domain,device, ' 'application'. | Optional | | offset | The index of first item to retrieve (starts and defaults to 0). | Optional | @@ -3037,7 +4019,8 @@ Get current user's or the user 'user_name' session rights (connections via proxi ### wab-get-sessionrights-user-name *** -Get current user's or the user 'user_name' session rights (connections via proxies). +Get current user's or the user 'user_name' session rights (connections via proxies) +category: Session Rights #### Base Command @@ -3048,8 +4031,8 @@ Get current user's or the user 'user_name' session rights (connections via proxi | **Argument Name** | **Description** | **Required** | | --- | --- | --- | | user_name | If specified, the user_name session rights is returned. | Required | -| count | The default value is false. When set to true, the headers x-total-count and x-filtered-count are returned. | Optional | -| last_connection | The default value is false. When set to true, the last connection date is returned for each authorizations. | Optional | +| count | The default value is false. When set to true, the headers x-total-count and x-filtered-count are returned. Possible values are: true, false. | Optional | +| last_connection | The default value is false. When set to true, the last connection date is returned for each authorizations. Possible values are: true, false. | Optional | | fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | #### Context Output @@ -3077,7 +4060,8 @@ Get current user's or the user 'user_name' session rights (connections via proxi ### wab-get-sessions *** -Get the sessions. +Get the sessions +category: Sessions #### Base Command @@ -3168,7 +4152,8 @@ Get the sessions. ### wab-edit-session *** -Edit a session. +Edit a session +category: Sessions #### Base Command @@ -3189,7 +4174,8 @@ There is no context output for this command. ### wab-get-session-metadata *** -Get the metadata of one or multiple sessions. +Get the metadata of one or multiple sessions +category: Sessions Metadata #### Base Command @@ -3200,7 +4186,7 @@ Get the metadata of one or multiple sessions. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | | session_ids | The session id, multiple IDs can be separated by commas. | Required | -| download | The default value is false. When it is set to true, the session metadata is sent as a file instead of JSON (recommended for large metadata). The download is possible only with a single session id. | Optional | +| download | The default value is false. When it is set to true, the session metadata is sent as a file instead of JSON (recommended for large metadata). The download is possible only with a single session id. Possible values are: true, false. | Optional | #### Context Output @@ -3212,7 +4198,8 @@ Get the metadata of one or multiple sessions. ### wab-get-session-sharing-requests *** -Get session sharing requests. +Get session sharing requests +category: Sessions Requests #### Base Command @@ -3242,7 +4229,8 @@ Get session sharing requests. ### wab-create-session-request *** -Create a session request. +Create a session request +category: Sessions Requests #### Base Command @@ -3253,7 +4241,7 @@ Create a session request. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | | session_request_post_session_id | The session id. | Required | -| session_request_post_mode | The session sharing mode. | Required | +| session_request_post_mode | The session sharing mode. Possible values are: view_only, view_control. | Required | #### Context Output @@ -3262,7 +4250,8 @@ There is no context output for this command. ### wab-delete-pending-or-live-session-request *** -Delete a pending or a live session request. +Delete a pending or a live session request +category: Sessions Requests #### Base Command @@ -3281,7 +4270,8 @@ There is no context output for this command. ### wab-get-latest-snapshot-of-running-session *** -Get the latest snapshot of a running session. +Get the latest snapshot of a running session +category: Sessions Snapshots #### Base Command @@ -3300,7 +4290,8 @@ There is no context output for this command. ### wab-get-status-of-trace-generation *** -Get the status of a trace generation. +Get the status of a trace generation +category: Sessions Traces #### Base Command @@ -3313,7 +4304,7 @@ Get the status of a trace generation. | session_id | The session id. | Required | | date | Generate the trace from this date/time (format: "yyyy-mm-dd hh:mm:ss"). | Optional | | duration | Duration of the trace to generate (in seconds). | Optional | -| download | The default value is false. When it is set to true, the session trace is sent as a file instead of JSON output with the generation status. | Optional | +| download | The default value is false. When it is set to true, the session trace is sent as a file instead of JSON output with the generation status. Possible values are: true, false. | Optional | #### Context Output @@ -3330,7 +4321,8 @@ Get the status of a trace generation. ### wab-generate-trace-for-session *** -Generate a trace for a session. +Generate a trace for a session +category: Sessions Traces #### Base Command @@ -3346,12 +4338,15 @@ Generate a trace for a session. #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.generate_trace_for_session.id | String | id of the created object. | ### wab-get-wallix-bastion-usage-statistics *** -Get the WALLIX Bastion usage statistics. If no from_date or to_date are supplied it will return the statistics for the last full calendar month. +Get the WALLIX Bastion usage statistics. If no from_date or to_date are supplied it will return the statistics for the last full calendar month +category: Statistics #### Base Command @@ -3386,7 +4381,8 @@ Get the WALLIX Bastion usage statistics. If no from_date or to_date are supplied ### wab-get-target-groups *** -Get the target groups. +Get the target groups +category: Target Groups #### Base Command @@ -3448,7 +4444,8 @@ Get the target groups. ### wab-add-target-group *** -Add a target group. +Add a target group +category: Target Groups #### Base Command @@ -3463,12 +4460,15 @@ Add a target group. #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_target_group.id | String | id of the created object. | ### wab-get-target-group *** -Get the target group. +Get the target group +category: Target Groups #### Base Command @@ -3527,7 +4527,8 @@ Get the target group. ### wab-edit-target-group *** -Edit a target group. +Edit a target group +category: Target Groups #### Base Command @@ -3538,7 +4539,7 @@ Edit a target group. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | | group_id | The group id or name to edit. | Required | -| force | The default value is false. When it is set to true the values of the targets are replaced, otherwise the values are added to the existing ones. | Optional | +| force | The default value is false. When it is set to true the values of the targets are replaced, otherwise the values are added to the existing ones. Possible values are: true, false. | Optional | | targetgroups_put_group_name | The target group name. | Optional | | targetgroups_put_description | The target group description. | Optional | @@ -3549,7 +4550,8 @@ There is no context output for this command. ### wab-delete-target-group *** -Delete a target group. +Delete a target group +category: Target Groups #### Base Command @@ -3568,7 +4570,8 @@ There is no context output for this command. ### wab-delete-target-from-group *** -Delete a target from a group. +Delete a target from a group +category: Target Groups #### Base Command @@ -3586,10 +4589,145 @@ Delete a target from a group. There is no context output for this command. +### wab-get-timeframes + +*** +Get the timeframes +category: Timeframes + +#### Base Command + +`wab-get-timeframes` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| q | Searches for a resource matching parameters. | Optional | +| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'timeframe_name'. | Optional | +| offset | The index of first item to retrieve (starts and defaults to 0). | Optional | +| limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.timeframe_get.id | String | The timeframe id. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.timeframe_get.timeframe_name | String | The timeframe name. No space is permitted at first or end. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.timeframe_get.description | String | The timeframe description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.timeframe_get.is_overtimable | Boolean | Do not close sessions at the end of the time period. | +| WAB.timeframe_get.periods.start_date | String | The period start date. Must respect the format "yyyy-mm-dd". | +| WAB.timeframe_get.periods.end_date | String | The period end date. Must respect the format "yyyy-mm-dd". | +| WAB.timeframe_get.periods.start_time | String | The period start time. Must respect the format "hh:mm". | +| WAB.timeframe_get.periods.end_time | String | The period end time. Must respect the format "hh:mm". | +| WAB.timeframe_get.periods.week_days | String | The period week days. | +| WAB.timeframe_get.url | String | The API URL to the resource. | + +### wab-add-timeframe + +*** +Add a timeframe +category: Timeframes + +#### Base Command + +`wab-add-timeframe` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| timeframe_post_timeframe_name | The timeframe name. No space is permitted at first or end. | Required | +| timeframe_post_description | The timeframe description. | Optional | +| timeframe_post_is_overtimable | Do not close sessions at the end of the time period. Possible values are: true, false. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_timeframe.id | String | id of the created object. | + +### wab-get-timeframe + +*** +Get the timeframe +category: Timeframes + +#### Base Command + +`wab-get-timeframe` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| timeframe_id | A timeframe id or name. If specified, only this timeframe is returned. | Required | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.timeframe_get.id | String | The timeframe id. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.timeframe_get.timeframe_name | String | The timeframe name. No space is permitted at first or end. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.timeframe_get.description | String | The timeframe description. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.timeframe_get.is_overtimable | Boolean | Do not close sessions at the end of the time period. | +| WAB.timeframe_get.periods.start_date | String | The period start date. Must respect the format "yyyy-mm-dd". | +| WAB.timeframe_get.periods.end_date | String | The period end date. Must respect the format "yyyy-mm-dd". | +| WAB.timeframe_get.periods.start_time | String | The period start time. Must respect the format "hh:mm". | +| WAB.timeframe_get.periods.end_time | String | The period end time. Must respect the format "hh:mm". | +| WAB.timeframe_get.periods.week_days | String | The period week days. | +| WAB.timeframe_get.url | String | The API URL to the resource. | + +### wab-edit-timeframe + +*** +Edit a timeframe +category: Timeframes + +#### Base Command + +`wab-edit-timeframe` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| timeframe_id | The timeframe id or name to edit. | Required | +| timeframe_put_timeframe_name | The timeframe name. No space is permitted at first or end. | Optional | +| timeframe_put_description | The timeframe description. | Optional | +| timeframe_put_is_overtimable | Do not close sessions at the end of the time period. Possible values are: true, false. | Optional | + +#### Context Output + +There is no context output for this command. + +### wab-delete-timeframe + +*** +Delete a timeframe +category: Timeframes + +#### Base Command + +`wab-delete-timeframe` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| timeframe_id | The timeframe id or name to delete. | Required | + +#### Context Output + +There is no context output for this command. + ### wab-get-user-groups *** -Get the user groups. +Get the user groups +category: User Groups #### Base Command @@ -3626,7 +4764,8 @@ Get the user groups. ### wab-get-user-group *** -Get the user group. +Get the user group +category: User Groups #### Base Command @@ -3660,7 +4799,8 @@ Get the user group. ### wab-get-users *** -Get the users. +Get the users +category: Users #### Base Command @@ -3670,7 +4810,7 @@ Get the users. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | -| password_hash | Export password hash if true. In Configuration Options menu > REST API then Advanced options, you should set User password hash and change the default Data encryption key. | Optional | +| password_hash | Export password hash if true. In Configuration Options menu > REST API then Advanced options, you should set User password hash and change the default Data encryption key. Possible values are: true, false. | Optional | | q | Searches for a resource matching parameters. | Optional | | sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'user_name'. | Optional | | offset | The index of first item to retrieve (starts and defaults to 0). | Optional | @@ -3703,7 +4843,8 @@ Get the users. ### wab-add-user *** -Add a user. +Add a user +category: Users #### Base Command @@ -3713,32 +4854,35 @@ Add a user. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | -| password_hash | Set password hash if true. In Configuration Options menu > REST API then Advanced options, you should set User password hash and change the default Data encryption key. | Optional | +| password_hash | Set password hash if true. In Configuration Options menu > REST API then Advanced options, you should set User password hash and change the default Data encryption key. Possible values are: true, false. | Optional | | user_post_user_name | The user name. /:*?"<>\| are forbidden. | Required | | user_post_display_name | The displayed name. | Optional | | user_post_email | The email address. | Required | | user_post_ip_source | The source IP to limit access. Format is a comma-separated list of IPv4 or IPV6 addresses, subnets, ranges or domain, for example: 1.2.3.4,2001:db8::1234:5678,192.168.1.10/24,10.11.12.13-14.15.16.17,example.com. | Optional | -| user_post_preferred_language | The preferred language. | Optional | +| user_post_preferred_language | The preferred language. Possible values are: de, en, es, fr, ru. | Optional | | user_post_profile | The user profile. | Required | -| user_post_groups | The groups containing this user. | Optional | -| user_post_user_auths | The authentication procedures(s). | Required | +| user_post_groups | The groups containing this user.
    Comma-separated list (use [] for an empty list). | Optional | +| user_post_user_auths | The authentication procedures(s).
    Comma-separated list (use [] for an empty list). | Required | | user_post_password | The password. | Optional | -| user_post_force_change_pwd | Force password change. | Optional | +| user_post_force_change_pwd | Force password change. Possible values are: true, false. | Optional | | user_post_ssh_public_key | The SSH public key. | Optional | | user_post_certificate_dn | The certificate DN (for X509 authentication). | Optional | -| user_post_last_connection | The last connection of this user. | Optional | +| user_post_last_connection | The last connection of this user. (enter null for null value). | Optional | | user_post_expiration_date | Account expiration date/time (format: "yyyy-mm-dd hh:mm"). | Optional | -| user_post_is_disabled | Account is disabled. | Optional | +| user_post_is_disabled | Account is disabled. Possible values are: true, false. | Optional | | user_post_gpg_public_key | The GPG public key (ascii output from the command: 'gpg --armor --export [USER_ID]'). | Optional | #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_user.id | String | id of the created object. | ### wab-get-user *** -Get the user. +Get the user +category: Users #### Base Command @@ -3749,7 +4893,7 @@ Get the user. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | | name | A user name. If specified, only this user is returned. | Required | -| password_hash | Export password hash if true. In Configuration Options menu > REST API then Advanced options, you should set User password hash and change the default Data encryption key. | Optional | +| password_hash | Export password hash if true. In Configuration Options menu > REST API then Advanced options, you should set User password hash and change the default Data encryption key. Possible values are: true, false. | Optional | | fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | #### Context Output @@ -3775,10 +4919,153 @@ Get the user. | WAB.user_get.url | String | The API URL to the resource. | | WAB.user_get.gpg_public_key | String | The GPG public key fingerprint. | +### wab-edit-user + +*** +Edit a user +category: Users + +#### Base Command + +`wab-edit-user` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| name | The user name to edit. | Required | +| force | The default value is false. When set to true, the values of the groups and user_auths are replaced, otherwise the values are added to the existing ones. Possible values are: true, false. | Optional | +| password_hash | Update password hash if true. In Configuration Options menu > REST API then Advanced options, you should set User password hash and change the default Data encryption key. Possible values are: true, false. | Optional | +| user_put_user_name | The user name. /:*?"<>\| are forbidden. | Optional | +| user_put_display_name | The displayed name. | Optional | +| user_put_email | The email address. | Optional | +| user_put_ip_source | The source IP to limit access. Format is a comma-separated list of IPv4 or IPV6 addresses, subnets, ranges or domain, for example: 1.2.3.4,2001:db8::1234:5678,192.168.1.10/24,10.11.12.13-14.15.16.17,example.com. | Optional | +| user_put_preferred_language | The preferred language. Possible values are: de, en, es, fr, ru. | Optional | +| user_put_profile | The user profile. | Optional | +| user_put_groups | The groups containing this user.
    Comma-separated list (use [] for an empty list). | Optional | +| user_put_user_auths | The authentication procedures(s).
    Comma-separated list (use [] for an empty list). | Optional | +| user_put_password | The password. | Optional | +| user_put_force_change_pwd | Force password change. Possible values are: true, false. | Optional | +| user_put_ssh_public_key | The SSH public key. | Optional | +| user_put_certificate_dn | The certificate DN (for X509 authentication). | Optional | +| user_put_last_connection | The last connection of this user. (enter null for null value). | Optional | +| user_put_expiration_date | Account expiration date/time (format: "yyyy-mm-dd hh:mm"). | Optional | +| user_put_is_disabled | Account is disabled. Possible values are: true, false. | Optional | +| user_put_gpg_public_key | The GPG public key (ascii output from the command: 'gpg --armor --export [USER_ID]'). | Optional | + +#### Context Output + +There is no context output for this command. + +### wab-get-target-group-restrictions + +*** +Get target group restrictions +category: Target Group Restrictions + +#### Base Command + +`wab-get-target-group-restrictions` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_id | A target group id or name. | Required | +| q | Searches for a resource matching parameters. | Optional | +| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'group_name'. | Optional | +| offset | The index of first item to retrieve (starts and defaults to 0). | Optional | +| limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.restriction_get.id | String | The restriction id. Usable in the "q" parameter. | +| WAB.restriction_get.action | String | The restriction type. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.restriction_get.rules | String | The restriction rules. Usable in the "sort" parameter. | +| WAB.restriction_get.subprotocol | String | The restriction subprotocol. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.restriction_get.url | String | The API URL to the resource. | + +### wab-get-target-group-restriction + +*** +Get one target group restriction +category: Target Group Restrictions + +#### Base Command + +`wab-get-target-group-restriction` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_id | A target group id or name. | Required | +| restriction_id | The identifier of the desired restriction. If specified, only this restriction is returned. | Required | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.restriction_get.id | String | The restriction id. Usable in the "q" parameter. | +| WAB.restriction_get.action | String | The restriction type. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.restriction_get.rules | String | The restriction rules. Usable in the "sort" parameter. | +| WAB.restriction_get.subprotocol | String | The restriction subprotocol. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.restriction_get.url | String | The API URL to the resource. | + +### wab-edit-restriction-from-targetgroup + +*** +Edit a restriction from a targetgroup +category: Target Group Restrictions + +#### Base Command + +`wab-edit-restriction-from-targetgroup` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_id | A target group id or name. | Required | +| restriction_id | The identifier of the desired restriction. | Required | +| restriction_put_action | The restriction type. Possible values are: kill, notify. | Optional | +| restriction_put_rules | The restriction rules. | Optional | +| restriction_put_subprotocol | The restriction subprotocol. Possible values are: SSH_SHELL_SESSION, SSH_REMOTE_COMMAND, SSH_SCP_UP, SSH_SCP_DOWN, SFTP_SESSION, RLOGIN, TELNET, RDP. | Optional | + +#### Context Output + +There is no context output for this command. + +### wab-delete-restriction-from-targetgroup + +*** +Delete a restriction from a targetgroup +category: Target Group Restrictions + +#### Base Command + +`wab-delete-restriction-from-targetgroup` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_id | A target group id or name. | Required | +| restriction_id | The identifier of the desired restriction. | Required | + +#### Context Output + +There is no context output for this command. + ### wab-get-password-for-target *** -Get the password for a given target. +Get the password for a given target +category: Target Passwords #### Base Command @@ -3814,7 +5101,8 @@ Get the password for a given target. ### wab-extend-duration-time-to-get-passwords-for-target *** -Extend the duration time to get the passwords for a given target. +Extend the duration time to get the passwords for a given target +category: Target Passwords #### Base Command @@ -3834,7 +5122,8 @@ There is no context output for this command. ### wab-release-passwords-for-target *** -Release the passwords for a given target. +Release the passwords for a given target +category: Target Passwords #### Base Command @@ -3846,7 +5135,7 @@ Release the passwords for a given target. | --- | --- | --- | | account_name | A target name: 'account@domain@device' for an account on a device, 'account@domain@application' for an account on an application or 'account@domain' for an account on a global domain. | Required | | authorization | The name of the authorization (in case of multiple authorizations to access the target). | Optional | -| force | The default value is false. When it is set to true, the checkin is forced. The user connected on the REST API must have an auditor profile and the configured limitations don't prohibit access to the account. | Optional | +| force | The default value is false. When it is set to true, the checkin is forced. The user connected on the REST API must have an auditor profile and the configured limitations don't prohibit access to the account. Possible values are: true, false. | Optional | | comment | A comment that is input by the auditor when an account checkin is forced. This argument is mandatory if the checkin is forced, and is ignored for a standard checkin. | Optional | #### Context Output @@ -3856,7 +5145,8 @@ There is no context output for this command. ### wab-get-target-by-type *** -Get the target by type. +Get the target by type +category: Targets #### Base Command @@ -3890,7 +5180,8 @@ Get the target by type. ### wab-get-mappings-of-user-group *** -Get the mappings of a user group. +Get the mappings of a user group +category: User Group Mappings #### Base Command @@ -3920,7 +5211,8 @@ Get the mappings of a user group. ### wab-add-mapping-in-group *** -Add a mapping in a group and set mapping fallback. If the field "external_group" is set to "*", it is used as the fallback mapping, which allows mapping of users in the domain that do not belong to the external_group to be mapped to the user group by default. +Add a mapping in a group and set mapping fallback. If the field "external_group" is set to "*", it is used as the fallback mapping, which allows mapping of users in the domain that do not belong to the external_group to be mapped to the user group by default +category: User Group Mappings #### Base Command @@ -3937,12 +5229,15 @@ Add a mapping in a group and set mapping fallback. If the field "external_group" #### Context Output -There is no context output for this command. +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_mapping_in_group.id | String | id of the created object. | ### wab-get-mapping-of-user-group *** -Get the mapping of a user group. +Get the mapping of a user group +category: User Group Mappings #### Base Command @@ -3969,7 +5264,8 @@ Get the mapping of a user group. ### wab-edit-mapping-of-user-group *** -Edit a mapping of a user group. +Edit a mapping of a user group +category: User Group Mappings #### Base Command @@ -3992,7 +5288,8 @@ There is no context output for this command. ### wab-delete-mapping-of-user-group *** -Delete the mapping of the given user group. +Delete the mapping of the given user group +category: User Group Mappings #### Base Command @@ -4008,3 +5305,159 @@ Delete the mapping of the given user group. #### Context Output There is no context output for this command. + +### wab-get-user-group-restrictions + +*** +Get user group restrictions +category: User Group Restrictions + +#### Base Command + +`wab-get-user-group-restrictions` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_id | A user group id or name. | Required | +| q | Searches for a resource matching parameters. | Optional | +| sort | Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: 'group_name'. | Optional | +| offset | The index of first item to retrieve (starts and defaults to 0). | Optional | +| limit | The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. | Optional | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.restriction_get.id | String | The restriction id. Usable in the "q" parameter. | +| WAB.restriction_get.action | String | The restriction type. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.restriction_get.rules | String | The restriction rules. Usable in the "sort" parameter. | +| WAB.restriction_get.subprotocol | String | The restriction subprotocol. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.restriction_get.url | String | The API URL to the resource. | + +### wab-add-restriction-to-usergroup + +*** +Add a restriction to a usergroup +category: User Group Restrictions + +#### Base Command + +`wab-add-restriction-to-usergroup` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_id | A user group id or name. | Required | +| restriction_post_action | The restriction type. Possible values are: kill, notify. | Required | +| restriction_post_rules | The restriction rules. | Required | +| restriction_post_subprotocol | The restriction subprotocol. Possible values are: SSH_SHELL_SESSION, SSH_REMOTE_COMMAND, SSH_SCP_UP, SSH_SCP_DOWN, SFTP_SESSION, RLOGIN, TELNET, RDP. | Required | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.add_restriction_to_usergroup.id | String | id of the created object. | + +### wab-get-user-group-restriction + +*** +Get one user group restriction +category: User Group Restrictions + +#### Base Command + +`wab-get-user-group-restriction` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_id | A user group id or name. | Required | +| restriction_id | The identifier of the desired restriction. If specified, only this restriction is returned. | Required | +| fields | The list of fields to return (separated by commas). By default all fields are returned. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.restriction_get.id | String | The restriction id. Usable in the "q" parameter. | +| WAB.restriction_get.action | String | The restriction type. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.restriction_get.rules | String | The restriction rules. Usable in the "sort" parameter. | +| WAB.restriction_get.subprotocol | String | The restriction subprotocol. Usable in the "q" parameter. Usable in the "sort" parameter. | +| WAB.restriction_get.url | String | The API URL to the resource. | + +### wab-edit-restriction-from-usergroup + +*** +Edit a restriction from a usergroup +category: User Group Restrictions + +#### Base Command + +`wab-edit-restriction-from-usergroup` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_id | A user group id or name. | Required | +| restriction_id | The identifier of the desired restriction. | Required | +| restriction_put_action | The restriction type. Possible values are: kill, notify. | Optional | +| restriction_put_rules | The restriction rules. | Optional | +| restriction_put_subprotocol | The restriction subprotocol. Possible values are: SSH_SHELL_SESSION, SSH_REMOTE_COMMAND, SSH_SCP_UP, SSH_SCP_DOWN, SFTP_SESSION, RLOGIN, TELNET, RDP. | Optional | + +#### Context Output + +There is no context output for this command. + +### wab-delete-restriction-from-usergroup + +*** +Delete a restriction from a usergroup +category: User Group Restrictions + +#### Base Command + +`wab-delete-restriction-from-usergroup` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| group_id | A user group id or name. | Required | +| restriction_id | The identifier of the desired restriction. | Required | + +#### Context Output + +There is no context output for this command. + +### wab-get-version + +*** +Get the REST API and WALLIX Bastion version numbers +category: Version + +#### Base Command + +`wab-get-version` + +#### Input + +There are no input arguments for this command. + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| WAB.version_get.version | String | The REST API version. | +| WAB.version_get.version_decimal | Number | The REST API version as decimal number. | +| WAB.version_get.wab_version | String | The WALLIX Bastion version \(format: X.Y\). | +| WAB.version_get.wab_form_factor | String | The WALLIX Bastion form factor \(appliance, cloud\). . | +| WAB.version_get.wab_version_decimal | Number | The WALLIX Bastion version as decimal number. | +| WAB.version_get.wab_version_hotfix | String | The WALLIX Bastion version with hotfix level \(format: X.Y.Z, Z being the hotfix level\). | +| WAB.version_get.wab_version_hotfix_decimal | Number | The WALLIX Bastion version with hotfix level as decimal. | +| WAB.version_get.wab_complete_version | String | The WALLIX Bastion complete version, with hotfix level and build date. | diff --git a/Packs/WALLIXBastion/Integrations/WAB/WAB.py b/Packs/WALLIXBastion/Integrations/WAB/WAB.py index fc96a946b0ba..5597b452dc69 100644 --- a/Packs/WALLIXBastion/Integrations/WAB/WAB.py +++ b/Packs/WALLIXBastion/Integrations/WAB/WAB.py @@ -11,20 +11,52 @@ class AuthError(Exception): pass -def str_arg(args, name): - return str(args.get(name, "")) +Null = object() -def int_arg(args, name): - return arg_to_number(args.get(name, None), arg_name=name) +def str_arg(args: Dict[str, Any], name: str, nullable=False): + arg = args.get(name, "") + if arg == "": + return None + if nullable and arg == "null": + return Null + return str(arg) -def bool_arg(args, name): - return argToBoolean(args.get(name, False)) +def int_arg(args: Dict[str, Any], name: str, nullable=False): + arg = args.get(name, "") + if arg == "": + return None + if nullable and arg == "null": + return Null + return arg_to_number(arg, arg_name=name) -def list_arg(args, name): - return argToList(args.get(name, [])) +def bool_arg(args: Dict[str, Any], name: str, nullable=False): + arg = args.get(name, "") + if arg == "": + return None + if nullable and arg == "null": + return Null + return argToBoolean(arg) + + +def list_arg(args: Dict[str, Any], name: str, nullable=False): + arg = args.get(name, "") + if arg == "": + return None + if nullable and arg == "null": + return Null + return argToList(arg) + + +def json_arg(args: Dict[str, Any], name: str, nullable=False): + arg = args.get(name, "") + if arg == "": + return None + if nullable and arg == "null": + return Null + return json.loads(arg) def add_key_to_outputs(outputs: dict, key_name: str, key_val): @@ -32,7 +64,7 @@ def add_key_to_outputs(outputs: dict, key_name: str, key_val): outputs[key_name] = str(key_val) -def to_markdown(name, t): +def to_markdown(name: str, t): try: return tableToMarkdown(name, t) except Exception as e: @@ -54,10 +86,19 @@ def _raise_client_exc(self, res: Response): raise AuthError self.client_error_handler(res) + def _convert_nulls(self, json_payload: dict): + for key, value in json_payload.items(): + if value is Null: + json_payload[key] = None + def _http_request(self, *args, **kwargs): headers: dict = kwargs.get("headers", {}) kwargs["headers"] = headers + data = kwargs.get("json_data") + if data: + self._convert_nulls(data) + first_auth = True token = get_session_token() if token: @@ -95,6 +136,9 @@ def _http_request(self, *args, **kwargs): update_session_token(token) if resp.status_code == 204: + obj_id = resp.headers.get("x-object-id") + if obj_id: + return {"id": obj_id} return {} return resp.json() @@ -110,6 +154,7 @@ def add_session_target_to_target_group(self, args: Dict[str, Any]): session_account_type = str_arg(args, "session_account_type") data = assign_params( + values_to_ignore=(None,), account=account, domain=domain, domain_type=domain_type, @@ -144,6 +189,7 @@ def add_password_target_to_target_group(self, args: Dict[str, Any]): application = str_arg(args, "application") data = assign_params( + values_to_ignore=(None,), account=account, domain=domain, domain_type=domain_type, @@ -166,20 +212,47 @@ def add_restriction_to_target_group(self, args: Dict[str, Any]): rules = str_arg(args, "rules") subprotocol = str_arg(args, "subprotocol") - data = assign_params( + body = assign_params( + values_to_ignore=(None,), action=action, rules=rules, subprotocol=subprotocol, ) - data = {"restrictions": [data]} - - response = self._http_request("put", f"/targetgroups/{group_id}", json_data=data) + response = self._http_request("post", f"/targetgroups/{group_id}/restrictions", json_data=body) return CommandResults( - readable_output="Success!", - raw_response=response, - ) + outputs_prefix="WAB.add_restriction_to_target_group", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-restriction-to-target-group", response), + raw_response=response, + ) + + def add_timeframe_period(self, args: Dict[str, Any]): + timeframe_id = str_arg(args, "timeframe_id") + start_date = str_arg(args, "start_date") + end_date = str_arg(args, "end_date") + start_time = str_arg(args, "start_time") + end_time = str_arg(args, "end_time") + week_days = list_arg(args, "week_days") + + body = { + "periods": [ + assign_params( + values_to_ignore=(None,), + start_date=start_date, + end_date=end_date, + start_time=start_time, + end_time=end_time, + week_days=week_days, + ) + ] + } + + response = self._http_request("put", f"/timeframes/{timeframe_id}", json_data=body) + + return CommandResults(readable_output="Success!", raw_response=response) def get_account_references(self, args: Dict[str, Any]): account_id = str_arg(args, "account_id") @@ -189,7 +262,7 @@ def get_account_references(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", f"/accounts/{account_id}/references", params=params) return CommandResults( @@ -205,7 +278,7 @@ def get_account_reference(self, args: Dict[str, Any]): reference_id = str_arg(args, "reference_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request("get", f"/accounts/{account_id}/references/{reference_id}", params=params) return CommandResults( @@ -216,6 +289,23 @@ def get_account_reference(self, args: Dict[str, Any]): raw_response=response, ) + def change_password_or_ssh_key_of_account(self, args: Dict[str, Any]): + account_id = str_arg(args, "account_id") + credential_type = str_arg(args, "credential_type") + changePasswordOrSshKeyOfAccount_password = str_arg(args, "changePasswordOrSshKeyOfAccount_password") + changePasswordOrSshKeyOfAccount_private_key = str_arg(args, "changePasswordOrSshKeyOfAccount_private_key") + changePasswordOrSshKeyOfAccount_passphrase = str_arg(args, "changePasswordOrSshKeyOfAccount_passphrase") + + body = assign_params( + values_to_ignore=(None,), + password=changePasswordOrSshKeyOfAccount_password, + private_key=changePasswordOrSshKeyOfAccount_private_key, + passphrase=changePasswordOrSshKeyOfAccount_passphrase, + ) + response = self._http_request("put", f"/accountchangepassword/{account_id}/{credential_type}", json_data=body) + + return CommandResults(readable_output="Success!", raw_response=response) + def get_all_accounts(self, args: Dict[str, Any]): account_type = str_arg(args, "account_type") application = str_arg(args, "application") @@ -229,6 +319,7 @@ def get_all_accounts(self, args: Dict[str, Any]): fields = str_arg(args, "fields") params = assign_params( + values_to_ignore=(None,), account_type=account_type, application=application, device=device, @@ -260,6 +351,7 @@ def get_one_account(self, args: Dict[str, Any]): fields = str_arg(args, "fields") params = assign_params( + values_to_ignore=(None,), account_type=account_type, application=application, device=device, @@ -293,7 +385,7 @@ def get_application_accounts(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", f"/applications/{application_id}/localdomains/{domain_id}/accounts", params=params) return CommandResults( @@ -316,6 +408,7 @@ def add_account_to_local_domain_of_application(self, args: Dict[str, Any]): app_account_post_can_edit_certificate_validity = bool_arg(args, "app_account_post_can_edit_certificate_validity") body = assign_params( + values_to_ignore=(None,), account_name=app_account_post_account_name, account_login=app_account_post_account_login, description=app_account_post_description, @@ -326,7 +419,13 @@ def add_account_to_local_domain_of_application(self, args: Dict[str, Any]): ) response = self._http_request("post", f"/applications/{application_id}/localdomains/{domain_id}/accounts", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.add_account_to_local_domain_of_application", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-account-to-local-domain-of-application", response), + raw_response=response, + ) def get_application_account(self, args: Dict[str, Any]): application_id = str_arg(args, "application_id") @@ -334,7 +433,7 @@ def get_application_account(self, args: Dict[str, Any]): account_id = str_arg(args, "account_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request( "get", f"/applications/{application_id}/localdomains/{domain_id}/accounts/{account_id}", params=params ) @@ -361,8 +460,9 @@ def edit_account_on_local_domain_of_application(self, args: Dict[str, Any]): app_account_put_can_edit_certificate_validity = bool_arg(args, "app_account_put_can_edit_certificate_validity") app_account_put_onboard_status = str_arg(args, "app_account_put_onboard_status") - params = assign_params(force=force) + params = assign_params(values_to_ignore=(None,), force=force) body = assign_params( + values_to_ignore=(None,), account_name=app_account_put_account_name, account_login=app_account_put_account_login, description=app_account_put_description, @@ -387,6 +487,41 @@ def delete_account_from_local_domain_of_application(self, args: Dict[str, Any]): return CommandResults(readable_output="Success!", raw_response=response) + def get_local_domains_data_for_application(self, args: Dict[str, Any]): + application_id = str_arg(args, "application_id") + q = str_arg(args, "q") + sort = str_arg(args, "sort") + offset = int_arg(args, "offset") + limit = int_arg(args, "limit") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) + response = self._http_request("get", f"/applications/{application_id}/localdomains", params=params) + + return CommandResults( + outputs_prefix="WAB.localdomain_app_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-local-domains-data-for-application", response), + raw_response=response, + ) + + def get_local_domain_data_for_application(self, args: Dict[str, Any]): + application_id = str_arg(args, "application_id") + domain_id = str_arg(args, "domain_id") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), fields=fields) + response = self._http_request("get", f"/applications/{application_id}/localdomains/{domain_id}", params=params) + + return CommandResults( + outputs_prefix="WAB.localdomain_app_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-local-domain-data-for-application", response), + raw_response=response, + ) + def get_applications(self, args: Dict[str, Any]): q = str_arg(args, "q") sort = str_arg(args, "sort") @@ -394,7 +529,7 @@ def get_applications(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", "/applications", params=params) return CommandResults( @@ -409,7 +544,7 @@ def get_application(self, args: Dict[str, Any]): application_id = str_arg(args, "application_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request("get", f"/applications/{application_id}", params=params) return CommandResults( @@ -426,13 +561,16 @@ def edit_application(self, args: Dict[str, Any]): application_put_application_name = str_arg(args, "application_put_application_name") application_put_description = str_arg(args, "application_put_description") application_put_parameters = str_arg(args, "application_put_parameters") + application_put_global_domains = list_arg(args, "application_put_global_domains") application_put_connection_policy = str_arg(args, "application_put_connection_policy") - params = assign_params(force=force) + params = assign_params(values_to_ignore=(None,), force=force) body = assign_params( + values_to_ignore=(None,), application_name=application_put_application_name, description=application_put_description, parameters=application_put_parameters, + global_domains=application_put_global_domains, connection_policy=application_put_connection_policy, ) response = self._http_request("put", f"/applications/{application_id}", params=params, json_data=body) @@ -454,7 +592,9 @@ def get_approvals(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(approval_id=approval_id, q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params( + values_to_ignore=(None,), approval_id=approval_id, q=q, sort=sort, offset=offset, limit=limit, fields=fields + ) response = self._http_request("get", "/approvals", params=params) return CommandResults( @@ -472,7 +612,7 @@ def get_approvals_for_all_approvers(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", "/approvals/assignments", params=params) return CommandResults( @@ -493,6 +633,7 @@ def reply_to_approval_request(self, args: Dict[str, Any]): approval_assignment_post_status = str_arg(args, "approval_assignment_post_status") body = assign_params( + values_to_ignore=(None,), id=approval_assignment_post_id, comment=approval_assignment_post_comment, duration=approval_assignment_post_duration, @@ -503,7 +644,13 @@ def reply_to_approval_request(self, args: Dict[str, Any]): ) response = self._http_request("post", "/approvals/assignments", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.reply_to_approval_request", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-reply-to-approval-request", response), + raw_response=response, + ) def get_approvals_for_approver(self, args: Dict[str, Any]): user_name = str_arg(args, "user_name") @@ -513,7 +660,7 @@ def get_approvals_for_approver(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", f"/approvals/assignments/{user_name}", params=params) return CommandResults( @@ -528,15 +675,23 @@ def cancel_accepted_approval(self, args: Dict[str, Any]): approval_assignment_cancel_post_id = str_arg(args, "approval_assignment_cancel_post_id") approval_assignment_cancel_post_comment = str_arg(args, "approval_assignment_cancel_post_comment") - body = assign_params(id=approval_assignment_cancel_post_id, comment=approval_assignment_cancel_post_comment) + body = assign_params( + values_to_ignore=(None,), id=approval_assignment_cancel_post_id, comment=approval_assignment_cancel_post_comment + ) response = self._http_request("post", "/approvals/assignments/cancel", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.cancel_accepted_approval", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-cancel-accepted-approval", response), + raw_response=response, + ) def notify_approvers_linked_to_approval_assignment(self, args: Dict[str, Any]): approval_assignment_notify_post_id = str_arg(args, "approval_assignment_notify_post_id") - body = assign_params(id=approval_assignment_notify_post_id) + body = assign_params(values_to_ignore=(None,), id=approval_assignment_notify_post_id) response = self._http_request("post", "/approvals/assignments/notify", json_data=body) add_key_to_outputs(response, "approval_assignment_notify_post_id", approval_assignment_notify_post_id) @@ -558,7 +713,16 @@ def get_approval_request_pending_for_user(self, args: Dict[str, Any]): fields = str_arg(args, "fields") approval_id = str_arg(args, "approval_id") - params = assign_params(user=user, q=q, sort=sort, offset=offset, limit=limit, fields=fields, approval_id=approval_id) + params = assign_params( + values_to_ignore=(None,), + user=user, + q=q, + sort=sort, + offset=offset, + limit=limit, + fields=fields, + approval_id=approval_id, + ) response = self._http_request("get", "/approvals/requests", params=params) return CommandResults( @@ -583,6 +747,7 @@ def make_new_approval_request_to_access_target(self, args: Dict[str, Any]): approval_request_post_duration = int_arg(args, "approval_request_post_duration") body = assign_params( + values_to_ignore=(None,), target_name=approval_request_post_target_name, authorization=approval_request_post_authorization, account=approval_request_post_account, @@ -608,15 +773,21 @@ def make_new_approval_request_to_access_target(self, args: Dict[str, Any]): def cancel_approval_request(self, args: Dict[str, Any]): approval_request_cancel_post_id = str_arg(args, "approval_request_cancel_post_id") - body = assign_params(id=approval_request_cancel_post_id) + body = assign_params(values_to_ignore=(None,), id=approval_request_cancel_post_id) response = self._http_request("post", "/approvals/requests/cancel", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.cancel_approval_request", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-cancel-approval-request", response), + raw_response=response, + ) def notify_approvers_linked_to_approval_request(self, args: Dict[str, Any]): approval_request_notify_post_id = str_arg(args, "approval_request_notify_post_id") - body = assign_params(id=approval_request_notify_post_id) + body = assign_params(values_to_ignore=(None,), id=approval_request_notify_post_id) response = self._http_request("post", "/approvals/requests/notify", json_data=body) add_key_to_outputs(response, "approval_request_notify_post_id", approval_request_notify_post_id) @@ -634,7 +805,7 @@ def check_if_approval_is_required_for_target(self, args: Dict[str, Any]): authorization = str_arg(args, "authorization") begin = str_arg(args, "begin") - params = assign_params(authorization=authorization, begin=begin) + params = assign_params(values_to_ignore=(None,), authorization=authorization, begin=begin) response = self._http_request("get", f"/approvals/requests/target/{target_name}", params=params) return CommandResults( @@ -645,6 +816,104 @@ def check_if_approval_is_required_for_target(self, args: Dict[str, Any]): raw_response=response, ) + def get_mappings_of_domain(self, args: Dict[str, Any]): + domain_id = str_arg(args, "domain_id") + q = str_arg(args, "q") + sort = str_arg(args, "sort") + offset = int_arg(args, "offset") + limit = int_arg(args, "limit") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) + response = self._http_request("get", f"/authdomains/{domain_id}/mappings", params=params) + + return CommandResults( + outputs_prefix="WAB.authdomain_mapping_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-mappings-of-domain", response), + raw_response=response, + ) + + def add_mapping_in_domain(self, args: Dict[str, Any]): + domain_id = str_arg(args, "domain_id") + authdomain_mapping_post_domain = str_arg(args, "authdomain_mapping_post_domain") + authdomain_mapping_post_user_group = str_arg(args, "authdomain_mapping_post_user_group") + authdomain_mapping_post_external_group = str_arg(args, "authdomain_mapping_post_external_group") + + body = assign_params( + values_to_ignore=(None,), + domain=authdomain_mapping_post_domain, + user_group=authdomain_mapping_post_user_group, + external_group=authdomain_mapping_post_external_group, + ) + response = self._http_request("post", f"/authdomains/{domain_id}/mappings", json_data=body) + + return CommandResults( + outputs_prefix="WAB.add_mapping_in_domain", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-mapping-in-domain", response), + raw_response=response, + ) + + def edit_mappings_of_domain(self, args: Dict[str, Any]): + domain_id = str_arg(args, "domain_id") + authdomain_mapping_put_domain = str_arg(args, "authdomain_mapping_put_domain") + authdomain_mapping_put_user_group = str_arg(args, "authdomain_mapping_put_user_group") + authdomain_mapping_put_external_group = str_arg(args, "authdomain_mapping_put_external_group") + + body = assign_params( + values_to_ignore=(None,), + domain=authdomain_mapping_put_domain, + user_group=authdomain_mapping_put_user_group, + external_group=authdomain_mapping_put_external_group, + ) + response = self._http_request("put", f"/authdomains/{domain_id}/mappings", json_data=body) + + return CommandResults(readable_output="Success!", raw_response=response) + + def get_mapping_of_domain(self, args: Dict[str, Any]): + domain_id = str_arg(args, "domain_id") + mapping_id = str_arg(args, "mapping_id") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), fields=fields) + response = self._http_request("get", f"/authdomains/{domain_id}/mappings/{mapping_id}", params=params) + + return CommandResults( + outputs_prefix="WAB.authdomain_mapping_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-mapping-of-domain", response), + raw_response=response, + ) + + def edit_mapping_of_domain(self, args: Dict[str, Any]): + domain_id = str_arg(args, "domain_id") + mapping_id = str_arg(args, "mapping_id") + authdomain_mapping_put_domain = str_arg(args, "authdomain_mapping_put_domain") + authdomain_mapping_put_user_group = str_arg(args, "authdomain_mapping_put_user_group") + authdomain_mapping_put_external_group = str_arg(args, "authdomain_mapping_put_external_group") + + body = assign_params( + values_to_ignore=(None,), + domain=authdomain_mapping_put_domain, + user_group=authdomain_mapping_put_user_group, + external_group=authdomain_mapping_put_external_group, + ) + response = self._http_request("put", f"/authdomains/{domain_id}/mappings/{mapping_id}", json_data=body) + + return CommandResults(readable_output="Success!", raw_response=response) + + def delete_mapping_of_domain(self, args: Dict[str, Any]): + domain_id = str_arg(args, "domain_id") + mapping_id = str_arg(args, "mapping_id") + + response = self._http_request("delete", f"/authdomains/{domain_id}/mappings/{mapping_id}") + + return CommandResults(readable_output="Success!", raw_response=response) + def get_auth_domains(self, args: Dict[str, Any]): q = str_arg(args, "q") sort = str_arg(args, "sort") @@ -652,7 +921,7 @@ def get_auth_domains(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", "/authdomains", params=params) return CommandResults( @@ -667,7 +936,7 @@ def get_auth_domain(self, args: Dict[str, Any]): domain_id = str_arg(args, "domain_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request("get", f"/authdomains/{domain_id}", params=params) return CommandResults( @@ -689,7 +958,15 @@ def get_authentications(self, args: Dict[str, Any]): fields = str_arg(args, "fields") params = assign_params( - from_date=from_date, to_date=to_date, date_field=date_field, q=q, sort=sort, offset=offset, limit=limit, fields=fields + values_to_ignore=(None,), + from_date=from_date, + to_date=to_date, + date_field=date_field, + q=q, + sort=sort, + offset=offset, + limit=limit, + fields=fields, ) response = self._http_request("get", "/authentications", params=params) @@ -708,7 +985,9 @@ def get_authentication(self, args: Dict[str, Any]): date_field = str_arg(args, "date_field") fields = str_arg(args, "fields") - params = assign_params(from_date=from_date, to_date=to_date, date_field=date_field, fields=fields) + params = assign_params( + values_to_ignore=(None,), from_date=from_date, to_date=to_date, date_field=date_field, fields=fields + ) response = self._http_request("get", f"/authentications/{auth_id}", params=params) return CommandResults( @@ -726,7 +1005,7 @@ def get_authorizations(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", "/authorizations", params=params) return CommandResults( @@ -761,6 +1040,7 @@ def add_authorization(self, args: Dict[str, Any]): authorization_post_session_sharing_mode = str_arg(args, "authorization_post_session_sharing_mode") body = assign_params( + values_to_ignore=(None,), user_group=authorization_post_user_group, target_group=authorization_post_target_group, authorization_name=authorization_post_authorization_name, @@ -785,13 +1065,19 @@ def add_authorization(self, args: Dict[str, Any]): ) response = self._http_request("post", "/authorizations", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.add_authorization", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-authorization", response), + raw_response=response, + ) def get_authorization(self, args: Dict[str, Any]): authorization_id = str_arg(args, "authorization_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request("get", f"/authorizations/{authorization_id}", params=params) return CommandResults( @@ -825,8 +1111,9 @@ def edit_authorization(self, args: Dict[str, Any]): authorization_put_authorize_session_sharing = bool_arg(args, "authorization_put_authorize_session_sharing") authorization_put_session_sharing_mode = str_arg(args, "authorization_put_session_sharing_mode") - params = assign_params(force=force) + params = assign_params(values_to_ignore=(None,), force=force) body = assign_params( + values_to_ignore=(None,), authorization_name=authorization_put_authorization_name, description=authorization_put_description, subprotocols=authorization_put_subprotocols, @@ -865,7 +1152,7 @@ def get_checkout_policies(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", "/checkoutpolicies", params=params) return CommandResults( @@ -880,7 +1167,7 @@ def get_checkout_policy(self, args: Dict[str, Any]): checkout_policy_id = str_arg(args, "checkout_policy_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request("get", f"/checkoutpolicies/{checkout_policy_id}", params=params) return CommandResults( @@ -891,6 +1178,39 @@ def get_checkout_policy(self, args: Dict[str, Any]): raw_response=response, ) + def get_clusters(self, args: Dict[str, Any]): + q = str_arg(args, "q") + sort = str_arg(args, "sort") + offset = int_arg(args, "offset") + limit = int_arg(args, "limit") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) + response = self._http_request("get", "/clusters", params=params) + + return CommandResults( + outputs_prefix="WAB.cluster_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-clusters", response), + raw_response=response, + ) + + def get_cluster(self, args: Dict[str, Any]): + cluster_id = str_arg(args, "cluster_id") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), fields=fields) + response = self._http_request("get", f"/clusters/{cluster_id}", params=params) + + return CommandResults( + outputs_prefix="WAB.cluster_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-cluster", response), + raw_response=response, + ) + def getx509_configuration_infos(self, args: Dict[str, Any]): response = self._http_request("get", "/config/x509") @@ -909,6 +1229,7 @@ def uploadx509_configuration(self, args: Dict[str, Any]): config_x509_post_enable = bool_arg(args, "config_x509_post_enable") body = assign_params( + values_to_ignore=(None,), ca_certificate=config_x509_post_ca_certificate, server_public_key=config_x509_post_server_public_key, server_private_key=config_x509_post_server_private_key, @@ -916,7 +1237,13 @@ def uploadx509_configuration(self, args: Dict[str, Any]): ) response = self._http_request("post", "/config/x509", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.uploadx509_configuration", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-uploadx509-configuration", response), + raw_response=response, + ) def updatex509_configuration(self, args: Dict[str, Any]): config_x509_put_ca_certificate = str_arg(args, "config_x509_put_ca_certificate") @@ -925,6 +1252,7 @@ def updatex509_configuration(self, args: Dict[str, Any]): config_x509_put_enable = bool_arg(args, "config_x509_put_enable") body = assign_params( + values_to_ignore=(None,), ca_certificate=config_x509_put_ca_certificate, server_public_key=config_x509_put_server_public_key, server_private_key=config_x509_put_server_private_key, @@ -951,6 +1279,93 @@ def get_current_serial_configuration_number_of_bastion(self, args: Dict[str, Any raw_response=response, ) + def get_connection_policies(self, args: Dict[str, Any]): + q = str_arg(args, "q") + sort = str_arg(args, "sort") + offset = int_arg(args, "offset") + limit = int_arg(args, "limit") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) + response = self._http_request("get", "/connectionpolicies", params=params) + + return CommandResults( + outputs_prefix="WAB.connectionpolicy_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-connection-policies", response), + raw_response=response, + ) + + def add_connection_policy(self, args: Dict[str, Any]): + connectionpolicy_post_connection_policy_name = str_arg(args, "connectionpolicy_post_connection_policy_name") + connectionpolicy_post_type = str_arg(args, "connectionpolicy_post_type") + connectionpolicy_post_description = str_arg(args, "connectionpolicy_post_description") + connectionpolicy_post_protocol = str_arg(args, "connectionpolicy_post_protocol") + connectionpolicy_post_authentication_methods = list_arg(args, "connectionpolicy_post_authentication_methods") + options = json_arg(args, "options") + + body = assign_params( + values_to_ignore=(None,), + connection_policy_name=connectionpolicy_post_connection_policy_name, + type=connectionpolicy_post_type, + description=connectionpolicy_post_description, + protocol=connectionpolicy_post_protocol, + authentication_methods=connectionpolicy_post_authentication_methods, + options=options, + ) + response = self._http_request("post", "/connectionpolicies", json_data=body) + + return CommandResults( + outputs_prefix="WAB.add_connection_policy", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-connection-policy", response), + raw_response=response, + ) + + def get_connection_policy(self, args: Dict[str, Any]): + connection_policy_id = str_arg(args, "connection_policy_id") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), fields=fields) + response = self._http_request("get", f"/connectionpolicies/{connection_policy_id}", params=params) + + return CommandResults( + outputs_prefix="WAB.connectionpolicy_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-connection-policy", response), + raw_response=response, + ) + + def edit_connection_policy(self, args: Dict[str, Any]): + connection_policy_id = str_arg(args, "connection_policy_id") + force = bool_arg(args, "force") + connectionpolicy_put_connection_policy_name = str_arg(args, "connectionpolicy_put_connection_policy_name") + connectionpolicy_put_description = str_arg(args, "connectionpolicy_put_description") + connectionpolicy_put_authentication_methods = list_arg(args, "connectionpolicy_put_authentication_methods") + options = json_arg(args, "options") + + params = assign_params(values_to_ignore=(None,), force=force) + body = assign_params( + values_to_ignore=(None,), + connection_policy_name=connectionpolicy_put_connection_policy_name, + description=connectionpolicy_put_description, + authentication_methods=connectionpolicy_put_authentication_methods, + options=options, + ) + response = self._http_request("put", f"/connectionpolicies/{connection_policy_id}", params=params, json_data=body) + + return CommandResults(readable_output="Success!", raw_response=response) + + def delete_connection_policy(self, args: Dict[str, Any]): + connection_policy_id = str_arg(args, "connection_policy_id") + + response = self._http_request("delete", f"/connectionpolicies/{connection_policy_id}") + + return CommandResults(readable_output="Success!", raw_response=response) + def get_all_accounts_on_device_local_domain(self, args: Dict[str, Any]): device_id = str_arg(args, "device_id") domain_id = str_arg(args, "domain_id") @@ -961,7 +1376,9 @@ def get_all_accounts_on_device_local_domain(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(key_format=key_format, q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params( + values_to_ignore=(None,), key_format=key_format, q=q, sort=sort, offset=offset, limit=limit, fields=fields + ) response = self._http_request("get", f"/devices/{device_id}/localdomains/{domain_id}/accounts", params=params) return CommandResults( @@ -986,6 +1403,7 @@ def add_account_to_local_domain_on_device(self, args: Dict[str, Any]): device_account_post_services = list_arg(args, "device_account_post_services") body = assign_params( + values_to_ignore=(None,), account_name=device_account_post_account_name, account_login=device_account_post_account_login, description=device_account_post_description, @@ -998,7 +1416,13 @@ def add_account_to_local_domain_on_device(self, args: Dict[str, Any]): ) response = self._http_request("post", f"/devices/{device_id}/localdomains/{domain_id}/accounts", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.add_account_to_local_domain_on_device", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-account-to-local-domain-on-device", response), + raw_response=response, + ) def get_one_account_on_device_local_domain(self, args: Dict[str, Any]): device_id = str_arg(args, "device_id") @@ -1007,7 +1431,7 @@ def get_one_account_on_device_local_domain(self, args: Dict[str, Any]): key_format = str_arg(args, "key_format") fields = str_arg(args, "fields") - params = assign_params(key_format=key_format, fields=fields) + params = assign_params(values_to_ignore=(None,), key_format=key_format, fields=fields) response = self._http_request( "get", f"/devices/{device_id}/localdomains/{domain_id}/accounts/{account_id}", params=params ) @@ -1036,8 +1460,9 @@ def edit_account_on_local_domain_of_device(self, args: Dict[str, Any]): device_account_put_onboard_status = str_arg(args, "device_account_put_onboard_status") device_account_put_services = list_arg(args, "device_account_put_services") - params = assign_params(force=force) + params = assign_params(values_to_ignore=(None,), force=force) body = assign_params( + values_to_ignore=(None,), account_name=device_account_put_account_name, account_login=device_account_put_account_login, description=device_account_put_description, @@ -1072,7 +1497,7 @@ def get_certificates_on_device(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", f"/devices/{device_id}/certificates", params=params) return CommandResults( @@ -1093,7 +1518,7 @@ def get_certificate_on_device(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", f"/devices/{device_id}/certificates/{cert_type}/{address}/{port}", params=params) return CommandResults( @@ -1113,7 +1538,7 @@ def revoke_certificate_of_device(self, args: Dict[str, Any]): return CommandResults(readable_output="Success!", raw_response=response) - def get_services_of_device(self, args: Dict[str, Any]): + def get_local_domains_of_device(self, args: Dict[str, Any]): device_id = str_arg(args, "device_id") q = str_arg(args, "q") sort = str_arg(args, "sort") @@ -1121,46 +1546,90 @@ def get_services_of_device(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) - response = self._http_request("get", f"/devices/{device_id}/services", params=params) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) + response = self._http_request("get", f"/devices/{device_id}/localdomains", params=params) return CommandResults( - outputs_prefix="WAB.service_get", + outputs_prefix="WAB.localdomain_get", outputs_key_field="id", outputs=response, - readable_output=to_markdown("wab-get-services-of-device", response), + readable_output=to_markdown("wab-get-local-domains-of-device", response), raw_response=response, ) - def add_service_in_device(self, args: Dict[str, Any]): + def get_local_domain_of_device(self, args: Dict[str, Any]): device_id = str_arg(args, "device_id") - service_post_id = str_arg(args, "service_post_id") - service_post_service_name = str_arg(args, "service_post_service_name") - service_post_protocol = str_arg(args, "service_post_protocol") - service_post_port = int_arg(args, "service_post_port") - service_post_subprotocols = list_arg(args, "service_post_subprotocols") - service_post_connection_policy = str_arg(args, "service_post_connection_policy") - service_post_global_domains = list_arg(args, "service_post_global_domains") + domain_id = str_arg(args, "domain_id") + fields = str_arg(args, "fields") - body = assign_params( - id=service_post_id, + params = assign_params(values_to_ignore=(None,), fields=fields) + response = self._http_request("get", f"/devices/{device_id}/localdomains/{domain_id}", params=params) + + return CommandResults( + outputs_prefix="WAB.localdomain_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-local-domain-of-device", response), + raw_response=response, + ) + + def get_services_of_device(self, args: Dict[str, Any]): + device_id = str_arg(args, "device_id") + q = str_arg(args, "q") + sort = str_arg(args, "sort") + offset = int_arg(args, "offset") + limit = int_arg(args, "limit") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) + response = self._http_request("get", f"/devices/{device_id}/services", params=params) + + return CommandResults( + outputs_prefix="WAB.service_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-services-of-device", response), + raw_response=response, + ) + + def add_service_in_device(self, args: Dict[str, Any]): + device_id = str_arg(args, "device_id") + service_post_id = str_arg(args, "service_post_id") + service_post_service_name = str_arg(args, "service_post_service_name") + service_post_protocol = str_arg(args, "service_post_protocol") + service_post_port = int_arg(args, "service_post_port") + service_post_subprotocols = list_arg(args, "service_post_subprotocols") + service_post_connection_policy = str_arg(args, "service_post_connection_policy") + service_post_global_domains = list_arg(args, "service_post_global_domains") + service_post_seamless_connection = bool_arg(args, "service_post_seamless_connection") + + body = assign_params( + values_to_ignore=(None,), + id=service_post_id, service_name=service_post_service_name, protocol=service_post_protocol, port=service_post_port, subprotocols=service_post_subprotocols, connection_policy=service_post_connection_policy, global_domains=service_post_global_domains, + seamless_connection=service_post_seamless_connection, ) response = self._http_request("post", f"/devices/{device_id}/services", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.add_service_in_device", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-service-in-device", response), + raw_response=response, + ) def get_service_of_device(self, args: Dict[str, Any]): device_id = str_arg(args, "device_id") service_id = str_arg(args, "service_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request("get", f"/devices/{device_id}/services/{service_id}", params=params) return CommandResults( @@ -1176,12 +1645,19 @@ def edit_service_of_device(self, args: Dict[str, Any]): service_id = str_arg(args, "service_id") force = bool_arg(args, "force") service_put_port = int_arg(args, "service_put_port") + service_put_subprotocols = list_arg(args, "service_put_subprotocols") service_put_connection_policy = str_arg(args, "service_put_connection_policy") service_put_global_domains = list_arg(args, "service_put_global_domains") + service_put_seamless_connection = bool_arg(args, "service_put_seamless_connection") - params = assign_params(force=force) + params = assign_params(values_to_ignore=(None,), force=force) body = assign_params( - port=service_put_port, connection_policy=service_put_connection_policy, global_domains=service_put_global_domains + values_to_ignore=(None,), + port=service_put_port, + subprotocols=service_put_subprotocols, + connection_policy=service_put_connection_policy, + global_domains=service_put_global_domains, + seamless_connection=service_put_seamless_connection, ) response = self._http_request("put", f"/devices/{device_id}/services/{service_id}", params=params, json_data=body) @@ -1202,7 +1678,7 @@ def get_devices(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", "/devices", params=params) return CommandResults( @@ -1220,6 +1696,7 @@ def add_device(self, args: Dict[str, Any]): device_post_host = str_arg(args, "device_post_host") body = assign_params( + values_to_ignore=(None,), device_name=device_post_device_name, description=device_post_description, alias=device_post_alias, @@ -1227,13 +1704,19 @@ def add_device(self, args: Dict[str, Any]): ) response = self._http_request("post", "/devices", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.add_device", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-device", response), + raw_response=response, + ) def get_device(self, args: Dict[str, Any]): device_id = str_arg(args, "device_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request("get", f"/devices/{device_id}", params=params) return CommandResults( @@ -1253,8 +1736,9 @@ def edit_device(self, args: Dict[str, Any]): device_put_host = str_arg(args, "device_put_host") device_put_onboard_status = str_arg(args, "device_put_onboard_status") - params = assign_params(force=force) + params = assign_params(values_to_ignore=(None,), force=force) body = assign_params( + values_to_ignore=(None,), device_name=device_put_device_name, description=device_put_description, alias=device_put_alias, @@ -1279,7 +1763,7 @@ def get_accounts_of_global_domain(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, offset=offset, limit=limit, fields=fields) response = self._http_request("get", f"/domains/{domain_id}/accounts", params=params) return CommandResults( @@ -1303,6 +1787,7 @@ def add_account_in_global_domain(self, args: Dict[str, Any]): domain_account_post_resources = list_arg(args, "domain_account_post_resources") body = assign_params( + values_to_ignore=(None,), account_name=domain_account_post_account_name, account_login=domain_account_post_account_login, description=domain_account_post_description, @@ -1315,14 +1800,20 @@ def add_account_in_global_domain(self, args: Dict[str, Any]): ) response = self._http_request("post", f"/domains/{domain_id}/accounts", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.add_account_in_global_domain", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-account-in-global-domain", response), + raw_response=response, + ) def get_account_of_global_domain(self, args: Dict[str, Any]): domain_id = str_arg(args, "domain_id") account_id = str_arg(args, "account_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request("get", f"/domains/{domain_id}/accounts/{account_id}", params=params) return CommandResults( @@ -1348,8 +1839,9 @@ def edit_account_in_global_domain(self, args: Dict[str, Any]): domain_account_put_onboard_status = str_arg(args, "domain_account_put_onboard_status") domain_account_put_resources = list_arg(args, "domain_account_put_resources") - params = assign_params(force=force) + params = assign_params(values_to_ignore=(None,), force=force) body = assign_params( + values_to_ignore=(None,), account_name=domain_account_put_account_name, account_login=domain_account_put_account_login, description=domain_account_put_description, @@ -1389,7 +1881,7 @@ def get_global_domains(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", "/domains", params=params) return CommandResults( @@ -1404,7 +1896,7 @@ def get_global_domain(self, args: Dict[str, Any]): domain_id = str_arg(args, "domain_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request("get", f"/domains/{domain_id}", params=params) return CommandResults( @@ -1415,6 +1907,26 @@ def get_global_domain(self, args: Dict[str, Any]): raw_response=response, ) + def get_external_authentication_group_mappings(self, args: Dict[str, Any]): + group_by = str_arg(args, "group_by") + q = str_arg(args, "q") + sort = str_arg(args, "sort") + offset = int_arg(args, "offset") + limit = int_arg(args, "limit") + fields = str_arg(args, "fields") + + params = assign_params( + values_to_ignore=(None,), group_by=group_by, q=q, sort=sort, offset=offset, limit=limit, fields=fields + ) + response = self._http_request("get", "/authmappings", params=params) + + return CommandResults( + outputs_prefix="WAB.authmappings_get", + outputs=response, + readable_output=to_markdown("wab-get-external-authentication-group-mappings", response), + raw_response=response, + ) + def get_ldap_users_of_domain(self, args: Dict[str, Any]): domain = str_arg(args, "domain") last_connection = bool_arg(args, "last_connection") @@ -1423,7 +1935,9 @@ def get_ldap_users_of_domain(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(last_connection=last_connection, q=q, offset=offset, limit=limit, fields=fields) + params = assign_params( + values_to_ignore=(None,), last_connection=last_connection, q=q, offset=offset, limit=limit, fields=fields + ) response = self._http_request("get", f"/ldapusers/{domain}", params=params) return CommandResults( @@ -1440,7 +1954,7 @@ def get_ldap_user_of_domain(self, args: Dict[str, Any]): last_connection = bool_arg(args, "last_connection") fields = str_arg(args, "fields") - params = assign_params(last_connection=last_connection, fields=fields) + params = assign_params(values_to_ignore=(None,), last_connection=last_connection, fields=fields) response = self._http_request("get", f"/ldapusers/{domain}/{user_name}", params=params) return CommandResults( @@ -1466,10 +1980,16 @@ def post_logsiem(self, args: Dict[str, Any]): logsiem_post_application = str_arg(args, "logsiem_post_application") logsiem_post_message = str_arg(args, "logsiem_post_message") - body = assign_params(application=logsiem_post_application, message=logsiem_post_message) + body = assign_params(values_to_ignore=(None,), application=logsiem_post_application, message=logsiem_post_message) response = self._http_request("post", "/logsiem", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.post_logsiem", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-post-logsiem", response), + raw_response=response, + ) def get_notifications(self, args: Dict[str, Any]): q = str_arg(args, "q") @@ -1477,7 +1997,7 @@ def get_notifications(self, args: Dict[str, Any]): offset = int_arg(args, "offset") limit = int_arg(args, "limit") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit) response = self._http_request("get", "/notifications", params=params) return CommandResults( @@ -1498,6 +2018,7 @@ def add_notification(self, args: Dict[str, Any]): notification_post_events = list_arg(args, "notification_post_events") body = assign_params( + values_to_ignore=(None,), notification_name=notification_post_notification_name, description=notification_post_description, enabled=notification_post_enabled, @@ -1508,7 +2029,13 @@ def add_notification(self, args: Dict[str, Any]): ) response = self._http_request("post", "/notifications", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.add_notification", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-notification", response), + raw_response=response, + ) def get_notification(self, args: Dict[str, Any]): notification_id = str_arg(args, "notification_id") @@ -1534,8 +2061,9 @@ def edit_notification(self, args: Dict[str, Any]): notification_put_language = str_arg(args, "notification_put_language") notification_put_events = list_arg(args, "notification_put_events") - params = assign_params(force=force) + params = assign_params(values_to_ignore=(None,), force=force) body = assign_params( + values_to_ignore=(None,), notification_name=notification_put_notification_name, description=notification_put_description, enabled=notification_put_enabled, @@ -1565,7 +2093,14 @@ def get_object_to_onboard(self, args: Dict[str, Any]): fields = str_arg(args, "fields") params = assign_params( - object_type=object_type, object_status=object_status, q=q, sort=sort, offset=offset, limit=limit, fields=fields + values_to_ignore=(None,), + object_type=object_type, + object_status=object_status, + q=q, + sort=sort, + offset=offset, + limit=limit, + fields=fields, ) response = self._http_request("get", "/onboarding_objects", params=params) @@ -1577,6 +2112,152 @@ def get_object_to_onboard(self, args: Dict[str, Any]): raw_response=response, ) + def get_password_change_policies(self, args: Dict[str, Any]): + q = str_arg(args, "q") + sort = str_arg(args, "sort") + offset = int_arg(args, "offset") + limit = int_arg(args, "limit") + + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit) + response = self._http_request("get", "/passwordchangepolicies", params=params) + + return CommandResults( + outputs_prefix="WAB.passwordchangepolicy_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-password-change-policies", response), + raw_response=response, + ) + + def add_password_change_policy(self, args: Dict[str, Any]): + passwordchangepolicy_post_password_change_policy_name = str_arg( + args, "passwordchangepolicy_post_password_change_policy_name" + ) + passwordchangepolicy_post_description = str_arg(args, "passwordchangepolicy_post_description") + passwordchangepolicy_post_password_length = int_arg(args, "passwordchangepolicy_post_password_length", nullable=True) + passwordchangepolicy_post_special_chars = int_arg(args, "passwordchangepolicy_post_special_chars", nullable=True) + passwordchangepolicy_post_lower_chars = int_arg(args, "passwordchangepolicy_post_lower_chars", nullable=True) + passwordchangepolicy_post_upper_chars = int_arg(args, "passwordchangepolicy_post_upper_chars", nullable=True) + passwordchangepolicy_post_digit_chars = int_arg(args, "passwordchangepolicy_post_digit_chars", nullable=True) + passwordchangepolicy_post_exclude_chars = str_arg(args, "passwordchangepolicy_post_exclude_chars", nullable=True) + passwordchangepolicy_post_ssh_key_type = str_arg(args, "passwordchangepolicy_post_ssh_key_type", nullable=True) + passwordchangepolicy_post_ssh_key_size = int_arg(args, "passwordchangepolicy_post_ssh_key_size", nullable=True) + passwordchangepolicy_post_change_period = str_arg(args, "passwordchangepolicy_post_change_period", nullable=True) + + body = assign_params( + values_to_ignore=(None,), + password_change_policy_name=passwordchangepolicy_post_password_change_policy_name, + description=passwordchangepolicy_post_description, + password_length=passwordchangepolicy_post_password_length, + special_chars=passwordchangepolicy_post_special_chars, + lower_chars=passwordchangepolicy_post_lower_chars, + upper_chars=passwordchangepolicy_post_upper_chars, + digit_chars=passwordchangepolicy_post_digit_chars, + exclude_chars=passwordchangepolicy_post_exclude_chars, + ssh_key_type=passwordchangepolicy_post_ssh_key_type, + ssh_key_size=passwordchangepolicy_post_ssh_key_size, + change_period=passwordchangepolicy_post_change_period, + ) + response = self._http_request("post", "/passwordchangepolicies", json_data=body) + + return CommandResults( + outputs_prefix="WAB.add_password_change_policy", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-password-change-policy", response), + raw_response=response, + ) + + def get_password_change_policy(self, args: Dict[str, Any]): + policy_id = str_arg(args, "policy_id") + + response = self._http_request("get", f"/passwordchangepolicies/{policy_id}") + + return CommandResults( + outputs_prefix="WAB.passwordchangepolicy_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-password-change-policy", response), + raw_response=response, + ) + + def edit_password_change_policy(self, args: Dict[str, Any]): + policy_id = str_arg(args, "policy_id") + passwordchangepolicy_put_password_change_policy_name = str_arg( + args, "passwordchangepolicy_put_password_change_policy_name" + ) + passwordchangepolicy_put_description = str_arg(args, "passwordchangepolicy_put_description") + passwordchangepolicy_put_password_length = int_arg(args, "passwordchangepolicy_put_password_length", nullable=True) + passwordchangepolicy_put_special_chars = int_arg(args, "passwordchangepolicy_put_special_chars", nullable=True) + passwordchangepolicy_put_lower_chars = int_arg(args, "passwordchangepolicy_put_lower_chars", nullable=True) + passwordchangepolicy_put_upper_chars = int_arg(args, "passwordchangepolicy_put_upper_chars", nullable=True) + passwordchangepolicy_put_digit_chars = int_arg(args, "passwordchangepolicy_put_digit_chars", nullable=True) + passwordchangepolicy_put_exclude_chars = str_arg(args, "passwordchangepolicy_put_exclude_chars", nullable=True) + passwordchangepolicy_put_ssh_key_type = str_arg(args, "passwordchangepolicy_put_ssh_key_type", nullable=True) + passwordchangepolicy_put_ssh_key_size = int_arg(args, "passwordchangepolicy_put_ssh_key_size", nullable=True) + passwordchangepolicy_put_change_period = str_arg(args, "passwordchangepolicy_put_change_period", nullable=True) + + body = assign_params( + values_to_ignore=(None,), + password_change_policy_name=passwordchangepolicy_put_password_change_policy_name, + description=passwordchangepolicy_put_description, + password_length=passwordchangepolicy_put_password_length, + special_chars=passwordchangepolicy_put_special_chars, + lower_chars=passwordchangepolicy_put_lower_chars, + upper_chars=passwordchangepolicy_put_upper_chars, + digit_chars=passwordchangepolicy_put_digit_chars, + exclude_chars=passwordchangepolicy_put_exclude_chars, + ssh_key_type=passwordchangepolicy_put_ssh_key_type, + ssh_key_size=passwordchangepolicy_put_ssh_key_size, + change_period=passwordchangepolicy_put_change_period, + ) + response = self._http_request("put", f"/passwordchangepolicies/{policy_id}", json_data=body) + + return CommandResults(readable_output="Success!", raw_response=response) + + def delete_password_change_policy(self, args: Dict[str, Any]): + policy_id = str_arg(args, "policy_id") + + response = self._http_request("delete", f"/passwordchangepolicies/{policy_id}") + + return CommandResults(readable_output="Success!", raw_response=response) + + def get_passwordrights(self, args: Dict[str, Any]): + count = bool_arg(args, "count") + q = str_arg(args, "q") + sort = str_arg(args, "sort") + offset = int_arg(args, "offset") + limit = int_arg(args, "limit") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), count=count, q=q, sort=sort, offset=offset, limit=limit, fields=fields) + response = self._http_request("get", "/passwordrights", params=params) + + return CommandResults( + outputs_prefix="WAB.passwordrights_get", + outputs=response, + readable_output=to_markdown("wab-get-passwordrights", response), + raw_response=response, + ) + + def get_passwordrights_user_name(self, args: Dict[str, Any]): + user_name = str_arg(args, "user_name") + count = bool_arg(args, "count") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), count=count, fields=fields) + response = self._http_request("get", f"/passwordrights/{user_name}", params=params) + + add_key_to_outputs(response, "user_name", user_name) + + return CommandResults( + outputs_prefix="WAB.passwordrights_get", + outputs_key_field="user_name", + outputs=response, + readable_output=to_markdown("wab-get-passwordrights-user-name", response), + raw_response=response, + ) + def get_profiles(self, args: Dict[str, Any]): q = str_arg(args, "q") sort = str_arg(args, "sort") @@ -1584,7 +2265,7 @@ def get_profiles(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", "/profiles", params=params) return CommandResults( @@ -1599,7 +2280,7 @@ def get_profile(self, args: Dict[str, Any]): profile_id = str_arg(args, "profile_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request("get", f"/profiles/{profile_id}", params=params) return CommandResults( @@ -1617,7 +2298,7 @@ def get_scanjobs(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", "/scanjobs", params=params) return CommandResults( @@ -1631,16 +2312,22 @@ def get_scanjobs(self, args: Dict[str, Any]): def start_scan_job_manually(self, args: Dict[str, Any]): scanjob_post_scan_id = str_arg(args, "scanjob_post_scan_id") - body = assign_params(scan_id=scanjob_post_scan_id) + body = assign_params(values_to_ignore=(None,), scan_id=scanjob_post_scan_id) response = self._http_request("post", "/scanjobs", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.start_scan_job_manually", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-start-scan-job-manually", response), + raw_response=response, + ) def get_scanjob(self, args: Dict[str, Any]): scanjob_id = str_arg(args, "scanjob_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request("get", f"/scanjobs/{scanjob_id}", params=params) return CommandResults( @@ -1665,7 +2352,7 @@ def get_scans(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", "/scans", params=params) return CommandResults( @@ -1680,7 +2367,7 @@ def get_scan(self, args: Dict[str, Any]): scan_id = str_arg(args, "scan_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request("get", f"/scans/{scan_id}", params=params) return CommandResults( @@ -1691,6 +2378,47 @@ def get_scan(self, args: Dict[str, Any]): raw_response=response, ) + def edit_scan(self, args: Dict[str, Any]): + scan_id = str_arg(args, "scan_id") + scan_put_name = str_arg(args, "scan_put_name") + scan_put_active = bool_arg(args, "scan_put_active") + scan_put_periodicity = str_arg(args, "scan_put_periodicity") + scan_put_description = str_arg(args, "scan_put_description") + scan_put_emails = list_arg(args, "scan_put_emails") + scan_put_subnets = list_arg(args, "scan_put_subnets") + scan_put_banner_regex = list_arg(args, "scan_put_banner_regex") + scan_put_scan_for_accounts = bool_arg(args, "scan_put_scan_for_accounts") + scan_put_master_accounts = list_arg(args, "scan_put_master_accounts") + scan_put_search_filter = str_arg(args, "scan_put_search_filter") + scan_put_dn_list = list_arg(args, "scan_put_dn_list") + scan_put_devices = list_arg(args, "scan_put_devices") + + body = assign_params( + values_to_ignore=(None,), + name=scan_put_name, + active=scan_put_active, + periodicity=scan_put_periodicity, + description=scan_put_description, + emails=scan_put_emails, + subnets=scan_put_subnets, + banner_regex=scan_put_banner_regex, + scan_for_accounts=scan_put_scan_for_accounts, + master_accounts=scan_put_master_accounts, + search_filter=scan_put_search_filter, + dn_list=scan_put_dn_list, + devices=scan_put_devices, + ) + response = self._http_request("put", f"/scans/{scan_id}", json_data=body) + + return CommandResults(readable_output="Success!", raw_response=response) + + def delete_scan(self, args: Dict[str, Any]): + scan_id = str_arg(args, "scan_id") + + response = self._http_request("delete", f"/scans/{scan_id}") + + return CommandResults(readable_output="Success!", raw_response=response) + def get_sessionrights(self, args: Dict[str, Any]): count = bool_arg(args, "count") last_connection = bool_arg(args, "last_connection") @@ -1701,7 +2429,14 @@ def get_sessionrights(self, args: Dict[str, Any]): fields = str_arg(args, "fields") params = assign_params( - count=count, last_connection=last_connection, q=q, sort=sort, offset=offset, limit=limit, fields=fields + values_to_ignore=(None,), + count=count, + last_connection=last_connection, + q=q, + sort=sort, + offset=offset, + limit=limit, + fields=fields, ) response = self._http_request("get", "/sessionrights", params=params) @@ -1718,7 +2453,7 @@ def get_sessionrights_user_name(self, args: Dict[str, Any]): last_connection = bool_arg(args, "last_connection") fields = str_arg(args, "fields") - params = assign_params(count=count, last_connection=last_connection, fields=fields) + params = assign_params(values_to_ignore=(None,), count=count, last_connection=last_connection, fields=fields) response = self._http_request("get", f"/sessionrights/{user_name}", params=params) add_key_to_outputs(response, "user_name", user_name) @@ -1745,6 +2480,7 @@ def get_sessions(self, args: Dict[str, Any]): fields = str_arg(args, "fields") params = assign_params( + values_to_ignore=(None,), session_id=session_id, otp=otp, status=status, @@ -1772,8 +2508,8 @@ def edit_session(self, args: Dict[str, Any]): action = str_arg(args, "action") session_put_edit_description = str_arg(args, "session_put_edit_description") - params = assign_params(session_id=session_id, action=action) - body = assign_params(description=session_put_edit_description) + params = assign_params(values_to_ignore=(None,), session_id=session_id, action=action) + body = assign_params(values_to_ignore=(None,), description=session_put_edit_description) response = self._http_request("put", "/sessions", params=params, json_data=body) return CommandResults(readable_output="Success!", raw_response=response) @@ -1782,7 +2518,7 @@ def get_session_metadata(self, args: Dict[str, Any]): session_ids = str_arg(args, "session_ids") download = bool_arg(args, "download") - params = assign_params(session_ids=session_ids, download=download) + params = assign_params(values_to_ignore=(None,), session_ids=session_ids, download=download) response = self._http_request("get", "/sessions/metadata", params=params) return CommandResults( @@ -1796,7 +2532,7 @@ def get_session_sharing_requests(self, args: Dict[str, Any]): request_id = str_arg(args, "request_id") session_id = str_arg(args, "session_id") - params = assign_params(request_id=request_id, session_id=session_id) + params = assign_params(values_to_ignore=(None,), request_id=request_id, session_id=session_id) response = self._http_request("get", "/sessions/requests", params=params) return CommandResults( @@ -1811,7 +2547,7 @@ def create_session_request(self, args: Dict[str, Any]): session_request_post_session_id = str_arg(args, "session_request_post_session_id") session_request_post_mode = str_arg(args, "session_request_post_mode") - body = assign_params(session_id=session_request_post_session_id, mode=session_request_post_mode) + body = assign_params(values_to_ignore=(None,), session_id=session_request_post_session_id, mode=session_request_post_mode) response = self._http_request("post", "/sessions/requests", json_data=body) return CommandResults(readable_output="Success!", raw_response=response) @@ -1836,7 +2572,7 @@ def get_status_of_trace_generation(self, args: Dict[str, Any]): duration = int_arg(args, "duration") download = bool_arg(args, "download") - params = assign_params(date=date, duration=duration, download=download) + params = assign_params(values_to_ignore=(None,), date=date, duration=duration, download=download) response = self._http_request("get", f"/sessions/traces/{session_id}", params=params) return CommandResults( @@ -1853,17 +2589,26 @@ def generate_trace_for_session(self, args: Dict[str, Any]): session_trace_post_duration = int_arg(args, "session_trace_post_duration") body = assign_params( - session_id=session_trace_post_session_id, date=session_trace_post_date, duration=session_trace_post_duration + values_to_ignore=(None,), + session_id=session_trace_post_session_id, + date=session_trace_post_date, + duration=session_trace_post_duration, ) response = self._http_request("post", "/sessions/traces", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.generate_trace_for_session", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-generate-trace-for-session", response), + raw_response=response, + ) def get_wallix_bastion_usage_statistics(self, args: Dict[str, Any]): from_date = str_arg(args, "from_date") to_date = str_arg(args, "to_date") - params = assign_params(from_date=from_date, to_date=to_date) + params = assign_params(values_to_ignore=(None,), from_date=from_date, to_date=to_date) response = self._http_request("get", "/statistics", params=params) return CommandResults( @@ -1884,7 +2629,15 @@ def get_target_groups(self, args: Dict[str, Any]): fields = str_arg(args, "fields") params = assign_params( - device=device, application=application, domain=domain, q=q, sort=sort, offset=offset, limit=limit, fields=fields + values_to_ignore=(None,), + device=device, + application=application, + domain=domain, + q=q, + sort=sort, + offset=offset, + limit=limit, + fields=fields, ) response = self._http_request("get", "/targetgroups", params=params) @@ -1900,10 +2653,18 @@ def add_target_group(self, args: Dict[str, Any]): targetgroups_post_group_name = str_arg(args, "targetgroups_post_group_name") targetgroups_post_description = str_arg(args, "targetgroups_post_description") - body = assign_params(group_name=targetgroups_post_group_name, description=targetgroups_post_description) + body = assign_params( + values_to_ignore=(None,), group_name=targetgroups_post_group_name, description=targetgroups_post_description + ) response = self._http_request("post", "/targetgroups", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.add_target_group", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-target-group", response), + raw_response=response, + ) def get_target_group(self, args: Dict[str, Any]): group_id = str_arg(args, "group_id") @@ -1912,7 +2673,7 @@ def get_target_group(self, args: Dict[str, Any]): domain = str_arg(args, "domain") fields = str_arg(args, "fields") - params = assign_params(device=device, application=application, domain=domain, fields=fields) + params = assign_params(values_to_ignore=(None,), device=device, application=application, domain=domain, fields=fields) response = self._http_request("get", f"/targetgroups/{group_id}", params=params) return CommandResults( @@ -1929,8 +2690,10 @@ def edit_target_group(self, args: Dict[str, Any]): targetgroups_put_group_name = str_arg(args, "targetgroups_put_group_name") targetgroups_put_description = str_arg(args, "targetgroups_put_description") - params = assign_params(force=force) - body = assign_params(group_name=targetgroups_put_group_name, description=targetgroups_put_description) + params = assign_params(values_to_ignore=(None,), force=force) + body = assign_params( + values_to_ignore=(None,), group_name=targetgroups_put_group_name, description=targetgroups_put_description + ) response = self._http_request("put", f"/targetgroups/{group_id}", params=params, json_data=body) return CommandResults(readable_output="Success!", raw_response=response) @@ -1951,6 +2714,83 @@ def delete_target_from_group(self, args: Dict[str, Any]): return CommandResults(readable_output="Success!", raw_response=response) + def get_timeframes(self, args: Dict[str, Any]): + q = str_arg(args, "q") + sort = str_arg(args, "sort") + offset = int_arg(args, "offset") + limit = int_arg(args, "limit") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) + response = self._http_request("get", "/timeframes", params=params) + + return CommandResults( + outputs_prefix="WAB.timeframe_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-timeframes", response), + raw_response=response, + ) + + def add_timeframe(self, args: Dict[str, Any]): + timeframe_post_timeframe_name = str_arg(args, "timeframe_post_timeframe_name") + timeframe_post_description = str_arg(args, "timeframe_post_description") + timeframe_post_is_overtimable = bool_arg(args, "timeframe_post_is_overtimable") + + body = assign_params( + values_to_ignore=(None,), + timeframe_name=timeframe_post_timeframe_name, + description=timeframe_post_description, + is_overtimable=timeframe_post_is_overtimable, + ) + response = self._http_request("post", "/timeframes", json_data=body) + + return CommandResults( + outputs_prefix="WAB.add_timeframe", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-timeframe", response), + raw_response=response, + ) + + def get_timeframe(self, args: Dict[str, Any]): + timeframe_id = str_arg(args, "timeframe_id") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), fields=fields) + response = self._http_request("get", f"/timeframes/{timeframe_id}", params=params) + + return CommandResults( + outputs_prefix="WAB.timeframe_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-timeframe", response), + raw_response=response, + ) + + def edit_timeframe(self, args: Dict[str, Any]): + timeframe_id = str_arg(args, "timeframe_id") + timeframe_put_timeframe_name = str_arg(args, "timeframe_put_timeframe_name") + timeframe_put_description = str_arg(args, "timeframe_put_description") + timeframe_put_is_overtimable = bool_arg(args, "timeframe_put_is_overtimable") + + body = assign_params( + values_to_ignore=(None,), + timeframe_name=timeframe_put_timeframe_name, + description=timeframe_put_description, + is_overtimable=timeframe_put_is_overtimable, + ) + response = self._http_request("put", f"/timeframes/{timeframe_id}", json_data=body) + + return CommandResults(readable_output="Success!", raw_response=response) + + def delete_timeframe(self, args: Dict[str, Any]): + timeframe_id = str_arg(args, "timeframe_id") + + response = self._http_request("delete", f"/timeframes/{timeframe_id}") + + return CommandResults(readable_output="Success!", raw_response=response) + def get_user_groups(self, args: Dict[str, Any]): q = str_arg(args, "q") sort = str_arg(args, "sort") @@ -1958,7 +2798,7 @@ def get_user_groups(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", "/usergroups", params=params) return CommandResults( @@ -1973,7 +2813,7 @@ def get_user_group(self, args: Dict[str, Any]): group_id = str_arg(args, "group_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request("get", f"/usergroups/{group_id}", params=params) return CommandResults( @@ -1992,7 +2832,9 @@ def get_users(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(password_hash=password_hash, q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params( + values_to_ignore=(None,), password_hash=password_hash, q=q, sort=sort, offset=offset, limit=limit, fields=fields + ) response = self._http_request("get", "/users", params=params) return CommandResults( @@ -2017,13 +2859,14 @@ def add_user(self, args: Dict[str, Any]): user_post_force_change_pwd = bool_arg(args, "user_post_force_change_pwd") user_post_ssh_public_key = str_arg(args, "user_post_ssh_public_key") user_post_certificate_dn = str_arg(args, "user_post_certificate_dn") - user_post_last_connection = str_arg(args, "user_post_last_connection") + user_post_last_connection = str_arg(args, "user_post_last_connection", nullable=True) user_post_expiration_date = str_arg(args, "user_post_expiration_date") user_post_is_disabled = bool_arg(args, "user_post_is_disabled") user_post_gpg_public_key = str_arg(args, "user_post_gpg_public_key") - params = assign_params(password_hash=password_hash) + params = assign_params(values_to_ignore=(None,), password_hash=password_hash) body = assign_params( + values_to_ignore=(None,), user_name=user_post_user_name, display_name=user_post_display_name, email=user_post_email, @@ -2043,14 +2886,20 @@ def add_user(self, args: Dict[str, Any]): ) response = self._http_request("post", "/users", params=params, json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.add_user", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-user", response), + raw_response=response, + ) def get_user(self, args: Dict[str, Any]): name = str_arg(args, "name") password_hash = bool_arg(args, "password_hash") fields = str_arg(args, "fields") - params = assign_params(password_hash=password_hash, fields=fields) + params = assign_params(values_to_ignore=(None,), password_hash=password_hash, fields=fields) response = self._http_request("get", f"/users/{name}", params=params) return CommandResults( @@ -2061,6 +2910,111 @@ def get_user(self, args: Dict[str, Any]): raw_response=response, ) + def edit_user(self, args: Dict[str, Any]): + name = str_arg(args, "name") + force = bool_arg(args, "force") + password_hash = bool_arg(args, "password_hash") + user_put_user_name = str_arg(args, "user_put_user_name") + user_put_display_name = str_arg(args, "user_put_display_name") + user_put_email = str_arg(args, "user_put_email") + user_put_ip_source = str_arg(args, "user_put_ip_source") + user_put_preferred_language = str_arg(args, "user_put_preferred_language") + user_put_profile = str_arg(args, "user_put_profile") + user_put_groups = list_arg(args, "user_put_groups") + user_put_user_auths = list_arg(args, "user_put_user_auths") + user_put_password = str_arg(args, "user_put_password") + user_put_force_change_pwd = bool_arg(args, "user_put_force_change_pwd") + user_put_ssh_public_key = str_arg(args, "user_put_ssh_public_key") + user_put_certificate_dn = str_arg(args, "user_put_certificate_dn") + user_put_last_connection = str_arg(args, "user_put_last_connection", nullable=True) + user_put_expiration_date = str_arg(args, "user_put_expiration_date") + user_put_is_disabled = bool_arg(args, "user_put_is_disabled") + user_put_gpg_public_key = str_arg(args, "user_put_gpg_public_key") + + params = assign_params(values_to_ignore=(None,), force=force, password_hash=password_hash) + body = assign_params( + values_to_ignore=(None,), + user_name=user_put_user_name, + display_name=user_put_display_name, + email=user_put_email, + ip_source=user_put_ip_source, + preferred_language=user_put_preferred_language, + profile=user_put_profile, + groups=user_put_groups, + user_auths=user_put_user_auths, + password=user_put_password, + force_change_pwd=user_put_force_change_pwd, + ssh_public_key=user_put_ssh_public_key, + certificate_dn=user_put_certificate_dn, + last_connection=user_put_last_connection, + expiration_date=user_put_expiration_date, + is_disabled=user_put_is_disabled, + gpg_public_key=user_put_gpg_public_key, + ) + response = self._http_request("put", f"/users/{name}", params=params, json_data=body) + + return CommandResults(readable_output="Success!", raw_response=response) + + def get_target_group_restrictions(self, args: Dict[str, Any]): + group_id = str_arg(args, "group_id") + q = str_arg(args, "q") + sort = str_arg(args, "sort") + offset = int_arg(args, "offset") + limit = int_arg(args, "limit") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) + response = self._http_request("get", f"/targetgroups/{group_id}/restrictions", params=params) + + return CommandResults( + outputs_prefix="WAB.restriction_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-target-group-restrictions", response), + raw_response=response, + ) + + def get_target_group_restriction(self, args: Dict[str, Any]): + group_id = str_arg(args, "group_id") + restriction_id = str_arg(args, "restriction_id") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), fields=fields) + response = self._http_request("get", f"/targetgroups/{group_id}/restrictions/{restriction_id}", params=params) + + return CommandResults( + outputs_prefix="WAB.restriction_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-target-group-restriction", response), + raw_response=response, + ) + + def edit_restriction_from_targetgroup(self, args: Dict[str, Any]): + group_id = str_arg(args, "group_id") + restriction_id = str_arg(args, "restriction_id") + restriction_put_action = str_arg(args, "restriction_put_action") + restriction_put_rules = str_arg(args, "restriction_put_rules") + restriction_put_subprotocol = str_arg(args, "restriction_put_subprotocol") + + body = assign_params( + values_to_ignore=(None,), + action=restriction_put_action, + rules=restriction_put_rules, + subprotocol=restriction_put_subprotocol, + ) + response = self._http_request("put", f"/targetgroups/{group_id}/restrictions/{restriction_id}", json_data=body) + + return CommandResults(readable_output="Success!", raw_response=response) + + def delete_restriction_from_targetgroup(self, args: Dict[str, Any]): + group_id = str_arg(args, "group_id") + restriction_id = str_arg(args, "restriction_id") + + response = self._http_request("delete", f"/targetgroups/{group_id}/restrictions/{restriction_id}") + + return CommandResults(readable_output="Success!", raw_response=response) + def get_password_for_target(self, args: Dict[str, Any]): account_name = str_arg(args, "account_name") key_format = str_arg(args, "key_format") @@ -2068,7 +3022,13 @@ def get_password_for_target(self, args: Dict[str, Any]): authorization = str_arg(args, "authorization") duration = int_arg(args, "duration") - params = assign_params(key_format=key_format, cert_format=cert_format, authorization=authorization, duration=duration) + params = assign_params( + values_to_ignore=(None,), + key_format=key_format, + cert_format=cert_format, + authorization=authorization, + duration=duration, + ) response = self._http_request("get", f"/targetpasswords/checkout/{account_name}", params=params) add_key_to_outputs(response, "account_name", account_name) @@ -2085,7 +3045,7 @@ def extend_duration_time_to_get_passwords_for_target(self, args: Dict[str, Any]) account_name = str_arg(args, "account_name") authorization = str_arg(args, "authorization") - params = assign_params(authorization=authorization) + params = assign_params(values_to_ignore=(None,), authorization=authorization) response = self._http_request("get", f"/targetpasswords/extendcheckout/{account_name}", params=params) return CommandResults(readable_output="Success!", raw_response=response) @@ -2096,7 +3056,7 @@ def release_passwords_for_target(self, args: Dict[str, Any]): force = bool_arg(args, "force") comment = str_arg(args, "comment") - params = assign_params(authorization=authorization, force=force, comment=comment) + params = assign_params(values_to_ignore=(None,), authorization=authorization, force=force, comment=comment) response = self._http_request("get", f"/targetpasswords/checkin/{account_name}", params=params) return CommandResults(readable_output="Success!", raw_response=response) @@ -2111,7 +3071,9 @@ def get_target_by_type(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(group=group, group_id=group_id, q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params( + values_to_ignore=(None,), group=group, group_id=group_id, q=q, sort=sort, offset=offset, limit=limit, fields=fields + ) response = self._http_request("get", f"/targets/{target_type}", params=params) return CommandResults( @@ -2130,7 +3092,7 @@ def get_mappings_of_user_group(self, args: Dict[str, Any]): limit = int_arg(args, "limit") fields = str_arg(args, "fields") - params = assign_params(q=q, sort=sort, offset=offset, limit=limit, fields=fields) + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) response = self._http_request("get", f"/usergroups/{group_id}/mappings", params=params) return CommandResults( @@ -2148,20 +3110,27 @@ def add_mapping_in_group(self, args: Dict[str, Any]): usergroup_mapping_post_profile = str_arg(args, "usergroup_mapping_post_profile") body = assign_params( + values_to_ignore=(None,), domain=usergroup_mapping_post_domain, external_group=usergroup_mapping_post_external_group, profile=usergroup_mapping_post_profile, ) response = self._http_request("post", f"/usergroups/{group_id}/mappings", json_data=body) - return CommandResults(readable_output="Success!", raw_response=response) + return CommandResults( + outputs_prefix="WAB.add_mapping_in_group", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-mapping-in-group", response), + raw_response=response, + ) def get_mapping_of_user_group(self, args: Dict[str, Any]): group_id = str_arg(args, "group_id") mapping_id = str_arg(args, "mapping_id") fields = str_arg(args, "fields") - params = assign_params(fields=fields) + params = assign_params(values_to_ignore=(None,), fields=fields) response = self._http_request("get", f"/usergroups/{group_id}/mappings/{mapping_id}", params=params) return CommandResults( @@ -2180,6 +3149,7 @@ def edit_mapping_of_user_group(self, args: Dict[str, Any]): usergroup_mapping_post_profile = str_arg(args, "usergroup_mapping_post_profile") body = assign_params( + values_to_ignore=(None,), domain=usergroup_mapping_post_domain, external_group=usergroup_mapping_post_external_group, profile=usergroup_mapping_post_profile, @@ -2196,6 +3166,99 @@ def delete_mapping_of_user_group(self, args: Dict[str, Any]): return CommandResults(readable_output="Success!", raw_response=response) + def get_user_group_restrictions(self, args: Dict[str, Any]): + group_id = str_arg(args, "group_id") + q = str_arg(args, "q") + sort = str_arg(args, "sort") + offset = int_arg(args, "offset") + limit = int_arg(args, "limit") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), q=q, sort=sort, offset=offset, limit=limit, fields=fields) + response = self._http_request("get", f"/usergroups/{group_id}/restrictions", params=params) + + return CommandResults( + outputs_prefix="WAB.restriction_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-user-group-restrictions", response), + raw_response=response, + ) + + def add_restriction_to_usergroup(self, args: Dict[str, Any]): + group_id = str_arg(args, "group_id") + restriction_post_action = str_arg(args, "restriction_post_action") + restriction_post_rules = str_arg(args, "restriction_post_rules") + restriction_post_subprotocol = str_arg(args, "restriction_post_subprotocol") + + body = assign_params( + values_to_ignore=(None,), + action=restriction_post_action, + rules=restriction_post_rules, + subprotocol=restriction_post_subprotocol, + ) + response = self._http_request("post", f"/usergroups/{group_id}/restrictions", json_data=body) + + return CommandResults( + outputs_prefix="WAB.add_restriction_to_usergroup", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-add-restriction-to-usergroup", response), + raw_response=response, + ) + + def get_user_group_restriction(self, args: Dict[str, Any]): + group_id = str_arg(args, "group_id") + restriction_id = str_arg(args, "restriction_id") + fields = str_arg(args, "fields") + + params = assign_params(values_to_ignore=(None,), fields=fields) + response = self._http_request("get", f"/usergroups/{group_id}/restrictions/{restriction_id}", params=params) + + return CommandResults( + outputs_prefix="WAB.restriction_get", + outputs_key_field="id", + outputs=response, + readable_output=to_markdown("wab-get-user-group-restriction", response), + raw_response=response, + ) + + def edit_restriction_from_usergroup(self, args: Dict[str, Any]): + group_id = str_arg(args, "group_id") + restriction_id = str_arg(args, "restriction_id") + restriction_put_action = str_arg(args, "restriction_put_action") + restriction_put_rules = str_arg(args, "restriction_put_rules") + restriction_put_subprotocol = str_arg(args, "restriction_put_subprotocol") + + body = assign_params( + values_to_ignore=(None,), + action=restriction_put_action, + rules=restriction_put_rules, + subprotocol=restriction_put_subprotocol, + ) + response = self._http_request("put", f"/usergroups/{group_id}/restrictions/{restriction_id}", json_data=body) + + return CommandResults(readable_output="Success!", raw_response=response) + + def delete_restriction_from_usergroup(self, args: Dict[str, Any]): + group_id = str_arg(args, "group_id") + restriction_id = str_arg(args, "restriction_id") + + response = self._http_request("delete", f"/usergroups/{group_id}/restrictions/{restriction_id}") + + return CommandResults(readable_output="Success!", raw_response=response) + + def get_version(self, args: Dict[str, Any]): + + response = self._http_request("get", "/version") + + return CommandResults( + outputs_prefix="WAB.version_get", + outputs=response, + readable_output=to_markdown("wab-get-version", response), + raw_response=response, + ) + def test_module(client: Client): """ @@ -2298,12 +3361,14 @@ def main() -> None: timeout, ) - commands = { + commands: Dict[str, Any] = { "wab-add-session-target-to-target-group": client.add_session_target_to_target_group, "wab-add-password-target-to-target-group": client.add_password_target_to_target_group, "wab-add-restriction-to-target-group": client.add_restriction_to_target_group, + "wab-add-timeframe-period": client.add_timeframe_period, "wab-get-account-references": client.get_account_references, "wab-get-account-reference": client.get_account_reference, + "wab-change-password-or-ssh-key-of-account": client.change_password_or_ssh_key_of_account, "wab-get-all-accounts": client.get_all_accounts, "wab-get-one-account": client.get_one_account, "wab-delete-account": client.delete_account, @@ -2312,6 +3377,8 @@ def main() -> None: "wab-get-application-account": client.get_application_account, "wab-edit-account-on-local-domain-of-application": client.edit_account_on_local_domain_of_application, "wab-delete-account-from-local-domain-of-application": client.delete_account_from_local_domain_of_application, + "wab-get-local-domains-data-for-application": client.get_local_domains_data_for_application, + "wab-get-local-domain-data-for-application": client.get_local_domain_data_for_application, "wab-get-applications": client.get_applications, "wab-get-application": client.get_application, "wab-edit-application": client.edit_application, @@ -2327,6 +3394,12 @@ def main() -> None: "wab-cancel-approval-request": client.cancel_approval_request, "wab-notify-approvers-linked-to-approval-request": client.notify_approvers_linked_to_approval_request, "wab-check-if-approval-is-required-for-target": client.check_if_approval_is_required_for_target, + "wab-get-mappings-of-domain": client.get_mappings_of_domain, + "wab-add-mapping-in-domain": client.add_mapping_in_domain, + "wab-edit-mappings-of-domain": client.edit_mappings_of_domain, + "wab-get-mapping-of-domain": client.get_mapping_of_domain, + "wab-edit-mapping-of-domain": client.edit_mapping_of_domain, + "wab-delete-mapping-of-domain": client.delete_mapping_of_domain, "wab-get-auth-domains": client.get_auth_domains, "wab-get-auth-domain": client.get_auth_domain, "wab-get-authentications": client.get_authentications, @@ -2338,11 +3411,18 @@ def main() -> None: "wab-delete-authorization": client.delete_authorization, "wab-get-checkout-policies": client.get_checkout_policies, "wab-get-checkout-policy": client.get_checkout_policy, + "wab-get-clusters": client.get_clusters, + "wab-get-cluster": client.get_cluster, "wab-getx509-configuration-infos": client.getx509_configuration_infos, "wab-uploadx509-configuration": client.uploadx509_configuration, "wab-updatex509-configuration": client.updatex509_configuration, "wab-resetx509-configuration": client.resetx509_configuration, "wab-get-current-serial-configuration-number-of-bastion": client.get_current_serial_configuration_number_of_bastion, + "wab-get-connection-policies": client.get_connection_policies, + "wab-add-connection-policy": client.add_connection_policy, + "wab-get-connection-policy": client.get_connection_policy, + "wab-edit-connection-policy": client.edit_connection_policy, + "wab-delete-connection-policy": client.delete_connection_policy, "wab-get-all-accounts-on-device-local-domain": client.get_all_accounts_on_device_local_domain, "wab-add-account-to-local-domain-on-device": client.add_account_to_local_domain_on_device, "wab-get-one-account-on-device-local-domain": client.get_one_account_on_device_local_domain, @@ -2351,6 +3431,8 @@ def main() -> None: "wab-get-certificates-on-device": client.get_certificates_on_device, "wab-get-certificate-on-device": client.get_certificate_on_device, "wab-revoke-certificate-of-device": client.revoke_certificate_of_device, + "wab-get-local-domains-of-device": client.get_local_domains_of_device, + "wab-get-local-domain-of-device": client.get_local_domain_of_device, "wab-get-services-of-device": client.get_services_of_device, "wab-add-service-in-device": client.add_service_in_device, "wab-get-service-of-device": client.get_service_of_device, @@ -2369,6 +3451,7 @@ def main() -> None: "wab-delete-resource-from-global-domain-account": client.delete_resource_from_global_domain_account, "wab-get-global-domains": client.get_global_domains, "wab-get-global-domain": client.get_global_domain, + "wab-get-external-authentication-group-mappings": client.get_external_authentication_group_mappings, "wab-get-ldap-users-of-domain": client.get_ldap_users_of_domain, "wab-get-ldap-user-of-domain": client.get_ldap_user_of_domain, "wab-get-information-about-wallix-bastion-license": client.get_information_about_wallix_bastion_license, @@ -2379,6 +3462,13 @@ def main() -> None: "wab-edit-notification": client.edit_notification, "wab-delete-notification": client.delete_notification, "wab-get-object-to-onboard": client.get_object_to_onboard, + "wab-get-password-change-policies": client.get_password_change_policies, + "wab-add-password-change-policy": client.add_password_change_policy, + "wab-get-password-change-policy": client.get_password_change_policy, + "wab-edit-password-change-policy": client.edit_password_change_policy, + "wab-delete-password-change-policy": client.delete_password_change_policy, + "wab-get-passwordrights": client.get_passwordrights, + "wab-get-passwordrights-user-name": client.get_passwordrights_user_name, "wab-get-profiles": client.get_profiles, "wab-get-profile": client.get_profile, "wab-get-scanjobs": client.get_scanjobs, @@ -2387,6 +3477,8 @@ def main() -> None: "wab-cancel-scan-job": client.cancel_scan_job, "wab-get-scans": client.get_scans, "wab-get-scan": client.get_scan, + "wab-edit-scan": client.edit_scan, + "wab-delete-scan": client.delete_scan, "wab-get-sessionrights": client.get_sessionrights, "wab-get-sessionrights-user-name": client.get_sessionrights_user_name, "wab-get-sessions": client.get_sessions, @@ -2405,11 +3497,21 @@ def main() -> None: "wab-edit-target-group": client.edit_target_group, "wab-delete-target-group": client.delete_target_group, "wab-delete-target-from-group": client.delete_target_from_group, + "wab-get-timeframes": client.get_timeframes, + "wab-add-timeframe": client.add_timeframe, + "wab-get-timeframe": client.get_timeframe, + "wab-edit-timeframe": client.edit_timeframe, + "wab-delete-timeframe": client.delete_timeframe, "wab-get-user-groups": client.get_user_groups, "wab-get-user-group": client.get_user_group, "wab-get-users": client.get_users, "wab-add-user": client.add_user, "wab-get-user": client.get_user, + "wab-edit-user": client.edit_user, + "wab-get-target-group-restrictions": client.get_target_group_restrictions, + "wab-get-target-group-restriction": client.get_target_group_restriction, + "wab-edit-restriction-from-targetgroup": client.edit_restriction_from_targetgroup, + "wab-delete-restriction-from-targetgroup": client.delete_restriction_from_targetgroup, "wab-get-password-for-target": client.get_password_for_target, "wab-extend-duration-time-to-get-passwords-for-target": client.extend_duration_time_to_get_passwords_for_target, "wab-release-passwords-for-target": client.release_passwords_for_target, @@ -2419,19 +3521,18 @@ def main() -> None: "wab-get-mapping-of-user-group": client.get_mapping_of_user_group, "wab-edit-mapping-of-user-group": client.edit_mapping_of_user_group, "wab-delete-mapping-of-user-group": client.delete_mapping_of_user_group, - } - - deprecated = { - "wab-get-metadata-of-one-or-multiple-sessions": client.get_session_metadata, + "wab-get-user-group-restrictions": client.get_user_group_restrictions, + "wab-add-restriction-to-usergroup": client.add_restriction_to_usergroup, + "wab-get-user-group-restriction": client.get_user_group_restriction, + "wab-edit-restriction-from-usergroup": client.edit_restriction_from_usergroup, + "wab-delete-restriction-from-usergroup": client.delete_restriction_from_usergroup, + "wab-get-version": client.get_version, } if command == "test-module": test_module(client) elif command in commands: return_results(commands[command](args)) - elif command in deprecated: - LOG(f"WARNING: use of deprecated command {command}") - return_results(deprecated[command](args)) else: raise NotImplementedError(f"{command} command is not implemented.") diff --git a/Packs/WALLIXBastion/Integrations/WAB/WAB.yml b/Packs/WALLIXBastion/Integrations/WAB/WAB.yml index bf5e04243123..c1400ad5be19 100644 --- a/Packs/WALLIXBastion/Integrations/WAB/WAB.yml +++ b/Packs/WALLIXBastion/Integrations/WAB/WAB.yml @@ -25,7 +25,7 @@ configuration: type: 4 required: false - name: is_password - display: Password authentication mode (false if you provided an API key) + display: Password authentication mode (set false if you provided an API key) defaultvalue: "false" type: 8 required: false @@ -53,7 +53,7 @@ script: script: "" type: python subtype: python3 - dockerimage: demisto/python3:3.11.10.111039 + dockerimage: demisto/python3:3.11.10.113941 commands: - name: wab-add-session-target-to-target-group description: Add a target account to a target group. @@ -61,99 +61,108 @@ script: - name: group_id description: The group id or name to edit. required: true - isArray: false - name: account description: The account name. required: true - isArray: false - name: domain description: 'The domain name (for an account or scenario account).' - required: false - isArray: false - name: domain_type description: 'The domain type: local or global (for an account or scenario account).' - required: false - isArray: false - name: device description: The device name (null for an application). - required: false - isArray: false - name: service description: The service name (null for an application). - required: false - isArray: false - name: application description: The application name (null for a device). - required: false - isArray: false - name: session_account_type description: '''account'', ''account_mapping'', ''interactive_login'' or ''scenario_account''.' required: true - isArray: false - name: wab-add-password-target-to-target-group description: Add a password checkout account to a target group. arguments: - name: group_id description: The group id or name to edit. required: true - isArray: false - name: account description: The account name. required: true - isArray: false - name: domain description: The domain name. required: true - isArray: false - name: domain_type description: 'The domain type: local or global.' required: true - isArray: false - name: device description: The device name (null for an application). - required: false - isArray: false - name: application description: The application name (null for a device). - required: false - isArray: false - name: wab-add-restriction-to-target-group - description: Add a restriction to a target group. + description: 'Add a restriction in a targetgroup + + category: Target Group Restrictions.' arguments: - name: group_id - description: The group id or name to edit. + description: A target group id or name. required: true - isArray: false - name: action - description: 'the restriction type: ''kill'' or ''notify''.' + description: 'The restriction type.' required: true - isArray: false + auto: PREDEFINED + predefined: + - kill + - notify - name: rules description: the restriction rules. required: true - isArray: false - name: subprotocol - description: 'the restriction subprotocol: SSH_SHELL_SESSION, SSH_REMOTE_COMMAND, SSH_SCP_UP, SSH_SCP_DOWN, SFTP_SESSION, RLOGIN, TELNET, RDP.' - required: true - isArray: false - - name: wab-get-metadata-of-one-or-multiple-sessions - description: Deprecated. Use wab-get-session-metadata instead. - arguments: - - name: session_ids - description: "The session id, multiple IDs can be se ted by commas." - required: true - - name: download - description: The default value is false. When it is set to true, the session metadata is sent as a file instead of JSON (recommended for large metadata). The download is possible only with a single session id. - deprecated: true + description: 'The restriction subprotocol.' + required: true + auto: PREDEFINED + predefined: + - SSH_SHELL_SESSION + - SSH_REMOTE_COMMAND + - SSH_SCP_UP + - SSH_SCP_DOWN + - SFTP_SESSION + - RLOGIN + - TELNET + - RDP outputs: - type: String - contextPath: WAB.session_metadata_get.metadata - description: The session metadata content. - - type: String - contextPath: WAB.session_metadata_get.session_id - description: The session id. + contextPath: WAB.add_restriction_in_targetgroup.id + description: id of the created object. + - name: wab-add-timeframe-period + description: 'Add a period to a timeframe + + category: Timeframes.' + arguments: + - name: timeframe_id + description: "The timeframe id or name to edit." + required: true + - name: start_date + description: The period start date. Must respect the format "yyyy-mm-dd". + required: true + - name: end_date + description: The period end date. Must respect the format "yyyy-mm-dd". + required: true + - name: start_time + description: The period start time. Must respect the format "hh:mm". + required: true + - name: end_time + description: The period end time. Must respect the format "hh:mm". + required: true + - name: week_days + description: 'The period week days. + + Comma-separated list (use [] for an empty list). + + Possible values: monday,tuesday,wednesday,thursday,friday,saturday,sunday.' + required: true + isArray: true - name: wab-get-account-references - description: Get account references. + description: 'Get account references + + category: Account References.' arguments: - name: account_id description: The referenced account id or name. @@ -200,7 +209,9 @@ script: contextPath: WAB.account_reference_get.devices.error_description description: The description of the error, of null if the status is not "error". - name: wab-get-account-reference - description: Get account reference. + description: 'Get account reference + + category: Account References.' arguments: - name: account_id description: The referenced account id or name. @@ -241,17 +252,44 @@ script: - type: String contextPath: WAB.account_reference_get.devices.error_description description: The description of the error, of null if the status is not "error". + - name: wab-change-password-or-ssh-key-of-account + description: 'Change password or SSH key of an account and propagate changes on the target host. If the body is empty, an automatic password change is performed: the password or the SSH key are changed to a newly generated value, according to the password change policy on the domain. Note: the password change must be enabled on the domain, with a plugin that will be used to change the password on the target host + + category: Account Change Password.' + arguments: + - name: account_id + description: 'The account id.' + required: true + - name: credential_type + description: '''password'' to change the password or ''ssh_key'' to change the SSH key.' + required: true + auto: PREDEFINED + predefined: + - password + - ssh_key + - name: changePasswordOrSshKeyOfAccount_password + description: The new password. + - name: changePasswordOrSshKeyOfAccount_private_key + description: 'The new SSH private key.' + - name: changePasswordOrSshKeyOfAccount_passphrase + description: 'The passphrase for the SSH private key (only for an encrypted private key). If provided, it must be between 4 and 1024 characters long.' - name: wab-get-all-accounts - description: Get all accounts. + description: 'Get all accounts + + category: Accounts.' arguments: - name: account_type description: 'The account type: "global" for only global domain accounts, "device" for only device accounts, "application" for only application accounts. By default accounts of any type are returned. Cannot be used if an account_name and/or device/application is specified.' - name: application - description: The name of the application whose accounts must be returned. Cannot be used if an account_name and/or an account_type/device is specified. + description: 'The name of the application whose accounts must be returned. Cannot be used if an account_name and/or an account_type/device is specified.' - name: device description: The name of the device whose accounts must be returned. Cannot be used if an account_name and/or an application is specified. - name: passwords description: 'Return credentials (passwords and SSH keys) as-is without replacing content by stars. Note: this requires the Password Manager license, the flag "Credential recovery" in the profile of the user logged on the API and the "Credential recovery" option must be enabled in REST API configuration.' + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: key_format description: 'Format of the returned SSH public key of the account. Accepted values are ''openssh'' (default value) and ''ssh.com''.' - name: q @@ -383,7 +421,9 @@ script: contextPath: WAB.account_get.url description: The API URL to the resource. - name: wab-get-one-account - description: "Get one account." + description: 'Get one account + + category: Accounts.' arguments: - name: account_id description: 'An account id or complete name with account name, domain name and device/application name, for example: "Administrator@local@win10".' @@ -396,6 +436,10 @@ script: description: The name of the device whose accounts must be returned. Cannot be used if an account_name and/or an application is specified. - name: passwords description: 'Return credentials (passwords and SSH keys) as-is without replacing content by stars. Note: this requires the Password Manager license, the flag "Credential recovery" in the profile of the user logged on the API and the "Credential recovery" option must be enabled in REST API configuration.' + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: key_format description: Format of the returned SSH public key of the account. Accepted values are 'openssh' (default value) and 'ssh.com'. - name: fields @@ -519,13 +563,17 @@ script: contextPath: WAB.account_get.url description: The API URL to the resource. - name: wab-delete-account - description: Delete an account. + description: 'Delete an account + + category: Accounts.' arguments: - name: account_id description: 'An account id or complete name with account name, domain name and device/application name, for example: "Administrator@local@win10".' required: true - name: wab-get-application-accounts - description: Get the application accounts. + description: 'Get the application accounts + + category: Application Accounts.' arguments: - name: application_id description: The application id or name. @@ -623,7 +671,9 @@ script: contextPath: WAB.app_account_get.url description: The API URL to the resource. - name: wab-add-account-to-local-domain-of-application - description: Add an account to a local domain of an application. + description: 'Add an account to a local domain of an application + + category: Application Accounts.' arguments: - name: application_id description: The application id or name. @@ -641,6 +691,10 @@ script: description: The account description. - name: app_account_post_auto_change_password description: Automatically change the password. It is enabled by default on a new account. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: app_account_post_checkout_policy description: The account checkout policy. required: true @@ -648,11 +702,21 @@ script: description: The validity duration of the signed ssh public key in the case a Certificate Authority is defined for the account's domain. - name: app_account_post_can_edit_certificate_validity description: True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. + auto: PREDEFINED + predefined: + - 'true' + - 'false' + outputs: + - type: String + contextPath: WAB.add_account_to_local_domain_of_application.id + description: id of the created object. - name: wab-get-application-account - description: Get the application account. + description: 'Get the application account + + category: Application Accounts.' arguments: - name: application_id - description: The application id or name. + description: 'The application id or name.' required: true - name: domain_id description: The local domain id or name. @@ -742,10 +806,12 @@ script: contextPath: WAB.app_account_get.url description: The API URL to the resource. - name: wab-edit-account-on-local-domain-of-application - description: Edit an account on a local domain of an application. + description: 'Edit an account on a local domain of an application + + category: Application Accounts.' arguments: - name: application_id - description: 'The application id or name.' + description: The application id or name. required: true - name: domain_id description: The local domain id or name. @@ -755,6 +821,10 @@ script: required: true - name: force description: The default value is false. When it is set to true the values of the credentials and services, if they are supplied, are replaced, otherwise the values are added to the existing ones. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: app_account_put_account_name description: The account name. /:*?"<>|@ and space are forbidden. - name: app_account_put_account_login @@ -763,28 +833,139 @@ script: description: The account description. - name: app_account_put_auto_change_password description: Automatically change the password. It is enabled by default on a new account. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: app_account_put_checkout_policy description: The account checkout policy. - name: app_account_put_certificate_validity description: The validity duration of the signed ssh public key in the case a Certificate Authority is defined for the account's domain. - name: app_account_put_can_edit_certificate_validity description: True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: app_account_put_onboard_status description: Onboarding status of the account. + auto: PREDEFINED + predefined: + - onboarded + - to_onboard + - hide + - manual - name: wab-delete-account-from-local-domain-of-application - description: Delete an account from a local domain of an application. + description: 'Delete an account from a local domain of an application + + category: Application Accounts.' arguments: - name: application_id description: The application id or name. required: true - name: domain_id - description: The local domain id or name. + description: 'The local domain id or name.' required: true - name: account_id description: The account id or name to delete. required: true + - name: wab-get-local-domains-data-for-application + description: 'Get local domains data for a given application + + category: Application Local Domains.' + arguments: + - name: application_id + description: The application id or name. + required: true + - name: q + description: Searches for a resource matching parameters. + - name: sort + description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''domain_name''.' + - name: offset + description: The index of first item to retrieve (starts and defaults to 0). + - name: limit + description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.localdomain_app_get.id + description: The domain id. Usable in the "q" parameter. + - type: String + contextPath: WAB.localdomain_app_get.domain_name + description: The domain name. /:*?"<>|@ are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.localdomain_app_get.description + description: The domain description. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Boolean + contextPath: WAB.localdomain_app_get.enable_password_change + description: Enable the change of password on this domain. + - type: String + contextPath: WAB.localdomain_app_get.admin_account + description: 'The administrator account used to change passwords on this domain (format: "account_name").' + - type: String + contextPath: WAB.localdomain_app_get.password_change_policy + description: The name of password change policy for this domain. + - type: String + contextPath: WAB.localdomain_app_get.password_change_plugin + description: The name of plugin used to change passwords on this domain. + - type: String + contextPath: WAB.localdomain_app_get.ca_private_key + description: 'The ssh private key of the signing authority for the ssh keys for accounts in the domain. Special values are allowed to automatically generate SSH key: "generate:RSA_1024", "generate:RSA_2048", "generate:RSA_4096", "generate:RSA_8192", "generate:DSA_1024", "generate:ECDSA_256", "generate:ECDSA_384", "generate:ECDSA_521", "generate:ED25519".' + - type: String + contextPath: WAB.localdomain_app_get.ca_public_key + description: The ssh public key of the signing authority for the ssh keys for accounts in the domain. + - type: String + contextPath: WAB.localdomain_app_get.url + description: The API URL to the resource. + - name: wab-get-local-domain-data-for-application + description: 'Get local domain data for a given application + + category: Application Local Domains.' + arguments: + - name: application_id + description: The application id or name. + required: true + - name: domain_id + description: The local domain id or name. + required: true + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.localdomain_app_get.id + description: The domain id. Usable in the "q" parameter. + - type: String + contextPath: WAB.localdomain_app_get.domain_name + description: The domain name. /:*?"<>|@ are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.localdomain_app_get.description + description: The domain description. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Boolean + contextPath: WAB.localdomain_app_get.enable_password_change + description: Enable the change of password on this domain. + - type: String + contextPath: WAB.localdomain_app_get.admin_account + description: 'The administrator account used to change passwords on this domain (format: "account_name").' + - type: String + contextPath: WAB.localdomain_app_get.password_change_policy + description: The name of password change policy for this domain. + - type: String + contextPath: WAB.localdomain_app_get.password_change_plugin + description: The name of plugin used to change passwords on this domain. + - type: String + contextPath: WAB.localdomain_app_get.ca_private_key + description: 'The ssh private key of the signing authority for the ssh keys for accounts in the domain. Special values are allowed to automatically generate SSH key: "generate:RSA_1024", "generate:RSA_2048", "generate:RSA_4096", "generate:RSA_8192", "generate:DSA_1024", "generate:ECDSA_256", "generate:ECDSA_384", "generate:ECDSA_521", "generate:ED25519".' + - type: String + contextPath: WAB.localdomain_app_get.ca_public_key + description: The ssh public key of the signing authority for the ssh keys for accounts in the domain. + - type: String + contextPath: WAB.localdomain_app_get.url + description: The API URL to the resource. - name: wab-get-applications - description: Get the applications. + description: 'Get the applications + + category: Applications.' arguments: - name: q description: Searches for a resource matching parameters. @@ -845,9 +1026,6 @@ script: - type: String contextPath: WAB.application_get.local_domains.url description: The API URL to the resource. - - type: String - contextPath: WAB.application_get.tags.id - description: The tag id. - type: String contextPath: WAB.application_get.tags.key description: The tag key. Must not start or end with a space. @@ -861,7 +1039,9 @@ script: contextPath: WAB.application_get.url description: The API URL to the resource. - name: wab-get-application - description: Get the application. + description: 'Get the application + + category: Applications.' arguments: - name: application_id description: An application id or name. If specified, only this application is returned. @@ -877,16 +1057,16 @@ script: description: The application name. \/:*?"<>| and space are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.application_get.description - description: The application description. Usable in the "q" parameter. Usable in the "sort" parameter. + description: 'The application description. Usable in the "q" parameter. Usable in the "sort" parameter.' - type: String contextPath: WAB.application_get.category - description: The application category. Usable in the "q" parameter. Usable in the "sort" parameter. + description: 'The application category. Usable in the "q" parameter. Usable in the "sort" parameter.' - type: String contextPath: WAB.application_get.last_connection description: 'The last connection on this application (format: "yyyy-mm-dd hh:mm:ss"). Usable in the "q" parameter. Usable in the "sort" parameter.' - type: String contextPath: WAB.application_get.parameters - description: The application parameters. Usable in the "q" parameter. Usable in the "sort" parameter. + description: 'The application parameters. Usable in the "q" parameter. Usable in the "sort" parameter.' - type: String contextPath: WAB.application_get.local_domains.id description: The domain id. Usable in the "q" parameter. @@ -913,19 +1093,16 @@ script: description: 'The ssh private key of the signing authority for the ssh keys for accounts in the domain. Special values are allowed to automatically generate SSH key: "generate:RSA_1024", "generate:RSA_2048", "generate:RSA_4096", "generate:RSA_8192", "generate:DSA_1024", "generate:ECDSA_256", "generate:ECDSA_384", "generate:ECDSA_521", "generate:ED25519".' - type: String contextPath: WAB.application_get.local_domains.ca_public_key - description: The ssh public key of the signing authority for the ssh keys for accounts in the domain. + description: 'The ssh public key of the signing authority for the ssh keys for accounts in the domain.' - type: String contextPath: WAB.application_get.local_domains.url description: The API URL to the resource. - - type: String - contextPath: WAB.application_get.tags.id - description: The tag id. - type: String contextPath: WAB.application_get.tags.key description: The tag key. Must not start or end with a space. - type: String contextPath: WAB.application_get.tags.value - description: The tag value. Must not start or end with a space. + description: 'The tag value. Must not start or end with a space.' - type: String contextPath: WAB.application_get.connection_policy description: The connection policy name. Usable in the "q" parameter. @@ -933,31 +1110,44 @@ script: contextPath: WAB.application_get.url description: The API URL to the resource. - name: wab-edit-application - description: Edit an application. + description: 'Edit an application + + category: Applications.' arguments: - name: application_id description: The application id or name to edit. required: true - name: force - description: The default value is false. When it is set to true the values of the global_domains and tags are replaced, otherwise the values are added to the existing ones. + description: 'The default value is false. When it is set to true the values of the global_domains and tags are replaced, otherwise the values are added to the existing ones.' + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: application_put_application_name description: The application name. \/:*?"<>| and space are forbidden. - name: application_put_description - description: The application description. + description: 'The application description.' - name: application_put_parameters description: The application parameters. + - name: application_put_global_domains + description: 'The global domains names. + + Comma-separated list (use [] for an empty list).' + isArray: true - name: application_put_connection_policy description: The connection policy name. - - name: application_put__meters - description: 'deprecated: use application_put_parameters instead.' - name: wab-delete-application - description: Delete an application. + description: 'Delete an application + + category: Applications.' arguments: - name: application_id description: The application id or name to delete. required: true - name: wab-get-approvals - description: Get the approvals. + description: 'Get the approvals + + category: Approvals.' arguments: - name: approval_id description: An approval id. If specified, only this approval is returned. @@ -1051,7 +1241,9 @@ script: contextPath: WAB.approval_get.url description: The API URL to the resource. - name: wab-get-approvals-for-all-approvers - description: Get the approvals for a given approver. + description: 'Get the approvals for a given approver + + category: Approvals Assignments.' arguments: - name: q description: Searches for a resource matching parameters. @@ -1143,7 +1335,9 @@ script: contextPath: WAB.approval_get.url description: The API URL to the resource. - name: wab-reply-to-approval-request - description: 'Reply to an approval request (approve/reject it). Note: you can answer to an approval request only if you are in approvers groups of authorization.' + description: 'Reply to an approval request (approve/reject it). Note: you can answer to an approval request only if you are in approvers groups of authorization + + category: Approvals Assignments.' arguments: - name: approval_assignment_post_id description: The approval id. @@ -1158,15 +1352,37 @@ script: - name: approval_assignment_post_approved description: Approve/reject the request. required: true + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: approval_assignment_post_is_active description: The approval is active. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: approval_assignment_post_status description: The approval status. + auto: PREDEFINED + predefined: + - accepted + - cancelled + - closed + - none + - pending + - rejected + outputs: + - type: String + contextPath: WAB.reply_to_approval_request.id + description: id of the created object. - name: wab-get-approvals-for-approver - description: Get the approvals for a given approver. + description: 'Get the approvals for a given approver + + category: Approvals Assignments.' arguments: - name: user_name - description: The name of a user (approver). + description: 'The name of a user (approver).' required: true - name: q description: Searches for a resource matching parameters. @@ -1177,7 +1393,7 @@ script: - name: limit description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' - name: fields - description: The list of fields to return (separated by commas). By default all fields are returned. + description: 'The list of fields to return (separated by commas). By default all fields are returned.' outputs: - type: String contextPath: WAB.approval_get.id @@ -1258,16 +1474,24 @@ script: contextPath: WAB.approval_get.url description: The API URL to the resource. - name: wab-cancel-accepted-approval - description: 'Cancel an accepted approval. Note: you can cancel an approval only if you are in approvers groups of authorization and the end date is still not reached.' + description: 'Cancel an accepted approval. Note: you can cancel an approval only if you are in approvers groups of authorization and the end date is still not reached + + category: Approvals Assignments.' arguments: - name: approval_assignment_cancel_post_id - description: The approval id. + description: 'The approval id.' required: true - name: approval_assignment_cancel_post_comment description: The cancel comment. required: true + outputs: + - type: String + contextPath: WAB.cancel_accepted_approval.id + description: id of the created object. - name: wab-notify-approvers-linked-to-approval-assignment - description: Notify approvers linked to an approval request by sending them an email. + description: 'Notify approvers linked to an approval request by sending them an email + + category: Approvals Assignments.' arguments: - name: approval_assignment_notify_post_id description: The approval id. @@ -1280,10 +1504,12 @@ script: contextPath: WAB.approval_assignment_notify_post_response.approval_assignment_notify_post_id description: the approval_assignment_notify_post_id. - name: wab-get-approval-request-pending-for-user - description: 'Get the approval request pending for this user (by default the user logged on the REST API), or the approval request with the given id.' + description: 'Get the approval request pending for this user (by default the user logged on the REST API), or the approval request with the given id + + category: Approvals Requests.' arguments: - name: user - description: '(1st option) The name of a user (by default the user logged on the REST API).' + description: (1st option) The name of a user (by default the user logged on the REST API). - name: q description: (1st option) Searches for a resource matching parameters. - name: sort @@ -1293,13 +1519,13 @@ script: - name: limit description: '(1st option) The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' - name: fields - description: 'The list of fields to return (separated by commas). By default all fields are returned.' + description: The list of fields to return (separated by commas). By default all fields are returned. - name: approval_id description: (2nd option) The approval request id (the 'id' returned when the approval was created). outputs: - type: String contextPath: WAB.approval_get.id - description: The approval id. Usable in the "q" parameter. Usable in the "sort" parameter. + description: 'The approval id. Usable in the "q" parameter. Usable in the "sort" parameter.' - type: String contextPath: WAB.approval_get.user_name description: The user name. Usable in the "q" parameter. Usable in the "sort" parameter. @@ -1376,13 +1602,15 @@ script: contextPath: WAB.approval_get.url description: The API URL to the resource. - name: wab-make-new-approval-request-to-access-target - description: 'Make a new approval request to access a target. Note: depending on the authorization settings, the fields "ticket" and "comment" may be required.' + description: 'Make a new approval request to access a target. Note: depending on the authorization settings, the fields "ticket" and "comment" may be required + + category: Approvals Requests.' arguments: - name: approval_request_post_target_name description: 'The target name (example: account@domain@device:service).' required: true - name: approval_request_post_authorization - description: The authorization name. + description: 'The authorization name.' - name: approval_request_post_account description: The account name. - name: approval_request_post_domain @@ -1405,51 +1633,192 @@ script: outputs: - type: String contextPath: WAB.approval_request_post_response_ok.id - description: The new approval id. + description: 'The new approval id.' - name: wab-cancel-approval-request - description: Cancel an approval request. + description: 'Cancel an approval request + + category: Approvals Requests.' arguments: - name: approval_request_cancel_post_id description: The approval id. required: true + outputs: + - type: String + contextPath: WAB.cancel_approval_request.id + description: id of the created object. - name: wab-notify-approvers-linked-to-approval-request - description: Notify approvers linked to an approval request by sending them an email. + description: 'Notify approvers linked to an approval request by sending them an email + + category: Approvals Requests.' arguments: - name: approval_request_notify_post_id - description: The approval id. + description: 'The approval id.' required: true outputs: - type: Number contextPath: WAB.approval_request_notify_post_response.emails_count - description: 'Number of e-mails sent to approvers.' + description: Number of e-mails sent to approvers. - type: String contextPath: WAB.approval_request_notify_post_response.approval_request_notify_post_id - description: the approval_request_notify_post_id. + description: 'the approval_request_notify_post_id.' - name: wab-check-if-approval-is-required-for-target - description: Check if an approval is required for this target (optionally for a given date in future). + description: 'Check if an approval is required for this target (optionally for a given date in future) + + category: Approvals Requests Target.' arguments: - name: target_name - description: The target name (for example 'account@domain@device:service'). + description: 'The target name (for example ''account@domain@device:service'').' required: true - name: authorization description: 'The name of the authorization (in case of multiple authorizations to access the target).' - name: begin - description: The date/time (in future) for the check, current date/time is used by default (format is 'yyyy-mm-dd hh:mm'). + description: 'The date/time (in future) for the check, current date/time is used by default (format is ''yyyy-mm-dd hh:mm'').' outputs: - type: String contextPath: WAB.approval_request_target_get.approval description: 'Tells whether an approval request is needed to access the target or not: not_authorized = connection is not authorized at all, not_required = connection is allowed without approval request, required = an approval request is required, pending = an approval request is pending, error = internal error.' - type: String contextPath: WAB.approval_request_target_get.message - description: A message with detail about the access to the target. + description: 'A message with detail about the access to the target.' - type: String contextPath: WAB.approval_request_target_get.id - description: The approval id if an approval request is already pending for this target. + description: 'The approval id if an approval request is already pending for this target.' + - name: wab-get-mappings-of-domain + description: 'Get the mappings of a domain + + category: Auth Domain Mappings.' + arguments: + - name: domain_id + description: "A domain id or name to retrieve." + required: true + - name: q + description: 'Searches for a resource matching parameters.' + - name: sort + description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''user_group''.' + - name: offset + description: 'The index of first item to retrieve (starts and defaults to 0).' + - name: limit + description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.authdomain_mapping_get.id + description: The mapping id. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.authdomain_mapping_get.domain + description: 'The name of the domain for which the mapping is defined. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter.' + - type: String + contextPath: WAB.authdomain_mapping_get.user_group + description: 'The name of the Bastion users group. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter.' + - type: String + contextPath: WAB.authdomain_mapping_get.external_group + description: 'The name of the external group (LDAP/AD: Distinguished Name, Azure AD: name or ID), "*" means fallback mapping. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter.' + - type: String + contextPath: WAB.authdomain_mapping_get.url + description: The API URL to the resource. + - name: wab-add-mapping-in-domain + description: 'Add a mapping in a domain and set mapping fallback. If the field "external_group" is set to "*", it is used as the fallback mapping, which allows mapping of users in the domain that do not belong to the external_group to be mapped to the user_group by default + + category: Auth Domain Mappings.' + arguments: + - name: domain_id + description: 'A domain id or name.' + required: true + - name: authdomain_mapping_post_domain + description: The name of the domain for which the mapping is defined. + - name: authdomain_mapping_post_user_group + description: The name of the Bastion users group. + required: true + - name: authdomain_mapping_post_external_group + description: 'The name of the external group (LDAP/AD: Distinguished Name, Azure AD: name or ID), "*" means fallback mapping.' + required: true + outputs: + - type: String + contextPath: WAB.add_mapping_in_domain.id + description: id of the created object. + - name: wab-edit-mappings-of-domain + description: 'Edit mappings of a domain + + category: Auth Domain Mappings.' + arguments: + - name: domain_id + description: A domain id or name. + required: true + - name: authdomain_mapping_put_domain + description: The name of the domain for which the mapping is defined. + - name: authdomain_mapping_put_user_group + description: The name of the Bastion users group. + required: true + - name: authdomain_mapping_put_external_group + description: 'The name of the external group (LDAP/AD: Distinguished Name, Azure AD: name or ID), "*" means fallback mapping.' + required: true + - name: wab-get-mapping-of-domain + description: 'Get the mapping of a domain + + category: Auth Domain Mappings.' + arguments: + - name: domain_id + description: A domain id or name to retrieve. + required: true + - name: mapping_id + description: A mapping id to retrieve. If specified, only this mapping information will be retrieved. + required: true + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.authdomain_mapping_get.id + description: The mapping id. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.authdomain_mapping_get.domain + description: The name of the domain for which the mapping is defined. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.authdomain_mapping_get.user_group + description: The name of the Bastion users group. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.authdomain_mapping_get.external_group + description: 'The name of the external group (LDAP/AD: Distinguished Name, Azure AD: name or ID), "*" means fallback mapping. Usable in the "q" parameter. Usable in the "sort" parameter. Usable in the "q" parameter. Usable in the "sort" parameter.' + - type: String + contextPath: WAB.authdomain_mapping_get.url + description: The API URL to the resource. + - name: wab-edit-mapping-of-domain + description: 'Edit a mapping of a domain + + category: Auth Domain Mappings.' + arguments: + - name: domain_id + description: A domain id or name. + required: true + - name: mapping_id + description: A mapping id to edit. + required: true + - name: authdomain_mapping_put_domain + description: The name of the domain for which the mapping is defined. + - name: authdomain_mapping_put_user_group + description: The name of the Bastion users group. + required: true + - name: authdomain_mapping_put_external_group + description: 'The name of the external group (LDAP/AD: Distinguished Name, Azure AD: name or ID), "*" means fallback mapping.' + required: true + - name: wab-delete-mapping-of-domain + description: 'Delete the mapping of the given domain + + category: Auth Domain Mappings.' + arguments: + - name: domain_id + description: A domain id or name. + required: true + - name: mapping_id + description: A mapping id. + required: true - name: wab-get-auth-domains - description: Get the auth domains. + description: 'Get the auth domains + + category: Auth Domains.' arguments: - name: q - description: Searches for a resource matching parameters. + description: 'Searches for a resource matching parameters.' - name: sort description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''domain_name''.' - name: offset @@ -1464,7 +1833,7 @@ script: description: The domain id. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.auth_domain_get.domain_name - description: The domain name.\ Only alphanumeric characters, dots (.) and hyphens (-) are allowed \ Length ranges between 3 and 63. Usable in the "q" parameter. Usable in the "sort" parameter. + description: 'The domain name.\ Only alphanumeric characters, dots (.) and hyphens (-) are allowed \ Length ranges between 3 and 63. Usable in the "q" parameter. Usable in the "sort" parameter.' - type: String contextPath: WAB.auth_domain_get.type description: The domain type. Usable in the "q" parameter. Usable in the "sort" parameter. @@ -1505,13 +1874,9 @@ script: contextPath: WAB.auth_domain_get.url description: The API URL to the resource. - name: wab-get-auth-domain - description: Get the auth domain. - arguments: - - name: domain_id - description: 'An auth domain id or name to retrieve. If specified, only this auth domain information will be retrieved.' - required: true - - name: fields - description: 'The list of fields to return (separated by commas). By default all fields are returned.' + description: 'Get the auth domain + + category: Auth Domains.' outputs: - type: String contextPath: WAB.auth_domain_get.id @@ -1521,7 +1886,7 @@ script: description: 'The domain name.\ Only alphanumeric characters, dots (.) and hyphens (-) are allowed \ Length ranges between 3 and 63. Usable in the "q" parameter. Usable in the "sort" parameter.' - type: String contextPath: WAB.auth_domain_get.type - description: 'The domain type. Usable in the "q" parameter. Usable in the "sort" parameter.' + description: The domain type. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.auth_domain_get.description description: The domain description. Usable in the "q" parameter. Usable in the "sort" parameter. @@ -1558,25 +1923,16 @@ script: - type: String contextPath: WAB.auth_domain_get.url description: The API URL to the resource. - - name: wab-get-authentications - description: Get the authentications. arguments: - - name: from_date - description: 'Return authentications from this date/time (format: "yyyy-mm-dd" or "yyyy-mm-dd hh:mm:ss").' - - name: to_date - description: 'Return authentications until this date/time (format: "yyyy-mm-dd" or "yyyy-mm-dd hh:mm:ss").' - - name: date_field - description: 'The field used for date comparison: "login" for the login time, "logout" for the logout time.' - - name: q - description: 'Searches for a resource matching parameters.' - - name: sort - description: Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is. - - name: offset - description: The index of first item to retrieve (starts and defaults to 0). - - name: limit - description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' + - name: domain_id + description: An auth domain id or name to retrieve. If specified, only this auth domain information will be retrieved. + required: true - name: fields description: The list of fields to return (separated by commas). By default all fields are returned. + - name: wab-get-authentications + description: 'Get the authentications + + category: Authentications.' outputs: - type: String contextPath: WAB.authentication_get.id @@ -1605,11 +1961,30 @@ script: - type: String contextPath: WAB.authentication_get.url description: The API URL to the resource. + arguments: + - name: from_date + description: 'Return authentications from this date/time (format: "yyyy-mm-dd" or "yyyy-mm-dd hh:mm:ss").' + - name: to_date + description: 'Return authentications until this date/time (format: "yyyy-mm-dd" or "yyyy-mm-dd hh:mm:ss").' + - name: date_field + description: 'The field used for date comparison: "login" for the login time, "logout" for the logout time.' + - name: q + description: Searches for a resource matching parameters. + - name: sort + description: Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is. + - name: offset + description: The index of first item to retrieve (starts and defaults to 0). + - name: limit + description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. - name: wab-get-authentication - description: Get the authentication. + description: 'Get the authentication + + category: Authentications.' arguments: - name: auth_id - description: "An authentication id. If specified, only this authentication is returned." + description: An authentication id. If specified, only this authentication is returned. required: true - name: from_date description: 'Return authentications from this date/time (format: "yyyy-mm-dd" or "yyyy-mm-dd hh:mm:ss").' @@ -1648,10 +2023,12 @@ script: contextPath: WAB.authentication_get.url description: The API URL to the resource. - name: wab-get-authorizations - description: Get the authorizations. + description: 'Get the authorizations + + category: Authorizations.' arguments: - name: q - description: 'Searches for a resource matching parameters.' + description: Searches for a resource matching parameters. - name: sort description: Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is. - name: offset @@ -1731,7 +2108,9 @@ script: contextPath: WAB.authorization_get.url description: The API URL to the resource. - name: wab-add-authorization - description: Add an authorization. + description: 'Add an authorization + + category: Authorizations.' arguments: - name: authorization_post_user_group description: The user group. @@ -1745,28 +2124,68 @@ script: - name: authorization_post_description description: The authorization description. - name: authorization_post_subprotocols - description: The authorization subprotocols. It is mandatory if "authorize_sessions" is enabled (default). + description: 'The authorization subprotocols. It is mandatory if "authorize_sessions" is enabled (default). + + Comma-separated list (use [] for an empty list).' isArray: true - name: authorization_post_is_critical description: Define if it's critical. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_post_is_recorded description: Define if it's recorded. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_post_authorize_password_retrieval description: Authorize password retrieval. Enabled by default. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_post_authorize_sessions description: Authorize sessions via proxies. Enabled by default. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_post_approval_required description: Approval is required to connect to targets. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_post_has_comment description: Comment is allowed in approval. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_post_mandatory_comment description: Comment is mandatory in approval. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_post_has_ticket description: Ticket is allowed in approval. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_post_mandatory_ticket description: Ticket is mandatory in approval. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_post_approvers - description: The approvers user groups. + description: 'The approvers user groups. + + Comma-separated list (use [] for an empty list).' isArray: true - name: authorization_post_active_quorum description: 'The quorum for active periods (-1: approval workflow with automatic approval, 0: no approval workflow (direct connection), > 0: quorum to reach).' @@ -1774,20 +2193,32 @@ script: description: 'The quorum for inactive periods (-1: approval workflow with automatic approval, 0: no connection allowed, > 0: quorum to reach).' - name: authorization_post_single_connection description: Limit to one single connection during the approval period (i.e. if the user disconnects, he will not be allowed to start a new session during the original requested time). + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_post_approval_timeout description: 'Set a timeout in minutes after which the approval will be automatically closed if no connection has been initiated (i.e. the user won''t be able to connect). 0: no timeout.' - name: authorization_post_authorize_session_sharing description: Enable Session Sharing. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_post_session_sharing_mode description: The Session Sharing Mode. + auto: PREDEFINED + predefined: + - view_only + - view_control + outputs: + - type: String + contextPath: WAB.add_authorization.id + description: id of the created object. - name: wab-get-authorization - description: Get the authorization. - arguments: - - name: authorization_id - description: An authorization id or name. If specified, only this authorization is returned. - required: true - - name: fields - description: The list of fields to return (separated by commas). By default all fields are returned. + description: 'Get the authorization + + category: Authorizations.' outputs: - type: String contextPath: WAB.authorization_get.id @@ -1858,41 +2289,93 @@ script: - type: String contextPath: WAB.authorization_get.url description: The API URL to the resource. + arguments: + - name: authorization_id + description: An authorization id or name. If specified, only this authorization is returned. + required: true + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. - name: wab-edit-authorization - description: Edit an authorization. + description: 'Edit an authorization + + category: Authorizations.' arguments: - name: authorization_id description: The authorization id or name to edit. required: true - name: force description: The default value is false. When it is set to true the values of subprotocols and approvers are replaced otherwise the values are added to the existing ones. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_put_authorization_name - description: The authorization name. \ /:*?"<>|@& and space are forbidden. + description: 'The authorization name. \ /:*?"<>|@& and space are forbidden.' - name: authorization_put_description description: The authorization description. - name: authorization_put_subprotocols - description: The authorization subprotocols. It is mandatory if "authorize_sessions" is enabled (default). + description: 'The authorization subprotocols. It is mandatory if "authorize_sessions" is enabled (default). + + Comma-separated list (use [] for an empty list).' isArray: true - name: authorization_put_is_critical description: Define if it's critical. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_put_is_recorded - description: Define if it's recorded. + description: 'Define if it''s recorded.' + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_put_authorize_password_retrieval description: Authorize password retrieval. Enabled by default. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_put_authorize_sessions description: Authorize sessions via proxies. Enabled by default. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_put_approval_required description: Approval is required to connect to targets. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_put_has_comment description: Comment is allowed in approval. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_put_mandatory_comment description: Comment is mandatory in approval. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_put_has_ticket description: Ticket is allowed in approval. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_put_mandatory_ticket description: Ticket is mandatory in approval. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_put_approvers - description: The approvers user groups. + description: 'The approvers user groups. + + Comma-separated list (use [] for an empty list).' isArray: true - name: authorization_put_active_quorum description: 'The quorum for active periods (-1: approval workflow with automatic approval, 0: no approval workflow (direct connection), > 0: quorum to reach).' @@ -1900,38 +2383,54 @@ script: description: 'The quorum for inactive periods (-1: approval workflow with automatic approval, 0: no connection allowed, > 0: quorum to reach).' - name: authorization_put_single_connection description: Limit to one single connection during the approval period (i.e. if the user disconnects, he will not be allowed to start a new session during the original requested time). + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_put_approval_timeout description: 'Set a timeout in minutes after which the approval will be automatically closed if no connection has been initiated (i.e. the user won''t be able to connect). 0: no timeout.' - name: authorization_put_authorize_session_sharing description: Enable Session Sharing. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: authorization_put_session_sharing_mode description: The Session Sharing Mode. + auto: PREDEFINED + predefined: + - view_only + - view_control - name: wab-delete-authorization - description: Delete an authorization. + description: 'Delete an authorization + + category: Authorizations.' arguments: - name: authorization_id description: The authorization id or name to delete. required: true - name: wab-get-checkout-policies - description: Get the checkout policies. + description: 'Get the checkout policies + + category: Checkout Policies.' arguments: - name: q - description: 'Searches for a resource matching parameters.' + description: Searches for a resource matching parameters. - name: sort description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''checkout_policy_name''.' - name: offset - description: The index of first item to retrieve (starts and defaults to 0). + description: 'The index of first item to retrieve (starts and defaults to 0).' - name: limit description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' - name: fields - description: The list of fields to return (separated by commas). By default all fields are returned. + description: "The list of fields to return (separated by commas). By default all fields are returned." outputs: - type: String contextPath: WAB.checkoutpolicy_get.id description: The checkout policy id. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.checkoutpolicy_get.checkout_policy_name - description: 'The checkout policy name. Usable in the "q" parameter. Usable in the "sort" parameter.' + description: The checkout policy name. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.checkoutpolicy_get.description description: The checkout policy description. Usable in the "q" parameter. Usable in the "sort" parameter. @@ -1949,19 +2448,27 @@ script: description: The max duration (in seconds). Usable in the "q" parameter. Usable in the "sort" parameter. - type: Boolean contextPath: WAB.checkoutpolicy_get.change_credentials_at_checkin - description: Change credentials at check-in. Usable in the "q" parameter. Usable in the "sort" parameter. + description: 'Change credentials at check-in. Usable in the "q" parameter. Usable in the "sort" parameter.' - type: String contextPath: WAB.checkoutpolicy_get.url description: The API URL to the resource. - name: wab-get-checkout-policy - description: Get the checkout policy. + description: 'Get the checkout policy + + category: Checkout Policies.' + arguments: + - name: checkout_policy_id + description: A checkout policy id or name. If specified, only this checkout policy is returned. + required: true + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. outputs: - type: String contextPath: WAB.checkoutpolicy_get.id description: The checkout policy id. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.checkoutpolicy_get.checkout_policy_name - description: 'The checkout policy name. Usable in the "q" parameter. Usable in the "sort" parameter.' + description: The checkout policy name. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.checkoutpolicy_get.description description: The checkout policy description. Usable in the "q" parameter. Usable in the "sort" parameter. @@ -1983,14 +2490,79 @@ script: - type: String contextPath: WAB.checkoutpolicy_get.url description: The API URL to the resource. + - name: wab-get-clusters + description: 'Get the clusters + + category: Clusters.' arguments: - - name: checkout_policy_id - description: A checkout policy id or name. If specified, only this checkout policy is returned. - required: true + - name: q + description: Searches for a resource matching parameters. + - name: sort + description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''cluster_name''.' + - name: offset + description: 'The index of first item to retrieve (starts and defaults to 0).' + - name: limit + description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' - name: fields description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.cluster_get.id + description: The cluster id. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.cluster_get.cluster_name + description: The cluster name. \/:*?"<>| and space are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.cluster_get.description + description: The cluster description. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.cluster_get.accounts + description: The cluster targets. The targets must exist in the Bastion. + - type: String + contextPath: WAB.cluster_get.account_mappings + description: The cluster targets with account mapping. The targets must exist in the Bastion. + - type: String + contextPath: WAB.cluster_get.interactive_logins + description: The cluster targets with interactive login. The targets must exist in the Bastion. + - type: String + contextPath: WAB.cluster_get.url + description: The API URL to the resource. + - name: wab-get-cluster + description: 'Get the cluster + + category: Clusters.' + arguments: + - name: cluster_id + description: A cluster id or name. If specified, only this cluster is returned. + required: true + - name: fields + description: 'The list of fields to return (separated by commas). By default all fields are returned.' + outputs: + - type: String + contextPath: WAB.cluster_get.id + description: The cluster id. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.cluster_get.cluster_name + description: The cluster name. \/:*?"<>| and space are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.cluster_get.description + description: The cluster description. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.cluster_get.accounts + description: 'The cluster targets. The targets must exist in the Bastion.' + - type: String + contextPath: WAB.cluster_get.account_mappings + description: 'The cluster targets with account mapping. The targets must exist in the Bastion.' + - type: String + contextPath: WAB.cluster_get.interactive_logins + description: The cluster targets with interactive login. The targets must exist in the Bastion. + - type: String + contextPath: WAB.cluster_get.url + description: The API URL to the resource. - name: wab-getx509-configuration-infos - description: Get the X509 configuration infos. + description: 'Get the X509 configuration infos + + category: Config X509.' outputs: - type: String contextPath: WAB.config_x509_get.ca_certificate @@ -2008,37 +2580,208 @@ script: contextPath: WAB.config_x509_get.default description: Default X509 configuration or not (true = default, false = set by user). - name: wab-uploadx509-configuration - description: Upload X509 configuration. + description: 'Upload X509 configuration + + category: Config X509.' arguments: - name: config_x509_post_ca_certificate description: Certificate Authority's certificate (*.cert file in PEM format).If there's several certificate to be added, they've to be concatenated and supplied to this field, as one string. - name: config_x509_post_server_public_key description: Server public key (*.cert file in PEM format). - name: config_x509_post_server_private_key - description: Server private key (*.key file in PEM format). + description: 'Server private key (*.key file in PEM format).' - name: config_x509_post_enable description: Enable X509 or not (true = enabled, false = disabled). + auto: PREDEFINED + predefined: + - 'true' + - 'false' + outputs: + - type: String + contextPath: WAB.uploadx509_configuration.id + description: id of the created object. - name: wab-updatex509-configuration - description: Update X509 Configuration. + description: 'Update X509 Configuration + + category: Config X509.' arguments: - name: config_x509_put_ca_certificate description: Certificate Authority's certificate (*.cert file in PEM format).If there's several certificate to be added, they've to be concatenated and supplied to this field, as one string. - name: config_x509_put_server_public_key description: Server public key (*.cert file in PEM format). - name: config_x509_put_server_private_key - description: Server private key (*.key file in PEM format). + description: 'Server private key (*.key file in PEM format).' - name: config_x509_put_enable - description: Enable X509 or not (true = enabled, false = disabled). + description: "Enable X509 or not (true = enabled, false = disabled)." + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: wab-resetx509-configuration - description: Reset X509 configuration. + description: 'Reset X509 configuration + + category: Config X509.' - name: wab-get-current-serial-configuration-number-of-bastion - description: Get current serial configuration number of the Bastion. This number can be used to know if the Bastion configuration was changed. + description: 'Get current serial configuration number of the Bastion. This number can be used to know if the Bastion configuration was changed + + category: Configuration Number.' outputs: - type: Number contextPath: WAB.confignumber_get.configuration_number description: The current serial configuration number of the WALLIX Bastion. + - name: wab-get-connection-policies + description: 'Get the connection policies + + category: Connection Policies.' + arguments: + - name: q + description: Searches for a resource matching parameters. + - name: sort + description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''connection_policy_name''.' + - name: offset + description: The index of first item to retrieve (starts and defaults to 0). + - name: limit + description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.connectionpolicy_get.id + description: The connection policy id. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.connectionpolicy_get.connection_policy_name + description: The connection policy name. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.connectionpolicy_get.type + description: The connection policy type. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.connectionpolicy_get.description + description: The connection policy description. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.connectionpolicy_get.protocol + description: The connection policy protocol. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Boolean + contextPath: WAB.connectionpolicy_get.is_default + description: True if the connection policy is a default one. + - type: String + contextPath: WAB.connectionpolicy_get.url + description: The API URL to the resource. + - name: wab-add-connection-policy + description: 'Add a connection policy + + category: Connection Policies.' + arguments: + - name: connectionpolicy_post_connection_policy_name + description: The connection policy name. + required: true + - name: connectionpolicy_post_type + description: 'The connection policy type.' + required: true + auto: PREDEFINED + predefined: + - RAWTCPIP + - RDP + - RLOGIN + - SSH + - TELNET + - VNC + - name: connectionpolicy_post_description + description: The connection policy description. + - name: connectionpolicy_post_protocol + description: The connection policy protocol. + required: true + auto: PREDEFINED + predefined: + - RAWTCPIP + - RDP + - RLOGIN + - SSH + - TELNET + - VNC + - name: connectionpolicy_post_authentication_methods + description: 'The allowed authentication methods. + + Comma-separated list (use [] for an empty list). + + Possible values: KERBEROS_FORWARDING,PASSWORD_INTERACTIVE,PASSWORD_MAPPING,PASSWORD_VAULT,PUBKEY_AGENT_FORWARDING,PUBKEY_VAULT.' + isArray: true + - name: options + description: Options for the connection policy, formatted in json. + outputs: + - type: String + contextPath: WAB.add_connection_policy.id + description: id of the created object. + - name: wab-get-connection-policy + description: 'Get the connection policy + + category: Connection Policies.' + arguments: + - name: connection_policy_id + description: A connection policy id or name. If specified, only this connection policy is returned. + required: true + - name: fields + description: 'The list of fields to return (separated by commas). By default all fields are returned.' + outputs: + - type: String + contextPath: WAB.connectionpolicy_get.id + description: The connection policy id. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.connectionpolicy_get.connection_policy_name + description: The connection policy name. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.connectionpolicy_get.type + description: The connection policy type. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.connectionpolicy_get.description + description: The connection policy description. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.connectionpolicy_get.protocol + description: The connection policy protocol. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Boolean + contextPath: WAB.connectionpolicy_get.is_default + description: 'True if the connection policy is a default one.' + - type: String + contextPath: WAB.connectionpolicy_get.url + description: The API URL to the resource. + - name: wab-edit-connection-policy + description: 'Edit a connection policy + + category: Connection Policies.' + arguments: + - name: connection_policy_id + description: A connection policy id or name to edit. + required: true + - name: force + description: 'The default value is false. When it is set to true the values of the authentication_methods are replaced, otherwise the values are added to the existing ones.' + auto: PREDEFINED + predefined: + - 'true' + - 'false' + - name: connectionpolicy_put_connection_policy_name + description: The connection policy name. + - name: connectionpolicy_put_description + description: The connection policy description. + - name: connectionpolicy_put_authentication_methods + description: 'The allowed authentication methods. + + Comma-separated list (use [] for an empty list). + + Possible values: KERBEROS_FORWARDING,PASSWORD_INTERACTIVE,PASSWORD_MAPPING,PASSWORD_VAULT,PUBKEY_AGENT_FORWARDING,PUBKEY_VAULT.' + isArray: true + - name: options + description: Options for the connection policy, formatted in json. + - name: wab-delete-connection-policy + description: 'Delete a connection policy. Note: it is not possible to delete the default Bastion connection policies + + category: Connection Policies.' + arguments: + - name: connection_policy_id + description: The connection policy id or name to delete. + required: true - name: wab-get-all-accounts-on-device-local-domain - description: Get all accounts on a device local domain. + description: 'Get all accounts on a device local domain + + category: Device Accounts.' arguments: - name: device_id description: The device id or name. @@ -2047,7 +2790,7 @@ script: description: The local domain id or name. required: true - name: key_format - description: 'Format of the returned SSH public key of the account. Accepted values are ''openssh'' (default value) and ''ssh.com''.' + description: Format of the returned SSH public key of the account. Accepted values are 'openssh' (default value) and 'ssh.com'. - name: q description: Searches for a resource matching parameters. - name: sort @@ -2165,26 +2908,36 @@ script: contextPath: WAB.device_account_get.services description: The account services. - name: wab-add-account-to-local-domain-on-device - description: Add an account to a local domain on a device. + description: 'Add an account to a local domain on a device + + category: Device Accounts.' arguments: - name: device_id description: The device id or name. required: true - name: domain_id - description: 'The local domain id or name.' + description: The local domain id or name. required: true - name: device_account_post_account_name description: The account name. /:*?"<>|@ and space are forbidden. required: true - name: device_account_post_account_login - description: "The account login." + description: The account login. required: true - name: device_account_post_description description: The account description. - name: device_account_post_auto_change_password description: Automatically change the password. It is enabled by default on a new account. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: device_account_post_auto_change_ssh_key description: Automatically change the ssh key. It is enabled by default on a new account. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: device_account_post_checkout_policy description: The account checkout policy. required: true @@ -2192,11 +2945,23 @@ script: description: The validity duration of the signed ssh public key in the case a Certificate Authority is defined for the account's domain. - name: device_account_post_can_edit_certificate_validity description: True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: device_account_post_services - description: The account services. + description: 'The account services. + + Comma-separated list (use [] for an empty list).' isArray: true + outputs: + - type: String + contextPath: WAB.add_account_to_local_domain_on_device.id + description: id of the created object. - name: wab-get-one-account-on-device-local-domain - description: Get one account on a device local domain. + description: 'Get one account on a device local domain + + category: Device Accounts.' arguments: - name: device_id description: The device id or name. @@ -2205,12 +2970,12 @@ script: description: The local domain id or name. required: true - name: account_id - description: 'The account id or name.' + description: The account id or name. required: true - name: key_format - description: Format of the returned SSH public key of the account. Accepted values are 'openssh' (default value) and 'ssh.com'. + description: 'Format of the returned SSH public key of the account. Accepted values are ''openssh'' (default value) and ''ssh.com''.' - name: fields - description: "The list of fields to return (separated by commas). By default all fields are returned." + description: The list of fields to return (separated by commas). By default all fields are returned. outputs: - type: String contextPath: WAB.device_account_get.id @@ -2318,7 +3083,9 @@ script: contextPath: WAB.device_account_get.services description: The account services. - name: wab-edit-account-on-local-domain-of-device - description: Edit an account on a local domain of a device. + description: 'Edit an account on a local domain of a device + + category: Device Accounts.' arguments: - name: device_id description: The device id or name. @@ -2327,10 +3094,14 @@ script: description: The local domain id or name. required: true - name: account_id - description: The account id or name to edit. + description: "The account id or name to edit." required: true - name: force description: The default value is false. When it is set to true the values of the credentials and services, if they are supplied, are replaced, otherwise the values are added to the existing ones. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: device_account_put_account_name description: The account name. /:*?"<>|@ and space are forbidden. - name: device_account_put_account_login @@ -2339,47 +3110,71 @@ script: description: The account description. - name: device_account_put_auto_change_password description: Automatically change the password. It is enabled by default on a new account. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: device_account_put_auto_change_ssh_key description: Automatically change the ssh key. It is enabled by default on a new account. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: device_account_put_checkout_policy description: The account checkout policy. - name: device_account_put_certificate_validity description: The validity duration of the signed ssh public key in the case a Certificate Authority is defined for the account's domain. - name: device_account_put_can_edit_certificate_validity description: True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: device_account_put_onboard_status description: Onboarding status of the account. + auto: PREDEFINED + predefined: + - onboarded + - to_onboard + - hide + - manual - name: device_account_put_services - description: The account services. + description: 'The account services. + + Comma-separated list (use [] for an empty list).' isArray: true - name: wab-delete-account-from-local-domain-of-device - description: Delete an account from a local domain of a device. + description: 'Delete an account from a local domain of a device + + category: Device Accounts.' arguments: - name: device_id description: The device id or name. required: true - name: domain_id - description: 'The local domain id or name.' + description: "The local domain id or name." required: true - name: account_id - description: 'The account id or name to delete.' + description: The account id or name to delete. required: true - name: wab-get-certificates-on-device - description: Get the certificates on a device. + description: 'Get the certificates on a device + + category: Device Certificates.' arguments: - name: device_id description: The device id or name. required: true - name: q - description: 'Search and return only certificates matching these words.' + description: Search and return only certificates matching these words. - name: sort description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''type,address''.' - name: offset - description: 'The index of first item to retrieve (starts and defaults to 0).' + description: The index of first item to retrieve (starts and defaults to 0). - name: limit description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' - name: fields - description: 'The list of fields to return (separated by commas). By default all fields are returned.' + description: The list of fields to return (separated by commas). By default all fields are returned. outputs: - type: String contextPath: WAB.device_certificates_get.type @@ -2392,10 +3187,10 @@ script: description: The certificate port. Usable in the "sort" parameter. - type: String contextPath: WAB.device_certificates_get.key_type - description: 'The certificate key type. Usable in the "sort" parameter.' + description: The certificate key type. Usable in the "sort" parameter. - type: String contextPath: WAB.device_certificates_get.fingerprint - description: 'The fingerprint of the certificate. Usable in the "sort" parameter.' + description: The fingerprint of the certificate. Usable in the "sort" parameter. - type: String contextPath: WAB.device_certificates_get.last_modification_date description: The last time the certificate was modified. Usable in the "sort" parameter. @@ -2403,16 +3198,18 @@ script: contextPath: WAB.device_certificates_get.url description: The API URL to the resource. - name: wab-get-certificate-on-device - description: Get the certificate on a device. + description: 'Get the certificate on a device + + category: Device Certificates.' arguments: - name: device_id - description: 'The device id or name.' + description: The device id or name. required: true - name: cert_type - description: 'The certificate type (SSH, RDP).' + description: The certificate type (SSH, RDP). required: true - name: address - description: 'The certificate address/ip.' + description: The certificate address/ip. required: true - name: port description: The certificate port. @@ -2450,32 +3247,129 @@ script: contextPath: WAB.device_certificates_get.url description: The API URL to the resource. - name: wab-revoke-certificate-of-device - description: Revoke a certificate of a device. + description: 'Revoke a certificate of a device + + category: Device Certificates.' arguments: - name: device_id description: The device id or name. required: true - name: cert_type - description: The certificate type (SSH, RDP). + description: 'The certificate type (SSH, RDP).' required: true - name: address - description: 'The certificate address/ip.' + description: The certificate address/ip. required: true - name: port description: The certificate port. required: true + - name: wab-get-local-domains-of-device + description: 'Get the local domains of a device + + category: Device Local Domains.' + arguments: + - name: device_id + description: "The device id or name." + required: true + - name: q + description: 'Searches for a resource matching parameters.' + - name: sort + description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''domain_name''.' + - name: offset + description: 'The index of first item to retrieve (starts and defaults to 0).' + - name: limit + description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.localdomain_get.id + description: The domain id. Usable in the "q" parameter. + - type: String + contextPath: WAB.localdomain_get.domain_name + description: The domain name. /:*?"<>|@ are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.localdomain_get.description + description: The domain description. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Boolean + contextPath: WAB.localdomain_get.enable_password_change + description: Enable the change of password on this domain. + - type: String + contextPath: WAB.localdomain_get.admin_account + description: 'The administrator account used to change passwords on this domain (format: "account_name").' + - type: String + contextPath: WAB.localdomain_get.password_change_policy + description: 'The name of password change policy for this domain.' + - type: String + contextPath: WAB.localdomain_get.password_change_plugin + description: The name of plugin used to change passwords on this domain. + - type: String + contextPath: WAB.localdomain_get.ca_private_key + description: 'The ssh private key of the signing authority for the ssh keys for accounts in the domain. Special values are allowed to automatically generate SSH key: "generate:RSA_1024", "generate:RSA_2048", "generate:RSA_4096", "generate:RSA_8192", "generate:DSA_1024", "generate:ECDSA_256", "generate:ECDSA_384", "generate:ECDSA_521", "generate:ED25519".' + - type: String + contextPath: WAB.localdomain_get.ca_public_key + description: The ssh public key of the signing authority for the ssh keys for accounts in the domain. + - type: String + contextPath: WAB.localdomain_get.url + description: The API URL to the resource. + - name: wab-get-local-domain-of-device + description: 'Get the local domain of a device + + category: Device Local Domains.' + arguments: + - name: device_id + description: 'The device id or name.' + required: true + - name: domain_id + description: 'The local domain id or name.' + required: true + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.localdomain_get.id + description: The domain id. Usable in the "q" parameter. + - type: String + contextPath: WAB.localdomain_get.domain_name + description: 'The domain name. /:*?"<>|@ are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter.' + - type: String + contextPath: WAB.localdomain_get.description + description: The domain description. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Boolean + contextPath: WAB.localdomain_get.enable_password_change + description: Enable the change of password on this domain. + - type: String + contextPath: WAB.localdomain_get.admin_account + description: 'The administrator account used to change passwords on this domain (format: "account_name").' + - type: String + contextPath: WAB.localdomain_get.password_change_policy + description: 'The name of password change policy for this domain.' + - type: String + contextPath: WAB.localdomain_get.password_change_plugin + description: The name of plugin used to change passwords on this domain. + - type: String + contextPath: WAB.localdomain_get.ca_private_key + description: 'The ssh private key of the signing authority for the ssh keys for accounts in the domain. Special values are allowed to automatically generate SSH key: "generate:RSA_1024", "generate:RSA_2048", "generate:RSA_4096", "generate:RSA_8192", "generate:DSA_1024", "generate:ECDSA_256", "generate:ECDSA_384", "generate:ECDSA_521", "generate:ED25519".' + - type: String + contextPath: WAB.localdomain_get.ca_public_key + description: The ssh public key of the signing authority for the ssh keys for accounts in the domain. + - type: String + contextPath: WAB.localdomain_get.url + description: 'The API URL to the resource.' - name: wab-get-services-of-device - description: Get the services of a device. + description: 'Get the services of a device + + category: Device Services.' arguments: - name: device_id description: The device id or name. required: true - name: q - description: Searches for a resource matching parameters. + description: 'Searches for a resource matching parameters.' - name: sort description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''service_name''.' - name: offset - description: "The index of first item to retrieve (starts and defaults to 0)." + description: The index of first item to retrieve (starts and defaults to 0). - name: limit description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' - name: fields @@ -2486,7 +3380,7 @@ script: description: The service id. Usable in the "sort" parameter. - type: String contextPath: WAB.service_get.service_name - description: The service name. Must start with a letter; only letters, digits and -_ are allowed. Usable in the "sort" parameter. / The service name. Must start with a letter; only letters, digits and -_ are allowed. Usable in the "q" parameter. Usable in the "sort" parameter. + description: 'The service name. Must start with a letter; only letters, digits and -_ are allowed. Usable in the "sort" parameter. / The service name. Must start with a letter; only letters, digits and -_ are allowed. Usable in the "q" parameter. Usable in the "sort" parameter.' - type: String contextPath: WAB.service_get.protocol description: The protocol. Usable in the "sort" parameter. / The protocol. Usable in the "q" parameter. Usable in the "sort" parameter. @@ -2503,7 +3397,13 @@ script: contextPath: WAB.service_get.url description: The API URL to the resource. - name: wab-add-service-in-device - description: Add a service in a device. + description: 'Add a service in a device + + category: Device Services.' + outputs: + - type: String + contextPath: WAB.add_service_in_device.id + description: id of the created object. arguments: - name: device_id description: The device id or name. @@ -2511,35 +3411,47 @@ script: - name: service_post_id description: The service id. Usable in the "sort" parameter. - name: service_post_service_name - description: The service name. Must start with a letter; only letters, digits and -_ are allowed. Usable in the "sort" parameter. / The service name. Must start with a letter; only letters, digits and -_ are allowed. Usable in the "q" parameter. Usable in the "sort" parameter. + description: 'The service name. Must start with a letter; only letters, digits and -_ are allowed. Usable in the "sort" parameter. / The service name. Must start with a letter; only letters, digits and -_ are allowed. Usable in the "q" parameter. Usable in the "sort" parameter.' required: true - name: service_post_protocol description: The protocol. Usable in the "sort" parameter. / The protocol. Usable in the "q" parameter. Usable in the "sort" parameter. required: true + auto: PREDEFINED + predefined: + - RAWTCPIP + - RDP + - RLOGIN + - SSH + - TELNET + - VNC - name: service_post_port description: The port number. Usable in the "sort" parameter. / The port number. Usable in the "q" parameter. Usable in the "sort" parameter. required: true - name: service_post_subprotocols - description: The sub protocols. - required: true + description: 'The sub protocols. + + Comma-separated list (use [] for an empty list). + + Possible values: RDP_AUDIO_INPUT,RDP_AUDIO_OUTPUT,RDP_CLIPBOARD_DOWN,RDP_CLIPBOARD_FILE,RDP_CLIPBOARD_UP,RDP_COM_PORT,RDP_DRIVE,RDP_PRINTER,RDP_SMARTCARD,SFTP_SESSION,SSH_AUTH_AGENT,SSH_DIRECT_TCPIP,SSH_DIRECT_UNIXSOCK,SSH_REMOTE_COMMAND,SSH_REVERSE_TCPIP,SSH_REVERSE_UNIXSOCK,SSH_SCP_DOWN,SSH_SCP_UP,SSH_SHELL_SESSION,SSH_X11.' isArray: true - name: service_post_connection_policy description: The connection policy name. Usable in the "q" parameter. Usable in the "sort" parameter. required: true - name: service_post_global_domains - description: The global domains names. + description: 'The global domains names. + + Comma-separated list (use [] for an empty list).' isArray: true + - name: service_post_seamless_connection + description: The seamless connection. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: wab-get-service-of-device - description: Get the service of a device. - arguments: - - name: device_id - description: The device id or name. - required: true - - name: service_id - description: The service id or name. - required: true - - name: fields - description: 'The list of fields to return (separated by commas). By default all fields are returned.' + description: 'Get the service of a device + + category: Device Services.' outputs: - type: String contextPath: WAB.service_get.id @@ -2562,8 +3474,19 @@ script: - type: String contextPath: WAB.service_get.url description: The API URL to the resource. + arguments: + - name: device_id + description: The device id or name. + required: true + - name: service_id + description: The service id or name. + required: true + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. - name: wab-edit-service-of-device - description: Edit a service of a device. + description: 'Edit a service of a device + + category: Device Services.' arguments: - name: device_id description: The device id or name. @@ -2573,15 +3496,36 @@ script: required: true - name: force description: The default value is false. When it is set to true the values of the subprotocols, global_domains and additional_interfaces are replaced, otherwise the values are added to the existing ones. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: service_put_port description: The port number. + - name: service_put_subprotocols + description: 'The sub protocols. + + Comma-separated list (use [] for an empty list). + + Possible values: RDP_AUDIO_INPUT,RDP_AUDIO_OUTPUT,RDP_CLIPBOARD_DOWN,RDP_CLIPBOARD_FILE,RDP_CLIPBOARD_UP,RDP_COM_PORT,RDP_DRIVE,RDP_PRINTER,RDP_SMARTCARD,SFTP_SESSION,SSH_AUTH_AGENT,SSH_DIRECT_TCPIP,SSH_DIRECT_UNIXSOCK,SSH_REMOTE_COMMAND,SSH_REVERSE_TCPIP,SSH_REVERSE_UNIXSOCK,SSH_SCP_DOWN,SSH_SCP_UP,SSH_SHELL_SESSION,SSH_X11.' + isArray: true - name: service_put_connection_policy description: The connection policy name. - name: service_put_global_domains - description: The global domains names. + description: 'The global domains names. + + Comma-separated list (use [] for an empty list).' isArray: true + - name: service_put_seamless_connection + description: The seamless connection. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: wab-delete-service-from-device - description: Delete a service from a device. + description: 'Delete a service from a device + + category: Device Services.' arguments: - name: device_id description: The device id or name. @@ -2590,7 +3534,9 @@ script: description: 'The service id or name.' required: true - name: wab-get-devices - description: Get the devices. + description: 'Get the devices + + category: Devices.' arguments: - name: q description: Searches for a resource matching parameters. @@ -2672,9 +3618,6 @@ script: - type: String contextPath: WAB.device_get.services.url description: The API URL to the resource. - - type: String - contextPath: WAB.device_get.tags.id - description: The tag id. - type: String contextPath: WAB.device_get.tags.key description: The tag key. Must not start or end with a space. @@ -2724,20 +3667,28 @@ script: contextPath: WAB.device_get.url description: The API URL to the resource. - name: wab-add-device - description: Add a device. + description: 'Add a device + + category: Devices.' arguments: - name: device_post_device_name description: The device name. \ /:*?"<>|@ and space are forbidden. required: true - name: device_post_description - description: 'The device description.' + description: The device description. - name: device_post_alias description: The device alias. \ /:*?"<>|@ and space are forbidden. - name: device_post_host description: The device host address. required: true + outputs: + - type: String + contextPath: WAB.add_device.id + description: id of the created object. - name: wab-get-device - description: Get the device. + description: 'Get the device + + category: Devices.' arguments: - name: device_id description: A device id or name. If specified, only this device is returned. @@ -2814,9 +3765,6 @@ script: - type: String contextPath: WAB.device_get.services.url description: The API URL to the resource. - - type: String - contextPath: WAB.device_get.tags.id - description: The tag id. - type: String contextPath: WAB.device_get.tags.key description: The tag key. Must not start or end with a space. @@ -2866,13 +3814,19 @@ script: contextPath: WAB.device_get.url description: The API URL to the resource. - name: wab-edit-device - description: Edit a device. + description: 'Edit a device + + category: Devices.' arguments: - name: device_id - description: The device id or name to edit. + description: 'The device id or name to edit.' required: true - name: force description: The default value is false. When it is set to true the values of the tags are replaced, otherwise the values are added to the existing ones. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: device_put_device_name description: The device name. \ /:*?"<>|@ and space are forbidden. - name: device_put_description @@ -2883,20 +3837,30 @@ script: description: The device host address. - name: device_put_onboard_status description: Onboarding status of the device. + auto: PREDEFINED + predefined: + - onboarded + - to_onboard + - hide + - manual - name: wab-delete-device - description: Delete a device. + description: 'Delete a device + + category: Devices.' arguments: - name: device_id - description: The device id or name to delete. + description: 'The device id or name to delete.' required: true - name: wab-get-accounts-of-global-domain - description: Get the accounts of a global domain. + description: 'Get the accounts of a global domain + + category: Domain Accounts.' arguments: - name: domain_id - description: The global domain id or name. + description: "The global domain id or name." required: true - name: q - description: Searches for a resource matching parameters. + description: 'Searches for a resource matching parameters.' - name: offset description: The index of first item to retrieve (starts and defaults to 0). - name: limit @@ -2993,7 +3957,7 @@ script: description: Scan type. - type: String contextPath: WAB.domain_account_get.last_seen.error - description: Error message. + description: 'Error message.' - type: String contextPath: WAB.domain_account_get.last_seen.status description: Scan job status. @@ -3005,28 +3969,38 @@ script: description: Scan job end timestamp. - type: String contextPath: WAB.domain_account_get.url - description: The API URL to the resource. + description: 'The API URL to the resource.' - type: String contextPath: WAB.domain_account_get.resources description: The account resources. - name: wab-add-account-in-global-domain - description: Add an account in a global domain. + description: 'Add an account in a global domain + + category: Domain Accounts.' arguments: - name: domain_id description: The global domain id or name. required: true - name: domain_account_post_account_name - description: The account name. /:*?"<>|@ and space are forbidden. + description: 'The account name. /:*?"<>|@ and space are forbidden.' required: true - name: domain_account_post_account_login - description: "The account login." + description: The account login. required: true - name: domain_account_post_description description: The account description. - name: domain_account_post_auto_change_password description: Automatically change the password. It is enabled by default on a new account. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: domain_account_post_auto_change_ssh_key description: Automatically change the ssh key. It is enabled by default on a new account. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: domain_account_post_checkout_policy description: The account checkout policy. required: true @@ -3034,17 +4008,29 @@ script: description: The validity duration of the signed ssh public key in the case a Certificate Authority is defined for the account's domain. - name: domain_account_post_can_edit_certificate_validity description: True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: domain_account_post_resources - description: The account resources. + description: 'The account resources. + + Comma-separated list (use [] for an empty list).' isArray: true + outputs: + - type: String + contextPath: WAB.add_account_in_global_domain.id + description: id of the created object. - name: wab-get-account-of-global-domain - description: Get the account of a global domain. + description: 'Get the account of a global domain + + category: Domain Accounts.' arguments: - name: domain_id description: The global domain id or name. required: true - name: account_id - description: "The account id or name." + description: 'The account id or name.' required: true - name: fields description: The list of fields to return (separated by commas). By default all fields are returned. @@ -3155,7 +4141,9 @@ script: contextPath: WAB.domain_account_get.resources description: The account resources. - name: wab-edit-account-in-global-domain - description: Edit an account in a global domain. + description: 'Edit an account in a global domain + + category: Domain Accounts.' arguments: - name: domain_id description: The global domain id or name. @@ -3165,6 +4153,10 @@ script: required: true - name: force description: The default value is false. When it is set to true the values of the credentials and services, if they are supplied, are replaced, otherwise the values are added to the existing ones. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: domain_account_put_account_name description: The account name. /:*?"<>|@ and space are forbidden. - name: domain_account_put_account_login @@ -3173,45 +4165,71 @@ script: description: The account description. - name: domain_account_put_auto_change_password description: Automatically change the password. It is enabled by default on a new account. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: domain_account_put_auto_change_ssh_key description: Automatically change the ssh key. It is enabled by default on a new account. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: domain_account_put_checkout_policy description: The account checkout policy. - name: domain_account_put_certificate_validity description: The validity duration of the signed ssh public key in the case a Certificate Authority is defined for the account's domain. - name: domain_account_put_can_edit_certificate_validity description: True if the field 'certificate_validity' can be edited based the availibility of CA certificate on the account's domain, false otherwise. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: domain_account_put_onboard_status description: Onboarding status of the account. + auto: PREDEFINED + predefined: + - onboarded + - to_onboard + - hide + - manual - name: domain_account_put_resources - description: The account resources. + description: 'The account resources. + + Comma-separated list (use [] for an empty list).' isArray: true - name: wab-delete-account-from-global-domain - description: Delete an account from a global domain. + description: 'Delete an account from a global domain + + category: Domain Accounts.' arguments: - name: domain_id - description: The global domain id or name. + description: "The global domain id or name." required: true - name: account_id description: The account id or name to delete. required: true - name: wab-delete-resource-from-global-domain-account - description: delete a resource from the global domain account. + description: 'delete a resource from the global domain account + + category: Domain Accounts.' arguments: - name: domain_id description: The global domain id or name. required: true - name: account_id - description: 'The account id or name.' + description: The account id or name. required: true - name: resource_name description: The name of the resource to remove from the account. required: true - name: wab-get-global-domains - description: Get the global domains. + description: 'Get the global domains + + category: Domains.' arguments: - name: q - description: "Searches for a resource matching parameters." + description: Searches for a resource matching parameters. - name: sort description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''domain_name''.' - name: offset @@ -3270,10 +4288,12 @@ script: contextPath: WAB.domain_get.url description: The API URL to the resource. - name: wab-get-global-domain - description: Get the global domain. + description: 'Get the global domain + + category: Domains.' arguments: - name: domain_id - description: 'A global domain id or name. If specified, only this domain is returned.' + description: A global domain id or name. If specified, only this domain is returned. required: true - name: fields description: 'The list of fields to return (separated by commas). By default all fields are returned.' @@ -3283,13 +4303,13 @@ script: description: The domain id. Usable in the "q" parameter. - type: String contextPath: WAB.domain_get.domain_name - description: 'The domain name. /:*?"<>|@ are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter.' + description: The domain name. /:*?"<>|@ are forbidden. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.domain_get.domain_real_name description: The domain name used for connection to a target. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.domain_get.description - description: The domain description. Usable in the "q" parameter. Usable in the "sort" parameter. + description: 'The domain description. Usable in the "q" parameter. Usable in the "sort" parameter.' - type: Boolean contextPath: WAB.domain_get.enable_password_change description: Enable the change of password on this domain. @@ -3298,7 +4318,7 @@ script: description: 'The administrator account used to change passwords on this domain (format: "account_name").' - type: String contextPath: WAB.domain_get.kerberos.kdc - description: IP address or hostname the KDC. + description: 'IP address or hostname the KDC.' - type: String contextPath: WAB.domain_get.kerberos.realm description: The Kerberos realm. @@ -3307,10 +4327,10 @@ script: description: The Kerberos port (88 by default). - type: String contextPath: WAB.domain_get.password_change_policy - description: 'The name of password change policy for this domain.' + description: The name of password change policy for this domain. - type: String contextPath: WAB.domain_get.password_change_plugin - description: "The name of plugin used to change passwords on this domain." + description: The name of plugin used to change passwords on this domain. - type: String contextPath: WAB.domain_get.ca_private_key description: 'The ssh private key of the signing authority for the ssh keys for accounts in the domain. Special values are allowed to automatically generate SSH key: "generate:RSA_1024", "generate:RSA_2048", "generate:RSA_4096", "generate:RSA_8192", "generate:DSA_1024", "generate:ECDSA_256", "generate:ECDSA_384", "generate:ECDSA_521", "generate:ED25519".' @@ -3326,18 +4346,51 @@ script: - type: String contextPath: WAB.domain_get.url description: The API URL to the resource. + - name: wab-get-external-authentication-group-mappings + description: 'Get the external authentication group mappings + + category: Ldap Mappings.' + arguments: + - name: group_by + description: Group the result-set by one property. Can take one of the values 'user_group' or 'domain'. + - name: q + description: Searches for a resource matching parameters. Used only if "group_by" is not set. + - name: sort + description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''domain,user_group''. Used only if "group_by" is not set.' + - name: offset + description: 'The index of first item to retrieve (starts and defaults to 0). Used only if "group_by" is not set.' + - name: limit + description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option. Used only if "group_by" is not set.' + - name: fields + description: 'The list of fields to return (separated by commas). By default all fields are returned.' + outputs: + - type: String + contextPath: WAB.authmappings_get.domain + description: The name of the domain for which the mapping is defined. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.authmappings_get.user_group + description: The name of the Bastion users group. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.authmappings_get.external_group + description: 'The name of the external group (LDAP/AD: Distinguished Name, Azure AD: name or ID), "*" means fallback mapping. Usable in the "q" parameter. Usable in the "sort" parameter.' - name: wab-get-ldap-users-of-domain - description: Get the LDAP users of a given domain. + description: 'Get the LDAP users of a given domain + + category: Ldap Users.' arguments: - name: domain description: A LDAP domain name. All users in this domain are returned. required: true - name: last_connection description: 'If set to true, the date of last connection is returned for each user returned. Be careful: this can slow down the request if a lot of users are returned.' + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: q description: 'Searches for a resource matching parameters.' - name: offset - description: The index of first item to retrieve (starts and defaults to 0). + description: 'The index of first item to retrieve (starts and defaults to 0).' - name: limit description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' - name: fields @@ -3351,7 +4404,7 @@ script: description: 'The user login.' - type: String contextPath: WAB.ldapuser_get.display_name - description: The displayed name. Usable in the "sort" parameter. + description: 'The displayed name. Usable in the "sort" parameter.' - type: String contextPath: WAB.ldapuser_get.email description: The email address. @@ -3377,14 +4430,31 @@ script: contextPath: WAB.ldapuser_get.url description: The API URL to the resource. - name: wab-get-ldap-user-of-domain - description: Get the LDAP user of a given domain. + description: 'Get the LDAP user of a given domain + + category: Ldap Users.' + arguments: + - name: domain + description: A LDAP domain name. All users in this domain are returned. + required: true + - name: user_name + description: 'A user name. If specified, only this user is returned.' + required: true + - name: last_connection + description: 'If set to true, the date of last connection is returned for each user returned. Be careful: this can slow down the request if a lot of users are returned.' + auto: PREDEFINED + predefined: + - 'true' + - 'false' + - name: fields + description: 'The list of fields to return (separated by commas). By default all fields are returned.' outputs: - type: String contextPath: WAB.ldapuser_get.user_name description: The user name. - type: String contextPath: WAB.ldapuser_get.login - description: The user login. + description: 'The user login.' - type: String contextPath: WAB.ldapuser_get.display_name description: 'The displayed name. Usable in the "sort" parameter.' @@ -3412,19 +4482,10 @@ script: - type: String contextPath: WAB.ldapuser_get.url description: The API URL to the resource. - arguments: - - name: domain - description: A LDAP domain name. All users in this domain are returned. - required: true - - name: user_name - description: A user name. If specified, only this user is returned. - required: true - - name: last_connection - description: 'If set to true, the date of last connection is returned for each user returned. Be careful: this can slow down the request if a lot of users are returned.' - - name: fields - description: The list of fields to return (separated by commas). By default all fields are returned. - name: wab-get-information-about-wallix-bastion-license - description: Get information about the WALLIX Bastion license. + description: 'Get information about the WALLIX Bastion license + + category: License Info.' outputs: - type: Boolean contextPath: WAB.licenseinfo_get.evaluation @@ -3529,7 +4590,9 @@ script: contextPath: WAB.licenseinfo_get.sm_target_max description: The max number of SM targets allowed by the license. - name: wab-post-logsiem - description: Write a message in /var/log/wabaudit.log and send it to the SIEM (if configured). + description: 'Write a message in /var/log/wabaudit.log and send it to the SIEM (if configured) + + category: Log Siem.' arguments: - name: logsiem_post_application description: The application name. @@ -3537,11 +4600,17 @@ script: - name: logsiem_post_message description: 'The message to write.' required: true + outputs: + - type: String + contextPath: WAB.post_logsiem.id + description: id of the created object. - name: wab-get-notifications - description: Get the notifications. + description: 'Get the notifications + + category: Notifications.' arguments: - name: q - description: Searches for a resource matching parameters. + description: "Searches for a resource matching parameters." - name: sort description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''notification_name''.' - name: offset @@ -3566,10 +4635,10 @@ script: description: Notification type. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.notification_get.destination - description: Destination for notification; for the type "email", this is a list of recipient emails separated by ";". Usable in the "q" parameter. Usable in the "sort" parameter. + description: 'Destination for notification; for the type "email", this is a list of recipient emails separated by ";". Usable in the "q" parameter. Usable in the "sort" parameter.' - type: String contextPath: WAB.notification_get.language - description: The notification language (in email). Usable in the "q" parameter. Usable in the "sort" parameter. + description: 'The notification language (in email). Usable in the "q" parameter. Usable in the "sort" parameter.' - type: String contextPath: WAB.notification_get.events description: The list of events that will trigger a notification. @@ -3577,7 +4646,9 @@ script: contextPath: WAB.notification_get.url description: The API URL to the resource. - name: wab-add-notification - description: Add a notification. + description: 'Add a notification + + category: Notifications.' arguments: - name: notification_post_notification_name description: The notification name. @@ -3587,20 +4658,44 @@ script: - name: notification_post_enabled description: Notification is enabled. required: true + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: notification_post_type description: Notification type. required: true + auto: PREDEFINED + predefined: + - email - name: notification_post_destination description: Destination for notification; for the type "email", this is a list of recipient emails separated by ";". required: true - name: notification_post_language description: The notification language (in email). required: true + auto: PREDEFINED + predefined: + - de + - en + - es + - fr + - ru - name: notification_post_events - description: The list of events that will trigger a notification. + description: 'The list of events that will trigger a notification. + + Comma-separated list (use [] for an empty list). + + Possible values: cx_equipment,daily_reporting,external_storage_full,filesystem_full,integrity_error,licence_notifications,new_fingerprint,password_expired,pattern_found,primary_cx_failed,raid_error,rdp_outcxn_found,rdp_pattern_found,rdp_process_found,secondary_cx_failed,sessionlog_purge,watchdog_notifications,wrong_fingerprint.' isArray: true + outputs: + - type: String + contextPath: WAB.add_notification.id + description: id of the created object. - name: wab-get-notification - description: Get the notification. + description: 'Get the notification + + category: Notifications.' arguments: - name: notification_id description: A notification id or name. If specified, only this notification is returned. @@ -3634,36 +4729,64 @@ script: contextPath: WAB.notification_get.url description: The API URL to the resource. - name: wab-edit-notification - description: Edit a notification. + description: 'Edit a notification + + category: Notifications.' arguments: - name: notification_id description: The notification id or name to edit. required: true - name: force description: The default value is false. When it is set to true the values of the events are replaced, otherwise the values are added to the existing ones. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: notification_put_notification_name description: The notification name. - name: notification_put_description description: The notification description. - name: notification_put_enabled description: Notification is enabled. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: notification_put_type description: Notification type. + auto: PREDEFINED + predefined: + - email - name: notification_put_destination description: Destination for notification; for the type "email", this is a list of recipient emails separated by ";". - name: notification_put_language description: The notification language (in email). + auto: PREDEFINED + predefined: + - de + - en + - es + - fr + - ru - name: notification_put_events - description: The list of events that will trigger a notification. + description: 'The list of events that will trigger a notification. + + Comma-separated list (use [] for an empty list). + + Possible values: cx_equipment,daily_reporting,external_storage_full,filesystem_full,integrity_error,licence_notifications,new_fingerprint,password_expired,pattern_found,primary_cx_failed,raid_error,rdp_outcxn_found,rdp_pattern_found,rdp_process_found,secondary_cx_failed,sessionlog_purge,watchdog_notifications,wrong_fingerprint.' isArray: true - name: wab-delete-notification - description: Delete a notification. + description: 'Delete a notification + + category: Notifications.' arguments: - name: notification_id - description: 'The notification id or name to delete.' + description: The notification id or name to delete. required: true - name: wab-get-object-to-onboard - description: Get object to onboard, by type (either devices with their linked accounts or global accounts alone). + description: 'Get object to onboard, by type (either devices with their linked accounts or global accounts alone) + + category: Onboarding Objects.' arguments: - name: object_type description: 'The type of object, one of : ''devices'', ''global_accounts''.' @@ -3687,10 +4810,10 @@ script: description: The device id. Usable in the "q" parameter. Usable in the "sort" parameter. / The account id. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.onboarding_objects_get.description - description: 'The device description. Usable in the "q" parameter. Usable in the "sort" parameter. / The account description. Usable in the "q" parameter. Usable in the "sort" parameter.' + description: The device description. Usable in the "q" parameter. Usable in the "sort" parameter. / The account description. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.onboarding_objects_get.onboard_status - description: 'Onboarding status of the device Usable in the "q" parameter. Usable in the "sort" parameter. / Onboarding status of the account Usable in the "q" parameter. Usable in the "sort" parameter.' + description: Onboarding status of the device Usable in the "q" parameter. Usable in the "sort" parameter. / Onboarding status of the account Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.onboarding_objects_get.first_seen.id description: The scan job id. @@ -3707,34 +4830,315 @@ script: contextPath: WAB.onboarding_objects_get.first_seen.start description: Scan job start timestamp. - type: String - contextPath: WAB.onboarding_objects_get.first_seen.end - description: Scan job end timestamp. + contextPath: WAB.onboarding_objects_get.first_seen.end + description: Scan job end timestamp. + - type: String + contextPath: WAB.onboarding_objects_get.last_seen.id + description: The scan job id. + - type: String + contextPath: WAB.onboarding_objects_get.last_seen.type + description: Scan type. + - type: String + contextPath: WAB.onboarding_objects_get.last_seen.error + description: Error message. + - type: String + contextPath: WAB.onboarding_objects_get.last_seen.status + description: Scan job status. + - type: String + contextPath: WAB.onboarding_objects_get.last_seen.start + description: Scan job start timestamp. + - type: String + contextPath: WAB.onboarding_objects_get.last_seen.end + description: Scan job end timestamp. + - type: String + contextPath: WAB.onboarding_objects_get.url + description: The API URL to the resource. + - name: wab-get-password-change-policies + description: 'Get the password change policies + + category: Password Change Policies.' + arguments: + - name: q + description: 'Searches for a resource matching parameters.' + - name: sort + description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''password_change_policy_name''.' + - name: offset + description: The index of first item to retrieve (starts and defaults to 0). + - name: limit + description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' + outputs: + - type: String + contextPath: WAB.passwordchangepolicy_get.id + description: 'The password change policy id. Usable in the "q" parameter. Usable in the "sort" parameter.' + - type: String + contextPath: WAB.passwordchangepolicy_get.password_change_policy_name + description: 'The password change policy name. Usable in the "q" parameter. Usable in the "sort" parameter.' + - type: String + contextPath: WAB.passwordchangepolicy_get.description + description: The password change policy description. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Number + contextPath: WAB.passwordchangepolicy_get.password_length + description: Number of chars in password. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Number + contextPath: WAB.passwordchangepolicy_get.special_chars + description: The minimum number of special chars in password (0 = no minimum, null = no special chars at all). Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Number + contextPath: WAB.passwordchangepolicy_get.lower_chars + description: The minimum number of lower case chars in password (0 = no minimum, null = no lower case chars at all). Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Number + contextPath: WAB.passwordchangepolicy_get.upper_chars + description: 'The minimum number of upper case chars in password (0 = no minimum, null = no upper case chars at all). Usable in the "q" parameter. Usable in the "sort" parameter.' + - type: Number + contextPath: WAB.passwordchangepolicy_get.digit_chars + description: The minimum number of digit chars in password (0 = no minimum, null = no digit chars at all). Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.passwordchangepolicy_get.exclude_chars + description: Characters to exclude in password. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.passwordchangepolicy_get.ssh_key_type + description: The SSH key type. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Number + contextPath: WAB.passwordchangepolicy_get.ssh_key_size + description: The SSH key size (in bits). Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.passwordchangepolicy_get.change_period + description: "\nThe period to change password.\n\nString value must be a valid cron syntax (e.g. '\\* \\* \\* \\* \\*').\n\nAliases are allowed:\n\n@hourly → 0 \\* \\* \\* \\*\n@daily → 0 0 \\* \\* \\*\n@weekly → 0 0 \\* \\* 0\n@monthly → 0 0 1 \\* \\*\n@yearly → 0 0 1 1 \\*\n\nNote: An empty string (or null) will deactivate the change password schedule.\nMoreover, @reboot is not allowed.\n Usable in the \"q\" parameter. Usable in the \"sort\" parameter." + - type: String + contextPath: WAB.passwordchangepolicy_get.url + description: The API URL to the resource. + - name: wab-add-password-change-policy + description: 'Add a password change policy. Note: at least password or SSH options must be given in the policy (and both can be used at same time) + + category: Password Change Policies.' + arguments: + - name: passwordchangepolicy_post_password_change_policy_name + description: The password change policy name. + required: true + - name: passwordchangepolicy_post_description + description: The password change policy description. + - name: passwordchangepolicy_post_password_length + description: Number of chars in password. (enter null for null value). + - name: passwordchangepolicy_post_special_chars + description: The minimum number of special chars in password (0 = no minimum, null = no special chars at all). (enter null for null value). + - name: passwordchangepolicy_post_lower_chars + description: 'The minimum number of lower case chars in password (0 = no minimum, null = no lower case chars at all). (enter null for null value).' + - name: passwordchangepolicy_post_upper_chars + description: The minimum number of upper case chars in password (0 = no minimum, null = no upper case chars at all). (enter null for null value). + - name: passwordchangepolicy_post_digit_chars + description: 'The minimum number of digit chars in password (0 = no minimum, null = no digit chars at all). (enter null for null value).' + - name: passwordchangepolicy_post_exclude_chars + description: Characters to exclude in password. (enter null for null value). + - name: passwordchangepolicy_post_ssh_key_type + description: The SSH key type. (enter null for null value). + - name: passwordchangepolicy_post_ssh_key_size + description: The SSH key size (in bits). (enter null for null value). + - name: passwordchangepolicy_post_change_period + description: "\nThe period to change password.\n\nString value must be a valid cron syntax (e.g. '\\* \\* \\* \\* \\*').\n\nAliases are allowed:\n\n@hourly → 0 \\* \\* \\* \\*\n@daily → 0 0 \\* \\* \\*\n@weekly → 0 0 \\* \\* 0\n@monthly → 0 0 1 \\* \\*\n@yearly → 0 0 1 1 \\*\n\nNote: An empty string (or null) will deactivate the change password schedule.\nMoreover, @reboot is not allowed.\n (enter null for null value)." + outputs: + - type: String + contextPath: WAB.add_password_change_policy.id + description: id of the created object. + - name: wab-get-password-change-policy + description: 'Get the password change policy + + category: Password Change Policies.' + arguments: + - name: policy_id + description: A password change policy id or name. If specified, only this password change policy is returned. + required: true + outputs: + - type: String + contextPath: WAB.passwordchangepolicy_get.id + description: The password change policy id. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.passwordchangepolicy_get.password_change_policy_name + description: The password change policy name. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.passwordchangepolicy_get.description + description: The password change policy description. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Number + contextPath: WAB.passwordchangepolicy_get.password_length + description: Number of chars in password. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Number + contextPath: WAB.passwordchangepolicy_get.special_chars + description: The minimum number of special chars in password (0 = no minimum, null = no special chars at all). Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Number + contextPath: WAB.passwordchangepolicy_get.lower_chars + description: The minimum number of lower case chars in password (0 = no minimum, null = no lower case chars at all). Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Number + contextPath: WAB.passwordchangepolicy_get.upper_chars + description: The minimum number of upper case chars in password (0 = no minimum, null = no upper case chars at all). Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Number + contextPath: WAB.passwordchangepolicy_get.digit_chars + description: The minimum number of digit chars in password (0 = no minimum, null = no digit chars at all). Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.passwordchangepolicy_get.exclude_chars + description: Characters to exclude in password. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.passwordchangepolicy_get.ssh_key_type + description: The SSH key type. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Number + contextPath: WAB.passwordchangepolicy_get.ssh_key_size + description: The SSH key size (in bits). Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.passwordchangepolicy_get.change_period + description: "\nThe period to change password.\n\nString value must be a valid cron syntax (e.g. '\\* \\* \\* \\* \\*').\n\nAliases are allowed:\n\n@hourly → 0 \\* \\* \\* \\*\n@daily → 0 0 \\* \\* \\*\n@weekly → 0 0 \\* \\* 0\n@monthly → 0 0 1 \\* \\*\n@yearly → 0 0 1 1 \\*\n\nNote: An empty string (or null) will deactivate the change password schedule.\nMoreover, @reboot is not allowed.\n Usable in the \"q\" parameter. Usable in the \"sort\" parameter." + - type: String + contextPath: WAB.passwordchangepolicy_get.url + description: The API URL to the resource. + - name: wab-edit-password-change-policy + description: 'Edit a password change policy + + category: Password Change Policies.' + arguments: + - name: policy_id + description: The password change policy id or name to edit. + required: true + - name: passwordchangepolicy_put_password_change_policy_name + description: The password change policy name. + - name: passwordchangepolicy_put_description + description: The password change policy description. + - name: passwordchangepolicy_put_password_length + description: Number of chars in password. (enter null for null value). + - name: passwordchangepolicy_put_special_chars + description: The minimum number of special chars in password (0 = no minimum, null = no special chars at all). (enter null for null value). + - name: passwordchangepolicy_put_lower_chars + description: The minimum number of lower case chars in password (0 = no minimum, null = no lower case chars at all). (enter null for null value). + - name: passwordchangepolicy_put_upper_chars + description: The minimum number of upper case chars in password (0 = no minimum, null = no upper case chars at all). (enter null for null value). + - name: passwordchangepolicy_put_digit_chars + description: The minimum number of digit chars in password (0 = no minimum, null = no digit chars at all). (enter null for null value). + - name: passwordchangepolicy_put_exclude_chars + description: Characters to exclude in password. (enter null for null value). + - name: passwordchangepolicy_put_ssh_key_type + description: The SSH key type. (enter null for null value). + - name: passwordchangepolicy_put_ssh_key_size + description: The SSH key size (in bits). (enter null for null value). + - name: passwordchangepolicy_put_change_period + description: "\nThe period to change password.\n\nString value must be a valid cron syntax (e.g. '\\* \\* \\* \\* \\*').\n\nAliases are allowed:\n\n@hourly → 0 \\* \\* \\* \\*\n@daily → 0 0 \\* \\* \\*\n@weekly → 0 0 \\* \\* 0\n@monthly → 0 0 1 \\* \\*\n@yearly → 0 0 1 1 \\*\n\nNote: An empty string (or null) will deactivate the change password schedule.\nMoreover, @reboot is not allowed.\n (enter null for null value)." + - name: wab-delete-password-change-policy + description: 'Delete a password change policy + + category: Password Change Policies.' + arguments: + - name: policy_id + description: The password change policy id or name to delete. + required: true + - name: wab-get-passwordrights + description: 'Get current user''s or the user ''user_name'' password rights on accounts (for checkout/checkin) + + category: Password Rights.' + arguments: + - name: count + description: The default value is false. When it is set to true, the headers x-total-count and x-filtered-count are returned. + auto: PREDEFINED + predefined: + - 'true' + - 'false' + - name: q + description: 'Only a simple string to search is allowed in this resource (for example: ''q=windows''). The search is performed on the following fields only: account, account_description, device, device_alias, device_description, application, application_description, domain, domain_description, authorization, authorization_description.' + - name: sort + description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''account,domain,device,application''.' + - name: offset + description: The index of first item to retrieve (starts and defaults to 0). + - name: limit + description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.passwordrights_get.type + description: The account type. + - type: String + contextPath: WAB.passwordrights_get.target + description: 'The complete target identifier which can be used in resource /targetpasswords (format: "account_name@global_domain_name"). / The complete target identifier which can be used in resource /targetpasswords (example: "account@domain@device"). / The complete target identifier which can be used in resource /targetpasswords (format: "account_name@local_domain_name@application_name").' + - type: String + contextPath: WAB.passwordrights_get.account + description: The account name. Usable in the "sort" parameter. + - type: String + contextPath: WAB.passwordrights_get.account_description + description: The account description. Usable in the "sort" parameter. + - type: String + contextPath: WAB.passwordrights_get.domain + description: The global domain name. Usable in the "sort" parameter. / The local domain name on device. Usable in the "sort" parameter. / The local domain name on application. Usable in the "sort" parameter. + - type: String + contextPath: WAB.passwordrights_get.domain_description + description: The domain description. Usable in the "sort" parameter. + - type: Boolean + contextPath: WAB.passwordrights_get.domain_vault + description: The domain accounts are stored on an external vault. Usable in the "sort" parameter. + - type: Boolean + contextPath: WAB.passwordrights_get.authorization_approval + description: True if an approval workflow is defined in the authorization, otherwise False. Usable in the "sort" parameter. + - type: String + contextPath: WAB.passwordrights_get.authorization + description: The authorization name. Usable in the "sort" parameter. + - type: String + contextPath: WAB.passwordrights_get.authorization_description + description: The authorization description. Usable in the "sort" parameter. + - type: String + contextPath: WAB.passwordrights_get.right_fingerprint + description: The fingerprint of the right (hash of authorization and target uid). + - name: wab-get-passwordrights-user-name + description: 'Get current user''s or the user ''user_name'' password rights on accounts (for checkout/checkin) + + category: Password Rights.' + arguments: + - name: user_name + description: If specified, the user_name password rights is returned. + required: true + - name: count + description: 'The default value is false. When it is set to true, the headers x-total-count and x-filtered-count are returned.' + auto: PREDEFINED + predefined: + - 'true' + - 'false' + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.passwordrights_get.type + description: The account type. + - type: String + contextPath: WAB.passwordrights_get.target + description: 'The complete target identifier which can be used in resource /targetpasswords (format: "account_name@global_domain_name"). / The complete target identifier which can be used in resource /targetpasswords (example: "account@domain@device"). / The complete target identifier which can be used in resource /targetpasswords (format: "account_name@local_domain_name@application_name").' + - type: String + contextPath: WAB.passwordrights_get.account + description: The account name. Usable in the "sort" parameter. - type: String - contextPath: WAB.onboarding_objects_get.last_seen.id - description: The scan job id. + contextPath: WAB.passwordrights_get.account_description + description: The account description. Usable in the "sort" parameter. - type: String - contextPath: WAB.onboarding_objects_get.last_seen.type - description: Scan type. + contextPath: WAB.passwordrights_get.domain + description: The global domain name. Usable in the "sort" parameter. / The local domain name on device. Usable in the "sort" parameter. / The local domain name on application. Usable in the "sort" parameter. - type: String - contextPath: WAB.onboarding_objects_get.last_seen.error - description: Error message. + contextPath: WAB.passwordrights_get.domain_description + description: The domain description. Usable in the "sort" parameter. + - type: Boolean + contextPath: WAB.passwordrights_get.domain_vault + description: The domain accounts are stored on an external vault. Usable in the "sort" parameter. + - type: Boolean + contextPath: WAB.passwordrights_get.authorization_approval + description: True if an approval workflow is defined in the authorization, otherwise False. Usable in the "sort" parameter. - type: String - contextPath: WAB.onboarding_objects_get.last_seen.status - description: Scan job status. + contextPath: WAB.passwordrights_get.authorization + description: The authorization name. Usable in the "sort" parameter. - type: String - contextPath: WAB.onboarding_objects_get.last_seen.start - description: Scan job start timestamp. + contextPath: WAB.passwordrights_get.authorization_description + description: The authorization description. Usable in the "sort" parameter. - type: String - contextPath: WAB.onboarding_objects_get.last_seen.end - description: Scan job end timestamp. + contextPath: WAB.passwordrights_get.right_fingerprint + description: The fingerprint of the right (hash of authorization and target uid). - type: String - contextPath: WAB.onboarding_objects_get.url - description: The API URL to the resource. + contextPath: WAB.passwordrights_get.user_name + description: the user_name. - name: wab-get-profiles - description: Get the profiles. + description: 'Get the profiles + + category: Profiles.' arguments: - name: q - description: "Searches for a resource matching parameters." + description: Searches for a resource matching parameters. - name: sort description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''profile_name''.' - name: offset @@ -3843,17 +5247,16 @@ script: - type: String contextPath: WAB.profile_get.url description: The API URL to the resource. - - type: String - contextPath: WAB.profile_get.gui_features.dashboards - description: 'deprecated: unused field.' - name: wab-get-profile - description: Get the profile. + description: 'Get the profile + + category: Profiles.' arguments: - name: profile_id description: A profile id or name. If specified, only this profile is returned. required: true - name: fields - description: 'The list of fields to return (separated by commas). By default all fields are returned.' + description: The list of fields to return (separated by commas). By default all fields are returned. outputs: - type: String contextPath: WAB.profile_get.id @@ -3866,7 +5269,7 @@ script: description: Profile is editable. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.profile_get.description - description: The target group description. Usable in the "q" parameter. Usable in the "sort" parameter. + description: 'The target group description. Usable in the "q" parameter. Usable in the "sort" parameter.' - type: String contextPath: WAB.profile_get.gui_features.wab_audit description: wab audit. @@ -3954,22 +5357,21 @@ script: - type: String contextPath: WAB.profile_get.url description: The API URL to the resource. - - type: String - contextPath: WAB.profile_get.gui_features.dashboards - description: 'deprecated: unused field.' - name: wab-get-scanjobs - description: Get the scanjobs. + description: 'Get the scanjobs + + category: Scan Jobs.' arguments: - name: q description: Searches for a resource matching parameters. - name: sort description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''scan_name''.' - name: offset - description: The index of first item to retrieve (starts and defaults to 0). + description: 'The index of first item to retrieve (starts and defaults to 0).' - name: limit description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' - name: fields - description: The list of fields to return (separated by commas). By default all fields are returned. + description: 'The list of fields to return (separated by commas). By default all fields are returned.' outputs: - type: String contextPath: WAB.scanjob_get.id @@ -3982,7 +5384,7 @@ script: description: Error message. - type: String contextPath: WAB.scanjob_get.status - description: Scan job status Usable in the "q" parameter. Usable in the "sort" parameter. + description: 'Scan job status Usable in the "q" parameter. Usable in the "sort" parameter.' - type: String contextPath: WAB.scanjob_get.start description: Scan job start timestamp. Usable in the "q" parameter. Usable in the "sort" parameter. @@ -3990,19 +5392,27 @@ script: contextPath: WAB.scanjob_get.end description: Scan job end timestamp Usable in the "q" parameter. Usable in the "sort" parameter. - name: wab-start-scan-job-manually - description: Start a scan job manually. + description: 'Start a scan job manually + + category: Scan Jobs.' arguments: - name: scanjob_post_scan_id description: Scan definition id. required: true + outputs: + - type: String + contextPath: WAB.start_scan_job_manually.id + description: id of the created object. - name: wab-get-scanjob - description: Get the scanjob. + description: 'Get the scanjob + + category: Scan Jobs.' arguments: - name: scanjob_id - description: "A scan job id or name. If specified, only this scan job is returned." + description: 'A scan job id or name. If specified, only this scan job is returned.' required: true - name: fields - description: The list of fields to return (separated by commas). By default all fields are returned. + description: 'The list of fields to return (separated by commas). By default all fields are returned.' outputs: - type: String contextPath: WAB.scanjob_get.id @@ -4015,7 +5425,7 @@ script: description: Error message. - type: String contextPath: WAB.scanjob_get.status - description: Scan job status Usable in the "q" parameter. Usable in the "sort" parameter. + description: 'Scan job status Usable in the "q" parameter. Usable in the "sort" parameter.' - type: String contextPath: WAB.scanjob_get.start description: Scan job start timestamp. Usable in the "q" parameter. Usable in the "sort" parameter. @@ -4023,16 +5433,20 @@ script: contextPath: WAB.scanjob_get.end description: Scan job end timestamp Usable in the "q" parameter. Usable in the "sort" parameter. - name: wab-cancel-scan-job - description: Cancel a scan job. + description: 'Cancel a scan job + + category: Scan Jobs.' arguments: - name: scanjob_id - description: The scan id or name to edit. + description: 'The scan id or name to edit.' required: true - name: wab-get-scans - description: Get the scans. + description: 'Get the scans + + category: Scans.' arguments: - name: q - description: Searches for a resource matching parameters. + description: 'Searches for a resource matching parameters.' - name: sort description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''scan_name''.' - name: offset @@ -4079,13 +5493,15 @@ script: contextPath: WAB.scan_get.url description: The API URL to the resource. - name: wab-get-scan - description: Get the scan. + description: 'Get the scan + + category: Scans.' arguments: - name: scan_id - description: A scan id or name. If specified, only this scan is returned. + description: 'A scan id or name. If specified, only this scan is returned.' required: true - name: fields - description: 'The list of fields to return (separated by commas). By default all fields are returned.' + description: The list of fields to return (separated by commas). By default all fields are returned. outputs: - type: String contextPath: WAB.scan_get.id @@ -4098,7 +5514,7 @@ script: description: State of the job schedule. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.scan_get.periodicity - description: 'Periodicity of the scan, in cron notation. Usable in the "q" parameter.' + description: Periodicity of the scan, in cron notation. Usable in the "q" parameter. - type: String contextPath: WAB.scan_get.description description: Description of the scan. Usable in the "q" parameter. Usable in the "sort" parameter. @@ -4107,7 +5523,7 @@ script: description: Emails to notify when a job is finished. - type: String contextPath: WAB.scan_get.last_job.id - description: 'UID of the job.' + description: UID of the job. - type: String contextPath: WAB.scan_get.last_job.status description: status. @@ -4123,13 +5539,89 @@ script: - type: String contextPath: WAB.scan_get.url description: The API URL to the resource. + - name: wab-edit-scan + description: 'Edit a scan + + category: Scans.' + arguments: + - name: scan_id + description: 'The scan id or name to edit.' + required: true + - name: scan_put_name + description: Scan name. + - name: scan_put_active + description: State of the job schedule. + auto: PREDEFINED + predefined: + - 'true' + - 'false' + - name: scan_put_periodicity + description: Periodicity of the scan, in cron notation. + - name: scan_put_description + description: 'Description of the scan.' + - name: scan_put_emails + description: 'Emails to notify when a job is finished. + + Comma-separated list (use [] for an empty list).' + isArray: true + - name: scan_put_subnets + description: 'List of subnets to scan. + + Comma-separated list (use [] for an empty list).' + isArray: true + - name: scan_put_banner_regex + description: 'Regexes to mach on SSH banner. + + Comma-separated list (use [] for an empty list).' + isArray: true + - name: scan_put_scan_for_accounts + description: Scan for accounts on discovered devices. + auto: PREDEFINED + predefined: + - 'true' + - 'false' + - name: scan_put_master_accounts + description: 'The master accounts used to log and the devices empty if scan_for_accounts is false. + + Comma-separated list (use [] for an empty list).' + isArray: true + - name: scan_put_search_filter + description: Active Directory search filter. + - name: scan_put_dn_list + description: 'List of Distinguished Names to search. + + Comma-separated list (use [] for an empty list).' + isArray: true + - name: scan_put_devices + description: 'The devices to scan. + + Comma-separated list (use [] for an empty list).' + isArray: true + - name: wab-delete-scan + description: 'Delete a scan + + category: Scans.' + arguments: + - name: scan_id + description: The scan id or name to delete. + required: true - name: wab-get-sessionrights - description: Get current user's or the user 'user_name' session rights (connections via proxies). + description: 'Get current user''s or the user ''user_name'' session rights (connections via proxies) + + category: Session Rights.' arguments: - name: count description: The default value is false. When set to true, the headers x-total-count and x-filtered-count are returned. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: last_connection description: The default value is false. When set to true, the last connection date is returned for each authorizations. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: q description: 'Only a simple string to search is allowed in this resource (for exemple: ''q=windows''). The search is performed on the following fields only: account, account_description, device, device_alias, device_description, application, application_description, service_protocol, domain, domain_description, authorization, authorization_description.' - name: sort @@ -4190,30 +5682,40 @@ script: contextPath: WAB.sessionrights_get.last_connection description: 'The date of the last connection (format: "yyyy-mm-dd hh:mm:ss"). Usable in the "sort" parameter.' - name: wab-get-sessionrights-user-name - description: Get current user's or the user 'user_name' session rights (connections via proxies). + description: 'Get current user''s or the user ''user_name'' session rights (connections via proxies) + + category: Session Rights.' arguments: - name: user_name description: If specified, the user_name session rights is returned. required: true - name: count - description: 'The default value is false. When set to true, the headers x-total-count and x-filtered-count are returned.' + description: The default value is false. When set to true, the headers x-total-count and x-filtered-count are returned. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: last_connection - description: 'The default value is false. When set to true, the last connection date is returned for each authorizations.' + description: The default value is false. When set to true, the last connection date is returned for each authorizations. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: fields - description: 'The list of fields to return (separated by commas). By default all fields are returned.' + description: The list of fields to return (separated by commas). By default all fields are returned. outputs: - type: String contextPath: WAB.sessionrights_get.type description: The resource type. - type: String contextPath: WAB.sessionrights_get.account - description: 'The account name. Usable in the "sort" parameter.' + description: The account name. Usable in the "sort" parameter. - type: String contextPath: WAB.sessionrights_get.account_description - description: 'The account description. Usable in the "sort" parameter.' + description: The account description. Usable in the "sort" parameter. - type: String contextPath: WAB.sessionrights_get.domain - description: The domain name. Usable in the "sort" parameter. + description: 'The domain name. Usable in the "sort" parameter.' - type: String contextPath: WAB.sessionrights_get.domain_description description: The domain description. Usable in the "sort" parameter. @@ -4254,12 +5756,14 @@ script: contextPath: WAB.sessionrights_get.user_name description: the user_name. - name: wab-get-sessions - description: Get the sessions. + description: 'Get the sessions + + category: Sessions.' arguments: - name: session_id description: A session id. If specified, only this session is returned. - name: otp - description: 'User''s OTP (One Time Password) If specified, only the session initiated with the provided OTP is returned.' + description: User's OTP (One Time Password) If specified, only the session initiated with the provided OTP is returned. - name: status description: 'Status of sessions to return: "closed" for closed sessions (default) or "current" for current sessions.' - name: from_date @@ -4463,10 +5967,12 @@ script: contextPath: WAB.session_get.url description: The API URL to the resource. - name: wab-edit-session - description: Edit a session. + description: 'Edit a session + + category: Sessions.' arguments: - name: session_id - description: 'The session id to edit.' + description: The session id to edit. required: true - name: action description: 'The action on the session: ''edit'' to edit the session (default), ''kill'' to kill the session.' @@ -4474,13 +5980,19 @@ script: description: The new session description. required: true - name: wab-get-session-metadata - description: 'Get the metadata of one or multiple sessions.' + description: 'Get the metadata of one or multiple sessions + + category: Sessions Metadata.' arguments: - name: session_ids description: The session id, multiple IDs can be separated by commas. required: true - name: download - description: 'The default value is false. When it is set to true, the session metadata is sent as a file instead of JSON (recommended for large metadata). The download is possible only with a single session id.' + description: The default value is false. When it is set to true, the session metadata is sent as a file instead of JSON (recommended for large metadata). The download is possible only with a single session id. + auto: PREDEFINED + predefined: + - 'true' + - 'false' outputs: - type: String contextPath: WAB.session_metadata_get.session_id @@ -4489,10 +6001,12 @@ script: contextPath: WAB.session_metadata_get.metadata description: The session metadata content. - name: wab-get-session-sharing-requests - description: Get session sharing requests. + description: 'Get session sharing requests + + category: Sessions Requests.' arguments: - name: request_id - description: "A request id. If specified, only this request is returned." + description: A request id. If specified, only this request is returned. - name: session_id description: A session id. If specified, only the request linked to this session is returned. outputs: @@ -4524,7 +6038,9 @@ script: contextPath: WAB.session_request_get.guest_id description: A Guest ID (random if unknown invited guest) or a username (if known Bastion user). Usable in the "sort" parameter. - name: wab-create-session-request - description: "Create a session request." + description: 'Create a session request + + category: Sessions Requests.' arguments: - name: session_request_post_session_id description: The session id. @@ -4532,20 +6048,30 @@ script: - name: session_request_post_mode description: The session sharing mode. required: true + auto: PREDEFINED + predefined: + - view_only + - view_control - name: wab-delete-pending-or-live-session-request - description: Delete a pending or a live session request. + description: 'Delete a pending or a live session request + + category: Sessions Requests.' arguments: - name: request_id description: The session sharing request to delete. required: true - name: wab-get-latest-snapshot-of-running-session - description: Get the latest snapshot of a running session. + description: 'Get the latest snapshot of a running session + + category: Sessions Snapshots.' arguments: - name: session_id description: The session id. required: true - name: wab-get-status-of-trace-generation - description: Get the status of a trace generation. + description: 'Get the status of a trace generation + + category: Sessions Traces.' arguments: - name: session_id description: The session id. @@ -4556,6 +6082,10 @@ script: description: Duration of the trace to generate (in seconds). - name: download description: The default value is false. When it is set to true, the session trace is sent as a file instead of JSON output with the generation status. + auto: PREDEFINED + predefined: + - 'true' + - 'false' outputs: - type: String contextPath: WAB.session_trace_get.session_id @@ -4579,17 +6109,25 @@ script: contextPath: WAB.session_trace_get.eta description: Estimated time before end of generation (in seconds). - name: wab-generate-trace-for-session - description: Generate a trace for a session. + description: 'Generate a trace for a session + + category: Sessions Traces.' arguments: - name: session_trace_post_session_id - description: 'The session id.' + description: The session id. required: true - name: session_trace_post_date description: 'The starting date/time (format: "yyyy-mm-dd hh:mm:ss").' - name: session_trace_post_duration description: The duration (in seconds). + outputs: + - type: String + contextPath: WAB.generate_trace_for_session.id + description: id of the created object. - name: wab-get-wallix-bastion-usage-statistics - description: Get the WALLIX Bastion usage statistics. If no from_date or to_date are supplied it will return the statistics for the last full calendar month. + description: 'Get the WALLIX Bastion usage statistics. If no from_date or to_date are supplied it will return the statistics for the last full calendar month + + category: Statistics.' arguments: - name: from_date description: 'Get statistics from this date at midnight (format: "yyyy-mm-dd").' @@ -4616,7 +6154,7 @@ script: description: Lowest simultaneous objects. - type: Number contextPath: WAB.statistics_get.secondary_connections.average - description: 'Average simultaneous objects.' + description: Average simultaneous objects. - type: Number contextPath: WAB.statistics_get.secondary_connections.max description: Maximum simultaneous objects. @@ -4639,7 +6177,9 @@ script: contextPath: WAB.statistics_get.application_count.max description: Maximum simultaneous objects. - name: wab-get-target-groups - description: Get the target groups. + description: 'Get the target groups + + category: Target Groups.' arguments: - name: device description: Return only the targetgroups this device belongs to. @@ -4764,15 +6304,23 @@ script: contextPath: WAB.targetgroups_get.url description: The API URL to the resource. - name: wab-add-target-group - description: Add a target group. + description: 'Add a target group + + category: Target Groups.' arguments: - name: targetgroups_post_group_name description: The target group name. required: true - name: targetgroups_post_description description: The target group description. + outputs: + - type: String + contextPath: WAB.add_target_group.id + description: id of the created object. - name: wab-get-target-group - description: Get the target group. + description: 'Get the target group + + category: Target Groups.' arguments: - name: group_id description: A target group id or name. If specified, only this target group is returned. @@ -4892,25 +6440,35 @@ script: contextPath: WAB.targetgroups_get.url description: The API URL to the resource. - name: wab-edit-target-group - description: Edit a target group. + description: 'Edit a target group + + category: Target Groups.' arguments: - name: group_id description: The group id or name to edit. required: true - name: force description: The default value is false. When it is set to true the values of the targets are replaced, otherwise the values are added to the existing ones. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: targetgroups_put_group_name description: The target group name. - name: targetgroups_put_description description: The target group description. - name: wab-delete-target-group - description: Delete a target group. + description: 'Delete a target group + + category: Target Groups.' arguments: - name: group_id description: The group id or name to delete. required: true - name: wab-delete-target-from-group - description: Delete a target from a group. + description: 'Delete a target from a group + + category: Target Groups.' arguments: - name: group_id description: The group id or name to delete. @@ -4921,8 +6479,143 @@ script: - name: target_id description: The target id or name to remove from the group. required: true + - name: wab-get-timeframes + description: 'Get the timeframes + + category: Timeframes.' + arguments: + - name: q + description: Searches for a resource matching parameters. + - name: sort + description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''timeframe_name''.' + - name: offset + description: The index of first item to retrieve (starts and defaults to 0). + - name: limit + description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.timeframe_get.id + description: The timeframe id. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.timeframe_get.timeframe_name + description: The timeframe name. No space is permitted at first or end. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.timeframe_get.description + description: The timeframe description. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Boolean + contextPath: WAB.timeframe_get.is_overtimable + description: Do not close sessions at the end of the time period. + - type: String + contextPath: WAB.timeframe_get.periods.start_date + description: The period start date. Must respect the format "yyyy-mm-dd". + - type: String + contextPath: WAB.timeframe_get.periods.end_date + description: The period end date. Must respect the format "yyyy-mm-dd". + - type: String + contextPath: WAB.timeframe_get.periods.start_time + description: The period start time. Must respect the format "hh:mm". + - type: String + contextPath: WAB.timeframe_get.periods.end_time + description: The period end time. Must respect the format "hh:mm". + - type: String + contextPath: WAB.timeframe_get.periods.week_days + description: The period week days. + - type: String + contextPath: WAB.timeframe_get.url + description: The API URL to the resource. + - name: wab-add-timeframe + description: 'Add a timeframe + + category: Timeframes.' + arguments: + - name: timeframe_post_timeframe_name + description: The timeframe name. No space is permitted at first or end. + required: true + - name: timeframe_post_description + description: The timeframe description. + - name: timeframe_post_is_overtimable + description: Do not close sessions at the end of the time period. + auto: PREDEFINED + predefined: + - 'true' + - 'false' + outputs: + - type: String + contextPath: WAB.add_timeframe.id + description: id of the created object. + - name: wab-get-timeframe + description: 'Get the timeframe + + category: Timeframes.' + arguments: + - name: timeframe_id + description: A timeframe id or name. If specified, only this timeframe is returned. + required: true + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.timeframe_get.id + description: The timeframe id. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.timeframe_get.timeframe_name + description: The timeframe name. No space is permitted at first or end. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.timeframe_get.description + description: The timeframe description. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: Boolean + contextPath: WAB.timeframe_get.is_overtimable + description: Do not close sessions at the end of the time period. + - type: String + contextPath: WAB.timeframe_get.periods.start_date + description: The period start date. Must respect the format "yyyy-mm-dd". + - type: String + contextPath: WAB.timeframe_get.periods.end_date + description: The period end date. Must respect the format "yyyy-mm-dd". + - type: String + contextPath: WAB.timeframe_get.periods.start_time + description: The period start time. Must respect the format "hh:mm". + - type: String + contextPath: WAB.timeframe_get.periods.end_time + description: The period end time. Must respect the format "hh:mm". + - type: String + contextPath: WAB.timeframe_get.periods.week_days + description: The period week days. + - type: String + contextPath: WAB.timeframe_get.url + description: The API URL to the resource. + - name: wab-edit-timeframe + description: 'Edit a timeframe + + category: Timeframes.' + arguments: + - name: timeframe_id + description: The timeframe id or name to edit. + required: true + - name: timeframe_put_timeframe_name + description: The timeframe name. No space is permitted at first or end. + - name: timeframe_put_description + description: The timeframe description. + - name: timeframe_put_is_overtimable + description: Do not close sessions at the end of the time period. + auto: PREDEFINED + predefined: + - 'true' + - 'false' + - name: wab-delete-timeframe + description: 'Delete a timeframe + + category: Timeframes.' + arguments: + - name: timeframe_id + description: The timeframe id or name to delete. + required: true - name: wab-get-user-groups - description: Get the user groups. + description: 'Get the user groups + + category: User Groups.' arguments: - name: q description: Searches for a resource matching parameters. @@ -4975,7 +6668,9 @@ script: contextPath: WAB.usergroups_get.url description: The API URL to the resource. - name: wab-get-user-group - description: Get the user group. + description: 'Get the user group + + category: User Groups.' arguments: - name: group_id description: A user group id or name. If specified, only this user group is returned. @@ -4994,7 +6689,7 @@ script: description: The group profile. - type: String contextPath: WAB.usergroups_get.description - description: 'The group description. Usable in the "q" parameter. Usable in the "sort" parameter.' + description: The group description. Usable in the "q" parameter. Usable in the "sort" parameter. - type: String contextPath: WAB.usergroups_get.timeframes description: The group timeframe(s). @@ -5023,10 +6718,16 @@ script: contextPath: WAB.usergroups_get.url description: The API URL to the resource. - name: wab-get-users - description: Get the users. + description: 'Get the users + + category: Users.' arguments: - name: password_hash description: Export password hash if true. In Configuration Options menu > REST API then Advanced options, you should set User password hash and change the default Data encryption key. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: q description: Searches for a resource matching parameters. - name: sort @@ -5093,10 +6794,16 @@ script: contextPath: WAB.user_get.gpg_public_key description: The GPG public key fingerprint. - name: wab-add-user - description: Add a user. + description: 'Add a user + + category: Users.' arguments: - name: password_hash description: Set password hash if true. In Configuration Options menu > REST API then Advanced options, you should set User password hash and change the default Data encryption key. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: user_post_user_name description: The user name. /:*?"<>| are forbidden. required: true @@ -5109,42 +6816,71 @@ script: description: 'The source IP to limit access. Format is a comma-separated list of IPv4 or IPV6 addresses, subnets, ranges or domain, for example: 1.2.3.4,2001:db8::1234:5678,192.168.1.10/24,10.11.12.13-14.15.16.17,example.com.' - name: user_post_preferred_language description: The preferred language. + auto: PREDEFINED + predefined: + - de + - en + - es + - fr + - ru - name: user_post_profile description: The user profile. required: true - name: user_post_groups - description: The groups containing this user. + description: 'The groups containing this user. + + Comma-separated list (use [] for an empty list).' isArray: true - name: user_post_user_auths - description: The authentication procedures(s). + description: 'The authentication procedures(s). + + Comma-separated list (use [] for an empty list).' required: true isArray: true - name: user_post_password description: The password. - name: user_post_force_change_pwd description: Force password change. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: user_post_ssh_public_key description: The SSH public key. - name: user_post_certificate_dn description: The certificate DN (for X509 authentication). - name: user_post_last_connection - description: The last connection of this user. + description: The last connection of this user. (enter null for null value). - name: user_post_expiration_date description: 'Account expiration date/time (format: "yyyy-mm-dd hh:mm").' - name: user_post_is_disabled description: Account is disabled. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: user_post_gpg_public_key description: 'The GPG public key (ascii output from the command: ''gpg --armor --export [USER_ID]'').' + outputs: + - type: String + contextPath: WAB.add_user.id + description: id of the created object. - name: wab-get-user - description: Get the user. + description: 'Get the user + + category: Users.' arguments: - name: name - description: 'A user name. If specified, only this user is returned.' + description: A user name. If specified, only this user is returned. required: true - name: password_hash - description: 'Export password hash if true. In Configuration Options menu > REST API then Advanced options, you should set User password hash and change the default Data encryption key.' + description: Export password hash if true. In Configuration Options menu > REST API then Advanced options, you should set User password hash and change the default Data encryption key. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: fields - description: 'The list of fields to return (separated by commas). By default all fields are returned.' + description: The list of fields to return (separated by commas). By default all fields are returned. outputs: - type: String contextPath: WAB.user_get.user_name @@ -5200,8 +6936,188 @@ script: - type: String contextPath: WAB.user_get.gpg_public_key description: The GPG public key fingerprint. + - name: wab-edit-user + description: 'Edit a user + + category: Users.' + arguments: + - name: name + description: The user name to edit. + required: true + - name: force + description: The default value is false. When set to true, the values of the groups and user_auths are replaced, otherwise the values are added to the existing ones. + auto: PREDEFINED + predefined: + - 'true' + - 'false' + - name: password_hash + description: Update password hash if true. In Configuration Options menu > REST API then Advanced options, you should set User password hash and change the default Data encryption key. + auto: PREDEFINED + predefined: + - 'true' + - 'false' + - name: user_put_user_name + description: The user name. /:*?"<>| are forbidden. + - name: user_put_display_name + description: The displayed name. + - name: user_put_email + description: The email address. + - name: user_put_ip_source + description: 'The source IP to limit access. Format is a comma-separated list of IPv4 or IPV6 addresses, subnets, ranges or domain, for example: 1.2.3.4,2001:db8::1234:5678,192.168.1.10/24,10.11.12.13-14.15.16.17,example.com.' + - name: user_put_preferred_language + description: The preferred language. + auto: PREDEFINED + predefined: + - de + - en + - es + - fr + - ru + - name: user_put_profile + description: The user profile. + - name: user_put_groups + description: 'The groups containing this user. + + Comma-separated list (use [] for an empty list).' + isArray: true + - name: user_put_user_auths + description: 'The authentication procedures(s). + + Comma-separated list (use [] for an empty list).' + isArray: true + - name: user_put_password + description: The password. + - name: user_put_force_change_pwd + description: Force password change. + auto: PREDEFINED + predefined: + - 'true' + - 'false' + - name: user_put_ssh_public_key + description: The SSH public key. + - name: user_put_certificate_dn + description: The certificate DN (for X509 authentication). + - name: user_put_last_connection + description: The last connection of this user. (enter null for null value). + - name: user_put_expiration_date + description: 'Account expiration date/time (format: "yyyy-mm-dd hh:mm").' + - name: user_put_is_disabled + description: Account is disabled. + auto: PREDEFINED + predefined: + - 'true' + - 'false' + - name: user_put_gpg_public_key + description: 'The GPG public key (ascii output from the command: ''gpg --armor --export [USER_ID]'').' + - name: wab-get-target-group-restrictions + description: 'Get target group restrictions + + category: Target Group Restrictions.' + arguments: + - name: group_id + description: A target group id or name. + required: true + - name: q + description: Searches for a resource matching parameters. + - name: sort + description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''group_name''.' + - name: offset + description: The index of first item to retrieve (starts and defaults to 0). + - name: limit + description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.restriction_get.id + description: The restriction id. Usable in the "q" parameter. + - type: String + contextPath: WAB.restriction_get.action + description: The restriction type. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.restriction_get.rules + description: The restriction rules. Usable in the "sort" parameter. + - type: String + contextPath: WAB.restriction_get.subprotocol + description: The restriction subprotocol. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.restriction_get.url + description: The API URL to the resource. + - name: wab-get-target-group-restriction + description: 'Get one target group restriction + + category: Target Group Restrictions.' + arguments: + - name: group_id + description: A target group id or name. + required: true + - name: restriction_id + description: The identifier of the desired restriction. If specified, only this restriction is returned. + required: true + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.restriction_get.id + description: The restriction id. Usable in the "q" parameter. + - type: String + contextPath: WAB.restriction_get.action + description: The restriction type. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.restriction_get.rules + description: The restriction rules. Usable in the "sort" parameter. + - type: String + contextPath: WAB.restriction_get.subprotocol + description: The restriction subprotocol. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.restriction_get.url + description: The API URL to the resource. + - name: wab-edit-restriction-from-targetgroup + description: 'Edit a restriction from a targetgroup + + category: Target Group Restrictions.' + arguments: + - name: group_id + description: A target group id or name. + required: true + - name: restriction_id + description: The identifier of the desired restriction. + required: true + - name: restriction_put_action + description: The restriction type. + auto: PREDEFINED + predefined: + - kill + - notify + - name: restriction_put_rules + description: The restriction rules. + - name: restriction_put_subprotocol + description: The restriction subprotocol. + auto: PREDEFINED + predefined: + - SSH_SHELL_SESSION + - SSH_REMOTE_COMMAND + - SSH_SCP_UP + - SSH_SCP_DOWN + - SFTP_SESSION + - RLOGIN + - TELNET + - RDP + - name: wab-delete-restriction-from-targetgroup + description: 'Delete a restriction from a targetgroup + + category: Target Group Restrictions.' + arguments: + - name: group_id + description: A target group id or name. + required: true + - name: restriction_id + description: The identifier of the desired restriction. + required: true - name: wab-get-password-for-target - description: Get the password for a given target. + description: 'Get the password for a given target + + category: Target Passwords.' arguments: - name: account_name description: 'A target name: ''account@domain@device'' for an account on a device, ''account@domain@application'' for an account on an application or ''account@domain'' for an account on a global domain.' @@ -5252,7 +7168,9 @@ script: contextPath: WAB.targetpasswords_get_checkout.account_name description: the account_name. - name: wab-extend-duration-time-to-get-passwords-for-target - description: Extend the duration time to get the passwords for a given target. + description: 'Extend the duration time to get the passwords for a given target + + category: Target Passwords.' arguments: - name: account_name description: 'A target name: ''account@domain@device'' for an account on a device, ''account@domain@application'' for an account on an application or ''account@domain'' for an account on a global domain.' @@ -5260,7 +7178,9 @@ script: - name: authorization description: The name of the authorization (in case of multiple authorizations to access the target). - name: wab-release-passwords-for-target - description: Release the passwords for a given target. + description: 'Release the passwords for a given target + + category: Target Passwords.' arguments: - name: account_name description: 'A target name: ''account@domain@device'' for an account on a device, ''account@domain@application'' for an account on an application or ''account@domain'' for an account on a global domain.' @@ -5269,10 +7189,16 @@ script: description: The name of the authorization (in case of multiple authorizations to access the target). - name: force description: The default value is false. When it is set to true, the checkin is forced. The user connected on the REST API must have an auditor profile and the configured limitations don't prohibit access to the account. + auto: PREDEFINED + predefined: + - 'true' + - 'false' - name: comment description: A comment that is input by the auditor when an account checkin is forced. This argument is mandatory if the checkin is forced, and is ignored for a standard checkin. - name: wab-get-target-by-type - description: Get the target by type. + description: 'Get the target by type + + category: Targets.' arguments: - name: target_type description: 'The type of target, one of: ''session_accounts'', ''session_account_mappings'', ''session_interactive_logins'', ''session_scenario_accounts'', ''password_retrieval_accounts''.' @@ -5314,7 +7240,9 @@ script: contextPath: WAB.getTargetByType.application description: The application name. Usable in the "q" parameter. Usable in the "sort" parameter. - name: wab-get-mappings-of-user-group - description: Get the mappings of a user group. + description: 'Get the mappings of a user group + + category: User Group Mappings.' arguments: - name: group_id description: A user group id or name to retrieve. @@ -5346,7 +7274,9 @@ script: contextPath: WAB.authdomain_mapping_get.url description: The API URL to the resource. - name: wab-add-mapping-in-group - description: Add a mapping in a group and set mapping fallback. If the field "external_group" is set to "*", it is used as the fallback mapping, which allows mapping of users in the domain that do not belong to the external_group to be mapped to the user group by default. + description: 'Add a mapping in a group and set mapping fallback. If the field "external_group" is set to "*", it is used as the fallback mapping, which allows mapping of users in the domain that do not belong to the external_group to be mapped to the user group by default + + category: User Group Mappings.' arguments: - name: group_id description: A group id or name. @@ -5360,8 +7290,14 @@ script: - name: usergroup_mapping_post_profile description: The name of the profile for which the mapping is defined. required: true + outputs: + - type: String + contextPath: WAB.add_mapping_in_group.id + description: id of the created object. - name: wab-get-mapping-of-user-group - description: Get the mapping of a user group. + description: 'Get the mapping of a user group + + category: User Group Mappings.' arguments: - name: group_id description: A user group id or name to retrieve. @@ -5388,7 +7324,9 @@ script: contextPath: WAB.authdomain_mapping_get.url description: The API URL to the resource. - name: wab-edit-mapping-of-user-group - description: Edit a mapping of a user group. + description: 'Edit a mapping of a user group + + category: User Group Mappings.' arguments: - name: group_id description: A group id or name. @@ -5406,7 +7344,9 @@ script: description: The name of the profile for which the mapping is defined. required: true - name: wab-delete-mapping-of-user-group - description: Delete the mapping of the given user group. + description: 'Delete the mapping of the given user group + + category: User Group Mappings.' arguments: - name: group_id description: A group id or name. @@ -5414,4 +7354,173 @@ script: - name: mapping_id description: A mapping id. required: true + - name: wab-get-user-group-restrictions + description: 'Get user group restrictions + + category: User Group Restrictions.' + arguments: + - name: group_id + description: A user group id or name. + required: true + - name: q + description: Searches for a resource matching parameters. + - name: sort + description: 'Comma-separated list of fields used to sort results; a field starting "-" reverses the order. The default sort for this resource is: ''group_name''.' + - name: offset + description: The index of first item to retrieve (starts and defaults to 0). + - name: limit + description: 'The number of items to retrieve (100 by default, -1 = no limit). Note: this default value of 100 can be changed in the REST API configuration option.' + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.restriction_get.id + description: The restriction id. Usable in the "q" parameter. + - type: String + contextPath: WAB.restriction_get.action + description: The restriction type. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.restriction_get.rules + description: The restriction rules. Usable in the "sort" parameter. + - type: String + contextPath: WAB.restriction_get.subprotocol + description: The restriction subprotocol. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.restriction_get.url + description: The API URL to the resource. + - name: wab-add-restriction-to-usergroup + description: 'Add a restriction to a usergroup + + category: User Group Restrictions.' + arguments: + - name: group_id + description: A user group id or name. + required: true + - name: restriction_post_action + description: The restriction type. + required: true + auto: PREDEFINED + predefined: + - kill + - notify + - name: restriction_post_rules + description: The restriction rules. + required: true + - name: restriction_post_subprotocol + description: The restriction subprotocol. + required: true + auto: PREDEFINED + predefined: + - SSH_SHELL_SESSION + - SSH_REMOTE_COMMAND + - SSH_SCP_UP + - SSH_SCP_DOWN + - SFTP_SESSION + - RLOGIN + - TELNET + - RDP + outputs: + - type: String + contextPath: WAB.add_restriction_to_usergroup.id + description: id of the created object. + - name: wab-get-user-group-restriction + description: 'Get one user group restriction + + category: User Group Restrictions.' + arguments: + - name: group_id + description: A user group id or name. + required: true + - name: restriction_id + description: The identifier of the desired restriction. If specified, only this restriction is returned. + required: true + - name: fields + description: The list of fields to return (separated by commas). By default all fields are returned. + outputs: + - type: String + contextPath: WAB.restriction_get.id + description: The restriction id. Usable in the "q" parameter. + - type: String + contextPath: WAB.restriction_get.action + description: The restriction type. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.restriction_get.rules + description: The restriction rules. Usable in the "sort" parameter. + - type: String + contextPath: WAB.restriction_get.subprotocol + description: The restriction subprotocol. Usable in the "q" parameter. Usable in the "sort" parameter. + - type: String + contextPath: WAB.restriction_get.url + description: The API URL to the resource. + - name: wab-edit-restriction-from-usergroup + description: 'Edit a restriction from a usergroup + + category: User Group Restrictions.' + arguments: + - name: group_id + description: A user group id or name. + required: true + - name: restriction_id + description: The identifier of the desired restriction. + required: true + - name: restriction_put_action + description: The restriction type. + auto: PREDEFINED + predefined: + - kill + - notify + - name: restriction_put_rules + description: The restriction rules. + - name: restriction_put_subprotocol + description: The restriction subprotocol. + auto: PREDEFINED + predefined: + - SSH_SHELL_SESSION + - SSH_REMOTE_COMMAND + - SSH_SCP_UP + - SSH_SCP_DOWN + - SFTP_SESSION + - RLOGIN + - TELNET + - RDP + - name: wab-delete-restriction-from-usergroup + description: 'Delete a restriction from a usergroup + + category: User Group Restrictions.' + arguments: + - name: group_id + description: A user group id or name. + required: true + - name: restriction_id + description: The identifier of the desired restriction. + required: true + - name: wab-get-version + description: 'Get the REST API and WALLIX Bastion version numbers + + category: Version.' + outputs: + - type: String + contextPath: WAB.version_get.version + description: The REST API version. + - type: Number + contextPath: WAB.version_get.version_decimal + description: The REST API version as decimal number. + - type: String + contextPath: WAB.version_get.wab_version + description: 'The WALLIX Bastion version (format: X.Y).' + - type: String + contextPath: WAB.version_get.wab_form_factor + description: The WALLIX Bastion form factor (appliance, cloud). . + - type: Number + contextPath: WAB.version_get.wab_version_decimal + description: The WALLIX Bastion version as decimal number. + - type: String + contextPath: WAB.version_get.wab_version_hotfix + description: 'The WALLIX Bastion version with hotfix level (format: X.Y.Z, Z being the hotfix level).' + - type: Number + contextPath: WAB.version_get.wab_version_hotfix_decimal + description: The WALLIX Bastion version with hotfix level as decimal. + - type: String + contextPath: WAB.version_get.wab_complete_version + description: The WALLIX Bastion complete version, with hotfix level and build date. isfetch: false diff --git a/Packs/WALLIXBastion/Integrations/WAB/WAB_description.md b/Packs/WALLIXBastion/Integrations/WAB/WAB_description.md index 272fe4ad19e0..454c52fd2dfd 100644 --- a/Packs/WALLIXBastion/Integrations/WAB/WAB_description.md +++ b/Packs/WALLIXBastion/Integrations/WAB/WAB_description.md @@ -1,21 +1,31 @@ # WALLIX Bastion integration for Palo Alto XSOAR -This integration provides access to the WALLIX Bastion administration API v3.12. +This integration provides partial access to the WALLIX Bastion administration API v3.12. -This includes management of users, accounts, devices, sessions and passwords. +This includes management of users, accounts, devices, sessions, passwords and more. -To use this integration, you must create an API key on your Bastion appliance. +To use this integration, you can provide a user/password or create an API key on your Bastion appliance. Go to `Configuration` > `API Keys` to create one. +> Note: using an API key rather than a password allows unrestricted administrative access to the Bastion. + ## Configure the API version This integration is based on the API 3.12 available since Bastion 10.4. -It may still work on older versions of the API. The version used can be configured in the integration parameters. +Some commands may still work on older versions of the API. The version used can be configured in the integration parameters. You can leave the field `api_version` empty to use the latest available API on your Bastion appliance. To use another version of the API, it is recommended to check the changes made since that version on the API resource related to the command used. -Changes between API versions are documented under the help section in `REST API documentation`. \ No newline at end of file +Please note that some features of the API 3.12 are only available to the most recent Bastion versions (12+). You should test each command manually to make sure it is well supported before using it in automation playbooks. + +**API endpoints and changes between API versions are documented under the help section in `REST API documentation` (https://my-example-bastion.com/api/doc/Usage.html).** + +## Bugs and feature requests + +If you encounter an unexpected error while using this integration, first make sure that the feature you want to use is documented in the REST API documentation of your Bastion appliance. + +Otherwise, or if you would like to submit a feature request, please contact the WALLIX Customer Success team. \ No newline at end of file diff --git a/Packs/WALLIXBastion/Integrations/WAB/WAB_test.py b/Packs/WALLIXBastion/Integrations/WAB/WAB_test.py index 83aa5ed373d5..08e7dc44bd39 100644 --- a/Packs/WALLIXBastion/Integrations/WAB/WAB_test.py +++ b/Packs/WALLIXBastion/Integrations/WAB/WAB_test.py @@ -248,18 +248,25 @@ def test_commands(mocker): "wab-add-account-to-local-domain-of-application", "wab-add-account-to-local-domain-on-device", "wab-add-authorization", + "wab-add-connection-policy", "wab-add-device", + "wab-add-mapping-in-domain", "wab-add-mapping-in-group", "wab-add-notification", + "wab-add-password-change-policy", "wab-add-password-target-to-target-group", "wab-add-restriction-to-target-group", + "wab-add-restriction-to-usergroup", "wab-add-service-in-device", "wab-add-session-target-to-target-group", "wab-add-target-group", + "wab-add-timeframe", + "wab-add-timeframe-period", "wab-add-user", "wab-cancel-accepted-approval", "wab-cancel-approval-request", "wab-cancel-scan-job", + "wab-change-password-or-ssh-key-of-account", "wab-check-if-approval-is-required-for-target", "wab-create-session-request", "wab-delete-account", @@ -268,25 +275,41 @@ def test_commands(mocker): "wab-delete-account-from-local-domain-of-device", "wab-delete-application", "wab-delete-authorization", + "wab-delete-connection-policy", "wab-delete-device", + "wab-delete-mapping-of-domain", "wab-delete-mapping-of-user-group", "wab-delete-notification", + "wab-delete-password-change-policy", "wab-delete-pending-or-live-session-request", "wab-delete-resource-from-global-domain-account", + "wab-delete-restriction-from-targetgroup", + "wab-delete-restriction-from-usergroup", + "wab-delete-scan", "wab-delete-service-from-device", "wab-delete-target-from-group", "wab-delete-target-group", + "wab-delete-timeframe", "wab-edit-account-in-global-domain", "wab-edit-account-on-local-domain-of-application", "wab-edit-account-on-local-domain-of-device", "wab-edit-application", "wab-edit-authorization", + "wab-edit-connection-policy", "wab-edit-device", + "wab-edit-mapping-of-domain", "wab-edit-mapping-of-user-group", + "wab-edit-mappings-of-domain", "wab-edit-notification", + "wab-edit-password-change-policy", + "wab-edit-restriction-from-targetgroup", + "wab-edit-restriction-from-usergroup", + "wab-edit-scan", "wab-edit-service-of-device", "wab-edit-session", "wab-edit-target-group", + "wab-edit-timeframe", + "wab-edit-user", "wab-extend-duration-time-to-get-passwords-for-target", "wab-generate-trace-for-session", "wab-get-account-of-global-domain", @@ -313,24 +336,38 @@ def test_commands(mocker): "wab-get-certificates-on-device", "wab-get-checkout-policies", "wab-get-checkout-policy", + "wab-get-cluster", + "wab-get-clusters", + "wab-get-connection-policies", + "wab-get-connection-policy", "wab-get-current-serial-configuration-number-of-bastion", "wab-get-device", "wab-get-devices", + "wab-get-external-authentication-group-mappings", "wab-get-global-domain", "wab-get-global-domains", "wab-get-information-about-wallix-bastion-license", "wab-get-latest-snapshot-of-running-session", "wab-get-ldap-user-of-domain", "wab-get-ldap-users-of-domain", + "wab-get-local-domain-data-for-application", + "wab-get-local-domain-of-device", + "wab-get-local-domains-data-for-application", + "wab-get-local-domains-of-device", + "wab-get-mapping-of-domain", "wab-get-mapping-of-user-group", + "wab-get-mappings-of-domain", "wab-get-mappings-of-user-group", - "wab-get-metadata-of-one-or-multiple-sessions", "wab-get-notification", "wab-get-notifications", "wab-get-object-to-onboard", "wab-get-one-account", "wab-get-one-account-on-device-local-domain", + "wab-get-password-change-policies", + "wab-get-password-change-policy", "wab-get-password-for-target", + "wab-get-passwordrights", + "wab-get-passwordrights-user-name", "wab-get-profile", "wab-get-profiles", "wab-get-scan", @@ -347,11 +384,18 @@ def test_commands(mocker): "wab-get-status-of-trace-generation", "wab-get-target-by-type", "wab-get-target-group", + "wab-get-target-group-restriction", + "wab-get-target-group-restrictions", "wab-get-target-groups", + "wab-get-timeframe", + "wab-get-timeframes", "wab-get-user", "wab-get-user-group", + "wab-get-user-group-restriction", + "wab-get-user-group-restrictions", "wab-get-user-groups", "wab-get-users", + "wab-get-version", "wab-get-wallix-bastion-usage-statistics", "wab-getx509-configuration-infos", "wab-make-new-approval-request-to-access-target", diff --git a/Packs/WALLIXBastion/ReleaseNotes/3_0_0.json b/Packs/WALLIXBastion/ReleaseNotes/3_0_0.json new file mode 100644 index 000000000000..1c7d8fbf364a --- /dev/null +++ b/Packs/WALLIXBastion/ReleaseNotes/3_0_0.json @@ -0,0 +1,4 @@ +{ + "breakingChanges": true, + "breakingChangesNotes": "- The deprecated command `wab-get-metadata-of-one-or-multiple-sessions` has been removed.\n- The deprecated argument `application_put__meters` has been removed from the `wab-edit-application` command.\n- The deprecated output `WAB.profile_get.gui_features.dashboards` has been removed from the `wab-get-profile` and `wab-get-profiles` commands.\n- The deprecated output `WAB.application_get.tags.id` has been removed from the following commands: `wab-get-application`, `wab-get-applications`.\n- The deprecated output `WAB.device_get.tags.id` has been removed from the following commands: `wab-get-device`, `wab-get-devices`." +} diff --git a/Packs/WALLIXBastion/ReleaseNotes/3_0_0.md b/Packs/WALLIXBastion/ReleaseNotes/3_0_0.md new file mode 100644 index 000000000000..9e1f7211d698 --- /dev/null +++ b/Packs/WALLIXBastion/ReleaseNotes/3_0_0.md @@ -0,0 +1,85 @@ + +#### Integrations + +##### WALLIX Bastion + +- Updated the Docker image to: *demisto/python3:3.11.10.113941*. + +- The integration now returns the ID of created objects on the Bastion. + +- Added support for nullable arguments. + +- Added new commands: + - wab-add-connection-policy + - wab-add-mapping-in-domain + - wab-add-password-change-policy + - wab-add-restriction-to-usergroup + - wab-add-timeframe + - wab-add-timeframe-period + - wab-change-password-or-ssh-key-of-account + - wab-delete-connection-policy + - wab-delete-mapping-of-domain + - wab-delete-password-change-policy + - wab-delete-restriction-from-targetgroup + - wab-delete-restriction-from-usergroup + - wab-delete-scan + - wab-delete-timeframe + - wab-edit-connection-policy + - wab-edit-mapping-of-domain + - wab-edit-mappings-of-domain + - wab-edit-password-change-policy + - wab-edit-restriction-from-targetgroup + - wab-edit-restriction-from-usergroup + - wab-edit-scan + - wab-edit-timeframe + - wab-edit-user + - wab-get-cluster + - wab-get-clusters + - wab-get-connection-policies + - wab-get-connection-policy + - wab-get-external-authentication-group-mappings + - wab-get-local-domain-data-for-application + - wab-get-local-domain-of-device + - wab-get-local-domains-data-for-application + - wab-get-local-domains-of-device + - wab-get-mapping-of-domain + - wab-get-mappings-of-domain + - wab-get-target-group-restriction + - wab-get-user-group-restriction + - wab-get-password-change-policies + - wab-get-password-change-policy + - wab-get-passwordrights + - wab-get-passwordrights-user-name + - wab-get-version + - wab-get-target-group-restrictions + - wab-get-timeframe + - wab-get-timeframes + - wab-get-user-group-restrictions + +- Updated wab-add-service-in-device arguments: + - set service_post_subprotocols as not required. + - added service_post_seamless_connection option for RAWTCPIP. + +- Updated wab-edit-service-of-device arguments: + - added service_post_subprotocols. + - added service_put_seamless_connection option for RAWTCPIP. + +- Updated wab-edit-application arguments: + - added application_put_global_domains. + +- **Breaking changes:** removed deprecated command wab-get-metadata-of-one-or-multiple-sessions. + +- **Breaking changes:** removed deprecated argument application_put__meters from wab-edit-application. + +- **Breaking changes:** removed WAB.profile_get.gui_features.dashboards from wab-get-profile(s) outputs. + +- **Breaking changes:** removed WAB.application_get.tags.id from wab-get-application(s) outputs. + +- **Breaking changes:** removed WAB.device_get.tags.id from wab-get-device(s) outputs. + +- **Breaking changes:** removed WAB.profile_get.gui_features.dashboards from wab-get-profile(s) outputs. + +- **Breaking changes:** removed WAB.application_get.tags.id from wab-get-application(s) outputs. + +- **Breaking changes:** removed WAB.device_get.tags.id from wab-get-device(s) outputs. + diff --git a/Packs/WALLIXBastion/pack_metadata.json b/Packs/WALLIXBastion/pack_metadata.json index 8c294a7e5301..8bc576a7be9f 100644 --- a/Packs/WALLIXBastion/pack_metadata.json +++ b/Packs/WALLIXBastion/pack_metadata.json @@ -2,7 +2,7 @@ "name": "WALLIX Bastion", "description": "Integrations for WALLIX Bastion appliances", "support": "partner", - "currentVersion": "2.1.0", + "currentVersion": "3.0.0", "author": "WALLIX", "url": "https://www.wallix.com/privileged-access-management/", "email": "", diff --git a/Packs/Workday/ParsingRules/WorkdayParsingRules/WorkdayParsingRules.xif b/Packs/Workday/ParsingRules/WorkdayParsingRules/WorkdayParsingRules.xif index 9f4682f93c00..7c7022a27b49 100644 --- a/Packs/Workday/ParsingRules/WorkdayParsingRules/WorkdayParsingRules.xif +++ b/Packs/Workday/ParsingRules/WorkdayParsingRules/WorkdayParsingRules.xif @@ -1,4 +1,4 @@ -[INGEST:vendor="workday", product="workday", target_dataset="workday_activity_raw", no_hit = keep] +[INGEST:vendor="workday", product="activity", target_dataset="workday_activity_raw", no_hit = keep] // Support only date time of format: YYYY-MM-DDTHH:MM:SS.E3S%z. For example: "2023-07-15T07:00:00.000Z" filter to_string(requestTime) ~= "\d{4}\-\d{2}\-\d{2}T\d{2}\:\d{2}\:\d{2}\.\d{3}Z" -| alter _time = requestTime; \ No newline at end of file +| alter _time = parse_timestamp("%FT%R:%E*SZ", to_string(requestTime)); \ No newline at end of file diff --git a/Packs/Workday/ReleaseNotes/1_4_12.md b/Packs/Workday/ReleaseNotes/1_4_12.md new file mode 100644 index 000000000000..c6ad1bda6cf6 --- /dev/null +++ b/Packs/Workday/ReleaseNotes/1_4_12.md @@ -0,0 +1,3 @@ +#### Parsing Rules +##### Workday Parsing Rule +Improved implementation of _time parsing. diff --git a/Packs/Workday/ReleaseNotes/1_4_13.md b/Packs/Workday/ReleaseNotes/1_4_13.md new file mode 100644 index 000000000000..c6ad1bda6cf6 --- /dev/null +++ b/Packs/Workday/ReleaseNotes/1_4_13.md @@ -0,0 +1,3 @@ +#### Parsing Rules +##### Workday Parsing Rule +Improved implementation of _time parsing. diff --git a/Packs/Workday/ReleaseNotes/1_4_14.md b/Packs/Workday/ReleaseNotes/1_4_14.md new file mode 100644 index 000000000000..93cd35368640 --- /dev/null +++ b/Packs/Workday/ReleaseNotes/1_4_14.md @@ -0,0 +1,3 @@ +#### Parsing Rules +##### Workday Parsing Rule +Modified the product value in the parsing rule. diff --git a/Packs/Workday/pack_metadata.json b/Packs/Workday/pack_metadata.json index 31ad380b17f0..6c363ab30583 100644 --- a/Packs/Workday/pack_metadata.json +++ b/Packs/Workday/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Workday", "description": "Workday offers enterprise-level software solutions for financial management, human resources, and planning.", "support": "xsoar", - "currentVersion": "1.4.11", + "currentVersion": "1.4.14", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/XSOARLabUpdates/ReleaseNotes/1_0_4.md b/Packs/XSOARLabUpdates/ReleaseNotes/1_0_4.md new file mode 100644 index 000000000000..b90275186572 --- /dev/null +++ b/Packs/XSOARLabUpdates/ReleaseNotes/1_0_4.md @@ -0,0 +1,6 @@ + +#### Scripts + +##### BuildSlackBlocksFromIndex + +- Updated the Docker image to: *demisto/unzip:1.0.0.114702*. diff --git a/Packs/XSOARLabUpdates/Scripts/BuildSlackBlocksFromIndex/BuildSlackBlocksFromIndex.py b/Packs/XSOARLabUpdates/Scripts/BuildSlackBlocksFromIndex/BuildSlackBlocksFromIndex.py index 2b022679bd2b..d19d82b1a342 100644 --- a/Packs/XSOARLabUpdates/Scripts/BuildSlackBlocksFromIndex/BuildSlackBlocksFromIndex.py +++ b/Packs/XSOARLabUpdates/Scripts/BuildSlackBlocksFromIndex/BuildSlackBlocksFromIndex.py @@ -8,7 +8,6 @@ from tempfile import mkdtemp from zipfile import ZipFile from datetime import datetime -from typing import List, Union DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ' MP_LINK = "https://xsoar.pan.dev/marketplace" @@ -31,7 +30,7 @@ def __init__(self, path: str, pack_id: str): self.created: str = self.metadata.get('created', '') self.created_datetime: datetime = datetime.strptime(self.created, DATE_FORMAT).replace(tzinfo=pytz.UTC) self.price: int = self.metadata.get('price', 0) - self._is_private_pack: bool = True if self.metadata.get('partnerId') else False + self._is_private_pack: bool = bool(self.metadata.get('partnerId')) self.support: str = self.metadata.get('support', 'xsoar') self.author: str = self.metadata.get('author', 'Cortex XSOAR') self.description: str = self.get_description() @@ -106,8 +105,8 @@ def __init__(self, index_file_entry_id: str): self.extract_destination_path: str = mkdtemp() self.index_folder_path: str = os.path.join(self.extract_destination_path, 'index') self.extract() - self.packs: List[IndexPack] = self.get_packs() - self.new_packs: List[IndexPack] = [] + self.packs: list[IndexPack] = self.get_packs() + self.new_packs: list[IndexPack] = [] def extract(self): """ Extract the index from the zip file """ @@ -126,7 +125,7 @@ def extract(self): demisto.error(error_msg) raise Exception(error_msg) - def get_packs(self) -> List[IndexPack]: + def get_packs(self) -> list[IndexPack]: """ Build IndexPack object for each pack in the index """ packs = [] @@ -137,7 +136,7 @@ def get_packs(self) -> List[IndexPack]: return packs - def get_new_packs_from_last_run(self, last_run_str: str) -> List[IndexPack]: + def get_new_packs_from_last_run(self, last_run_str: str) -> list[IndexPack]: """ Creates a list of all packs that were released after the given time. Args: @@ -159,7 +158,7 @@ def get_new_packs_from_last_run(self, last_run_str: str) -> List[IndexPack]: return self.new_packs - def get_latest_new_pack_created_time(self) -> Union[None, str]: + def get_latest_new_pack_created_time(self) -> None | str: """ The new pack with the latest created time is the last new pack that the script has detected, therefore, the next run should start from its created time. @@ -181,12 +180,12 @@ def get_latest_new_pack_created_time(self) -> Union[None, str]: class SlackBlocks: """ A class that builds the Slack Blocks object """ - def __init__(self, packs: List[IndexPack]): - self.packs: List[IndexPack] = sorted( + def __init__(self, packs: list[IndexPack]): + self.packs: list[IndexPack] = sorted( packs, key=lambda p: SUPPORT.index(p.support) if p.support in SUPPORT else 3 ) - self._preview_packs: List[IndexPack] = self.packs[:NUM_FULL_PREVIEW] - self._list_packs: List[IndexPack] = self.packs[NUM_FULL_PREVIEW:] + self._preview_packs: list[IndexPack] = self.packs[:NUM_FULL_PREVIEW] + self._list_packs: list[IndexPack] = self.packs[NUM_FULL_PREVIEW:] def build(self) -> str: if self.packs: @@ -309,7 +308,7 @@ def get_bottom_block() -> dict: def load_json(file_path: str) -> dict: try: if file_path and os.path.exists(file_path): - with open(file_path, 'r') as json_file: + with open(file_path) as json_file: result = json.load(json_file) else: result = {} @@ -384,8 +383,8 @@ def main(): last_run: str = args['last_run_str'] index: Index = Index(index_file_entry_id) - new_packs: List[IndexPack] = index.get_new_packs_from_last_run(last_run) - latest_new_pack_created_time: Union[None, str] = index.get_latest_new_pack_created_time() + new_packs: list[IndexPack] = index.get_new_packs_from_last_run(last_run) + latest_new_pack_created_time: None | str = index.get_latest_new_pack_created_time() updated_last_run: str = latest_new_pack_created_time or datetime.utcnow().strftime(DATE_FORMAT) blocks: str = SlackBlocks(new_packs).build() diff --git a/Packs/XSOARLabUpdates/Scripts/BuildSlackBlocksFromIndex/BuildSlackBlocksFromIndex.yml b/Packs/XSOARLabUpdates/Scripts/BuildSlackBlocksFromIndex/BuildSlackBlocksFromIndex.yml index 8f29113fc7f2..2afbbabbf9af 100644 --- a/Packs/XSOARLabUpdates/Scripts/BuildSlackBlocksFromIndex/BuildSlackBlocksFromIndex.yml +++ b/Packs/XSOARLabUpdates/Scripts/BuildSlackBlocksFromIndex/BuildSlackBlocksFromIndex.yml @@ -11,7 +11,7 @@ comment: 'Extracts the index.zip and filters new packs since the last run. commonfields: id: BuildSlackBlocksFromIndex version: -1 -dockerimage: demisto/unzip:1.0.0.100283 +dockerimage: demisto/unzip:1.0.0.114702 enabled: true name: BuildSlackBlocksFromIndex outputs: diff --git a/Packs/XSOARLabUpdates/pack_metadata.json b/Packs/XSOARLabUpdates/pack_metadata.json index 7d02fa74c0b2..6d89c810ff03 100644 --- a/Packs/XSOARLabUpdates/pack_metadata.json +++ b/Packs/XSOARLabUpdates/pack_metadata.json @@ -2,7 +2,7 @@ "name": "XSOAR Lab Updates", "description": "Manage Cortex XSOAR updates", "support": "community", - "currentVersion": "1.0.3", + "currentVersion": "1.0.4", "author": "XSOAR Lab", "url": "", "email": "", diff --git a/Packs/Zafran/.pack-ignore b/Packs/Zafran/.pack-ignore new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/Packs/Zafran/.secrets-ignore b/Packs/Zafran/.secrets-ignore new file mode 100644 index 000000000000..5f1851a0ace4 --- /dev/null +++ b/Packs/Zafran/.secrets-ignore @@ -0,0 +1 @@ +https://api.zafran.io \ No newline at end of file diff --git a/Packs/Zafran/Author_image.png b/Packs/Zafran/Author_image.png new file mode 100644 index 000000000000..a3f11cf938e4 Binary files /dev/null and b/Packs/Zafran/Author_image.png differ diff --git a/Packs/Zafran/Integrations/Zafran/README.md b/Packs/Zafran/Integrations/Zafran/README.md new file mode 100644 index 000000000000..d2a46fcdd29c --- /dev/null +++ b/Packs/Zafran/Integrations/Zafran/README.md @@ -0,0 +1,100 @@ +In today’s complex security landscape, resource-constrained teams struggle to efficiently mitigate exposure risks across large infrastructures. The Zafran Integration with Palo XSOAR helps you implement **Automated, High Impact Mitigations at scale**. With this integration, teams can prioritize mitigation actions, trigger playbooks with a single click, and streamline their response efforts, all from within the Palo XSOAR environment. + +## Configure Zafran API on Cortex XSOAR + +1. Navigate to **Settings** > **Integrations** > **Servers & Services**. +2. Search for Zafran API. +3. Click **Add instance** to create and configure a new integration instance. + + | **Parameter** | **Required** | + | --- | --- | + | Server URL (e.g. api.zafran.io) | True | + | API Key | True | + | Trust any certificate (not secure) | False | + | Use system proxy settings | False | + +4. Click **Test** to validate the URLs, token, and connection. + +## Commands + +You can execute these commands from the Cortex XSOAR 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. + +### zafran-mitigation-performed + +*** +Update on mitigations performed + +#### Base Command + +`zafran-mitigation-performed` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| external_ticket_id | External service ticket ID. | Optional | +| external_ticket_url | External service ticket link. | Optional | +| id | Mitigation ID. | Required | +| state | Mitigation status new - New mitigation pending_approval - Waiting for mitigation approval rejected - Mitigative action was rejected. in_progress - Mitigation approved and in progress. completed - Mitigation applied successfully. Possible values are: new, pending_approval, rejected, in_progress, completed. | Required | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| Zafran.MitigationsPerformedResponse.internal_status_code | Number | Internal status code. | +| Zafran.MitigationsPerformedResponse.message | String | Error message. | + +### zafran-mitigations-export + +*** +Export recommended mitigations + +#### Base Command + +`zafran-mitigations-export` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| filter | ZQL filter. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| Zafran.UpstreamMitigation.assets_count | Number | Assets count. | +| Zafran.UpstreamMitigation.control_product | String | Control Product. | +| Zafran.UpstreamMitigation.exposure | Number | Exposure in days. | +| Zafran.UpstreamMitigation.id | String | Zafran mitigation unique id. | +| Zafran.UpstreamMitigation.mitigation_type | String | Mitigation type. | +| Zafran.UpstreamMitigation.recommendation | String | Recommendation. | +| Zafran.UpstreamMitigation.title | String | Title. | +| Zafran.UpstreamMitigation.vulnerabilities_count | Number | Vulnerabilities count. | +| Zafran.UpstreamMitigation.internal_status_code | Number | Internal status code. | +| Zafran.UpstreamMitigation.message | String | Error message | + +### zafran-mitigations-performed + +*** +Update on mitigations performed + +#### Base Command + +`zafran-mitigations-performed` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| mitigation_id | Mitigation ID. | Optional | +| mitigation_ids | Mitigation IDs. | Optional | +| state | Mitigation status new - New mitigation pending_approval - Waiting for mitigation approval rejected - Mitigative action was rejected. in_progress - Mitigation approved and in progress. completed - Mitigation applied successfully. Possible values are: new, pending_approval, rejected, in_progress, completed. | Required | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| Zafran.MitigationsPerformedResponse.internal_status_code | Number | Internal status code. | +| Zafran.MitigationsPerformedResponse.message | String | Error message. | diff --git a/Packs/Zafran/Integrations/Zafran/Zafran.py b/Packs/Zafran/Integrations/Zafran/Zafran.py new file mode 100644 index 000000000000..37f8cdf1062e --- /dev/null +++ b/Packs/Zafran/Integrations/Zafran/Zafran.py @@ -0,0 +1,152 @@ +import demistomock as demisto +from CommonServerPython import * + + +class Client(BaseClient): + def __init__(self, server_url, verify, proxy, headers, auth): + super().__init__(base_url=server_url, verify=verify, proxy=proxy, headers=headers, auth=auth) + + def findings_request(self, count): + params = assign_params(count=count) + headers = self._headers + + response = self._http_request('post', 'findings', params=params, headers=headers, return_empty_response=True) + + return response + + def mitigation_performed_request(self, + mitigationstatus_external_ticket_id, + mitigationstatus_external_ticket_url, + mitigationstatus_id, + mitigationstatus_state): + data = assign_params(external_ticket_id=mitigationstatus_external_ticket_id, + external_ticket_url=mitigationstatus_external_ticket_url, id=mitigationstatus_id, + state=mitigationstatus_state) + headers = self._headers + + response = self._http_request('post', 'mitigations/performed', json_data=data, headers=headers) + + return response + + def mitigations_export_request(self, filter_): + params = assign_params(filter=filter_) + headers = self._headers + + response = self._http_request('get', 'mitigations', params=params, headers=headers) + + return response + + def mitigations_performed_request(self, mitigationsstatus_mitigation_id, + mitigationsstatus_mitigation_ids, mitigationsstatus_state): + data = assign_params(mitigation_id=mitigationsstatus_mitigation_id, + mitigation_ids=mitigationsstatus_mitigation_ids, state=mitigationsstatus_state) + headers = self._headers + + response = self._http_request('post', 'mitigations', json_data=data, headers=headers) + + return response + + +def mitigation_performed_command(client: Client, args: Dict[str, Any]) -> CommandResults: + mitigationstatus_external_ticket_id = args.get('external_ticket_id', '') + mitigationstatus_external_ticket_url = args.get('external_ticket_url', '') + mitigationstatus_id = args.get('id', '') + mitigationstatus_state = args.get('state', '') + + response = client.mitigation_performed_request( + mitigationstatus_external_ticket_id, mitigationstatus_external_ticket_url, + mitigationstatus_id, mitigationstatus_state) + command_results = CommandResults( + outputs_prefix='Zafran.MitigationsPerformedResponse', + outputs_key_field='', + outputs=response, + readable_output='Mitigation status updated successfully', + + raw_response=response + ) + + return command_results + + +def mitigations_export_command(client: Client, args: Dict[str, Any]) -> CommandResults: + filter_arg = args.get('filter', '') + + response = client.mitigations_export_request(filter_arg) + human_readable = tableToMarkdown('Zafran Mitigations', response, headerTransform=string_to_table_header) + command_results = CommandResults( + outputs_prefix='Zafran.UpstreamMitigation', + outputs_key_field='id', + outputs=response, + readable_output=human_readable, + raw_response=response + ) + + return command_results + + +def mitigations_performed_command(client: Client, args: Dict[str, Any]) -> CommandResults: + mitigationsstatus_mitigation_id = args.get('mitigation_id', '') + mitigationsstatus_mitigation_ids = argToList(args.get('mitigation_ids', [])) + mitigationsstatus_state = args.get('state', '') + + response = client.mitigations_performed_request( + mitigationsstatus_mitigation_id, mitigationsstatus_mitigation_ids, mitigationsstatus_state) + + command_results = CommandResults( + outputs_prefix='Zafran.MitigationsPerformedResponse', + outputs_key_field='', + outputs=response, + readable_output='Mitigations status updated successfully', + raw_response=response + ) + + return command_results + + +def api_test_connection(client: Client) -> str: + try: + response = client.findings_request(0) + # Test functions here + if response.status_code == 204: + return 'ok' + except DemistoException: + pass + return 'API test failed' + + +def main() -> None: + + params: Dict[str, Any] = demisto.params() + args: Dict[str, Any] = demisto.args() + url = params.get('url') + verify_certificate: bool = not params.get('insecure', False) + proxy = params.get('proxy', False) + headers = {} + headers['Authorization'] = 'Bearer ' + params['api_key'] + + command = demisto.command() + demisto.debug(f'Command being called is {command}') + + try: + requests.packages.urllib3.disable_warnings() # type: ignore + client: Client = Client(urljoin(url, '/api/v2/'), verify_certificate, proxy, headers=headers, auth=None) + + commands = { + 'zafran-mitigation-performed': mitigation_performed_command, + 'zafran-mitigations-export': mitigations_export_command, + 'zafran-mitigations-performed': mitigations_performed_command, + } + + if command == 'test-module': + return_results(api_test_connection(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() diff --git a/Packs/Zafran/Integrations/Zafran/Zafran.yml b/Packs/Zafran/Integrations/Zafran/Zafran.yml new file mode 100644 index 000000000000..cc77f632a293 --- /dev/null +++ b/Packs/Zafran/Integrations/Zafran/Zafran.yml @@ -0,0 +1,136 @@ +commonfields: + id: Zafran API + version: -1 +name: Zafran API +display: Zafran API +category: Utilities +description: 'The Zafran API provides a programmatic way to interact with the Zafran Exposure Management Platform for various use cases.' +configuration: +- name: url + display: Server URL (e.g. api.zafran.io) + defaultvalue: https://api.zafran.io + type: 0 + required: true +- name: api_key + display: API Key + defaultvalue: '' + type: 4 + required: true +- name: insecure + display: Trust any certificate (not secure) + defaultvalue: 'false' + type: 8 + required: false +- name: proxy + display: Use system proxy settings + defaultvalue: 'false' + type: 8 + required: false +script: + script: '' + type: python + subtype: python3 + dockerimage: demisto/python3:3.11.9.107902 + isfetch: false + commands: + - name: zafran-mitigation-performed + description: Update on mitigations performed + arguments: + - name: external_ticket_id + description: 'External service ticket ID.' + required: false + isArray: false + - name: external_ticket_url + description: 'External service ticket link.' + required: false + isArray: false + - name: id + description: 'Mitigation ID.' + required: true + isArray: false + - name: state + description: 'Mitigation status new - New mitigation pending_approval - Waiting for mitigation approval rejected - Mitigative action was rejected. in_progress - Mitigation approved and in progress. completed - Mitigation applied successfully.' + required: true + isArray: false + auto: PREDEFINED + predefined: + - new + - pending_approval + - rejected + - in_progress + - completed + outputs: + - type: Number + contextPath: Zafran.MitigationsPerformedResponse.internal_status_code + description: 'Internal status code.' + - type: String + contextPath: Zafran.MitigationsPerformedResponse.message + description: 'Error message.' + - name: zafran-mitigations-export + description: Export recommended mitigations. + arguments: + - name: filter + description: ZQL filter. + required: false + isArray: false + outputs: + - type: Number + contextPath: Zafran.UpstreamMitigation.assets_count + description: 'Assets count.' + - type: String + contextPath: Zafran.UpstreamMitigation.control_product + description: 'Control Product.' + - type: Number + contextPath: Zafran.UpstreamMitigation.exposure + description: 'Exposure in days.' + - type: String + contextPath: Zafran.UpstreamMitigation.id + description: 'Zafran mitigation unique id.' + - type: String + contextPath: Zafran.UpstreamMitigation.mitigation_type + description: 'Mitigation type.' + - type: String + contextPath: Zafran.UpstreamMitigation.recommendation + description: 'Recommendation.' + - type: String + contextPath: Zafran.UpstreamMitigation.title + description: 'Title.' + - type: Number + contextPath: Zafran.UpstreamMitigation.vulnerabilities_count + description: 'Vulnerabilities count.' + - type: Number + contextPath: Zafran.UpstreamMitigation.internal_status_code + description: 'Internal status code.' + - type: String + contextPath: Zafran.UpstreamMitigation.message + description: 'Error message.' + - name: zafran-mitigations-performed + description: Update on mitigations performed + arguments: + - name: mitigation_id + description: 'Mitigation ID.' + required: false + isArray: false + - name: mitigation_ids + description: 'Mitigation IDs.' + required: false + isArray: true + - name: state + description: 'Mitigation status new - New mitigation pending_approval - Waiting for mitigation approval rejected - Mitigative action was rejected. in_progress - Mitigation approved and in progress. completed - Mitigation applied successfully.' + required: true + isArray: false + auto: PREDEFINED + predefined: + - new + - pending_approval + - rejected + - in_progress + - completed + outputs: + - type: Number + contextPath: Zafran.MitigationsPerformedResponse.internal_status_code + description: 'Internal status code.' + - type: String + contextPath: Zafran.MitigationsPerformedResponse.message + description: 'Error message.' +fromversion: 6.0.0 \ No newline at end of file diff --git a/Packs/Zafran/Integrations/Zafran/Zafran_description.md b/Packs/Zafran/Integrations/Zafran/Zafran_description.md new file mode 100644 index 000000000000..82649199842f --- /dev/null +++ b/Packs/Zafran/Integrations/Zafran/Zafran_description.md @@ -0,0 +1,2 @@ +The Zafran API provides a programmatic way to interact with the Zafran Exposure Management Platform for various use cases. +Using the API requires an API token, which can be obtained by contacting the Zafran support team at support@zafran.io. \ No newline at end of file diff --git a/Packs/Zafran/Integrations/Zafran/Zafran_image.png b/Packs/Zafran/Integrations/Zafran/Zafran_image.png new file mode 100644 index 000000000000..dfb1d78bc877 Binary files /dev/null and b/Packs/Zafran/Integrations/Zafran/Zafran_image.png differ diff --git a/Packs/Zafran/Integrations/Zafran/Zafran_test.py b/Packs/Zafran/Integrations/Zafran/Zafran_test.py new file mode 100644 index 000000000000..6eb376399f2d --- /dev/null +++ b/Packs/Zafran/Integrations/Zafran/Zafran_test.py @@ -0,0 +1,81 @@ +import pytest +from CommonServerPython import * +from Zafran import Client, mitigation_performed_command, mitigations_export_command, \ + mitigations_performed_command, api_test_connection + +SERVER_URL = 'https://api.zafran.io' + + +def util_load_json(path): + with open(path, encoding='utf-8') as f: + return json.loads(f.read()) + + +@pytest.fixture() +def client(): + return Client(server_url=SERVER_URL, verify=None, proxy=None, headers=None, auth=None) + + +def test_mitigation_performed_command(client, requests_mock): + """ + When: + Given: + Then: + """ + args = {'external_ticket_id': 'ticketid', 'external_ticket_url': + 'ticketurl', 'id': 'id', 'state': 'in_progress'} + mock_response_mitigation_performed_request = util_load_json( + './test_data/outputs/mitigation_performed_request.json') + requests_mock.post(f"{SERVER_URL}/mitigations/performed", json=mock_response_mitigation_performed_request) + results = mitigation_performed_command(client=client, args=args) + assert results.outputs_prefix == 'Zafran.MitigationsPerformedResponse' + assert results.outputs_key_field == '' + assert results.readable_output == 'Mitigation status updated successfully' + assert results.raw_response == mock_response_mitigation_performed_request + + +def test_mitigations_export_command(client, requests_mock): + """ + When: + Given: + Then: + """ + args = {} + mock_response_mitigations_export_request = util_load_json( + './test_data/outputs/mitigations_export_request.json') + mock_results = util_load_json( + './test_data/outputs/mitigations_export_command.json') + requests_mock.get(f"{SERVER_URL}/mitigations", json=mock_response_mitigations_export_request) + results = mitigations_export_command(client=client, args=args) + assert results.outputs_prefix == 'Zafran.UpstreamMitigation' + assert results.outputs_key_field == 'id' + assert results.outputs == mock_results.get('outputs') + assert results.raw_response == mock_response_mitigations_export_request + + +def test_mitigations_performed_command(client, requests_mock): + """ + When: + Given: + Then: + """ + args = {'mitigation_id': None, 'mitigation_ids': 'id1,id2', 'state': + 'in_progress'} + mock_response_mitigations_performed_request = util_load_json( + './test_data/outputs/mitigations_performed_request.json') + requests_mock.post(f"{SERVER_URL}/mitigations", json=mock_response_mitigations_performed_request) + results = mitigations_performed_command(client=client, args=args) + assert results.outputs_prefix == 'Zafran.MitigationsPerformedResponse' + assert results.outputs_key_field == '' + assert results.readable_output == 'Mitigations status updated successfully' + assert results.raw_response == mock_response_mitigations_performed_request + + +def test_api_test_connection(client, requests_mock): + requests_mock.post(f"{SERVER_URL}/findings?count=0", status_code=204) + result = api_test_connection(client) + assert result == 'ok' + + requests_mock.post(f"{SERVER_URL}/findings?count=0", status_code=403) + result = api_test_connection(client) + assert result == 'API test failed' diff --git a/Packs/Zafran/Integrations/Zafran/command_examples.txt b/Packs/Zafran/Integrations/Zafran/command_examples.txt new file mode 100644 index 000000000000..6fdd64248f6a --- /dev/null +++ b/Packs/Zafran/Integrations/Zafran/command_examples.txt @@ -0,0 +1,3 @@ +!zafran-mitigations-export +!zafran-mitigation-performed mitigationstatus_id="id" mitigationstatus_external_ticket_id="ticketid" mitigationstatus_external_ticket_url="ticketurl" mitigationstatus_state=in_progress +!zafran-mitigations-performed mitigationsstatus_mitigation_ids=id1,id2 mitigationsstatus_state=in_progress \ No newline at end of file diff --git a/Packs/Zafran/Integrations/Zafran/test_data/outputs/mitigation_performed_request.json b/Packs/Zafran/Integrations/Zafran/test_data/outputs/mitigation_performed_request.json new file mode 100644 index 000000000000..9e26dfeeb6e6 --- /dev/null +++ b/Packs/Zafran/Integrations/Zafran/test_data/outputs/mitigation_performed_request.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/Packs/Zafran/Integrations/Zafran/test_data/outputs/mitigations_export_command.json b/Packs/Zafran/Integrations/Zafran/test_data/outputs/mitigations_export_command.json new file mode 100644 index 000000000000..16cc90b65a50 --- /dev/null +++ b/Packs/Zafran/Integrations/Zafran/test_data/outputs/mitigations_export_command.json @@ -0,0 +1,12 @@ +{ + "outputs": [ + { + "assets_count": 9, + "control_product": "crowdstrike", + "exposure": 149, + "id": "id", + "recommendation": "text", + "vulnerabilities_count": 18 + } + ] +} \ No newline at end of file diff --git a/Packs/Zafran/Integrations/Zafran/test_data/outputs/mitigations_export_request.json b/Packs/Zafran/Integrations/Zafran/test_data/outputs/mitigations_export_request.json new file mode 100644 index 000000000000..f06e568f2efd --- /dev/null +++ b/Packs/Zafran/Integrations/Zafran/test_data/outputs/mitigations_export_request.json @@ -0,0 +1,10 @@ +[ + { + "assets_count": 9, + "control_product": "crowdstrike", + "exposure": 149, + "id": "id", + "recommendation": "text", + "vulnerabilities_count": 18 + } +] \ No newline at end of file diff --git a/Packs/Zafran/Integrations/Zafran/test_data/outputs/mitigations_performed_request.json b/Packs/Zafran/Integrations/Zafran/test_data/outputs/mitigations_performed_request.json new file mode 100644 index 000000000000..9e26dfeeb6e6 --- /dev/null +++ b/Packs/Zafran/Integrations/Zafran/test_data/outputs/mitigations_performed_request.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/Packs/Zafran/README.md b/Packs/Zafran/README.md new file mode 100644 index 000000000000..50e2ada2d53f --- /dev/null +++ b/Packs/Zafran/README.md @@ -0,0 +1,10 @@ +# Zafran Integration for Palo XSOAR + +## Overview +In today’s complex security landscape, resource-constrained teams struggle to efficiently mitigate exposure risks across large infrastructures. The Zafran Integration with Palo XSOAR helps you implement **Automated, High Impact Mitigations at scale**. With this integration, teams can prioritize mitigation actions, trigger playbooks with a single click, and streamline their response efforts, all from within the Palo XSOAR environment. +# Zafran Integration for Palo XSOAR + +### What Does This Pack Do? +- **Automated, High Impact Mitigations:** Zafran’s integration enables teams to view a **stack-ranked list of actions** that address exposure risks. For instance, it might recommend a configuration change in your Firewall to counter a vulnerability affecting over 7,000 assets. +- With **one click**, you can create an XSOAR incident and trigger a playbook, populated with evidence and specifics of required actions. The Zafran playbook ensures a swift and effective response to identified risks. +- **Mitigate & Automate:** Continuously streamline relevant configurations, policies, and IOCs across your security tools to defuse risks and automate response processes, ensuring that your environment is secure and up to date. diff --git a/Packs/Zafran/pack_metadata.json b/Packs/Zafran/pack_metadata.json new file mode 100644 index 000000000000..b018de70a42b --- /dev/null +++ b/Packs/Zafran/pack_metadata.json @@ -0,0 +1,37 @@ +{ + "name": "Zafran", + "description": "Integrate with Zafran to automate high-impact mitigations for exposure risks at scale.", + "support": "partner", + "currentVersion": "1.0.0", + "author": "Zafran", + "url": "https://www.zafran.io", + "videos": [ + "https://vimeo.com/992474252" + ], + "email": "support@zafran.io", + "categories": [ + "Vulnerability Management" + ], + "tags": [ + "Security", + "Threat Intelligence", + "Feed", + "Incident Handling", + "Incident Response" + ], + "useCases": [ + "Vulnerability Management", + "Threat Intelligence Management" + ], + "keywords": [ + "Zafran", + "Mitigations", + "Risk Mitigations", + "Proactive Exposure Hunting" + ], + "marketplaces": [ + "xsoar", + "marketplacev2" + ], + "githubUser": [] +} \ No newline at end of file diff --git a/Packs/ZeroNetworksSegment/ModelingRules/ZeroNetworksSegment/ZeroNetworksSegment.xif b/Packs/ZeroNetworksSegment/ModelingRules/ZeroNetworksSegment/ZeroNetworksSegment.xif index aa186c0e01a1..e3e4078db7f9 100644 --- a/Packs/ZeroNetworksSegment/ModelingRules/ZeroNetworksSegment/ZeroNetworksSegment.xif +++ b/Packs/ZeroNetworksSegment/ModelingRules/ZeroNetworksSegment/ZeroNetworksSegment.xif @@ -2,16 +2,20 @@ // Audit logs filter source_log_type = "audit" | alter - useRole_string = if(userRole = 1, "Admin", userRole = 2, "Viewer", userRole = 3, "Regular", userRole = 4, "API-FullAccess", userRole = 5, "API-ReadOnly", userRole = 6, "SelfService", userRole = 7, "CloudConnectorProvisioning", userRole = 8, "JAMF Asset", userRole = 9, "Asset Manager", userRole = 10, "Operaror", userRole = 11, "Service Now Token", to_string(userRole)), + userRole_string = to_string(userRole), + auditType_string = to_string(auditType), + enforcementSource_string = to_string(enforcementSource) +| alter + userRole_normalized = if(userRole_string = "1", "Admin", userRole_string = "2", "Viewer", userRole_string = "3", "Regular", userRole_string = "4", "API-FullAccess", userRole_string = "5", "API-ReadOnly", userRole_string = "6", "SelfService", userRole_string = "7", "CloudConnectorProvisioning", userRole_string = "8", "JAMF Asset", userRole_string = "9", "Asset Manager", userRole_string = "10", "Operaror", userRole_string = "11", "Service Now Token", userRole_string), destinationEntityIDs = arraystring(arraymap(destinationEntitiesList -> [], json_extract_scalar("@element", "$.id")), ", "), destinationEntityNames = arraystring(arraymap(destinationEntitiesList -> [], json_extract_scalar("@element", "$.name")), ", ") | alter - xdm.event.type = if (auditType = 1, "Asset is being segmented (network)", auditType = 2, "Asset segmented (network)", auditType = 3, "Asset failed being segmented (network)", auditType = 4, "Asset is being unsegmented (network)", auditType = 5, "Asset unsegmented (network)", auditType = 6, "Asset failed being unsegmented (network)", auditType = 7, "Asset added to learning (network)", auditType = 8, "Asset removed from learning (network)", auditType = 9, "Inbound allow rule created", auditType = 10, "Inbound allow rule deleted", auditType = 11, "Inbound allow rule expired", auditType = 12, "Inbound allow rule edited", auditType = 17, "Inbound MFA policy created", auditType = 18, "Inbound MFA policy edited", auditType = 19, "Inbound MFA policy deleted", auditType = 20, "Inbound JIT rule created", auditType = 21, "Inbound JIT rule deleted", auditType = 22, "Inbound JIT rule expired", auditType = 23, "Inbound JIT rule revived", auditType = 24, "Inbound JIT rule edited", auditType = 25, "API Token created", auditType = 26, "API Token deleted", auditType = 27, "API Token regenerated", auditType = 28, "Asset segmentation date postponed (network)", auditType = 29, "Outbound block rule created", auditType = 30, "Outbound block rule deleted", auditType = 31, "Outbound block rule expired", auditType = 32, "Outbound block rule edited", auditType = 33, "Inbound block rule created", auditType = 34, "Inbound block rule deleted", auditType = 35, "Inbound block rule expired", auditType = 36, "Inbound block rule edited", auditType = 39, "Asset unsegmented (network) (overriding policy)", auditType = 40, "Asset is being unsegmented (network) (overriding policy)", auditType = 41, "Asset removed from learning (network) (overriding policy)", auditType = 42, "Asset is being segmented (network) (policy)", auditType = 43, "Asset segmented (network) (policy)", auditType = 44, "Asset added to learning (network) (policy)", auditType = 45, "Segmentation policy created", auditType = 46, "Segmentation policy deleted", auditType = 47, "Segmentation policy edited", auditType = 48, "Inbound JIT access rejected", auditType = 49, "Inbound JIT fallback rule created", auditType = 50, "Inbound JIT fallback rule deleted", auditType = 51, "Inbound JIT fallback rule expired", auditType = 53, "Outbound allow rule created", auditType = 54, "Outbound allow rule deleted", auditType = 55, "Outbound allow rule expired", auditType = 56, "Outbound allow rule edited", auditType = 58, "Admin portal role changed to admin", auditType = 59, "Admin portal role changed to viewer", auditType = 60, "Admin portal role revoked", auditType = 61, "Outbound JIT rule created", auditType = 62, "Outbound JIT rule deleted", auditType = 63, "Outbound JIT rule expired", auditType = 64, "Outbound MFA policy created", auditType = 65, "Outbound MFA policy deleted", auditType = 66, "Outbound MFA policy edited", auditType = 67, "Outbound JIT access rejected", auditType = 68, "Asset learning is done (network)", auditType = 69, "Asset learning (policy) is done (network)", auditType = 70, "Manual Linux asset created", auditType = 71, "Manual OT/IoT asset created", auditType = 72, "Asset learning extended (network)", auditType = 73, "Admin portal logon", auditType = 74, "Asset manager added", auditType = 75, "Asset manager removed", auditType = 76, "Asset is monitored by Cloud connector", auditType = 77, "Asset is no longer monitored by Cloud connector", auditType = 78, "Asset is monitored by Segment server", auditType = 79, "Asset is back to learning (network)", auditType = 80, "Manual OT/IoT asset edited", auditType = 81, "Admin portal role changed to operator", auditType = 82, "Segment server deployed", auditType = 83, "AI inbound allow rule rejected", auditType = 84, "AI inbound block rule rejected", auditType = 85, "AI outbound allow rule rejected", auditType = 86, "AI outbound block rule rejected", auditType = 87, "AI inbound allow rule approved", auditType = 88, "AI inbound block rule approved", auditType = 89, "AI outbound allow rule approved", auditType = 90, "AI outbound block rule approved", auditType = 91, "AI inbound allow rule approved with changes", auditType = 92, "AI inbound block rule approved with changes", auditType = 93, "AI outbound allow rule approved with changes", auditType = 94, "AI outbound block rule approved with changes", auditType = 95, "Connect region created", auditType = 96, "Connect session created", auditType = 97, "Connect session expired", auditType = 98, "Connect session revoked", auditType = 99, "Connect session logged out", auditType = 100, "User access configuration created", auditType = 101, "User access configuration edited", auditType = 102, "User access configuration deleted", auditType = 103, "Connect server deployed", auditType = 104, "Connect asset created", auditType = 105, "Asset segmentation postponed (network) (pending review rules)", auditType = 106, "Connect region edited", auditType = 107, "Connect server edited", auditType = 108, "Asset is being segmented (identity)", auditType = 109, "Asset segmented (identity)", auditType = 110, "Asset is being unsegmented (identity)", auditType = 111, "Asset unsegmented (identity)", auditType = 112, "Identity rule created", auditType = 113, "Identity rule deleted", auditType = 114, "Identity rule expired", auditType = 115, "Identity rule edited", auditType = 116, "User segmented (identity)", auditType = 117, "User unsegmented (identity)", auditType = 118, "User added to learning (identity)", auditType = 119, "User removed from learning (identity)", auditType = 120, "Asset added to RPC monitoring", auditType = 121, "Asset removed from RPC monitoring", auditType = 122, "User classification changed", auditType = 123, "Connect session extended", auditType = 124, "Asset marked as inactive by repository (deleted)", auditType = 125, "Asset marked as active by repository", auditType = 126, "Asset marked as inactive by user", auditType = 127, "Asset marked as active by user", auditType = 128, "Break glass configuration activated", auditType = 129, "Break glass configuration deactivated", auditType = 130, "Asset marked as inactive by repository (disable)", auditType = 131, "Asset marked as active by repository (enable)", auditType = 132, "Break glass configuration activated (asset)", auditType = 133, "Break glass configuration deactivated (asset)", auditType = 134, "Asset is being segmented (RPC)", auditType = 135, "Asset segmented (RPC)", auditType = 136, "Asset is being unsegmented (RPC)", auditType = 137, "Asset unsegmented (RPC)", auditType = 138, "RPC rule created", auditType = 139, "RPC rule deleted", auditType = 140, "RPC rule expired", auditType = 141, "RPC rule edited", to_string(auditType)), - xdm.event.original_event_type = to_string(auditType), - xdm.event.operation_sub_type = if(enforcementSource = 1, "ReacticePolicy", enforcementSource = 2, "Automated", enforcementSource = 3, "AccessPortal", enforcementSource = 4, "AdminPortal", enforcementSource = 5, "AI", enforcementSource = 6, "API", enforcementSource = 7, "Setup", to_string(enforcementSource)), + xdm.event.type = if (auditType_string = "1", "Asset is being segmented (network)", auditType_string = "2", "Asset segmented (network)", auditType_string = "3", "Asset failed being segmented (network)", auditType_string = "4", "Asset is being unsegmented (network)", auditType_string = "5", "Asset unsegmented (network)", auditType_string = "6", "Asset failed being unsegmented (network)", auditType_string = "7", "Asset added to learning (network)", auditType_string = "8", "Asset removed from learning (network)", auditType_string = "9", "Inbound allow rule created", auditType_string = "10", "Inbound allow rule deleted", auditType_string = "11", "Inbound allow rule expired", auditType_string = "12", "Inbound allow rule edited", auditType_string = "17", "Inbound MFA policy created", auditType_string = "18", "Inbound MFA policy edited", auditType_string = "19", "Inbound MFA policy deleted", auditType_string = "20", "Inbound JIT rule created", auditType_string = "21", "Inbound JIT rule deleted", auditType_string = "22", "Inbound JIT rule expired", auditType_string = "23", "Inbound JIT rule revived", auditType_string = "24", "Inbound JIT rule edited", auditType_string = "25", "API Token created", auditType_string = "26", "API Token deleted", auditType_string = "27", "API Token regenerated", auditType_string = "28", "Asset segmentation date postponed (network)", auditType_string = "29", "Outbound block rule created", auditType_string = "30", "Outbound block rule deleted", auditType_string = "31", "Outbound block rule expired", auditType_string = "32", "Outbound block rule edited", auditType_string = "33", "Inbound block rule created", auditType_string = "34", "Inbound block rule deleted", auditType_string = "35", "Inbound block rule expired", auditType_string = "36", "Inbound block rule edited", auditType_string = "39", "Asset unsegmented (network) (overriding policy)", auditType_string = "40", "Asset is being unsegmented (network) (overriding policy)", auditType_string = "41", "Asset removed from learning (network) (overriding policy)", auditType_string = "42", "Asset is being segmented (network) (policy)", auditType_string = "43", "Asset segmented (network) (policy)", auditType_string = "44", "Asset added to learning (network) (policy)", auditType_string = "45", "Segmentation policy created", auditType_string = "46", "Segmentation policy deleted", auditType_string = "47", "Segmentation policy edited", auditType_string = "48", "Inbound JIT access rejected", auditType_string = "49", "Inbound JIT fallback rule created", auditType_string = "50", "Inbound JIT fallback rule deleted", auditType_string = "51", "Inbound JIT fallback rule expired", auditType_string = "53", "Outbound allow rule created", auditType_string = "54", "Outbound allow rule deleted", auditType_string = "55", "Outbound allow rule expired", auditType_string = "56", "Outbound allow rule edited", auditType_string = "58", "Admin portal role changed to admin", auditType_string = "59", "Admin portal role changed to viewer", auditType_string = "60", "Admin portal role revoked", auditType_string = "61", "Outbound JIT rule created", auditType_string = "62", "Outbound JIT rule deleted", auditType_string = "63", "Outbound JIT rule expired", auditType_string = "64", "Outbound MFA policy created", auditType_string = "65", "Outbound MFA policy deleted", auditType_string = "66", "Outbound MFA policy edited", auditType_string = "67", "Outbound JIT access rejected", auditType_string = "68", "Asset learning is done (network)", auditType_string = "69", "Asset learning (policy) is done (network)", auditType_string = "70", "Manual Linux asset created", auditType_string = "71", "Manual OT/IoT asset created", auditType_string = "72", "Asset learning extended (network)", auditType_string = "73", "Admin portal logon", auditType_string = "74", "Asset manager added", auditType_string = "75", "Asset manager removed", auditType_string = "76", "Asset is monitored by Cloud connector", auditType_string = "77", "Asset is no longer monitored by Cloud connector", auditType_string = "78", "Asset is monitored by Segment server", auditType_string = "79", "Asset is back to learning (network)", auditType_string = "80", "Manual OT/IoT asset edited", auditType_string = "81", "Admin portal role changed to operator", auditType_string = "82", "Segment server deployed", auditType_string = "83", "AI inbound allow rule rejected", auditType_string = "84", "AI inbound block rule rejected", auditType_string = "85", "AI outbound allow rule rejected", auditType_string = "86", "AI outbound block rule rejected", auditType_string = "87", "AI inbound allow rule approved", auditType_string = "88", "AI inbound block rule approved", auditType_string = "89", "AI outbound allow rule approved", auditType_string = "90", "AI outbound block rule approved", auditType_string = "91", "AI inbound allow rule approved with changes", auditType_string = "92", "AI inbound block rule approved with changes", auditType_string = "93", "AI outbound allow rule approved with changes", auditType_string = "94", "AI outbound block rule approved with changes", auditType_string = "95", "Connect region created", auditType_string = "96", "Connect session created", auditType_string = "97", "Connect session expired", auditType_string = "98", "Connect session revoked", auditType_string = "99", "Connect session logged out", auditType_string = "100", "User access configuration created", auditType_string = "101", "User access configuration edited", auditType_string = "102", "User access configuration deleted", auditType_string = "103", "Connect server deployed", auditType_string = "104", "Connect asset created", auditType_string = "105", "Asset segmentation postponed (network) (pending review rules)", auditType_string = "106", "Connect region edited", auditType_string = "107", "Connect server edited", auditType_string = "108", "Asset is being segmented (identity)", auditType_string = "109", "Asset segmented (identity)", auditType_string = "110", "Asset is being unsegmented (identity)", auditType_string = "111", "Asset unsegmented (identity)", auditType_string = "112", "Identity rule created", auditType_string = "113", "Identity rule deleted", auditType_string = "114", "Identity rule expired", auditType_string = "115", "Identity rule edited", auditType_string = "116", "User segmented (identity)", auditType_string = "117", "User unsegmented (identity)", auditType_string = "118", "User added to learning (identity)", auditType_string = "119", "User removed from learning (identity)", auditType_string = "120", "Asset added to RPC monitoring", auditType_string = "121", "Asset removed from RPC monitoring", auditType_string = "122", "User classification changed", auditType_string = "123", "Connect session extended", auditType_string = "124", "Asset marked as inactive by repository (deleted)", auditType_string = "125", "Asset marked as active by repository", auditType_string = "126", "Asset marked as inactive by user", auditType_string = "127", "Asset marked as active by user", auditType_string = "128", "Break glass configuration activated", auditType_string = "129", "Break glass configuration deactivated", auditType_string = "130", "Asset marked as inactive by repository (disable)", auditType_string = "131", "Asset marked as active by repository (enable)", auditType_string = "132", "Break glass configuration activated (asset)", auditType_string = "133", "Break glass configuration deactivated (asset)", auditType_string = "134", "Asset is being segmented (RPC)", auditType_string = "135", "Asset segmented (RPC)", auditType_string = "136", "Asset is being unsegmented (RPC)", auditType_string = "137", "Asset unsegmented (RPC)", auditType_string = "138", "RPC rule created", auditType_string = "139", "RPC rule deleted", auditType_string = "140", "RPC rule expired", auditType_string = "141", "RPC rule edited", auditType_string), + xdm.event.original_event_type = auditType_string, + xdm.event.operation_sub_type = if(enforcementSource_string = "1", "ReacticePolicy", enforcementSource_string = "2", "Automated", enforcementSource_string = "3", "AccessPortal", enforcementSource_string = "4", "AdminPortal", enforcementSource_string = "5", "AI", enforcementSource_string = "6", "API", enforcementSource_string = "7", "Setup", enforcementSource_string), xdm.source.user.identifier = json_extract_scalar(performedBy, "$.id"), xdm.source.user.username = json_extract_scalar(performedBy, "$.name"), - xdm.auth.privilege_level = if(useRole_string = "Admin", XDM_CONST.PRIVILEGE_LEVEL_ADMIN, useRole_string in("Viewer", "Regular"), XDM_CONST.PRIVILEGE_LEVEL_USER, null), + xdm.auth.privilege_level = if(userRole_normalized = "Admin", XDM_CONST.PRIVILEGE_LEVEL_ADMIN, userRole_normalized in("Viewer", "Regular"), XDM_CONST.PRIVILEGE_LEVEL_USER, null), xdm.target.resource.parent_id = if(parentObjectId != null and parentObjectId != "", parentObjectId, null), xdm.target.resource.id = if(reportedObjectId != null and reportedObjectId != "", reportedObjectId, reportedObjectId = null or reportedObjectId = "", destinationEntityIDs, null), xdm.target.resource.name = if(reportedObjectId = null or reportedObjectId = "", destinationEntityNames, null), @@ -22,17 +26,18 @@ filter source_log_type = "audit" filter source_log_type = "network_activities" | alter protocol_string = to_string(protocol), - src_assetType = to_integer(json_extract_scalar(src, "$.assetType")), - dst_assetType = to_integer(json_extract_scalar(dst, "$.assetType")), + state_string = to_string(state), + src_assetType = to_string(json_extract_scalar(src, "$.assetType")), + dst_assetType = to_string(json_extract_scalar(dst, "$.assetType")), inbound_rules_ids = arraymap(inboundRuleMatches -> [], json_extract_scalar("@element", "$.ruleId")), outbound_rules_ids = arraymap(outboundRuleMatches -> [], json_extract_scalar("@element", "$.ruleId")) | alter xdm.event.type = source_log_type, xdm.network.ip_protocol = if(protocol_string = "0", XDM_CONST.IP_PROTOCOL_HOPOPT, protocol_string = "1", XDM_CONST.IP_PROTOCOL_ICMP, protocol_string = "2", XDM_CONST.IP_PROTOCOL_IGMP, protocol_string = "3", XDM_CONST.IP_PROTOCOL_GGP, protocol_string = "4", XDM_CONST.IP_PROTOCOL_IP, protocol_string = "5", XDM_CONST.IP_PROTOCOL_ST, protocol_string = "6", XDM_CONST.IP_PROTOCOL_TCP, protocol_string = "7", XDM_CONST.IP_PROTOCOL_CBT, protocol_string = "8", XDM_CONST.IP_PROTOCOL_EGP, protocol_string = "9", XDM_CONST.IP_PROTOCOL_IGP, protocol_string = "10", XDM_CONST.IP_PROTOCOL_BBN_RCC_MON, protocol_string = "11", XDM_CONST.IP_PROTOCOL_NVP_II, protocol_string = "12", XDM_CONST.IP_PROTOCOL_PUP, protocol_string = "13", XDM_CONST.IP_PROTOCOL_ARGUS, protocol_string = "14", XDM_CONST.IP_PROTOCOL_EMCON, protocol_string = "15", XDM_CONST.IP_PROTOCOL_XNET, protocol_string = "16", XDM_CONST.IP_PROTOCOL_CHAOS, protocol_string = "17", XDM_CONST.IP_PROTOCOL_UDP, protocol_string = "18", XDM_CONST.IP_PROTOCOL_MUX, protocol_string = "19", XDM_CONST.IP_PROTOCOL_DCN_MEAS, protocol_string = "20", XDM_CONST.IP_PROTOCOL_HMP, protocol_string = "21", XDM_CONST.IP_PROTOCOL_PRM, protocol_string = "22", XDM_CONST.IP_PROTOCOL_XNS_IDP, protocol_string = "23", XDM_CONST.IP_PROTOCOL_TRUNK_1, protocol_string = "24", XDM_CONST.IP_PROTOCOL_TRUNK_2, protocol_string = "25", XDM_CONST.IP_PROTOCOL_LEAF_1, protocol_string = "26", XDM_CONST.IP_PROTOCOL_LEAF_2, protocol_string = "27", XDM_CONST.IP_PROTOCOL_RDP, protocol_string = "28", XDM_CONST.IP_PROTOCOL_IRTP, protocol_string = "29", XDM_CONST.IP_PROTOCOL_ISO_TP4, protocol_string = "30", XDM_CONST.IP_PROTOCOL_NETBLT, protocol_string = "31", XDM_CONST.IP_PROTOCOL_MFE_NSP, protocol_string = "32", XDM_CONST.IP_PROTOCOL_MERIT_INP, protocol_string = "33", XDM_CONST.IP_PROTOCOL_DCCP, protocol_string = "34", XDM_CONST.IP_PROTOCOL_3PC, protocol_string = "35", XDM_CONST.IP_PROTOCOL_IDPR, protocol_string = "36", XDM_CONST.IP_PROTOCOL_XTP, protocol_string = "37", XDM_CONST.IP_PROTOCOL_DDP, protocol_string = "38", XDM_CONST.IP_PROTOCOL_IDPR_CMTP, protocol_string = "39", XDM_CONST.IP_PROTOCOL_TP, protocol_string = "40", XDM_CONST.IP_PROTOCOL_IL, protocol_string = "41", XDM_CONST.IP_PROTOCOL_IPV6, protocol_string = "42", XDM_CONST.IP_PROTOCOL_SDRP, protocol_string = "43", XDM_CONST.IP_PROTOCOL_IPV6_ROUTE, protocol_string = "44", XDM_CONST.IP_PROTOCOL_IPV6_FRAG, protocol_string = "45", XDM_CONST.IP_PROTOCOL_IDRP, protocol_string = "46", XDM_CONST.IP_PROTOCOL_RSVP, protocol_string = "47", XDM_CONST.IP_PROTOCOL_GRE, protocol_string = "48", XDM_CONST.IP_PROTOCOL_DSR, protocol_string = "49", XDM_CONST.IP_PROTOCOL_BNA, protocol_string = "50", XDM_CONST.IP_PROTOCOL_ESP, protocol_string = "51", XDM_CONST.IP_PROTOCOL_AH, protocol_string = "52", XDM_CONST.IP_PROTOCOL_I_NLSP, protocol_string = "53", XDM_CONST.IP_PROTOCOL_SWIPE, protocol_string = "54", XDM_CONST.IP_PROTOCOL_NARP, protocol_string = "55", XDM_CONST.IP_PROTOCOL_MOBILE, protocol_string = "56", XDM_CONST.IP_PROTOCOL_TLSP, protocol_string = "57", XDM_CONST.IP_PROTOCOL_SKIP, protocol_string = "58", XDM_CONST.IP_PROTOCOL_IPV6_ICMP, protocol_string = "59", XDM_CONST.IP_PROTOCOL_IPV6_NONXT, protocol_string = "60", XDM_CONST.IP_PROTOCOL_IPV6_OPTS, protocol_string = "62", XDM_CONST.IP_PROTOCOL_CFTP, protocol_string = "64", XDM_CONST.IP_PROTOCOL_SAT_EXPAK, protocol_string = "65", XDM_CONST.IP_PROTOCOL_KRYPTOLAN, protocol_string = "66", XDM_CONST.IP_PROTOCOL_RVD, protocol_string = "67", XDM_CONST.IP_PROTOCOL_IPPC, protocol_string = "69", XDM_CONST.IP_PROTOCOL_SAT_MON, protocol_string = "70", XDM_CONST.IP_PROTOCOL_VISA, protocol_string = "71", XDM_CONST.IP_PROTOCOL_IPCV, protocol_string = "72", XDM_CONST.IP_PROTOCOL_CPNX, protocol_string = "73", XDM_CONST.IP_PROTOCOL_CPHB, protocol_string = "74", XDM_CONST.IP_PROTOCOL_WSN, protocol_string = "75", XDM_CONST.IP_PROTOCOL_PVP, protocol_string = "76", XDM_CONST.IP_PROTOCOL_BR_SAT_MON, protocol_string = "77", XDM_CONST.IP_PROTOCOL_SUN_ND, protocol_string = "78", XDM_CONST.IP_PROTOCOL_WB_MON, protocol_string = "79", XDM_CONST.IP_PROTOCOL_WB_EXPAK, protocol_string = "80", XDM_CONST.IP_PROTOCOL_ISO_IP, protocol_string = "81", XDM_CONST.IP_PROTOCOL_VMTP, protocol_string = "82", XDM_CONST.IP_PROTOCOL_SECURE_VMTP, protocol_string = "83", XDM_CONST.IP_PROTOCOL_VINES, protocol_string = "84", XDM_CONST.IP_PROTOCOL_TTP, protocol_string = "85", XDM_CONST.IP_PROTOCOL_NSFNET_IGP, protocol_string = "86", XDM_CONST.IP_PROTOCOL_DGP, protocol_string = "87", XDM_CONST.IP_PROTOCOL_TCF, protocol_string = "88", XDM_CONST.IP_PROTOCOL_EIGRP, protocol_string = "89", XDM_CONST.IP_PROTOCOL_OSPFIGP, protocol_string = "90", XDM_CONST.IP_PROTOCOL_SPRITE_RPC, protocol_string = "91", XDM_CONST.IP_PROTOCOL_LARP, protocol_string = "92", XDM_CONST.IP_PROTOCOL_MTP, protocol_string = "93", XDM_CONST.IP_PROTOCOL_AX25, protocol_string = "94", XDM_CONST.IP_PROTOCOL_IPIP, protocol_string = "95", XDM_CONST.IP_PROTOCOL_MICP, protocol_string = "96", XDM_CONST.IP_PROTOCOL_SCC_SP, protocol_string = "97", XDM_CONST.IP_PROTOCOL_ETHERIP, protocol_string = "98", XDM_CONST.IP_PROTOCOL_ENCAP, protocol_string = "100", XDM_CONST.IP_PROTOCOL_GMTP, protocol_string = "101", XDM_CONST.IP_PROTOCOL_IFMP, protocol_string = "102", XDM_CONST.IP_PROTOCOL_PNNI, protocol_string = "103", XDM_CONST.IP_PROTOCOL_PIM, protocol_string = "104", XDM_CONST.IP_PROTOCOL_ARIS, protocol_string = "105", XDM_CONST.IP_PROTOCOL_SCPS, protocol_string = "106", XDM_CONST.IP_PROTOCOL_QNX, protocol_string = "107", XDM_CONST.IP_PROTOCOL_AN, protocol_string = "108", XDM_CONST.IP_PROTOCOL_IPCOMP, protocol_string = "109", XDM_CONST.IP_PROTOCOL_SNP, protocol_string = "110", XDM_CONST.IP_PROTOCOL_COMPAQ_PEER, protocol_string = "111", XDM_CONST.IP_PROTOCOL_IPX_IN_IP, protocol_string = "112", XDM_CONST.IP_PROTOCOL_VRRP, protocol_string = "113", XDM_CONST.IP_PROTOCOL_PGM, protocol_string = "115", XDM_CONST.IP_PROTOCOL_L2TP, protocol_string = "116", XDM_CONST.IP_PROTOCOL_DDX, protocol_string = "117", XDM_CONST.IP_PROTOCOL_IATP, protocol_string = "118", XDM_CONST.IP_PROTOCOL_STP, protocol_string = "119", XDM_CONST.IP_PROTOCOL_SRP, protocol_string = "120", XDM_CONST.IP_PROTOCOL_UTI, protocol_string = "121", XDM_CONST.IP_PROTOCOL_SMP, protocol_string = "122", XDM_CONST.IP_PROTOCOL_SM, protocol_string = "123", XDM_CONST.IP_PROTOCOL_PTP, protocol_string = "124", XDM_CONST.IP_PROTOCOL_ISIS, protocol_string = "125", XDM_CONST.IP_PROTOCOL_FIRE, protocol_string = "126", XDM_CONST.IP_PROTOCOL_CRTP, protocol_string = "127", XDM_CONST.IP_PROTOCOL_CRUDP, protocol_string = "128", XDM_CONST.IP_PROTOCOL_SSCOPMCE, protocol_string = "129", XDM_CONST.IP_PROTOCOL_IPLT, protocol_string = "130", XDM_CONST.IP_PROTOCOL_SPS, protocol_string = "131", XDM_CONST.IP_PROTOCOL_PIPE, protocol_string = "132", XDM_CONST.IP_PROTOCOL_SCTP, protocol_string = "133", XDM_CONST.IP_PROTOCOL_FC, protocol_string = "134", XDM_CONST.IP_PROTOCOL_RSVP_E2E_IGNORE, protocol_string = "135", XDM_CONST.IP_PROTOCOL_MOBILITY, protocol_string = "136", XDM_CONST.IP_PROTOCOL_UDPLITE, protocol_string = "137", XDM_CONST.IP_PROTOCOL_MPLS_IN_IP, protocol_string = "138", XDM_CONST.IP_PROTOCOL_MANET, protocol_string = "139", XDM_CONST.IP_PROTOCOL_HIP, protocol_string = "140", XDM_CONST.IP_PROTOCOL_SHIM6, protocol_string = "141", XDM_CONST.IP_PROTOCOL_WESP, protocol_string = "142", XDM_CONST.IP_PROTOCOL_ROHC, protocol_string = "255", XDM_CONST.IP_PROTOCOL_RESERVED, to_string(protocol_string)), - xdm.observer.action = if(state = 1, "Blocked", state = 2, "Requested", state = 3, "Established", state = 4, "Blocked At Source", state = 5, "Blocked By Third Party", state = 6, "Blocked At Source By Third Party", to_string(state)), + xdm.observer.action = if(state_string = "1", "Blocked", state_string = "2", "Requested", state_string = "3", "Established", state_string = "4", "Blocked At Source", state_string = "5", "Blocked By Third Party", state_string = "6", "Blocked At Source By Third Party", state_string), xdm.event.outcome_reason = to_string(reason), xdm.source.host.device_id = if(json_extract_scalar(src, "$.assetId") != "", json_extract_scalar(src, "$.assetId"), null), - xdm.source.host.device_category = if(src_assetType = 1, "Client", src_assetType = 2, "Server", src_assetType = 3, "Virtual cluster", src_assetType = 4, "IP camera", src_assetType = 5, "Smart TV", src_assetType = 6, "Factory controller", src_assetType = 7, "Medical device", src_assetType = 8, "Printer", src_assetType = 9, "Scanner", src_assetType = 10, "Smart card reader", src_assetType = 11, "Router", src_assetType = 12, "Hypervisor", src_assetType = 13, "PLC", src_assetType = 14, "HMI", src_assetType = 15, "Switch", src_assetType = 16, "Terminal station", src_assetType = 17, "RTU", src_assetType = 18, "Wireless access point", src_assetType = 19, "Historian", src_assetType = 20, "Game console", src_assetType = 21, "Fire alarm", src_assetType = 22, "UPS", src_assetType = 23, "Storage appliance", src_assetType = 24, "Virtualization appliance", src_assetType = 25, "Firewall appliance", src_assetType = 26, "Security scanner", src_assetType = 27, "Security controller", src_assetType = 28 , "Door lock", src_assetType = 29, "Biometric entry system", src_assetType = 30, "HVAC", src_assetType = 31, "Room scheduler", src_assetType = 32, "Load Balancer Appliance", src_assetType = 33, "WAN Concentrator", src_assetType = 34, "IPAM Appliance", to_string(src_assetType)), + xdm.source.host.device_category = if(src_assetType = "1", "Client", src_assetType = "2", "Server", src_assetType = "3", "Virtual cluster", src_assetType = "4", "IP camera", src_assetType = "5", "Smart TV", src_assetType = "6", "Factory controller", src_assetType = "7", "Medical device", src_assetType = "8", "Printer", src_assetType = "9", "Scanner", src_assetType = "10", "Smart card reader", src_assetType = "11", "Router", src_assetType = "12", "Hypervisor", src_assetType = "13", "PLC", src_assetType = "14", "HMI", src_assetType = "15", "Switch", src_assetType = "16", "Terminal station", src_assetType = "17", "RTU", src_assetType = "18", "Wireless access point", src_assetType = "19", "Historian", src_assetType = "20", "Game console", src_assetType = "21", "Fire alarm", src_assetType = "22", "UPS", src_assetType = "23", "Storage appliance", src_assetType = "24", "Virtualization appliance", src_assetType = "25", "Firewall appliance", src_assetType = "26", "Security scanner", src_assetType = "27", "Security controller", src_assetType = "28", "Door lock", src_assetType = "29", "Biometric entry system", src_assetType = "30", "HVAC", src_assetType = "31", "Room scheduler", src_assetType = "32", "Load Balancer Appliance", src_assetType = "33", "WAN Concentrator", src_assetType = "34", "IPAM Appliance", src_assetType), xdm.source.host.fqdn = if(json_extract_scalar(src, "$.fqdn") != "", json_extract_scalar(src, "$.fqdn"), null), xdm.source.ipv4 = if(json_extract_scalar(src, "$.ip") ~= "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", json_extract_scalar(src, "$.ip"), null), xdm.source.ipv6 = if(json_extract_scalar(src, "$.ip") ~= "(?:[a-fA-F\d]{0,4}\:){1,7}[a-fA-F\d]{0,4}", json_extract_scalar(src, "$.ip"), null), @@ -44,7 +49,7 @@ filter source_log_type = "network_activities" xdm.source.user.username = if(json_extract_scalar(src, "$.userName") contains """\\""", arrayindex(regextract(json_extract_scalar(src, "$.userName"), "[^\\]+\\([^\\]+)"), 0), json_extract_scalar(src, "$.userName") != "", json_extract_scalar(src, "$.userName"), null), xdm.source.user.domain = if(arrayindex(regextract(json_extract_scalar(src, "$.userName"), """([^\\\\]+)\\\\"""), 0) != "", arrayindex(regextract(json_extract_scalar(src, "$.userName"), "([^\\]+)\\"), 0), null), xdm.target.host.device_id = if(json_extract_scalar(dst, "$.assetId") != "", json_extract_scalar(dst, "$.assetId"), null), - xdm.target.host.device_category = if(dst_assetType = 1, "Client", dst_assetType = 2, "Server", dst_assetType = 3, "Virtual cluster", dst_assetType = 4, "IP camera", dst_assetType = 5, "Smart TV", dst_assetType = 6, "Factory controller", dst_assetType = 7, "Medical device", dst_assetType = 8, "Printer", dst_assetType = 9, "Scanner", dst_assetType = 10, "Smart card reader", dst_assetType = 11, "Router", dst_assetType = 12, "Hypervisor", dst_assetType = 13, "PLC", dst_assetType = 14, "HMI", dst_assetType = 15, "Switch", dst_assetType = 16, "Terminal station", dst_assetType = 17, "RTU", dst_assetType = 18, "Wireless access point", dst_assetType = 19, "Historian", dst_assetType = 20, "Game console", dst_assetType = 21, "Fire alarm", dst_assetType = 22, "UPS", dst_assetType = 23, "Storage appliance", dst_assetType = 24, "Virtualization appliance", dst_assetType = 25, "Firewall appliance", dst_assetType = 26, "Security scanner", dst_assetType = 27, "Security controller", dst_assetType = 28 , "Door lock", dst_assetType = 29, "Biometric entry system", dst_assetType = 30, "HVAC", dst_assetType = 31, "Room scheduler", dst_assetType = 32, "Load Balancer Appliance", dst_assetType = 33, "WAN Concentrator", dst_assetType = 34, "IPAM Appliance", to_string(dst_assetType)), + xdm.target.host.device_category = if(dst_assetType = "1", "Client", dst_assetType = "2", "Server", dst_assetType = "3", "Virtual cluster", dst_assetType = "4", "IP camera", dst_assetType = "5", "Smart TV", dst_assetType = "6", "Factory controller", dst_assetType = "7", "Medical device", dst_assetType = "8", "Printer", dst_assetType = "9", "Scanner", dst_assetType = "10", "Smart card reader", dst_assetType = "11", "Router", dst_assetType = "12", "Hypervisor", dst_assetType = "13", "PLC", dst_assetType = "14", "HMI", dst_assetType = "15", "Switch", dst_assetType = "16", "Terminal station", dst_assetType = "17", "RTU", dst_assetType = "18", "Wireless access point", dst_assetType = "19", "Historian", dst_assetType = "20", "Game console", dst_assetType = "21", "Fire alarm", dst_assetType = "22", "UPS", dst_assetType = "23", "Storage appliance", dst_assetType = "24", "Virtualization appliance", dst_assetType = "25", "Firewall appliance", dst_assetType = "26", "Security scanner", dst_assetType = "27", "Security controller", dst_assetType = "28", "Door lock", dst_assetType = "29", "Biometric entry system", dst_assetType = "30", "HVAC", dst_assetType = "31", "Room scheduler", dst_assetType = "32", "Load Balancer Appliance", dst_assetType = "33", "WAN Concentrator", dst_assetType = "34", "IPAM Appliance", dst_assetType), xdm.target.host.fqdn = if(json_extract_scalar(dst, "$.fqdn") != "", json_extract_scalar(dst, "$.fqdn"), null), xdm.target.ipv4 = if(json_extract_scalar(dst, "$.ip") ~= "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", json_extract_scalar(dst, "$.ip"), null), xdm.target.ipv6 = if(json_extract_scalar(dst, "$.ip") ~= "(?:[a-fA-F\d]{0,4}\:){1,7}[a-fA-F\d]{0,4}", json_extract_scalar(dst, "$.ip"), null), diff --git a/Packs/ZeroNetworksSegment/ReleaseNotes/1_0_2.md b/Packs/ZeroNetworksSegment/ReleaseNotes/1_0_2.md new file mode 100644 index 000000000000..55dc3e4d286d --- /dev/null +++ b/Packs/ZeroNetworksSegment/ReleaseNotes/1_0_2.md @@ -0,0 +1,3 @@ +#### Modeling Rules +##### Zero Networks Segment Modeling Rule +Improved implementation of modeling rules to support additional field types. diff --git a/Packs/ZeroNetworksSegment/pack_metadata.json b/Packs/ZeroNetworksSegment/pack_metadata.json index f19130a00200..145de2059826 100644 --- a/Packs/ZeroNetworksSegment/pack_metadata.json +++ b/Packs/ZeroNetworksSegment/pack_metadata.json @@ -2,16 +2,24 @@ "name": "Zero Networks Segment", "description": "Integrates with Zero Networks Segment API to fetch and process audit and network events.", "support": "xsoar", - "currentVersion": "1.0.1", + "currentVersion": "1.0.2", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", "categories": [ "Network Security" ], - "tags": ["Security", "Network"], + "tags": [ + "Security", + "Network" + ], "useCases": [], - "keywords": ["zero", "networks", "segment", "zeronetworks"], + "keywords": [ + "zero", + "networks", + "segment", + "zeronetworks" + ], "marketplaces": [ "marketplacev2" ] diff --git a/Packs/Zoom/Integrations/Zoom/README.md b/Packs/Zoom/Integrations/Zoom/README.md index 9575e23f9fe3..123e662bcdb0 100644 --- a/Packs/Zoom/Integrations/Zoom/README.md +++ b/Packs/Zoom/Integrations/Zoom/README.md @@ -1919,6 +1919,36 @@ Searches chat messages or shared files between a user and an individual contact >| 2023-05-22T08:24:14Z | None | a62636c8-b6c1-4135-9352-88ac61eafc31 | | message | admin zoom | None | uJiZN-O7Rp6Jp_995FpZGg | >| 2023-05-22T08:20:22Z | None | 4a59df4a-9668-46bd-bff2-3e1f3462ecc3 | | my message | admin zoom | None | uJiZN-O7Rp6Jp_995FpZGg | +### zoom-delete-user-token + +*** +Revoke a user's Zoom SSO session. +To list all available users use the `zoom-list-users` command. + + +#### Base Command + +`zoom-delete-user-token` + +#### Input + +| **Argument Name** | **Description** | **Required** | +|-------------------|-----------------------------------------------------------------------------------------| --- | +| user_id | The user ID or email to be revoked. | Required | + +#### Command example + +```!zoom-delete-user-token user_id=useremail@myself.com``` + +#### Context Output + +There is no context output for this command. + +#### Human Readable Output + +>### Message +>User SSO token for user usetobe@myself.com is deleted + ### send-notification *** diff --git a/Packs/Zoom/Integrations/Zoom/Zoom.py b/Packs/Zoom/Integrations/Zoom/Zoom.py index 8f69c73723f7..0ea0505d0f0c 100644 --- a/Packs/Zoom/Integrations/Zoom/Zoom.py +++ b/Packs/Zoom/Integrations/Zoom/Zoom.py @@ -395,6 +395,14 @@ def zoom_get_admin_user_id_from_token(self): headers={'authorization': f'Bearer {self.access_token}'} ) + def zoom_delete_user_token(self, url_suffix: str): + return self.error_handled_http_request( + method='DELETE', + url_suffix=url_suffix, + resp_type='response', + headers={'authorization': f'Bearer {self.access_token}'} + ) + '''HELPER FUNCTIONS''' @@ -2007,6 +2015,19 @@ def zoom_update_message_command(client, **args) -> CommandResults: ) +def zoom_delete_user_token_command(client, **args) -> CommandResults: + """ + Revoke a user's Zoom SSO session + """ + client = client + user_id = args.get('user_id') + url_suffix = f'/users/{user_id}/token' + client.zoom_delete_user_token(url_suffix) + return CommandResults( + readable_output=f'User SSO token for user {user_id} is deleted', + ) + + def zoom_get_user_id_by_email(client, email): """ Retrieves the user ID associated with the given email address. @@ -2555,6 +2576,8 @@ def main(): # pragma: no cover results = zoom_delete_message_command(client, **args) elif command == 'zoom-update-message': results = zoom_update_message_command(client, **args) + elif command == 'zoom-delete-user-token': + results = zoom_delete_user_token_command(client, **args) elif command == 'send-notification': results = send_notification(client, **args) diff --git a/Packs/Zoom/Integrations/Zoom/Zoom.yml b/Packs/Zoom/Integrations/Zoom/Zoom.yml index 2d3a1eca4d48..4c4e362f8bf9 100644 --- a/Packs/Zoom/Integrations/Zoom/Zoom.yml +++ b/Packs/Zoom/Integrations/Zoom/Zoom.yml @@ -1225,6 +1225,15 @@ script: name: channel_id description: Delete a mirrored Zoom channel. name: close-channel + - name: zoom-delete-user-token + description: Revoke a user's Zoom SSO session. Use the zoom-list-users command to get the user ID or user email. + execution: true + arguments: + - name: user_id + description: Email or unique identifier of the user. + required: true + type: string + outputs: [ ] - name: send-notification description: Send a message using a chatbot app. arguments: diff --git a/Packs/Zoom/Integrations/Zoom/Zoom_test.py b/Packs/Zoom/Integrations/Zoom/Zoom_test.py index 5aef2afa4549..6442b4f4a9d7 100644 --- a/Packs/Zoom/Integrations/Zoom/Zoom_test.py +++ b/Packs/Zoom/Integrations/Zoom/Zoom_test.py @@ -1813,6 +1813,31 @@ def test_zoom_send_notification_command(mocker): assert mock_send_chat_message.call_args[0][1] == expected_request_payload +def test_zoom_delete_user_token_command(mocker): + """ + Given - + Zoom client + When - + zoom-delete-user-token has called + Then - + Validate that the zoom_delete_user_token function is called with the correct arguments + Validate the command results return the correct readable output + """ + + client = Client(base_url='https://test.com', account_id="mockaccount", + client_id="mockclient", client_secret="mocksecret") + mocker.patch.object(Client, "generate_oauth_token") + + user_id = 'mock_user_id' + zoom_delete_user_token_mock = mocker.patch.object(client, "zoom_delete_user_token") + + from Zoom import zoom_delete_user_token_command + + result = zoom_delete_user_token_command(client, user_id=user_id) + zoom_delete_user_token_mock.assert_called_with(f"/users/{user_id}/token") + assert result.readable_output == 'User SSO token for user mock_user_id is deleted' + + @pytest.mark.parametrize("channel_name, investigation_id, expected_result", [ ('Channel1', None, 'JID1'), # Scenario 1: Find by channel_name (None, 'Incident123', 'JID1'), # Scenario 2: Find by investigation_id diff --git a/Packs/Zoom/Integrations/Zoom/commands.txt b/Packs/Zoom/Integrations/Zoom/commands.txt index e73c7d64a780..03c92ce54895 100644 --- a/Packs/Zoom/Integrations/Zoom/commands.txt +++ b/Packs/Zoom/Integrations/Zoom/commands.txt @@ -17,4 +17,5 @@ !zoom-list-messages user_id=userid to_contact=example@example.com date=today !zoom-send-message user_id=userid message="message" to_contact=example@example.com !zoom-update-message user_id=userid message="message2" to_contact=example@example.com message_id=messageid -!zoom-delete-message user_id=userid to_contact=example@example.com message_id=messageid \ No newline at end of file +!zoom-delete-message user_id=userid to_contact=example@example.com message_id=messageid +!zoom-delete-user-token user_id=userid \ No newline at end of file diff --git a/Packs/Zoom/ReleaseNotes/1_6_14.md b/Packs/Zoom/ReleaseNotes/1_6_14.md new file mode 100644 index 000000000000..d719b9734145 --- /dev/null +++ b/Packs/Zoom/ReleaseNotes/1_6_14.md @@ -0,0 +1,7 @@ + +#### Integrations + +##### Zoom + +Added the following command: +- ***zoom-delete-user-token*** \ No newline at end of file diff --git a/Packs/Zoom/pack_metadata.json b/Packs/Zoom/pack_metadata.json index 5af7d4e0c5ce..825ebf8207c2 100644 --- a/Packs/Zoom/pack_metadata.json +++ b/Packs/Zoom/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Zoom", "description": "Use the Zoom integration manage your Zoom users and meetings", "support": "xsoar", - "currentVersion": "1.6.13", + "currentVersion": "1.6.14", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/Zscaler/Integrations/Zscaler/Zscaler.py b/Packs/Zscaler/Integrations/Zscaler/Zscaler.py index 5ec8e36fbfd0..588cd6acf333 100644 --- a/Packs/Zscaler/Integrations/Zscaler/Zscaler.py +++ b/Packs/Zscaler/Integrations/Zscaler/Zscaler.py @@ -893,7 +893,7 @@ def logout_command(): ) try: DEFAULT_HEADERS["cookie"] = session_id - raw_res = logout().json() + raw_res = logout() except AuthorizationError: return CommandResults( readable_output="API session is not authenticated. No action was performed." @@ -905,7 +905,7 @@ def logout_command(): def activate_command(): - raw_res = activate_changes().json() + raw_res = activate_changes() return CommandResults( readable_output="Changes have been activated successfully.", raw_response=raw_res, diff --git a/Packs/Zscaler/ReleaseNotes/1_3_27.md b/Packs/Zscaler/ReleaseNotes/1_3_27.md new file mode 100644 index 000000000000..1113e98e909e --- /dev/null +++ b/Packs/Zscaler/ReleaseNotes/1_3_27.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Zscaler Internet Access + +Fixed an issue where the **zscaler-logout** and **zscaler-activate-changes** commands returned an error after a successful execution. diff --git a/Packs/Zscaler/pack_metadata.json b/Packs/Zscaler/pack_metadata.json index 1f940bde1f20..8c672f7ced7d 100644 --- a/Packs/Zscaler/pack_metadata.json +++ b/Packs/Zscaler/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Zscaler Internet Access", "description": "Zscaler is a cloud security solution built for performance and flexible scalability.", "support": "xsoar", - "currentVersion": "1.3.26", + "currentVersion": "1.3.27", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/ctf01/ReleaseNotes/1_0_30.md b/Packs/ctf01/ReleaseNotes/1_0_30.md new file mode 100644 index 000000000000..938ec5cdb828 --- /dev/null +++ b/Packs/ctf01/ReleaseNotes/1_0_30.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Cortex XDR - IR CTF + +No changes related directly to this integration. \ No newline at end of file diff --git a/Packs/ctf01/pack_metadata.json b/Packs/ctf01/pack_metadata.json index 1c5f26381861..ed516887437d 100644 --- a/Packs/ctf01/pack_metadata.json +++ b/Packs/ctf01/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Capture The Flag - 01", "description": "XSOAR's Capture the flag (CTF)", "support": "xsoar", - "currentVersion": "1.0.29", + "currentVersion": "1.0.30", "serverMinVersion": "8.2.0", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", diff --git a/Packs/knowbe4Phisher/Integrations/knowbe4Phisher/knowbe4Phisher.py b/Packs/knowbe4Phisher/Integrations/knowbe4Phisher/knowbe4Phisher.py index 586220cf95ae..74155a7c8df5 100644 --- a/Packs/knowbe4Phisher/Integrations/knowbe4Phisher/knowbe4Phisher.py +++ b/Packs/knowbe4Phisher/Integrations/knowbe4Phisher/knowbe4Phisher.py @@ -4,7 +4,6 @@ import json import urllib3 import traceback -from typing import Tuple # Disable insecure warnings @@ -321,7 +320,7 @@ def __init__(self, base_url, verify, proxy, first_fetch_time, headers=None, max_ self.max_fetch = max_fetch if not headers: - headers = dict() + headers = {} headers["X-KB4-Integration"] = "Cortex XSOAR PhishER" super().__init__(base_url=base_url, verify=verify, headers=headers, proxy=proxy) @@ -639,7 +638,7 @@ def phisher_delete_tags_command(client: Client, args: dict) -> str: return "The tags weren't deleted - check the ID" -def fetch_incidents(client: Client, last_run: dict, first_fetch_time: str, max_fetch: int) -> Tuple[str, list]: +def fetch_incidents(client: Client, last_run: dict, first_fetch_time: str, max_fetch: int) -> tuple[str, list]: """ fetch_incidents is being called from the fetch_incidents_command function. it checks the last message fetch, checking number of new events, and getting all messages diff --git a/Packs/knowbe4Phisher/Integrations/knowbe4Phisher/knowbe4Phisher.yml b/Packs/knowbe4Phisher/Integrations/knowbe4Phisher/knowbe4Phisher.yml index 101198c6992c..b39af890b5ba 100644 --- a/Packs/knowbe4Phisher/Integrations/knowbe4Phisher/knowbe4Phisher.yml +++ b/Packs/knowbe4Phisher/Integrations/knowbe4Phisher/knowbe4Phisher.yml @@ -43,7 +43,7 @@ configuration: name: proxy type: 8 required: false -description: KnowBE4 PhishER integration allows to pull events from PhishER system and do mutations +description: KnowBE4 PhishER integration allows to pull events from PhishER system and do mutations. display: PhishER name: Phisher defaultmapperin: PhishER-mapper @@ -51,11 +51,11 @@ script: commands: - arguments: - defaultValue: '50' - description: The maximum number of messages to fetch + description: The maximum number of messages to fetch. name: limit - - description: The Lucene query to search against + - description: The Lucene query to search against. name: query - - description: ID of specific message to retrieve. If ID is given query will be ignored + - description: ID of specific message to retrieve. If ID is given query will be ignored. name: id - auto: PREDEFINED defaultValue: 'False' @@ -64,17 +64,17 @@ script: - 'False' - 'True' description: Whether to include all message events in the result. - description: Command to get messages from PhishER + description: Command to get messages from PhishER. name: phisher-message-list outputs: - contextPath: Phisher.Message.actionStatus - description: Action Status + description: Action Status. type: String - contextPath: Phisher.Message.attachments - description: A collection of attachments associated with this message + description: A collection of attachments associated with this message. type: String - contextPath: Phisher.Message.category - description: The message's category + description: The message's category. type: String - contextPath: Phisher.Message.comments description: A collection of comments associated with this message. @@ -83,7 +83,7 @@ script: description: A collection of events associated with this message. type: String - contextPath: Phisher.Message.from - description: Sender's email + description: Sender's email. type: String - contextPath: Phisher.Message.id description: Unique identifier for the message. @@ -92,22 +92,22 @@ script: description: A collection of links that were found in the message. type: String - contextPath: Phisher.Message.phishmlReport - description: The PhishML report associated with this message + description: The PhishML report associated with this message. type: String - contextPath: Phisher.Message.pipelineStatus - description: Pipeline Status + description: Pipeline Status. type: String - contextPath: Phisher.Message.reportedBy description: The person who reported the message. type: String - contextPath: Phisher.Message.rawUrl - description: URL where to download the raw message + description: URL where to download the raw message. type: String - contextPath: Phisher.Message.rules description: A collection of rules associated with this message. type: String - contextPath: Phisher.Message.severity - description: The message's severity + description: The message's severity. type: String - contextPath: Phisher.Message.subject description: Subject of the message. @@ -116,17 +116,17 @@ script: description: A collection of tags associated with this message. type: String - arguments: - - description: Message ID + - description: Message ID. name: id required: true - description: The comment to add. name: comment required: true - description: Adds a comment to a PhishER message + description: Adds a comment to a PhishER message. name: phisher-create-comment - arguments: - auto: PREDEFINED - description: "Message Category, can be: UNKNOWN,CLEAN,SPAM,THREAT\t\t" + description: "Message Category, can be: UNKNOWN,CLEAN,SPAM,THREAT\t\t." name: category predefined: - UNKNOWN @@ -134,14 +134,14 @@ script: - SPAM - THREAT - auto: PREDEFINED - description: 'Message Status, can be: RECEIVED,IN_REVIEW,RESOLVED' + description: 'Message Status, can be: RECEIVED,IN_REVIEW,RESOLVED.' name: status predefined: - RECEIVED - IN_REVIEW - RESOLVED - auto: PREDEFINED - description: 'Message Severity, can be: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL' + description: 'Message Severity, can be: UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL.' name: severity predefined: - UNKNOWN @@ -149,22 +149,22 @@ script: - MEDIUM - HIGH - CRITICAL - - description: Message ID + - description: Message ID. name: id required: true description: Updates a PhishER message status. User must provide at least one argument. name: phisher-update-message - arguments: - - description: Message ID + - description: Message ID. name: id required: true - description: Comma separated list of tags to add. name: tags required: true - description: Add tags to a given message + description: Add tags to a given message. name: phisher-tags-create - arguments: - - description: Message ID + - description: Message ID. name: id required: true - description: Comma separated list of tags to remove. @@ -172,7 +172,7 @@ script: required: true description: Removes tags from a given message. name: phisher-tags-delete - dockerimage: demisto/python3:3.10.14.90585 + dockerimage: demisto/python3:3.11.10.113941 isfetch: true runonce: false script: '-' diff --git a/Packs/knowbe4Phisher/ReleaseNotes/1_0_13.md b/Packs/knowbe4Phisher/ReleaseNotes/1_0_13.md new file mode 100644 index 000000000000..72e74fbfffe6 --- /dev/null +++ b/Packs/knowbe4Phisher/ReleaseNotes/1_0_13.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### PhishER + +- Updated the Docker image to: *demisto/python3:3.11.10.113941*. diff --git a/Packs/knowbe4Phisher/pack_metadata.json b/Packs/knowbe4Phisher/pack_metadata.json index 77467fb78563..9edfa7e4680b 100644 --- a/Packs/knowbe4Phisher/pack_metadata.json +++ b/Packs/knowbe4Phisher/pack_metadata.json @@ -2,7 +2,7 @@ "name": "PhishER", "description": "A pack for KnowBe4 PhishER integration", "support": "partner", - "currentVersion": "1.0.12", + "currentVersion": "1.0.13", "author": "KnowBe4", "url": "https://www.knowbe4.com/products/phisher", "email": "support@knowbe4.com", diff --git a/Packs/qualys/Integrations/Qualysv2/Qualysv2.py b/Packs/qualys/Integrations/Qualysv2/Qualysv2.py index e6178ad9c6f6..bba7b85f8542 100644 --- a/Packs/qualys/Integrations/Qualysv2/Qualysv2.py +++ b/Packs/qualys/Integrations/Qualysv2/Qualysv2.py @@ -11,6 +11,8 @@ disable_warnings() # pylint: disable=no-member + + """ CONSTANTS """ VENDOR = 'qualys' @@ -29,6 +31,7 @@ HOST_LAST_FETCH = 'host_last_fetch' ASSETS_FETCH_FROM = '90 days' HOST_LIMIT = 2000 +ASSET_SIZE_LIMIT = 10 ** 6 # 1MB TEST_FROM_DATE = 'one day' FETCH_ASSETS_COMMAND_TIME_OUT = 180 @@ -1666,7 +1669,7 @@ def get_user_activity_logs(self, since_datetime: str, max_fetch: int = 0, next_p return response.text - def get_host_list_detection(self, since_datetime, next_page=None, limit=HOST_LIMIT) -> Union[str, bytes]: + def get_host_list_detection(self, since_datetime, next_page=None, limit=HOST_LIMIT) -> tuple[Union[str, bytes], bool]: """ Make a http request to Qualys API to get assets Args: @@ -1675,6 +1678,7 @@ def get_host_list_detection(self, since_datetime, next_page=None, limit=HOST_LIM Raises: DemistoException: can be raised by the _http_request function """ + set_new_limit = False self._headers.update({"Content-Type": 'application/json'}) params: dict[str, Any] = { "truncation_limit": limit, @@ -1693,11 +1697,10 @@ def get_host_list_detection(self, since_datetime, next_page=None, limit=HOST_LIM error_handler=self.error_handler, ) except requests.exceptions.ReadTimeout: - new_limit = set_last_run_with_new_limit(limit) - raise TimeoutError(f"Request to get host_list_detection exceeded the defined timeout ({timeout} secs). " - f"The integration will automatically reduce the request host limit from {limit} " - f"to {new_limit} in the next iteration") - return response + set_new_limit = True + response = '' + + return response, set_new_limit def get_vulnerabilities(self, since_datetime) -> Union[str, bytes]: """ @@ -2803,6 +2806,30 @@ def add_fields_to_events(events, time_field_path, event_type_field): event['event_type'] = event_type_field +def truncate_asset_size(asset): + host_id = asset.get('ID') or 'NO_ID' + detection_id = asset.get('DETECTION', {}).get('UNIQUE_VULN_ID', 'No detection') + + asset_size = get_size_of_object(asset) + if asset_size > ASSET_SIZE_LIMIT: + demisto.debug(f'{asset_size=}>{ASSET_SIZE_LIMIT=}') + detection_str = f' detection ID: {detection_id}' if detection_id else '' + demisto.debug(f'Asset ID: {host_id}{detection_str} has size of {asset_size}.') + results_characters_lim = 10000 + + if results := asset.get('DETECTION', {}).get('RESULTS'): + asset['DETECTION']['RESULTS'] = results[:results_characters_lim] + asset['isTruncated'] = True + demisto.debug(f'Truncated Asset ID: {host_id}{detection_str} to {results_characters_lim}') + demisto.debug(json.dumps(asset)) + + # For extra debugging in case other/additional keys has oversize data + for key, val in asset.items(): + if (val_size := get_size_of_object(val)) > ASSET_SIZE_LIMIT: # 1 MB + demisto.debug(f'Data under key "{key}" has size of {val_size}:\n' + f'{str(val)[:10000]}...') + + def get_detections_from_hosts(hosts): """ Parses detections from hosts. @@ -2834,22 +2861,18 @@ def get_detections_from_hosts(hosts): """ fetched_events = [] for host in hosts: - if detections_list := host.get('DETECTION_LIST', {}).get('DETECTION'): - if isinstance(detections_list, list): - for detection in detections_list: - new_detection = copy.deepcopy(host) - del new_detection['DETECTION_LIST'] - new_detection['DETECTION'] = detection - fetched_events.append(new_detection) - elif isinstance(detections_list, dict): - new_detection = copy.deepcopy(host) - new_detection['DETECTION'] = detections_list - del new_detection['DETECTION_LIST'] - fetched_events.append(new_detection) - else: - del host['DETECTION_LIST'] - host['DETECTION'] = {} - fetched_events.append(host) + detections_list = host.get('DETECTION_LIST', {}).get('DETECTION') or [{}] + + if not isinstance(detections_list, list): # In case detections_list = {} + detections_list = [detections_list] + + for detection in detections_list: + new_detection = copy.deepcopy(host) + del new_detection['DETECTION_LIST'] + new_detection['DETECTION'] = detection + fetched_events.append(new_detection) + truncate_asset_size(new_detection) + return fetched_events @@ -2901,18 +2924,21 @@ def get_host_list_detections_events(client, since_datetime, next_page='', limit= Returns: Host list detections assets """ - demisto.debug('Starting to fetch assets') - host_list_detections = client.get_host_list_detection(since_datetime=since_datetime, next_page=next_page, limit=limit) - host_list_assets, next_url = handle_host_list_detection_result(host_list_detections) or [] + demisto.debug('Pulling host list detections') + assets = [] + host_list_detections, set_new_limit = client.get_host_list_detection(since_datetime=since_datetime, + next_page=next_page, + limit=limit) + if not set_new_limit: + host_list_assets, next_url = handle_host_list_detection_result(host_list_detections) or [] - next_page = get_next_page_from_url(next_url, 'id_min') + next_page = get_next_page_from_url(next_url, 'id_min') - assets = get_detections_from_hosts(host_list_assets) if host_list_assets and not is_test else [] - demisto.debug(f'Parsed detections from hosts, got {len(assets)=} assets.') + assets = get_detections_from_hosts(host_list_assets) if host_list_assets and not is_test else [] + demisto.debug(f'Parsed detections from hosts, got {len(assets)=} assets.') + add_fields_to_events(assets, ['DETECTION', 'FIRST_FOUND_DATETIME'], 'host_list_detection') - add_fields_to_events(assets, ['DETECTION', 'FIRST_FOUND_DATETIME'], 'host_list_detection') - - return assets, next_page + return assets, next_page, set_new_limit def get_vulnerabilities(client, since_datetime) -> list: @@ -2943,40 +2969,40 @@ def fetch_assets(client, assets_last_run): since_datetime = assets_last_run.get('since_datetime', '') next_page = assets_last_run.get('next_page', '') total_assets = assets_last_run.get('total_assets', 0) - snapshot_id = assets_last_run.get('snapshot_id', str(round(time.time() * 1000))) + snapshot_id = str(assets_last_run.get('snapshot_id', str(round(time.time() * 1000)))) limit = assets_last_run.get('limit', HOST_LIMIT) + demisto.debug(f'Starting fetch process for assets {snapshot_id=}') + if not since_datetime: since_datetime = arg_to_datetime(ASSETS_FETCH_FROM).strftime(ASSETS_DATE_FORMAT) # type: ignore[union-attr] - assets, next_run_page = get_host_list_detections_events(client, since_datetime, next_page, limit) + assets, next_run_page, set_new_limit = get_host_list_detections_events(client, since_datetime, next_page, limit) total_assets += len(assets) stage = 'assets' if next_run_page else 'vulnerabilities' - amount_to_send = 1 if next_run_page else total_assets + amount_to_report = 1 if next_run_page else total_assets # We report 1 as long as we have not finished pulling new_last_run = {'stage': stage, 'next_page': next_run_page, 'total_assets': total_assets, 'since_datetime': since_datetime, 'snapshot_id': snapshot_id, 'nextTrigger': '0', "type": FETCH_COMMAND.get('assets')} - return assets, new_last_run, amount_to_send, snapshot_id + return assets, new_last_run, amount_to_report, snapshot_id, set_new_limit -def check_fetch_duration_time(start_time, limit=HOST_LIMIT): +def check_fetch_duration_time_exceeded(start_time): if (time.time() - start_time) > FETCH_ASSETS_COMMAND_TIME_OUT: demisto.debug('We passed the defined timeout, so we will not send the results to XSIAM,' 'because there is not enough time left, and we will lower the limit for the next time') - new_limit = set_last_run_with_new_limit(limit) - raise TimeoutError(f"passed the defined timeout, we will lower the limit {limit=} for the next run {new_limit}") + return True + return False -def set_last_run_with_new_limit(limit): +def set_last_run_with_new_limit(last_run, limit): new_limit = int(limit / 2) if limit > 1 else 1 demisto.debug(f'Setting host limit to: {new_limit}') - last_run = demisto.getAssetsLastRun() last_run['limit'] = new_limit - demisto.setAssetsLastRun(last_run) - return new_limit + return last_run def fetch_vulnerabilities(client, last_run): @@ -3039,7 +3065,7 @@ def fetch_events(client, last_run, first_fetch_time, fetch_function, newest_even if last_fetch_time := new_next_run.get(HOST_LAST_FETCH): updated_next_run[HOST_LAST_FETCH] = last_fetch_time - demisto.info(f"Sending len{len(events)} to XSIAM. updated_next_run={updated_next_run}.") + demisto.info(f"Sending {len(events)} to XSIAM. updated_next_run={updated_next_run}.") return updated_next_run, events @@ -3179,6 +3205,9 @@ def main(): # pragma: no cover args = demisto.args() command = demisto.command() + # We start a counter mainly for fetch assets as it is might be long. It can be used in other commands as well + start_time = time.time() + base_url = params.get('url') verify_certificate = not params.get("insecure", False) proxy = params.get("proxy", False) @@ -3454,7 +3483,7 @@ def main(): # pragma: no cover elif command == "qualys-get-assets": should_push_events = argToBoolean(args.get('should_push_assets', False)) since_datetime = arg_to_datetime('1 hour').strftime(ASSETS_DATE_FORMAT) # type: ignore[union-attr] - assets, _ = get_host_list_detections_events(client=client, since_datetime=since_datetime, limit=1) + assets, _, _ = get_host_list_detections_events(client=client, since_datetime=since_datetime, limit=1) if should_push_events: send_data_to_xsiam(data=assets, vendor=VENDOR, product='host_detections', data_type='assets') return_results(assets) @@ -3483,14 +3512,17 @@ def main(): # pragma: no cover fetch_stage = last_run.get('stage', 'assets') if fetch_stage == 'assets': - start_time = time.time() - demisto.debug(f'Starting fetch for assets, {start_time=}') - assets, new_last_run, total_assets, snapshot_id = fetch_assets(client=client, assets_last_run=last_run) - check_fetch_duration_time(start_time, last_run.get('limit', HOST_LIMIT)) - demisto.debug('sending assets to XSIAM.') - send_data_to_xsiam(data=assets, vendor=VENDOR, product='assets', data_type='assets', - snapshot_id=snapshot_id, items_count=total_assets, should_update_health_module=False) + demisto.debug(f'Starting fetch for assets, {start_time=}') + assets, new_last_run, total_assets, snapshot_id, set_new_limit = fetch_assets(client=client, + assets_last_run=last_run) + if set_new_limit or check_fetch_duration_time_exceeded(start_time): + new_last_run = set_last_run_with_new_limit(last_run, last_run.get('limit', HOST_LIMIT)) + last_run['nextTrigger'] = '0' + else: + demisto.debug(f'sending {len(assets)} assets to XSIAM. Total assets collected so far: {total_assets}') + send_data_to_xsiam(data=assets, vendor=VENDOR, product='assets', data_type='assets', + snapshot_id=snapshot_id, items_count=str(total_assets), should_update_health_module=False) demisto.setAssetsLastRun(new_last_run) demisto.updateModuleHealth({'{data_type}Pulled'.format(data_type='assets'): total_assets}) @@ -3500,7 +3532,7 @@ def main(): # pragma: no cover send_data_to_xsiam(data=vulnerabilities, vendor=VENDOR, product='vulnerabilities', data_type='assets') demisto.setAssetsLastRun(new_last_run) - demisto.debug('finished fetch assets run') + demisto.debug(f'finished fetch assets run. lastrun object is: {new_last_run}') else: return_results( qualys_command_flow_manager(client, demisto.args(), command, commands_methods[command]) diff --git a/Packs/qualys/Integrations/Qualysv2/Qualysv2_test.py b/Packs/qualys/Integrations/Qualysv2/Qualysv2_test.py index bd52e74e748f..bac629903cde 100644 --- a/Packs/qualys/Integrations/Qualysv2/Qualysv2_test.py +++ b/Packs/qualys/Integrations/Qualysv2/Qualysv2_test.py @@ -23,12 +23,12 @@ get_simple_response_from_raw, validate_required_group, get_activity_logs_events_command, - fetch_events, get_activity_logs_events, fetch_assets, fetch_vulnerabilities, ASSETS_FETCH_FROM, ASSETS_DATE_FORMAT, HOST_LIMIT + fetch_events, get_activity_logs_events, fetch_assets, fetch_vulnerabilities, ASSETS_FETCH_FROM, ASSETS_DATE_FORMAT, + HOST_LIMIT ) from CommonServerPython import * # noqa: F401 - ACTIVITY_LOGS_NEWEST_EVENT_DATETIME = 'activity_logs_newest_event_datetime' ACTIVITY_LOGS_NEXT_PAGE = 'activity_logs_next_page' ACTIVITY_LOGS_SINCE_DATETIME_PREV_RUN = 'activity_logs_since_datetime_prev_run' @@ -162,9 +162,9 @@ def test_fetch_assets_command(requests_mock): username='demisto', password='demisto', ) - assets, last_run, total_assets, snapshot_id = fetch_assets(client=client, assets_last_run={}) + assets, last_run, amount_to_report, snapshot_id, set_new_limit = fetch_assets(client=client, assets_last_run={}) assert len(assets) == 8 - assert total_assets == 8 + assert amount_to_report == 8 assert snapshot_id assert last_run['stage'] == 'vulnerabilities' @@ -178,14 +178,13 @@ def test_fetch_assets_command_time_out(requests_mock, mocker): Then: - Ensure the limit was reduced. """ - time_out_error = False base_url = 'https://server_url/' with open('./test_data/host_list_detections_raw.xml') as f: assets = f.read() requests_mock.get(f'{base_url}api/2.0/fo/asset/host/vm/detection/' f'?action=list&truncation_limit={HOST_LIMIT}&vm_scan_date_after=' - f'{arg_to_datetime(ASSETS_FETCH_FROM).strftime(ASSETS_DATE_FORMAT)}', exc=requests.exceptions.ReadTimeout) - set_last_run_call = mocker.patch.object(demisto, 'setAssetsLastRun') + f'{arg_to_datetime(ASSETS_FETCH_FROM).strftime(ASSETS_DATE_FORMAT)}', + exc=requests.exceptions.ReadTimeout) client = Client(base_url=base_url, verify=True, @@ -194,12 +193,9 @@ def test_fetch_assets_command_time_out(requests_mock, mocker): username='demisto', password='demisto', ) - try: - assets, last_run, total_assets, snapshot_id = fetch_assets(client=client, assets_last_run={}) - except TimeoutError: - time_out_error = True - assert time_out_error - assert set_last_run_call.call_args.args[0].get('limit') == 1000 + assets, new_last_run, amount_to_report, snapshot_id, set_new_limit = fetch_assets(client=client, assets_last_run={}) + assert not assets + assert set_new_limit def test_fetch_vulnerabilities_command(requests_mock): @@ -389,7 +385,8 @@ def test_format_and_validate_response_bad_json(self): raw_xml_response_success, { "SIMPLE_RETURN": { - "RESPONSE": {"DATETIME": "2021-03-24T15:40:23Z", "TEXT": "IPs successfully added to Vulnerability Management"} + "RESPONSE": {"DATETIME": "2021-03-24T15:40:23Z", + "TEXT": "IPs successfully added to Vulnerability Management"} } }, ), @@ -415,7 +412,7 @@ def test_parse_raw_response(self, response, expected): "SIMPLE_RETURN": { "RESPONSE": { "DATETIME": "2021-03-24T15:40:23Z", - "TEXT": "IPs successfully added to Vulnerability " "Management", + "TEXT": "IPs successfully added to Vulnerability Management", } } }, @@ -452,7 +449,8 @@ def test_handle_general_result_path_exists(self, mocker): mocker.patch.object(Qualysv2, "format_and_validate_response", return_value=json_obj) dummy_response = requests.Response() - assert handle_general_result(dummy_response, "qualys-ip-list") == {"DATETIME": "sometime", "IP_SET": {"IP": ["1.1.1.1"]}} + assert handle_general_result(dummy_response, "qualys-ip-list") == {"DATETIME": "sometime", + "IP_SET": {"IP": ["1.1.1.1"]}} def test_handle_general_result_doesnt_exist(self, mocker): """ @@ -895,7 +893,8 @@ def test_build_args_dict_date_args(self): "launched_after_datetime": "2021-12-26T08:49:29Z", "start_date": "2021-12-26T08:49:29Z", } - expected_result = {"launched_after_datetime": "2021-12-26", "published_before": "2021-12-26", "start_date": "12/26/2021"} + expected_result = {"launched_after_datetime": "2021-12-26", "published_before": "2021-12-26", + "start_date": "12/26/2021"} build_args_dict(args, {"args": ["published_before", "launched_after_datetime", "start_date"]}, False) assert Qualysv2.args_values == expected_result @@ -1020,7 +1019,8 @@ def test_build_host_list_detection_outputs(self, result, readable, expected_outp """ Qualysv2.inner_args_values["limit"] = 1 assert build_host_list_detection_outputs( - handled_result=result, command_parse_and_output_data=COMMANDS_PARSE_AND_OUTPUT_DATA["qualys-host-list-detection"] + handled_result=result, + command_parse_and_output_data=COMMANDS_PARSE_AND_OUTPUT_DATA["qualys-host-list-detection"] ) == (expected_outputs, readable) @@ -1058,7 +1058,7 @@ class TestClientClass: """, 500, ), - "Error in API call [500] - None\nError Code: 999\nError Message: Internal error. Please " "contact customer support.", + "Error in API call [500] - None\nError Code: 999\nError Message: Internal error. Please contact customer support.", ), (MockResponse("Invalid XML", 500), "Error in API call [500] - None\nInvalid XML"), ] @@ -1090,7 +1090,8 @@ class TestInputValidations: VALIDATE_DEPENDED_ARGS_INPUT = [ ({}, {}), ({"required_depended_args": DEPENDANT_ARGS}, {}), - ({"required_depended_args": DEPENDANT_ARGS}, {k: 3 for k, v in DEPENDANT_ARGS.items() if v == "frequency_months"}), + ({"required_depended_args": DEPENDANT_ARGS}, + {k: 3 for k, v in DEPENDANT_ARGS.items() if v == "frequency_months"}), ] @pytest.mark.parametrize("command_data, args", VALIDATE_DEPENDED_ARGS_INPUT) @@ -1122,7 +1123,8 @@ def test_validate_depended_args_invalid(self): - Ensure exception is thrown. """ Qualysv2.args_values = {"frequency_months": 1} - with pytest.raises(DemistoException, match="Argument day_of_month is required when argument frequency_months is given."): + with pytest.raises(DemistoException, + match="Argument day_of_month is required when argument frequency_months is given."): validate_depended_args({"required_depended_args": self.DEPENDANT_ARGS}) EXACTLY_ONE_GROUP_ARGS = [ @@ -1203,9 +1205,14 @@ def test_validate_required_group_invalid(self, args): AT_MOST_ONE_ARGS_INPUT = [ ({}, {}), ({"at_most_one_groups": AT_MOST_ONE_GROUP_ARGS}, {}), - ({"at_most_one_groups": AT_MOST_ONE_GROUP_ARGS}, {"asset_group_ids": 1, "scanners_in_ag": 1, "frequency_days": 1}), - ({"at_most_one_groups": AT_MOST_ONE_GROUP_ARGS}, {"asset_groups": 1, "scanners_in_ag": 1, "frequency_weeks": 1}), - ({"at_most_one_groups": AT_MOST_ONE_GROUP_ARGS}, {"ip": "1.1.1.1", "default_scanner": 1, "frequency_months": 1}), + ({"at_most_one_groups": AT_MOST_ONE_GROUP_ARGS}, + {"asset_group_ids": 1, "scanners_in_ag": 1, "frequency_days": 1}), + ( + {"at_most_one_groups": AT_MOST_ONE_GROUP_ARGS}, + {"asset_groups": 1, "scanners_in_ag": 1, "frequency_weeks": 1}), + ( + {"at_most_one_groups": AT_MOST_ONE_GROUP_ARGS}, + {"ip": "1.1.1.1", "default_scanner": 1, "frequency_months": 1}), ] @pytest.mark.parametrize("command_data, args", AT_MOST_ONE_ARGS_INPUT) @@ -1452,3 +1459,76 @@ def test_build_ip_and_range_dicts(): and another list which consists of single values dictionaries of ranges """ assert Qualysv2.build_ip_and_range_dicts(['-', 'example']) == [[{'ip': 'example'}], [{'range': '-'}]] + + +truncate_test_cases = [ + # Case 1: Asset with ID and detection unique vuln ID, and exceeds size limit + ({ + "ID": "12345", + "DETECTION": { + "UNIQUE_VULN_ID": "vuln1", + "RESULTS": "A" * 2 * 10 ** 6 # Exceeds size limit + } + }, + True), + + # Case 2: Asset with no ID and detection unique vuln ID, and exceeds size limit + ({ + "DETECTION": { + "UNIQUE_VULN_ID": "vuln2", + "RESULTS": "A" * 2 * 10 ** 6 # Exceeds size limit + } + }, + True), + # Case 3: Asset with ID and no detection unique vuln ID, and does not exceed size limit + ({ + "ID": "12345", + "DETECTION": { + "RESULTS": "A" * 100 # Does not exceed size limit + } + }, + False), + # Case 4: Asset with no ID and no detection unique vuln ID, and does not exceed size limit + ({ + "DETECTION": { + "RESULTS": "A" * 100 # Does not exceed size limit + } + }, + False) +] + + +@pytest.mark.parametrize('asset, expected_truncated', truncate_test_cases) +def test_truncate_asset_size(mocker, asset, expected_truncated): + """ + Given: + - Case 1: Asset which exceeds size limit with ID and detection unique vuln ID. + - Case 2: Asset which exceeds size limit with no ID and detection unique vuln ID. + - Case 3: Asset which does not exceed size limit with ID and no detection unique vuln ID. + - Case 4: Asset which does not exceed size limit with no ID and no detection unique vuln ID. + + When: calling truncate_asset_size with the given asset + + Then: + - Case 1: ensure the isTruncated flag is set to true, that the size of the assets was truncated to 1000 and that + debug logs were printed. + - Case 2: ensure the isTruncated flag is set to true, that the size of the assets was truncated to 1000 and that + debug logs were printed. + - Case 3: ensure the isTruncated flag is set to false or does not exist and that debug logs were not printed. + - Case 4: ensure the isTruncated flag is set to false or does not exist and that debug logs were not printed. + + """ + mock_debug = mocker.patch.object(demisto, 'debug') + + Qualysv2.truncate_asset_size(asset) + + if expected_truncated: + assert asset.get('isTruncated', False) is True + assert len(asset['DETECTION']['RESULTS']) == 10000 + assert mock_debug.call_count >= 3 # Expecting at least 3 debug messages + else: + assert asset.get('isTruncated', False) is False + assert mock_debug.call_count == 0 # No debug messages if not truncated + + # Reset mock_debug for the next test case + mock_debug.reset_mock() diff --git a/Packs/qualys/ReleaseNotes/3_1_0.md b/Packs/qualys/ReleaseNotes/3_1_0.md new file mode 100644 index 000000000000..b85283923bd6 --- /dev/null +++ b/Packs/qualys/ReleaseNotes/3_1_0.md @@ -0,0 +1,7 @@ + +#### Integrations + +##### Qualys VMDR + +- Improved fetch assets process when handling large objects - Assets larger than 1MB will be truncated, a key called 'isTruncated' will indicate that the assets were truncated. +- Improved the integration behavior in cases of timeouts when pulling assets - The integration will now immediately retry to fetch the assets instead of waiting for the next fetch window. diff --git a/Packs/qualys/pack_metadata.json b/Packs/qualys/pack_metadata.json index 4d343e6dc331..bf0e5525b216 100644 --- a/Packs/qualys/pack_metadata.json +++ b/Packs/qualys/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Qualys", "description": "Qualys Vulnerability Management let's you create, run, fetch and manage reports, launch and manage vulnerability and compliance scans, and manage the host assets you want to scan for vulnerabilities and compliance", "support": "xsoar", - "currentVersion": "3.0.7", + "currentVersion": "3.1.0", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Packs/rasterize/Integrations/rasterize/rasterize.py b/Packs/rasterize/Integrations/rasterize/rasterize.py index 1a12deb60f1e..f3e046376e38 100644 --- a/Packs/rasterize/Integrations/rasterize/rasterize.py +++ b/Packs/rasterize/Integrations/rasterize/rasterize.py @@ -798,14 +798,32 @@ def perform_rasterize(path: str | list[str], :param width: window width :param height: window height """ - demisto.debug(f"perform_rasterize, {path=}, {rasterize_type=}") + + # convert the path param to list in case we have only one string + paths = argToList(path) + + # create a list with all the paths that start with "mailto:" + mailto_paths = [path_value for path_value in paths if path_value.startswith('mailto:')] + + if mailto_paths: + # remove the mailto from the paths to rasterize + paths = list(set(paths) - set(mailto_paths)) + demisto.error(f'Not rasterizing the following invalid paths: {mailto_paths}') + return_results(CommandResults( + readable_output=f'URLs that start with "mailto:" cannot be rasterized.\nURL: {mailto_paths}')) + + if not paths: + message = 'There are no valid paths to rasterize' + demisto.error(message) + return_error(message) + return None + + demisto.debug(f"perform_rasterize, {paths=}, {rasterize_type=}") browser, chrome_port = chrome_manager() if browser: support_multithreading() with ThreadPoolExecutor(max_workers=MAX_CHROME_TABS_COUNT) as executor: - demisto.debug(f'path type is: {type(path)}') - paths = [path] if isinstance(path, str) else path demisto.debug(f"perform_rasterize, {paths=}, {rasterize_type=}") rasterization_threads = [] rasterization_results = [] diff --git a/Packs/rasterize/Integrations/rasterize/rasterize_test.py b/Packs/rasterize/Integrations/rasterize/rasterize_test.py index c5c0671b2418..bb3f9d6f6d2e 100644 --- a/Packs/rasterize/Integrations/rasterize/rasterize_test.py +++ b/Packs/rasterize/Integrations/rasterize/rasterize_test.py @@ -761,3 +761,24 @@ def test_read_json_file(mocker): mock_file_content = util_load_json("test_data/chrome_instances.json") file_result = read_json_file("test_data/chrome_instances.json") assert file_result == mock_file_content + + +def test_rasterize_mailto(capfd, mocker): + """ + Given: + - mailto argument as path. + When: + - Running the 'rasterize' function. + Then: + - Verify that perform_rasterize exit with the expected error message. + """ + mocker_output = mocker.patch('rasterize.return_results') + + with pytest.raises(SystemExit) as excinfo: + with capfd.disabled(): + perform_rasterize(path='mailto:some.person@gmail.com', width=250, height=250, rasterize_type=RasterizeType.PNG) + + assert mocker_output.call_args.args[0].readable_output == 'URLs that start with "mailto:" cannot be rasterized.' \ + '\nURL: [\'mailto:some.person@gmail.com\']' + assert excinfo.type == SystemExit + assert excinfo.value.code == 0 diff --git a/Packs/rasterize/ReleaseNotes/2_0_25.md b/Packs/rasterize/ReleaseNotes/2_0_25.md new file mode 100644 index 000000000000..6f09db998ca0 --- /dev/null +++ b/Packs/rasterize/ReleaseNotes/2_0_25.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Rasterize + +Fixed an issue in which calling `rasterize` with URLs that started with `mailto:` would cause the script to timeout; an error will be thrown instead. diff --git a/Packs/rasterize/pack_metadata.json b/Packs/rasterize/pack_metadata.json index 7af9723defb6..ba9ee4527e93 100644 --- a/Packs/rasterize/pack_metadata.json +++ b/Packs/rasterize/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Rasterize", "description": "Converts URLs, PDF files, and emails to an image file or PDF file.", "support": "xsoar", - "currentVersion": "2.0.24", + "currentVersion": "2.0.25", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Tests/conf.json b/Tests/conf.json index 308d2b2c003e..38ce2783825a 100644 --- a/Tests/conf.json +++ b/Tests/conf.json @@ -5964,6 +5964,8 @@ "TestCloudflareWAFPlaybook": "No instance", "DBot Build Phishing Classifier Test - Multiple Algorithms": "Issue 48350", "Elasticsearch_v2_test-v8": "CRTX-61980", + "Elasticsearch_Fetch_Custom_Indicators_Test": "CRTX-134283", + "Elasticsearch_Fetch_Demisto_Indicators_Test": "CRTX-134283", "Carbon Black Enterprise Protection V2 Test": "No credentials", "TruSTAR v2-Test": "No credentials", "Archer v2 - Test": "Test doesn't pass in the builds because of the creds, but creds seems ok, need to debug further", @@ -6013,7 +6015,8 @@ "Test_XFE_v2": "CRTX-112127", "test-ProofpointThreatProtectionIntegration-Playbook": "No instance", "Generic Webhook - Test": "CIAC-11234", - "Netskope_V2_Test": "No instance - developed by Qmasters" + "Netskope_V2_Test": "No instance - developed by Qmasters", + "IAMInitOktaUser - Test": "CIAC-12093" }, "skipped_integrations": { "AWS - Lambda": "No instance - wrong creds, issue CRTX-110456", diff --git a/poetry.lock b/poetry.lock index f5905cf6e940..904b0637bcc3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "astroid" @@ -709,13 +709,13 @@ reference = "pypi-public" [[package]] name = "demisto-sdk" -version = "1.32.2" +version = "1.32.3" description = "\"A Python library for the Demisto SDK\"" optional = false -python-versions = ">=3.9,<3.12" +python-versions = ">=3.9,<3.13" files = [ - {file = "demisto_sdk-1.32.2-py3-none-any.whl", hash = "sha256:7d56f58effd69c89a9a5c8f0faed15d76cfb4f22f234742c824896ce16386bbe"}, - {file = "demisto_sdk-1.32.2.tar.gz", hash = "sha256:44094b067eb653264717a9ea1971718c06fb11df11e970f282508d43b0e1f14f"}, + {file = "demisto_sdk-1.32.3-py3-none-any.whl", hash = "sha256:8c4455fa76a6814d852a8349138b39eda83c2d54130bbdb1182bbb9251848862"}, + {file = "demisto_sdk-1.32.3.tar.gz", hash = "sha256:0ca9e52d158c1fad20ad22a251bb3151a7cccc634be4a31c60494bc8138e9d2b"}, ] [package.dependencies] @@ -4535,4 +4535,4 @@ reference = "pypi-public" [metadata] lock-version = "2.0" python-versions = "^3.9,<3.11" -content-hash = "daa83a284dcf00d8817854d7f5f7ca67fbcf6ee46ab9f8684b9d279c95b542c1" +content-hash = "959f5f91bf940464fd81b9a53ca61c0f2844e58e75902b30d651ff776f50e120" diff --git a/pyproject.toml b/pyproject.toml index d645924fa070..763a298d9d05 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,7 @@ sendgrid = "^6.11" slack_sdk = "^3.31.0" [tool.poetry.group.dev.dependencies] -demisto-sdk = "1.32.2" # Only affects GitHub Actions. To control the SDK version elsewhere, modify the infra repo's pyproject file +demisto-sdk = "1.32.3" # Only affects GitHub Actions. To control the SDK version elsewhere, modify the infra repo's pyproject file pytest = ">=7.1.2" requests-mock = ">=1.9.3" pytest-mock = ">=3.7.0"