From d66c3054cfb1c8c77007813eb55141d9d26e06ff Mon Sep 17 00:00:00 2001 From: merit-maita <49760643+merit-maita@users.noreply.github.com> Date: Wed, 6 Dec 2023 18:18:25 +0200 Subject: [PATCH] Support Threat Assessment functionality in MS Graph Security (#30110) * added yml and the first command in code * added commands * added to description in yml * added readme for first command * added readme to second command * added third command to readme * added url command to readme * added list command to readme * added tests files * minor edits * added unittests * added unittest * updated docker image * added rn * edited readme * edit * fixed lint errors * fixed validation errors * fixed rn * edits precommits errors * fixed unittest for test auth code * edited tpb * added unittests * to revert some of these changes * update after doc review * added unittests * removed checking server version in CSP * updated docker image * added rn * Bump pack from version Base to 1.32.41. * reverted changes for csp * reveeted changes * deleted rn * added fromversion field * added unittest * updated for pre commit * updated for pre commit * edits after build failed * removed file * edits * added the tpb * fixed tpb * edited the list command * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/ReleaseNotes/2_2_5.md Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * Update Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> * updated docker image * edited after build failed * reverted changes * updated do * added arg * added rn * updated docker image * edit * edits after cr * updated do * edited the get user call * checked the 2 other commands * edited yml * updated do * edited test * removed comments * updated do * edit * edit --------- Co-authored-by: Content Bot Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com> --- .../MicrosoftGraphSecurity.py | 344 +++++++++- .../MicrosoftGraphSecurity.yml | 418 +++++++++++- .../MicrosoftGraphSecurity_test.py | 87 ++- .../MicrosoftGraphSecurity/README.md | 462 +++++++++++++ .../email_file_assessment_request.json | 26 + .../test_data/file_assessment_request.json | 25 + .../test_data/list_threat_assessment.json | 74 +++ .../test_data/mail_assessment_request.json | 27 + .../test_data/url_assessment_request.json | 24 + .../ReleaseNotes/2_2_6.md | 7 + ..._Graph_Security_test_threat_assessment.yml | 611 ++++++++++++++++++ ...crosoft_Graph_security_test_ediscovery.yml | 3 + .../MicrosoftGraphSecurity/pack_metadata.json | 2 +- Tests/conf.json | 8 +- 14 files changed, 2106 insertions(+), 12 deletions(-) create mode 100644 Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/email_file_assessment_request.json create mode 100644 Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/file_assessment_request.json create mode 100644 Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/list_threat_assessment.json create mode 100644 Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/mail_assessment_request.json create mode 100644 Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/url_assessment_request.json create mode 100644 Packs/MicrosoftGraphSecurity/ReleaseNotes/2_2_6.md create mode 100644 Packs/MicrosoftGraphSecurity/TestPlaybooks/Microsoft_Graph_Security_test_threat_assessment.yml diff --git a/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.py b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.py index d3e1766bf398..a5767f1eb6a7 100644 --- a/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.py +++ b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.py @@ -5,6 +5,7 @@ from enum import Enum import urllib3 +import re from CommonServerUserPython import * from typing import Any @@ -23,6 +24,7 @@ API_VER = API_V2 PAGE_SIZE_LIMIT_DICT = {API_V2: 2000, API_V1: 1000} API_V1_PAGE_LIMIT = 500 +THREAT_ASSESSMENT_URL_PREFIX = 'informationProtection/threatAssessmentRequests' DataSourceType = { 'USER': { @@ -45,6 +47,8 @@ } } +EMAIL_REGEX = r"[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+" + class HoldAction(Enum): APPLY = 'apply' @@ -250,6 +254,73 @@ def purge_ediscovery_data(self, case_id, search_id, purge_type, purge_areas): } return self.ms_client.http_request(method='POST', url_suffix=url, json_data=body, resp_type='response') + def create_mail_assessment_request(self, recipient_email, expected_assessment, category, user_id, message_id): + body = { + "@odata.type": "#microsoft.graph.mailAssessmentRequest", + "recipientEmail": recipient_email, + "expectedAssessment": expected_assessment, + "category": category, + "messageUri": f"https://graph.microsoft.com/v1.0/users/{user_id}/messages/{message_id}" + } + return self.ms_client.http_request(method='POST', url_suffix=THREAT_ASSESSMENT_URL_PREFIX, json_data=body) + + def get_user_id(self, email): + return self.ms_client.http_request(method='GET', url_suffix='users', params={'$filter': f"mail eq '{email}'"}) + + def get_threat_assessment_request(self, request_id): + return self.ms_client.http_request(method='GET', + url_suffix=f'{THREAT_ASSESSMENT_URL_PREFIX}/{request_id}', + params={'$expand': 'results'}) + + def get_threat_assessment_request_status(self, request_id): + return self.ms_client.http_request(method='GET', + url_suffix=f'{THREAT_ASSESSMENT_URL_PREFIX}/{request_id}', + params={'$select': 'status'}) + + def create_email_file_assessment_request(self, recipient_email, expected_assessment, category, content_data): + body = { + "@odata.type": "#microsoft.graph.emailFileAssessmentRequest", + "recipientEmail": recipient_email, + "expectedAssessment": expected_assessment, + "category": category, + "contentData": content_data + } + return self.ms_client.http_request(method='POST', url_suffix=THREAT_ASSESSMENT_URL_PREFIX, json_data=body) + + def create_file_assessment_request(self, expected_assessment, category, file_name, content_data): + body = { + "@odata.type": "#microsoft.graph.fileAssessmentRequest", + "expectedAssessment": expected_assessment, + "category": category, + "fileName": file_name, + "contentData": content_data + } + return self.ms_client.http_request(method='POST', url_suffix=THREAT_ASSESSMENT_URL_PREFIX, json_data=body) + + def create_url_assessment_request(self, expected_assessment, category, url): + body = { + "@odata.type": "#microsoft.graph.urlAssessmentRequest", + "expectedAssessment": expected_assessment, + "category": category, + "url": url, + } + return self.ms_client.http_request(method='POST', url_suffix=THREAT_ASSESSMENT_URL_PREFIX, json_data=body) + + def list_threat_assessment_requests(self, filters=None, order_by=None, sort_order=None, next_token=None): + params = {} + if next_token: + return self.ms_client.http_request(method='GET', url_suffix=THREAT_ASSESSMENT_URL_PREFIX, + params={'$skipToken': next_token}, retries=1, status_list_to_retry=[405]) + if filters: + params['$filter'] = filters + if order_by: + params['$orderby'] = order_by + if sort_order: + params['$orderby'] = f"{order_by} {sort_order}" + + return self.ms_client.http_request(method='GET', url_suffix=THREAT_ASSESSMENT_URL_PREFIX, + params=params, retries=1, status_list_to_retry=[405]) + ''' HELPER FUNCTIONS ''' @@ -1199,10 +1270,9 @@ def test_auth_code_command(client: MsGraphClient, args): Called to test authorization code flow (since integration context cant be accessed during test_module) Calls list cases with no arguments """ - permissions = args.get('permission_type', 'all') if permissions == 'all': - permissions = "ediscovery, alerts" + permissions = "ediscovery, alerts, threat assessment" for permission in argToList(permissions): try: demisto.debug(f'checking permission {permission}') @@ -1211,13 +1281,15 @@ def test_auth_code_command(client: MsGraphClient, args): list_ediscovery_case_command(client, {}) case 'alerts': test_function(client, args, True) + case 'threat assessment': + list_threat_assessment_requests_command(client, {}) except Exception as e: raise DemistoException(f'Authorization was not successful for permission {permission} ' 'Check that you have the required permissions') from e return CommandResults(readable_output='Authentication was successful.') -def test_function(client: MsGraphClient, args, has_access_to_context=False): +def test_function(client: MsGraphClient, args, has_access_to_context=False): # pragma: no cover """ Args: has_access_to_context (bool): Whether this function is called from a command that allows this integration to access the @@ -1274,8 +1346,261 @@ def test_function(client: MsGraphClient, args, has_access_to_context=False): f'Please check authentication related parameters. [{response.status_code}]') +def get_message_user(client, message_user): + is_email = re.search(EMAIL_REGEX, message_user) + if is_email: + user_result = (client.get_user_id(message_user)).get('value') + if not user_result: + raise DemistoException(f'{message_user} is not a valid user') + return user_result[0].get('id') + return message_user + + +def is_base_64(string: str) -> bool: # pragma: no cover + """ + Validate if string is base 64 encoded. + Args: + string (str): String to validate. + + Returns: + bool: True if the string is base 64 encoded , else False. + + """ + try: + if isinstance(string, str): + # If there's any unicode here, an exception will be thrown and the function will return false + string_bytes = bytes(string, 'ascii') + elif isinstance(string, bytes): + string_bytes = string + else: + raise ValueError("Argument must be string or bytes") + return base64.b64encode(base64.b64decode(string_bytes)) == string_bytes + except Exception: + return False + + +def get_content_data(entry_id, content_data): # pragma: no cover + + if not (entry_id or content_data) or (entry_id and content_data): + raise DemistoException('Just one of entry_id or content_data arguments has to be provided.') + try: + if entry_id: + file = demisto.getFilePath(entry_id) + file_path = file['path'] + with open(file_path, 'rb') as fp: + content = base64.b64encode(fp.read()) + return str(content, encoding='utf-8') + if content_data: + return content_data if is_base_64(content_data) else base64.b64encode(content_data) + + except Exception as e: + raise DemistoException(f'Failed loading content data: {e}') + + +def get_result_outputs(result) -> Dict: + output = { + 'ID': result.get('id'), + 'Created DateTime': result.get('createdDateTime'), + 'Content Type': result.get('contentType'), + 'Expected Assessment': result.get('expectedAssessment'), + 'Category': result.get('category'), + 'Status': result.get('status'), + 'Request Source': result.get('requestSource'), + 'Recipient Email': result.get('recipientEmail'), + 'Destination Routing Reason': result.get('destinationRoutingReason'), + 'URL': result.get('url'), + 'File Name': result.get('fileName'), + } + if created_by := result.get('createdBy'): + output['Created User ID'] = created_by.get('user', {}).get('id') + output['Created Username'] = created_by.get('user', {}).get('displayName') + + if results := result.get('results'): + output['Result Type'] = results[0].get('resultType') + output['Result message'] = results[0].get('message') + return output + + +def get_threat_assessment_request(client: MsGraphClient, request_id): + result = client.get_threat_assessment_request(request_id) + outputs = get_result_outputs(result) + readable_output = tableToMarkdown('Threat assessment request:', outputs, removeNull=True) + + return [CommandResults(readable_output=readable_output, + raw_response=result, + outputs=outputs, + outputs_prefix='MSGraphMail.AssessmentRequest')] + + +@polling_function('msg-create-mail-assessment-request', + timeout=arg_to_number(demisto.args().get("timeout_in_seconds", 720)), + requires_polling_arg=False) +def create_mail_assessment_request_command(args, client: MsGraphClient) -> PollResult | CommandResults: + + if not (request_id := args.get('request_id')): + message_user = get_message_user(client, args.get('message_user')) + result = client.create_mail_assessment_request(args.get('recipient_email'), + args.get('expected_assessment'), + args.get('category'), + message_user, + args.get('message_id')) + request_id = result.get('id') + + result = client.get_threat_assessment_request(request_id) + status = result.get('status') + demisto.debug(f"status is: {status}") + if status == 'completed' or result.get('results'): + outputs = get_result_outputs(result) + outputs['Message ID'] = args.get('message_id') + readable_output = tableToMarkdown('Mail assessment request:', outputs, removeNull=True) + + results = CommandResults(readable_output=readable_output, + raw_response=result, + outputs=outputs, + outputs_prefix='MSGraphMail.MailAssessment') + return PollResult(response=results) + else: + return PollResult(continue_to_poll=True, args_for_next_run={"request_id": request_id, **args}, + response=None, + partial_result=CommandResults(readable_output="The status is pending, still waiting to get results...")) + + +@polling_function('msg-create-email-file-assessment-request', + timeout=arg_to_number(demisto.args().get("timeout_in_seconds", 720)), + requires_polling_arg=False) +def create_email_file_request_command(args, client: MsGraphClient) -> PollResult | CommandResults: + + if not (request_id := args.get('request_id')): + content_data = get_content_data(args.get('entry_id'), args.get('content_data')) + result = client.create_email_file_assessment_request(args.get('recipient_email'), + args.get('expected_assessment'), + args.get('category'), + content_data) + request_id = result.get('id') + demisto.debug(f"got request id: {request_id}") + result = client.get_threat_assessment_request(request_id) + status = result.get('status') + demisto.debug(f"status is: {status}") + if status == 'completed' or result.get('results'): + outputs = get_result_outputs(result) + readable_output = tableToMarkdown('Email file assessment request results:', outputs, removeNull=True) + + results = CommandResults(readable_output=readable_output, + raw_response=result, + outputs=outputs, + outputs_prefix='MSGraphMail.EmailAssessment') + return PollResult(response=results) + else: + return PollResult(continue_to_poll=True, args_for_next_run={"request_id": request_id, **args}, + response=None, + partial_result=CommandResults(readable_output="The status is pending, still waiting to get results...")) + + +@polling_function('msg-create-file-assessment-request', requires_polling_arg=False) +def create_file_assessment_request_command(args, client) -> PollResult | CommandResults: + + if not (request_id := args.get('request_id')): + content_data = get_content_data(args.get('entry_id'), args.get('content_data')) + demisto.debug(f"got content data: {content_data}") + result = client.create_file_assessment_request(args.get('expected_assessment'), + args.get('category'), + args.get('file_name'), + content_data) + request_id = result.get('id') + + demisto.debug(f"got request id: {request_id}") + result = client.get_threat_assessment_request_status(request_id) + status = result.get('status') + + demisto.debug(f"status is: {status}") + if status == 'completed': + result = client.get_threat_assessment_request(request_id) + outputs = get_result_outputs(result) + readable_output = tableToMarkdown('File assessment request results:', outputs, removeNull=True) + + results = CommandResults(readable_output=readable_output, + raw_response=result, + outputs=outputs, + outputs_prefix='MSGraphMail.FileAssessment') + return PollResult(response=results) + else: + return PollResult(continue_to_poll=True, args_for_next_run={"request_id": request_id, **args}, + response=None, + partial_result=CommandResults(readable_output="The status is pending, still waiting to get results...")) + + +@polling_function('msg-create-url-assessment-request', + timeout=arg_to_number(demisto.args().get("timeout_in_seconds", 720)), + requires_polling_arg=False) +def create_url_assessment_request_command(args, client: MsGraphClient) -> PollResult | CommandResults: + + if not (request_id := args.get('request_id')): + result = client.create_url_assessment_request(args.get('expected_assessment'), + args.get('category'), + args.get('url')) + request_id = result.get('id') + + result = client.get_threat_assessment_request_status(request_id) + status = result.get('status') + demisto.debug(f"status is : {status}") + if status == 'completed': + result = client.get_threat_assessment_request(request_id) + outputs = get_result_outputs(result) + readable_output = tableToMarkdown('URL assessment request results:', outputs, removeNull=True) + + results = CommandResults(readable_output=readable_output, + raw_response=result, + outputs=outputs, + outputs_prefix='MSGraphMail.UrlAssessment') + return PollResult(response=results) + else: + return PollResult(continue_to_poll=True, args_for_next_run={"request_id": request_id, **args}, + response=None, + partial_result=CommandResults(readable_output="The status is pending, still waiting to get results...")) + + +def list_threat_assessment_requests_command(client: MsGraphClient, args) -> list[CommandResults]: + command_results = [] + limit = args.get('limit') + + if request_id := args.get('request_id'): + return get_threat_assessment_request(client, request_id) + + result = client.list_threat_assessment_requests( + args.get('filter'), + args.get('order_by'), + args.get('sort_order'), + args.get('next_token') + ) + outputs = [] + requests_list = result.get('value') + if limit: + requests_list = requests_list[:limit] + for req in requests_list: + outputs.append(get_result_outputs(req)) + readable_outputs = tableToMarkdown('Threat assessment request results:', outputs, removeNull=True) + command_results.append(CommandResults(readable_output=readable_outputs, + raw_response=result, + outputs=outputs, + outputs_prefix='MSGraphMail.AssessmentRequest')) + + skip_token_field = result.get('@odata.nextLink') + demisto.debug(f"skip_token_field: {skip_token_field}") + if skip_token_field: + next_token_value: List[str] = re.split(r'skip[t|T]oken=', skip_token_field) + if len(next_token_value) > 1: + next_token: str = next_token_value[1] + + command_results.append(CommandResults(readable_output=f'Next token is: {next_token}\n' if next_token else None, + outputs={"next_token": next_token}, + outputs_prefix='MsGraph.AssessmentRequestNextToken')) + + return command_results + + def main(): params: dict = demisto.params() + args: dict = demisto.args() url = params.get('host', '').rstrip('/') + '/v1.0/' tenant = params.get('creds_tenant_id', {}).get('password') or params.get('tenant_id') auth_and_token_url = params.get('creds_auth_id', {}).get('password') or params.get('auth_id', '') @@ -1331,7 +1656,6 @@ def main(): 'msg-list-ediscovery-searchs': list_ediscovery_search_command, 'msg-delete-ediscovery-search': delete_ediscovery_search_command, 'msg-purge-ediscovery-data': purge_ediscovery_data_command, - } command = demisto.command() LOG(f'Command being called is {command}') @@ -1366,6 +1690,16 @@ def main(): filter=fetch_filter, providers=fetch_providers, service_sources=fetch_service_sources) demisto.incidents(incidents) + elif command == 'msg-create-mail-assessment-request': + return_results(create_mail_assessment_request_command(args, client)) + elif command == 'msg-create-email-file-assessment-request': + return_results(create_email_file_request_command(args, client)) + elif command == 'msg-create-file-assessment-request': + return_results(create_file_assessment_request_command(args, client)) + elif command == 'msg-create-url-assessment-request': + return_results(create_url_assessment_request_command(args, client)) + elif command == 'msg-list-threat-assessment-requests': + return_results(list_threat_assessment_requests_command(client, args)) elif command == "ms-graph-security-auth-reset": return_results(reset_auth()) elif demisto.command() == 'msg-generate-login-url': @@ -1373,7 +1707,7 @@ def main(): else: if command not in commands: raise NotImplementedError(f'The provided command {command} was not implemented.') - command_res = commands[command](client, demisto.args()) # type: ignore + command_res = commands[command](client, args) # type: ignore if isinstance(command_res, CommandResults): return_results(command_res) else: diff --git a/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml index b670fbefd531..0549545d5769 100644 --- a/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml +++ b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity.yml @@ -790,6 +790,7 @@ script: predefined: - 'ediscovery' - 'alerts' + - 'threat assessment' - 'all' description: Tests connectivity to Microsoft Graph Security. execution: false @@ -1623,7 +1624,421 @@ script: Shared channels - Message posts, replies, and attachments shared in a shared Teams channel. execution: false name: msg-purge-ediscovery-data - dockerimage: demisto/crypto:1.0.0.68914 + - arguments: + - description: The email address of the user who received the email. + isArray: false + name: recipient_email + required: true + - description: The expected assessment. + isArray: false + name: expected_assessment + auto: PREDEFINED + predefined: + - 'block' + - 'unblock' + required: true + - description: The category of the threat. + isArray: false + name: category + defaultValue: all + auto: PREDEFINED + predefined: + - 'spam' + - 'phishing' + - 'malware' + required: true + - description: Message user. Could be the user's ID or the user's email. + isArray: false + name: message_user + required: true + - description: "Message ID. Message has to contain the 'X-MS-Exchange-Organization-Network-Message-Id' header in the message or the 'X-MS-Office365-Filtering-Correlation-Id' header in quarantined messages. Use the msgraph-mail-list-emails command from the Microsoft Graph Mail pack with the proper user_id in order to get all available messages." + isArray: false + name: message_id + required: true + - description: The ID of the request (generated in the polling command). + name: request_id + deprecated: true + - description: The timeout in seconds until polling ends. + name: timeout_in_seconds + deprecated: true + defaultValue: '720' + description: Create and retrieve a mail threat assessment. + execution: false + name: msg-create-mail-assessment-request + polling: true + outputs: + - contextPath: MSGraphMail.MailAssessment.ID + description: Mail assessment ID. + type: String + - contextPath: MSGraphMail.MailAssessment.CreatedDateTime + description: The datetime the mail assessment was created. + type: String + - contextPath: MSGraphMail.MailAssessment.ContentType + description: The content type. + type: String + - contextPath: MSGraphMail.MailAssessment.ExpectedAssessment + description: The expected assessment. + type: String + - contextPath: MSGraphMail.MailAssessment.Category + description: The category of the mail assessment. + type: String + - contextPath: MSGraphMail.MailAssessment.Status + description: The status of the mail assessment. + type: String + - contextPath: MSGraphMail.MailAssessment.RequestSource + description: The request source of the mail assessment. + type: String + - contextPath: MSGraphMail.MailAssessment.RecipientEmail + description: The email recipient of the mail assessment. + type: String + - contextPath: MSGraphMail.MailAssessment.DestinationRoutingReason + description: The destination routing reason for the mail assessment. + type: String + - contextPath: MSGraphMail.MailAssessment.MessageID + description: The message ID of the mail assessment. + type: String + - contextPath: MSGraphMail.MailAssessment.CreatedUserID + description: The user ID that was created for the mail assessment. + type: String + - contextPath: MSGraphMail.MailAssessment.CreatedUsername + description: The user name that was created for the mail assessment. + type: String + - contextPath: MSGraphMail.MailAssessment.ResultType + description: The result type of the mail assessment. + type: String + - contextPath: MSGraphMail.MailAssessment.ResultMessage + description: The result message of the mail assessment. + type: String + - arguments: + - description: The email of the user who recieved the mail. + isArray: false + name: recipient_email + required: true + - description: The expected assessment. + isArray: false + name: expected_assessment + defaultValue: all + auto: PREDEFINED + predefined: + - 'block' + - 'unblock' + required: true + - description: The category of the threat. + isArray: false + name: category + defaultValue: all + auto: PREDEFINED + predefined: + - 'spam' + - 'phishing' + - 'malware' + required: true + - description: Base 64 encoded eml file. + isArray: false + name: content_data + required: false + - description: Entry ID. + isArray: false + name: entry_id + required: false + - description: The ID of the request (generated in the polling command). + name: request_id + deprecated: true + - description: The timeout in seconds until polling ends. + name: timeout_in_seconds + deprecated: true + defaultValue: '720' + description: Create email file assessment request. + execution: false + name: msg-create-email-file-assessment-request + polling: true + outputs: + - contextPath: MSGraphMail.EmailAssessment.ID + description: The mail assessment ID. + type: String + - contextPath: MSGraphMail.EmailAssessment.CreatedDateTime + description: The datetime the mail assessment was created. + type: String + - contextPath: MSGraphMail.EmailAssessment.ContentType + description: The content type. + type: String + - contextPath: MSGraphMail.EmailAssessment.ExpectedAssessment + description: The expected assessment. + type: String + - contextPath: MSGraphMail.EmailAssessment.Category + description: The category of the mail assessment. + type: String + - contextPath: MSGraphMail.EmailAssessment.Status + description: The status of the mail assessment. + type: String + - contextPath: MSGraphMail.EmailAssessment.RequestSource + description: The request source of the mail assessment. + type: String + - contextPath: MSGraphMail.EmailAssessment.RecipientEmail + description: The email recipient of the mail assessment. + type: String + - contextPath: MSGraphMail.EmailAssessment.DestinationRoutingReason + description: The destination routing reason for the mail assessment. + type: String + - contextPath: MSGraphMail.EmailAssessment.CreatedUserID + description: The user ID that was created for the mail assessment. + type: String + - contextPath: MSGraphMail.EmailAssessment.CreatedUsername + description: The user name that was created for the mail assessment. + type: String + - contextPath: MSGraphMail.EmailAssessment.ResultType + description: The result type of the mail assessment. + type: String + - contextPath: MSGraphMail.EmailAssessment.ResultMessage + description: The result message of the mail assessment. + type: String + - arguments: + - description: The expected assessment. + isArray: false + name: expected_assessment + defaultValue: all + auto: PREDEFINED + predefined: + - 'block' + - 'unblock' + required: true + - description: The category of the threat. + isArray: false + name: category + defaultValue: all + auto: PREDEFINED + predefined: + - 'phishing' + - 'malware' + required: true + - description: The file name. + isArray: false + name: file_name + required: true + - description: Base 64 encoded text file. + isArray: false + name: content_data + required: false + - description: Entry ID. + isArray: false + name: entry_id + required: false + - description: Whether to hide the polling result (automatically filled by polling). + name: hide_polling_output + deprecated: true + - description: The ID of the request (generated in the polling command). + name: request_id + deprecated: true + description: Create file assessment request. + execution: false + name: msg-create-file-assessment-request + polling: true + outputs: + - contextPath: MSGraphMail.FileAssessment.ID + description: The mail assessment ID. + type: String + - contextPath: MSGraphMail.FileAssessment.CreatedDateTime + description: The datetime the file assessment was created. + type: String + - contextPath: MSGraphMail.FileAssessment.ContentType + description: The content type. + type: String + - contextPath: MSGraphMail.FileAssessment.ExpectedAssessment + description: The expected assessment. + type: String + - contextPath: MSGraphMail.FileAssessment.Category + description: The category of the file assessment. + type: String + - contextPath: MSGraphMail.FileAssessment.Status + description: The status of the file assessment. + type: String + - contextPath: MSGraphMail.FileAssessment.RequestSource + description: The request source of the file assessment. + type: String + - contextPath: MSGraphMail.FileAssessment.FileName + description: The file name of the file assessment. + type: String + - contextPath: MSGraphMail.FileAssessment.CreatedUserID + description: The user ID that was created for the file assessment. + type: String + - contextPath: MSGraphMail.FileAssessment.CreatedUsername + description: The user name that was created for the mail assessment. + type: String + - contextPath: MSGraphMail.FileAssessment.ResultType + description: The result type of the file assessment. + type: String + - contextPath: MSGraphMail.FileAssessment.ResultMessage + description: The result message of the file assessment. + type: String + - arguments: + - description: The expected assessment. + isArray: false + name: expected_assessment + defaultValue: all + auto: PREDEFINED + predefined: + - 'block' + - 'unblock' + required: true + - description: The category of the threat. + isArray: false + name: category + defaultValue: all + auto: PREDEFINED + predefined: + - 'phishing' + - 'malware' + required: true + - description: The URL of the threat. + isArray: false + name: url + required: true + - description: The request_id (generated in the polling command). + name: request_id + deprecated: true + - description: The timeout in seconds until polling ends. + name: timeout_in_seconds + deprecated: true + defaultValue: '720' + description: Create the URL assessment request. + execution: false + name: msg-create-url-assessment-request + polling: true + outputs: + - contextPath: MSGraphMail.UrlAssessment.ID + description: The mail assessment ID. + type: String + - contextPath: MSGraphMail.UrlAssessment.Url + description: The URL of the URL assessment. + type: string + - contextPath: MSGraphMail.UrlAssessment.CreatedDateTime + description: The datetime the URL assessment was created. + type: String + - contextPath: MSGraphMail.UrlAssessment.ContentType + description: The content type of the URL assessment. + type: String + - contextPath: MSGraphMail.UrlAssessment.ExpectedAssessment + description: The expected assessment of the URL assessment. + type: String + - contextPath: MSGraphMail.UrlAssessment.Category + description: The category of the URL assessment. + type: String + - contextPath: MSGraphMail.UrlAssessment.Status + description: The status of the URL assessment. + type: String + - contextPath: MSGraphMail.UrlAssessment.RequestSource + description: The request source for the URL assessment. + type: String + - contextPath: MSGraphMail.UrlAssessment.RecipientEmail + description: The recipient email for the URL assessment. + type: String + - contextPath: MSGraphMail.UrlAssessment.DestinationRoutingReason + description: The destination routing reason for the URL assessment. + type: String + - contextPath: MSGraphMail.UrlAssessment.CreatedUserID + description: The user ID created for the URL assessment. + type: String + - contextPath: MSGraphMail.UrlAssessment.CreatedUsername + description: The user name created for the URL assessment. + type: String + - contextPath: MSGraphMail.UrlAssessment.ResultType + description: The result type of the URL assessment. + type: String + - contextPath: MSGraphMail.UrlAssessment.ResultMessage + description: The result message of the URL assessment. + type: String + - arguments: + - description: The request ID. + isArray: false + name: request_id + required: false + - description: The filter for the request. Example category eq 'malware’ and ContentType eq 'file'. Available fields are expectedAssessment, ContentType, status, requestSource. + isArray: false + name: filter + required: false + - description: The order by which to retrieve the results. + isArray: false + name: order_by + auto: PREDEFINED + predefined: + - 'id' + - 'createdDateTime' + - 'ContentType' + - 'expectedAssessment' + - 'category' + - 'status' + - 'requestSource' + required: false + - description: The sort order. + isArray: false + name: sort_order + auto: PREDEFINED + predefined: + - 'asc' + - 'desc' + required: false + - description: The maximum number of results to retrieve. + isArray: false + name: limt + required: false + - description: The next token. + isArray: false + name: next_token + required: false + description: Create URL assessment request. + execution: false + name: msg-list-threat-assessment-requests + polling: true + outputs: + - contextPath: MsGraph.AssessmentRequestNextToken.next_token + description: The next token for the assessment request. + type: String + - contextPath: MSGraphMail.AssessmentRequest.ID + description: The assessment request ID. + type: String + - contextPath: MSGraphMail.AssessmentRequest.CreatedDateTime + description: The datetime the assessment request was created. + type: String + - contextPath: MSGraphMail.AssessmentRequest.ContentType + description: The content type of the assessment request. + type: String + - contextPath: MSGraphMail.AssessmentRequest.ExpectedAssessment + description: The expected assessment of the assessment request. + type: String + - contextPath: MSGraphMail.AssessmentRequest.Category + description: The category of the assessment request. + type: String + - contextPath: MSGraphMail.AssessmentRequest.Status + description: The status of the assessment request. + type: String + - contextPath: MSGraphMail.AssessmentRequest.URL + description: The URL of the assessment request. + type: String + - contextPath: MSGraphMail.AssessmentRequest.RequestSource + description: The request source for the assessment request. + type: String + - contextPath: MSGraphMail.AssessmentRequest.RecipientEmail + description: The email recipient for the assessment request. + type: String + - contextPath: MSGraphMail.AssessmentRequest.FileName + description: The file name of the assessment request. + type: String + - contextPath: MSGraphMail.AssessmentRequest.DestinationRoutingReason + description: The destination routing reason for the assessment request. + type: String + - contextPath: MSGraphMail.AssessmentRequest.CreatedUserID + description: The user ID create for the assessment request. + type: String + - contextPath: MSGraphMail.AssessmentRequest.CreatedUsername + description: The user name created for the assessment request. + type: String + - contextPath: MSGraphMail.AssessmentRequest.ResultType + description: The result type of the assessment request. + type: String + - contextPath: MSGraphMail.AssessmentRequest.ResultMessage + description: The result message of the assessment request. + type: String + dockerimage: demisto/crypto:1.0.0.82826 isfetch: true runonce: false script: '-' @@ -1638,4 +2053,5 @@ tests: - Microsoft Graph Security Test prod v2 - Microsoft Graph Security Test self deployed v2 - MSG-ediscovery-tpb +- MSG-Threat-Assessment-test fromversion: 5.0.0 diff --git a/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity_test.py b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity_test.py index ef5e264627cb..c40dfdad70ba 100644 --- a/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity_test.py +++ b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/MicrosoftGraphSecurity_test.py @@ -8,7 +8,9 @@ capitalize_dict_keys_first_letter, created_by_fields_to_hr, list_ediscovery_search_command, purge_ediscovery_data_command, \ list_ediscovery_non_custodial_data_source_command, list_ediscovery_case_command, activate_ediscovery_custodian_command, \ release_ediscovery_custodian_command, close_ediscovery_case_command, reopen_ediscovery_case_command, \ - create_ediscovery_non_custodial_data_source_command, list_ediscovery_custodian_command + create_ediscovery_non_custodial_data_source_command, list_ediscovery_custodian_command, \ + create_mail_assessment_request_command, create_email_file_request_command, create_file_assessment_request_command, \ + create_url_assessment_request_command, list_threat_assessment_requests_command, get_message_user from CommonServerPython import DemistoException import pytest import json @@ -544,28 +546,37 @@ def test_test_auth_code_command(mocker, command_to_check): mock_ediscovery = mocker.patch.object(client_mocker, "list_ediscovery_cases", return_value=load_json("./test_data/list_cases_response.json")) mock_alerts = mocker.patch('MicrosoftGraphSecurity.test_function') + mock_threat_assessment = mocker.patch.object(client_mocker, "list_threat_assessment_requests", + return_value=load_json("./test_data/list_threat_assessment.json")) test_auth_code_command(client_mocker, {'permission_type': command_to_check}) if command_to_check == 'alerts': assert not mock_ediscovery.called + assert not mock_threat_assessment.called assert mock_alerts.called elif command_to_check == 'any': assert mock_ediscovery.called assert mock_alerts.called + assert mock_threat_assessment.called elif command_to_check == 'ediscovery': assert mock_ediscovery.called assert not mock_alerts.called + assert not mock_threat_assessment.called + elif command_to_check == 'threat assessment': + assert not mock_ediscovery.called + assert not mock_alerts.called + assert mock_threat_assessment.called def test_purge_ediscovery_data_command(mocker): mocker.patch.object(client_mocker, 'purge_ediscovery_data', return_value=SimpleNamespace(headers={})) - assert 'eDiscovery purge status is success.' == purge_ediscovery_data_command(client_mocker, {}).readable_output + assert purge_ediscovery_data_command(client_mocker, {}).readable_output == 'eDiscovery purge status is success.' def test_list_ediscovery_non_custodial_data_source_command_empty_output(mocker): mocker.patch.object(client_mocker, 'list_ediscovery_noncustodial_datasources', return_value={'value': []}) - assert '### Results:\n**No entries.**\n' == \ - list_ediscovery_non_custodial_data_source_command(client_mocker, {}).readable_output + assert list_ediscovery_non_custodial_data_source_command(client_mocker, {}).readable_output == \ + '### Results:\n**No entries.**\n' def test_list_ediscovery_case_command(mocker): @@ -626,3 +637,71 @@ def test_create_ediscovery_non_custodial_data_source_command_invalid_args(mocker def test_empty_list_ediscovery_custodian_command(mocker): mocker.patch.object(client_mocker, 'list_ediscovery_custodians', return_value={}) assert list_ediscovery_custodian_command(client_mocker, {}).readable_output == '### Results:\n**No entries.**\n' + + +THREAT_ASSESSMENT_COMMANDS = { + 'mail_assessment_request': create_mail_assessment_request_command, + 'email_file_assessment_request': create_email_file_request_command, + 'file_assessment_request': create_file_assessment_request_command, + 'url_assessment_request': create_url_assessment_request_command, + 'list_assessment_requests': list_threat_assessment_requests_command +} + + +@pytest.mark.parametrize('mock_func, command_name, expected_result', + [ + ('create_mail_assessment_request', 'mail_assessment_request', 'mail_assessment_request.json'), + ('create_email_file_assessment_request', 'email_file_assessment_request', + 'email_file_assessment_request.json'), + ('create_file_assessment_request', 'file_assessment_request', 'file_assessment_request.json'), + ('create_url_assessment_request', 'url_assessment_request', 'url_assessment_request.json')]) +def test_create_mail_assessment_request_command(mocker, mock_func, command_name, expected_result): + """ + + Given: + A raw response with one result + When: + calling list search command + Then: + Nested value is in the readable output + """ + raw_response = load_json(f"./test_data/{expected_result}") + mocker.patch.object(client_mocker, mock_func, + return_value={'request_id': '123'}) + mocker.patch.object(client_mocker, "get_threat_assessment_request_status", + return_value={'status': 'completed'}) + mocker.patch.object(client_mocker, "get_threat_assessment_request", + return_value=raw_response) + mocker.patch("MicrosoftGraphSecurity.get_content_data", return_value="content_data") + mocker.patch("MicrosoftGraphSecurity.get_message_user", return_value="user_mail") + mocker.patch("CommonServerPython.is_demisto_version_ge", return_value=True) + results = THREAT_ASSESSMENT_COMMANDS[command_name]({}, client_mocker) + + assert results.raw_response == raw_response + assert results.outputs.get('ID') == raw_response.get('id') + assert results.outputs.get("Content Type") == raw_response.get("contentType") + + +def test_list_threat_assessment_requests_command(mocker): + raw_response = load_json("./test_data/list_threat_assessment.json") + mocker.patch.object(client_mocker, "list_threat_assessment_requests", + return_value=raw_response) + + result = list_threat_assessment_requests_command(client_mocker, {}) + assert len(result) == 2 + assert result[0].outputs_prefix == 'MSGraphMail.AssessmentRequest' + assert len(result[0].outputs) == 4 + assert result[1].outputs_prefix == 'MsGraph.AssessmentRequestNextToken' + assert result[1].outputs == {'next_token': 'test_token'} + + +@pytest.mark.parametrize('user, expected_result', + [ + ('testuser@test.com', 'test user id'), + ('test user id', 'test user id') + ]) +def test_get_message_user(mocker, user, expected_result): + mocker.patch.object(client_mocker, "get_user_id", + return_value={'value': [{"id": "test user id"}]}) + message_user = get_message_user(client_mocker, user) + assert message_user == expected_result diff --git a/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/README.md b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/README.md index 80567a9d065b..dd810ab4fd86 100644 --- a/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/README.md +++ b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/README.md @@ -11,6 +11,15 @@ Note: eDiscovery commands only support the `Delegated (work or school account)` For more information, see: https://github.com/microsoftgraph/security-api-solutions/issues/56. - When using Alerts V2, only the following properties are supported as filters for the *Fetched incidents filter* parameter and *filter* arguments: assignedTo, classification, determination, createdDateTime, lastUpdateDateTime, severity, serviceSource and status. See [Microsoft optional query parameters](https://learn.microsoft.com/en-us/graph/api/security-list-alerts_v2?view=graph-rest-1.0&tabs=http#optional-query-parameters). - As of July 2023, Microsoft Graph API does **not support** a solution to search for and delete emails. To do this, refer to the [Security & Compliance](https://xsoar.pan.dev/docs/reference/integrations/security-and-compliance) integration. +- When using Threat Assessment, only the following properties are supported as filters for *filter* parameter: expectedAssessment, ContentType ,status and requestSource. +- For Threat Assessment commands the only authorization that supported is [Authorize on Behalf of a User](https://xsoar.pan.dev/docs/reference/articles/microsoft-integrations---authentication#authorize-on-behalf-of-a-user) +- When using Threat Assessment, for information protection, The following limits apply to any request on /informationProtection: + - For email, the resource is a unique network message ID/recipient pair. For example, submitting an email with the same message ID sent to the same person multiple times in a 15 minutes period will trigger the limit per resource limits listed in the following table. However, you can submit up to 150 unique emails every 15 minutes (tenant limit). + + | **Operation** | **Limit per tenant** | **Limit per resource (email, URL, file)** | + | --- | --- | --- | + | POST | 150 requests per 15 minutes and 10000 requests per 24 hours. | 1 request per 15 minutes and 3 requests per 24 hours. | + ### Required Permissions @@ -30,6 +39,12 @@ EDiscovery: 1. eDiscovery.Read.All - Delegated (Required for the `list-ediscovery` commands) 2. eDiscovery.ReadWrite.All - Delegated (Required for the `create/update-ediscovery` commands) +Threat Assessment: + +1. Mail.Read.Shared - Delegated +2. ThreatAssessment.ReadWrite.All - Delegated +3. User.Read.All - Delegated + ## Configure Microsoft Graph Security on Cortex XSOAR 1. Navigate to **Settings** > **Integrations** > **Servers & Services**. @@ -1706,6 +1721,453 @@ There is no context output for this command. #### Human Readable Output + +### msg-create-mail-assessment-request + +*** +Create and retrieve a mail threat assessment. + +Note: +- The message given in the command's argument *message_id* has to contain *X-MS-Exchange-Organization-Network-Message-Id* header in the message or in the *X-MS-Office365-Filtering-Correlation-Id* header in quarantined messages. +- Delegated Mail permissions (Mail.Read or Mail.Read.Shared) are required to access the mail received by the user (recipient email and message user), which means that if the authenticated user is different from the user specified in the recipient_email and message_user, then *Read and manage permissions* on behalf of the given user need to be added for the authenticated user via [Microsoft 365 admin center](https://admin.microsoft.com/Adminportal/Home#/users). + + - Go to [Microsoft 365 admin center](https://admin.microsoft.com/Adminportal/Home#/users). + - Choose the user email which will be provided in the command's arguments. + - Click on *Manage product licenses*. + - Go to *Mail*. + - Under *Mailbox permissions*, click on *Read and manage permissions*. + - click on *Add permissions*. + - Choose the authenticated user email from the list of given users. + - Click on *add*. + +#### Base Command + +`msg-create-mail-assessment-request` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| recipient_email | The email of the user who recieved the mail. | Required | +| expected_assessment | the expected assessment: blocked or unblocked | Required | +| category | The category of the threat: phishing, malware or spam. | Required | +| message_user | Message user, the user's id or the user's email. | Required | +| message_id | Message id, Message has to contain 'X-MS-Exchange-Organization-Network-Message-Id' header in the message or the 'X-MS-Office365-Filtering-Correlation-Id' header in quarantined messages. | Required | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| MSGraphMail.MailAssessment.ID | String | Request id. | +| MSGraphMail.MailAssessment.CreatedDateTime | Date | Created data of the threat assessment request. | +| MSGraphMail.MailAssessment.ContentType | String | The content type of threat assessment. | +| MSGraphMail.MailAssessment.ExpectedAssessment | String | The expected assessment from submitter. Possible values are: block, unblock. | +| MSGraphMail.MailAssessment.Category | String | The threat category. Possible values are: spam, phishing, malware. | +| MSGraphMail.MailAssessment.Status | String | The assessment process status. Possible values are: pending, completed. | +| MSGraphMail.MailAssessment.RequestSource | String | The source of threat assessment request. Possible values are: administrator. | +| MSGraphMail.MailAssessment.RecipientEmail | String | The mail recipient whose policies are used to assess the mail. | +| MSGraphMail.MailAssessment.DestinationRoutingReason | String | The reason for mail routed to its destination. Possible values are: none, mailFlowRule, safeSender, blockedSender, advancedSpamFiltering, domainAllowList, domainBlockList, notInAddressBook, firstTimeSender, autoPurgeToInbox, autoPurgeToJunk, autoPurgeToDeleted, outbound, notJunk, junk. | +| MSGraphMail.MailAssessment.MessageID | String | Extracted from the message URI which is The resource URI of the mail message for assessment. | +| MSGraphMail.MailAssessment.CreatedUserID | String | User id. | +| MSGraphMail.MailAssessment.CreatedUsername | String | Username. | +| MSGraphMail.MailAssessment.ResultType | String | Result of the request. | +| MSGraphMail.MailAssessment.ResultMessage | String | Message of the result. | + +#### Command example + +```!msg-create-mail-assessment-request recipient_email="avishai@demistodev.onmicrosoft.com" expectedAssessment=unblock category=spam user_id=3fa9f28b-eb0e-463a-ba7b-8089fe9991e2 user_message=AAMkAGY3OTQyMzMzLWYxNjktNDE0My05NmZhLWQ5MGY1YjIyNzBkNABGAAAAAACYCKjWAnXBTrnhgWJCcLX7BwDrxRwRjq-zTrN6vWSzK4OWAAAAAAEJAADrxRwRjq-zTrN6vWSzK4OWAAY5aBb-AAA=``` + +#### Context Example + +```json +{ + + "id": "11922306-b25b-4605-ff0d-08d772fcf996", + "createdDateTime": "2019-11-27T05:45:14.0962061Z", + "contentType": "mail", + "expectedAssessment": "unblock", + "category": "spam", + "status": "completed", + "requestSource": "administrator", + "recipientEmail": "avishai@demistodev.onmicrosoft.com", + "destinationRoutingReason": "notJunk", + "messageUri": "", + "createdBy": { + "user": { + "id": "c52ce8db-3e4b-4181-93c4-7d6b6bffaf60", + "displayName": "Ronald Admin" + } + }, + "results": [ + { + "id": "63798129-a62c-4f9e-2c6d-08d772fcfb0e", + "createdDateTime": "2019-11-27T05:45:16.55Z", + "resultType": "checkPolicy", + "message": "No policy was hit." + }, + { + "id": "d38c2448-79eb-467e-2495-08d772fdb7d1", + "createdDateTime": "2019-11-27T05:50:33.243Z", + "resultType": "rescan", + "message": "Not Spam" + } + ] +} +``` + +#### Human Readable Output + +>### Mail assessment request: + +>|ID|Created DateTime|Content Type|Expected Assessment|Category|Status|Request Source|Recipient Email|Destination Routing Reason|Created User ID|Created Username| +>|---|---|---|---|---|---|---|---|---|---|---| +>| 11922306-b25b-4605-ff0d-08d772fcf996 | "2019-11-27T05:45:14.0962061Z"| mail | unblock| spam| completed | administrator | avishai@demistodev.onmicrosoft.com |notJunk|63798129-a62c-4f9e-2c6d-08d772fcfb0e|No policy was hit.| + + +### msg-create-email-file-assessment-request + +*** +Create and retrieve an email file threat assessment. + +Note: File has to contain X-MS-Exchange-Organization-Network-Message-Id header in the message or in the X-MS-Office365-Filtering-Correlation-Id header in quarantined messages. + +#### Base Command + +`msg-create-email-file-assessment-request` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| recipient_email | The email of the user who recieved the mail. | Required | +| expected_assessment | the expected assessment: blocked or unblocked | Required | +| category | The category of the threat: phishing, malware or spam. | Required | +| content_data | content of an email file. | Optional | +| entry_id | entry id of file uploaded in the war room. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| MSGraphMail.EmailAssessment.ID | String | Request id. | +| MSGraphMail.EmailAssessment.CreatedDateTime | Date | Created data of the threat assessment request. | +| MSGraphMail.EmailAssessment.ContentType | String | The content type of threat assessment. | +| MSGraphMail.EmailAssessment.ExpectedAssessment | String | The expected assessment from submitter. Possible values are: block, unblock. | +| MSGraphMail.EmailAssessment.Category | String | The threat category. Possible values are: spam, phishing, malware. | +| MSGraphMail.EmailAssessment.Status | String | The assessment process status. Possible values are: pending, completed. | +| MSGraphMail.EmailAssessment.RequestSource | String | The source of threat assessment request. Possible values are: administrator. | +| MSGraphMail.EmailAssessment.RecipientEmail | String | The mail recipient whose policies are used to assess the mail. | +| MSGraphMail.EmailAssessment.DestinationRoutingReason | String | The reason for mail routed to its destination. Possible values are: none, mailFlowRule, safeSender, blockedSender, advancedSpamFiltering, domainAllowList, domainBlockList, notInAddressBook, firstTimeSender, autoPurgeToInbox, autoPurgeToJunk, autoPurgeToDeleted, outbound, notJunk, junk. | +| MSGraphMail.EmailAssessment.CreatedUserID | String | User id. | +| MSGraphMail.EmailAssessment.CreatedUsername | String | Username. | +| MSGraphMail.EmailAssessment.ResultType | String | Result of the request. | +| MSGraphMail.EmailAssessment.ResultMessage | String | Message of the result. | + +#### Command example + +```!msg-create-email-file-assessment-request recipient_email="avishai@demistodev.onmicrosoft.com" expectedAssessment=unblock category=phishing entry_id=12359704829584``` + +#### Context Example + +```json +{ + + "id": "76598306-b25b-4605-ff0d-03kgmtfcf996", + "createdDateTime": "2019-11-27T05:45:14.0962061Z", + "contentType": "mail", + "expectedAssessment": "unblock", + "category": "phishing", + "status": "completed", + "requestSource": "administrator", + "recipientEmail": "avishai@demistodev.onmicrosoft.com", + "destinationRoutingReason": "notJunk", + "createdBy": { + "user": { + "id": "c52ce8db-3e4b-4181-93c4-7d6b6bffaf60", + "displayName": "Ronald Admin" + } + }, + "results": [ + { + "id": "63798129-a62c-4f9e-2c6d-08d772fcfb0e", + "createdDateTime": "2019-11-27T05:45:16.55Z", + "resultType": "checkPolicy", + "message": "Phishing attempt." + } + ] +} +``` + +#### Human Readable Output + +>### Mail assessment request: + +>|ID|Created DateTime|Content Type|Expected Assessment|Category|Status|Request Source|Recipient Email|Destination Routing Reason|Created User ID|Created Username| +>|---|---|---|---|---|---|---|---|---|---|---| +>| 76598306-b25b-4605-ff0d-03kgmtfcf996 | "2019-11-27T05:45:14.0962061Z"| mail | unblock| phishing| completed | administrator | avishai@demistodev.onmicrosoft.com |notJunk|63798129-a62c-4f9e-2c6d-08d772fcfb0e|Phishing attempt.| + + +### msg-create-file-assessment-request + +*** +Create and retrieve a file threat assessment. + +#### Base Command + +`msg-create-file-assessment-request` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| file_name | The file name. | Required | +| expected_assessment | the expected assessment: blocked or unblocked | Required | +| category | The category of the threat: phishing, malware or spam. | Required | +| content_data | content of an email file. | Optional | +| entry_id | entry id of file uploaded in the war room. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| MSGraphMail.FileAssessment.ID | String | Request id. | +| MSGraphMail.FileAssessment.CreatedDateTime | Date | Created data of the threat assessment request. | +| MSGraphMail.FileAssessment.ContentType | String | The content type of threat assessment. | +| MSGraphMail.FileAssessment.ExpectedAssessment | String | The expected assessment from submitter. Possible values are: block, unblock. | +| MSGraphMail.FileAssessment.Category | String | The threat category. Possible values are: phishing, malware. | +| MSGraphMail.FileAssessment.Status | String | The assessment process status. Possible values are: pending, completed. | +| MSGraphMail.FileAssessment.RequestSource | String | The source of threat assessment request. Possible values are: administrator. | +| MSGraphMail.FileAssessment.FileName | String | The file name. | +| MSGraphMail.FileAssessment.CreatedUserID | String | User id. | +| MSGraphMail.FileAssessment.CreatedUsername | String | Username. | +| MSGraphMail.FileAssessment.ResultType | String | Result of the request. | +| MSGraphMail.FileAssessment.ResultMessage | String | Message of the result. | + +#### Command example + +```!msg-create-file-assessment-request file_name="test_file.txt" expectedAssessment=block category=phishing entry_id=1235970482958bkf4``` + +#### Context Example + +```json +{ + + "id": "0796306-b456-4605-ff0d-03kgmtfcf876", + "createdDateTime": "2019-11-27T05:45:14.0962061Z", + "contentType": "file", + "expectedAssessment": "block", + "category": "phishing", + "status": "completed", + "requestSource": "administrator", + "fileName": "test_file.txt", + "createdBy": { + "user": { + "id": "c52ce8db-3e4b-4181-93c4-7d6b6bffaf60", + "displayName": "Ronald Admin" + } + }, + "results": [ + { + "id": "63798129-a62c-4f9e-2c6d-08d772fcfb0e", + "createdDateTime": "2019-11-27T05:45:16.55Z", + "resultType": "checkPolicy", + "message": "Phishing attempt." + } + ] +} +``` + +#### Human Readable Output + +>### Mail assessment request: + +>|ID|Created DateTime|Content Type|Expected Assessment|Category|Status|Request Source|File Name|Created User ID|Created Username| +>|---|---|---|---|---|---|---|---|---|---| +>| 0796306-b456-4605-ff0d-03kgmtfcf876 | "2019-11-27T05:45:14.0962061Z"| file | block| phishing| completed | administrator | test_file.txt |63798129-a62c-4f9e-2c6d-08d772fcfb0e|Phishing attempt.| + +### msg-create-url-assessment-request + +*** +Create and retrieve url threat assessment. + +#### Base Command + +`msg-create-url-assessment-request` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| url | The URL. | Required | +| expected_assessment | the expected assessment: blocked or unblocked | Required | +| category | The category of the threat: phishing, malware or spam. | Required | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| MSGraphMail.UrlAssessment.ID | String | Request id. | +| MSGraphMail.UrlAssessment.CreatedDateTime | Date | Created data of the threat assessment request. | +| MSGraphMail.UrlAssessment.ContentType | String | The content type of threat assessment. | +| MSGraphMail.UrlAssessment.ExpectedAssessment | String | The expected assessment from submitter. Possible values are: block, unblock. | +| MSGraphMail.UrlAssessment.Category | String | The threat category. Possible values are: spam, phishing, malware. | +| MSGraphMail.UrlAssessment.Status | String | The assessment process status. Possible values are: pending, completed. | +| MSGraphMail.UrlAssessment.RequestSource | String | The source of threat assessment request. Possible values are: administrator. | +| MSGraphMail.UrlAssessment.Url | String | The url. | +| MSGraphMail.UrlAssessment.CreatedUserID | String | User id. | +| MSGraphMail.UrlAssessment.CreatedUsername | String | Username. | +| MSGraphMail.UrlAssessment.ResultType | String | Result of the request. | +| MSGraphMail.UrlAssessment.ResultMessage | String | Message of the result. | +| MSGraphMail.UrlAssessment.RecipientEmail | String | Recipient Email. | +| MSGraphMail.UrlAssessment.DestinationRoutingReason | String | Destination Routing Reason. | + + +#### Command example + +```!msg-create-url-assessment-request url="httpp://support.clean-mx.de/clean-mx/viruses.php" expectedAssessment=block category=malware``` + +#### Context Example + +```json +{ + + "id": "0796306-b456-4605-ff0d-03okmtgcf876", + "createdDateTime": "2019-11-27T05:45:14.0962061Z", + "contentType": "url", + "expectedAssessment": "block", + "category": "malware", + "status": "completed", + "requestSource": "administrator", + "url": "httpp://support.clean-mx.de/clean-mx/viruses.php", + "createdBy": { + "user": { + "id": "c52ce8db-3e4b-4181-93c4-7d6b6bffaf60", + "displayName": "Ronald Admin" + } + }, + "results": [ + { + "id": "63798129-a62c-4f9e-2c6d-08d772fcfb0e", + "createdDateTime": "2019-11-27T05:45:16.55Z", + "resultType": "checkPolicy", + "message": "Malware attempt." + } + ] +} +``` + +#### Human Readable Output + +>### Mail assessment request: + +>|ID|Created DateTime|Content Type|Expected Assessment|Category|Status|Request Source|URL|Created User ID|Created Username| +>|---|---|---|---|---|---|---|---|---|---| +>| 0796306-b456-4605-ff0d-03okmtgcf876 | "2019-11-27T05:45:14.0962061Z"| url | block| malware| completed | administrator | httpp://support.clean-mx.de/clean-mx/viruses.php |63798129-a62c-4f9e-2c6d-08d772fcfb0e|Malware attempt.| + + +### msg-list-threat-assessment-requests + +*** +Retrieve all threat assessment requests. + +#### Base Command + +`msg-list-threat-assessment-requests` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| request_id | The request id. | Optional | +| filter | Available fields for filter are:expectedAssessment,ContentType,status,requestSource. Example:category eq 'malware’| Optional | +| order_by | Drop -down: id, createdDateTime, ContentType, expectedAssessment, category, status, requestSource, category | Optional | +| sort_order | desc or asc. | Optional | +| limit | Default is 50. | Optional | +| next_token | the retrieved token from first run when there's more data to retrieve. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| MSGraphMail.AssessmentRequest.ID | String | Request id. | +| MSGraphMail.AssessmentRequest.CreatedDateTime | Date | Created data of the threat assessment request. | +| MSGraphMail.AssessmentRequest.ContentType | String | The content type of threat assessment. | +| MSGraphMail.AssessmentRequest.ExpectedAssessment | String | The expected assessment from submitter. Possible values are: block, unblock. | +| MSGraphMail.AssessmentRequest.Category | String | The threat category. Possible values are: spam, phishing, malware. | +| MSGraphMail.AssessmentRequest.Status | String | The assessment process status. Possible values are: pending, completed. | +| MSGraphMail.AssessmentRequest.RequestSource | String | The source of threat assessment request. Possible values are: administrator. | +| MSGraphMail.AssessmentRequest.DestinationRoutingReason | String | The destination Routing Reason. | +| MSGraphMail.AssessmentRequest.RecipientEmail | String | The recipient email. | +| MSGraphMail.AssessmentRequest.URL | String | The url. | +| MSGraphMail.AssessmentRequest.FileName | String | The file name. | +| MSGraphMail.AssessmentRequest.CreatedUserID | String | User id. | +| MSGraphMail.AssessmentRequest.CreatedUsername | String | Username. | +| MSGraphMail.AssessmentRequest.ResultType | String | Result of the request. | +| MSGraphMail.AssessmentRequest.ResultMessage | String | Message of the result. | +| MsGraph.AssessmentRequestNextToken.next_token |String |the next token from the previous run.| + +#### Command example + +```!msg-list-threat-assessment-requests``` + +#### Context Example + +```json +{ + "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#informationProtection/threatAssessmentRequests", + "@odata.nextLink": "https://graph.microsoft.com/v1.0/informationProtection/threatAssessmentRequests?$skiptoken=eyJQYWdlQ29va2llIjoiPHJvdyBpZF9JZGVudGl0", + "value": [ + { + "@odata.type": "#microsoft.graph.mailAssessmentRequest", + "id": "49c5ef5b-1f65-444a-e6b9-08d772ea2059", + "createdDateTime": "2019-11-27T03:30:18.6890937Z", + "contentType": "mail", + "expectedAssessment": "block", + "category": "spam", + "status": "pending", + "requestSource": "administrator", + "recipientEmail": "avishaibrandies@microsoft.com", + "destinationRoutingReason": "notJunk", + "messageUri": "https://graph.microsoft.com/v1.0/users/c52ce8db-3e4b-4181-93c4-7d6b6bffaf60/messages/AAMkADU3MWUxOTU0LWNlOTEt=", + "createdBy": { + "user": { + "id": "c52ce8db-3e4b-4181-93c4-7d6b6bffaf60", + "displayName": "Ronald Admin" + } + } + }, + { + "@odata.type": "#microsoft.graph.emailFileAssessmentRequest", + "id": "ab2ad9b3-2213-4091-ae0c-08d76ddbcacf", + "createdDateTime": "2019-11-20T17:05:06.4088076Z", + "contentType": "mail", + "expectedAssessment": "block", + "category": "malware", + "status": "completed", + "requestSource": "administrator", + "recipientEmail": "tifc@a830edad9050849EQTPWBJZXODQ.onmicrosoft.com", + "destinationRoutingReason": "notJunk", + "contentData": "", + "createdBy": { + "user": { + "id": "c52ce8db-3e4b-4181-93c4-7d6b6bffaf60", + "displayName": "Ronald Admin" + } + } + } + ] +} +``` + +#### Human Readable Output +>###Next Token is: eyJQYWdlQ29va2llIjoiPHJvdyBpZF9JZGVudGl +>### Mail assessment request: + +>|ID|Created DateTime|Content Type|Expected Assessment|Category|Status|Request Source|Recipient Email|Created User ID|Created Username|destinationRoutingReason| +>|---|---|---|---|---|---|---|---|---|---|---| +>| 49c5ef5b-1f65-444a-e6b9-08d772ea2059 | "2019-11-27T03:30:18.6890937Z"| mail | block| spam| pending| administrator | avishaibrandies@microsoft.com |63798129-a62c-4f9e-2c6d-08d772fcfb0e|spam attempt.|notJunk| +>| ab2ad9b3-2213-4091-ae0c-08d76ddbcacf | 2019-11-20T17:05:06.4088076Z| mail | block| malware| pending| administrator | avishaibrandies@microsoft.com |63798129-a62c-4f9e-2c6d-08d772fcfb0e|Malware attempt.|notJunk| + >### Authorization instructions >1. Click on the [login URL]() to sign in and grant Cortex XSOAR permissions for your Azure Service Management. You will be automatically redirected to a link with the following structure: diff --git a/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/email_file_assessment_request.json b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/email_file_assessment_request.json new file mode 100644 index 000000000000..1fb65bf89f2c --- /dev/null +++ b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/email_file_assessment_request.json @@ -0,0 +1,26 @@ +{ + + "id": "email_file_id", + "createdDateTime": "2019-11-27T05:45:14.0962061Z", + "contentType": "mail", + "expectedAssessment": "unblock", + "category": "phishing", + "status": "completed", + "requestSource": "administrator", + "recipientEmail": "test_email", + "destinationRoutingReason": "notJunk", + "createdBy": { + "user": { + "id": "id", + "displayName": "Test Admin" + } + }, + "results": [ + { + "id": "id", + "createdDateTime": "2019-11-27T05:50:33.243Z", + "resultType": "rescan", + "message": "Not Spam" + } + ] +} \ No newline at end of file diff --git a/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/file_assessment_request.json b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/file_assessment_request.json new file mode 100644 index 000000000000..3731315c80e0 --- /dev/null +++ b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/file_assessment_request.json @@ -0,0 +1,25 @@ +{ + "id": "file_test_id", + "createdDateTime": "2019-11-27T05:44:00.4051536Z", + "contentType": "file", + "expectedAssessment": "block", + "category": "phishing", + "status": "completed", + "requestSource": "administrator", + "fileName": "file_name.csv", + "contentData": "", + "createdBy": { + "user": { + "id": "c52ce8db-3e4b-4181-93c4-7d6b6bffaf60", + "displayName": "Ronald Admin" + } + }, + "results": [ + { + "id": "id", + "createdDateTime": "2019-11-27T05:50:33.243Z", + "resultType": "rescan", + "message": "Phishing" + } + ] +} \ No newline at end of file diff --git a/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/list_threat_assessment.json b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/list_threat_assessment.json new file mode 100644 index 000000000000..bab4c5fef193 --- /dev/null +++ b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/list_threat_assessment.json @@ -0,0 +1,74 @@ +{ + "@odata.nextLink": "testskiptoken=test_token", + "value": [ + { + "id": "email_id", + "createdDateTime": "2019-11-27T03:30:18.6890937Z", + "contentType": "mail", + "expectedAssessment": "block", + "category": "spam", + "status": "pending", + "requestSource": "administrator", + "recipientEmail": "test_email", + "destinationRoutingReason": "notJunk", + "messageUri": "https://graph.microsoft.com/v1.0/users/email_id/messages/message_id", + "createdBy": { + "user": { + "id": "c52ce8db-3e4b-4181-93c4-7d6b6bffaf60", + "displayName": "Test Admin" + } + } + }, + { + "createdDateTime": "2019-11-20T17:05:06.4088076Z", + "id": "email_file_test", + "contentType": "mail", + "expectedAssessment": "block", + "category": "malware", + "status": "completed", + "requestSource": "administrator", + "recipientEmail": "email_test", + "destinationRoutingReason": "notJunk", + "contentData": "", + "createdBy": { + "user": { + "id": "c52ce8db-3e4b-4181-93c4-7d6b6bffaf60", + "displayName": "Test Admin" + } + } + }, + { + "id": "file_id", + "createdDateTime": "2019-11-27T05:44:00.4051536Z", + "contentType": "file", + "expectedAssessment": "block", + "category": "malware", + "status": "completed", + "requestSource": "administrator", + "fileName": "file_name.csv", + "contentData": "", + "createdBy": { + "user": { + "id": "c52ce8db-3e4b-4181-93c4-7d6b6bffaf60", + "displayName": "Test Admin" + } + } + }, + { + "id": "723c35be-8b5a-47ae-29c0-08d76ddb7f5b", + "createdDateTime": "2019-11-20T17:02:59.8160832Z", + "contentType": "url", + "expectedAssessment": "unblock", + "category": "phishing", + "status": "completed", + "requestSource": "administrator", + "url": "http://test.com", + "createdBy": { + "user": { + "id": "c52ce8db-3e4b-4181-93c4-7d6b6bffaf60", + "displayName": "Test Admin" + } + } + } + ] +} \ No newline at end of file diff --git a/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/mail_assessment_request.json b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/mail_assessment_request.json new file mode 100644 index 000000000000..02bebd89b5da --- /dev/null +++ b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/mail_assessment_request.json @@ -0,0 +1,27 @@ +{ + + "id": "mail_test_id", + "createdDateTime": "2019-11-27T05:45:14.0962061Z", + "contentType": "mail", + "expectedAssessment": "unblock", + "category": "spam", + "status": "completed", + "requestSource": "administrator", + "recipientEmail": "test_email", + "destinationRoutingReason": "notJunk", + "messageUri": "", + "createdBy": { + "user": { + "id": "id_test", + "displayName": "Test Admin" + } + }, + "results": [ + { + "id": "test_id_two", + "createdDateTime": "2019-11-27T05:45:16.55Z", + "resultType": "checkPolicy", + "message": "No policy was hit." + } + ] +} \ No newline at end of file diff --git a/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/url_assessment_request.json b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/url_assessment_request.json new file mode 100644 index 000000000000..f85e897df332 --- /dev/null +++ b/Packs/MicrosoftGraphSecurity/Integrations/MicrosoftGraphSecurity/test_data/url_assessment_request.json @@ -0,0 +1,24 @@ +{ + "id": "url_id", + "createdDateTime": "2019-11-29T08:26:09.8196703Z", + "contentType": "url", + "expectedAssessment": "block", + "category": "phishing", + "status": "completed", + "requestSource": "administrator", + "url": "http://test.com", + "createdBy": { + "user": { + "id": "c52ce8db-3e4b-4181-93c4-7d6b6bffaf60", + "displayName": "Test Admin" + } + }, + "results": [ + { + "id": "id", + "createdDateTime": "2019-11-27T05:50:33.243Z", + "resultType": "checking", + "message": "Malware" + } + ] +} \ No newline at end of file diff --git a/Packs/MicrosoftGraphSecurity/ReleaseNotes/2_2_6.md b/Packs/MicrosoftGraphSecurity/ReleaseNotes/2_2_6.md new file mode 100644 index 000000000000..fba5536dc406 --- /dev/null +++ b/Packs/MicrosoftGraphSecurity/ReleaseNotes/2_2_6.md @@ -0,0 +1,7 @@ + +#### Integrations + +##### Microsoft Graph Security + +- Added support for threat assessment functionality to help organizations assess the threat received by any user in a tenant. +- Updated the Docker image to: *demisto/crypto:1.0.0.82826*. diff --git a/Packs/MicrosoftGraphSecurity/TestPlaybooks/Microsoft_Graph_Security_test_threat_assessment.yml b/Packs/MicrosoftGraphSecurity/TestPlaybooks/Microsoft_Graph_Security_test_threat_assessment.yml new file mode 100644 index 000000000000..022aff77bfc3 --- /dev/null +++ b/Packs/MicrosoftGraphSecurity/TestPlaybooks/Microsoft_Graph_Security_test_threat_assessment.yml @@ -0,0 +1,611 @@ +id: MSG-Threat-Assessment-test +version: 6 +name: MSG-Threat-Assessment-test +fromversion: 5.0.0 +starttaskid: "0" +tasks: + "0": + id: "0" + taskid: 945f2a4f-cf3d-435b-80d0-3d7d8b7ba13a + type: start + task: + id: 945f2a4f-cf3d-435b-80d0-3d7d8b7ba13a + version: -1 + name: "" + iscommand: false + brand: "" + nexttasks: + '#none#': + - "1" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 50 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "1": + id: "1" + taskid: 973e318d-d379-4077-8947-79b05c58d5b2 + type: regular + task: + id: 973e318d-d379-4077-8947-79b05c58d5b2 + version: -1 + name: auth test + description: Tests connectivity to Microsoft Graph Security. + script: '|||msg-auth-test' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "10" + scriptarguments: + permission_type: + simple: threat assessment + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 195 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "2": + id: "2" + taskid: 2893b9ef-a3ac-437f-8c49-9a1213884cf3 + type: regular + task: + id: 2893b9ef-a3ac-437f-8c49-9a1213884cf3 + version: -1 + name: create URL assessment request + description: Create url assessment request. + script: '|||msg-create-url-assessment-request' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "3" + scriptarguments: + category: + simple: malware + expected_assessment: + simple: block + url: + simple: api.interfacecache.com + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 1070 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "3": + id: "3" + taskid: e4876147-087a-4614-8d2a-592b85e9b9c1 + type: condition + task: + id: e4876147-087a-4614-8d2a-592b85e9b9c1 + version: -1 + name: Check outputs + type: condition + iscommand: false + brand: "" + nexttasks: + "yes": + - "4" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: isEqualString + left: + value: + simple: MSGraphMail.UrlAssessment.ContentType + iscontext: true + right: + value: + simple: url + - - operator: isEqualString + left: + value: + simple: MSGraphMail.UrlAssessment.ExpectedAssessment + iscontext: true + right: + value: + simple: block + - - operator: isEqualString + left: + value: + simple: MSGraphMail.UrlAssessment.Category + iscontext: true + right: + value: + simple: malware + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 1245 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "4": + id: "4" + taskid: 5c8a057d-1ac1-41b7-860a-01cb51d74d0c + type: regular + task: + id: 5c8a057d-1ac1-41b7-860a-01cb51d74d0c + version: -1 + name: Create file assessment request + description: Create file assessment request. + script: '|||msg-create-file-assessment-request' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "5" + scriptarguments: + category: + simple: malware + content_data: + simple: VGhpcyBpcyBhIHRlc3QgZmlsZQ== + expected_assessment: + simple: unblock + file_name: + simple: test.txt + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 1420 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "5": + id: "5" + taskid: 450ddad6-e43e-4ee0-8e23-b084dadf6ed6 + type: condition + task: + id: 450ddad6-e43e-4ee0-8e23-b084dadf6ed6 + version: -1 + name: Check outputs + type: condition + iscommand: false + brand: "" + nexttasks: + "yes": + - "6" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: isEqualString + left: + value: + simple: MSGraphMail.FileAssessment.ContentType + iscontext: true + right: + value: + simple: file + - - operator: isEqualString + left: + value: + simple: MSGraphMail.FileAssessment.FileName + iscontext: true + right: + value: + simple: test.txt + - - operator: isEqualString + left: + value: + simple: MSGraphMail.FileAssessment.Category + iscontext: true + right: + value: + simple: malware + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 1595 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "6": + id: "6" + taskid: 1380e4c1-ee3f-4a98-87b6-3cd19e2f2888 + type: regular + task: + id: 1380e4c1-ee3f-4a98-87b6-3cd19e2f2888 + version: -1 + name: List theat assessment requests with request id + description: Create url assessment request. + script: '|||msg-list-threat-assessment-requests' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "7" + scriptarguments: + request_id: + simple: 3e8c68f-9a57-4332-1739-08dbd2e880ba + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 1770 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "7": + id: "7" + taskid: e4b9ae7c-2a5d-409d-8cff-b4373de5c3da + type: condition + task: + id: e4b9ae7c-2a5d-409d-8cff-b4373de5c3da + version: -1 + name: Check outputs + type: condition + iscommand: false + brand: "" + nexttasks: + "yes": + - "8" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: isEqualString + left: + value: + simple: MSGraphMail.AssesmentRequest.ContentType + iscontext: true + right: + value: + simple: file + - - operator: isEqualString + left: + value: + simple: MSGraphMail.AssesmentRequest.ID + iscontext: true + right: + value: + simple: 3e8c68f-9a57-4332-1739-08dbd2e880ba + - - operator: isEqualString + left: + value: + simple: MSGraphMail.AssesmentRequest.FileName + iscontext: true + right: + value: + simple: test.txt + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 1945 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "8": + id: "8" + taskid: a04d8a64-b816-4f82-8680-3395a0a905e6 + type: regular + task: + id: a04d8a64-b816-4f82-8680-3395a0a905e6 + version: -1 + name: List all threat assessment requests + description: Create url assessment request. + script: '|||msg-list-threat-assessment-requests' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "9" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 2120 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "9": + id: "9" + taskid: 9007910c-ca69-41a7-8f0f-1adb3ead0d9c + type: title + task: + id: 9007910c-ca69-41a7-8f0f-1adb3ead0d9c + version: -1 + name: Done + type: title + iscommand: false + brand: "" + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 2295 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "10": + id: "10" + taskid: 94f99d6b-15be-4e38-8b52-73636b5ccf4f + type: regular + task: + id: 94f99d6b-15be-4e38-8b52-73636b5ccf4f + version: -1 + name: Create mail assessment request + description: Create and retrieve a mail threat assessment. + script: '|||msg-create-mail-assessment-request' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "11" + scriptarguments: + category: + simple: phishing + expected_assessment: + simple: unblock + message_id: + simple: AAMkAGY3OTQyMzMzLWYxNjktNDE0My05NmZhLWQ5MGY1YjIyNzBkNABGAAAAAACYCKjWAnXBTrnhgWJCcLX7BwDrxRwRjq-zTrN6vWSzK4OWAAAAAAEMAADrxRwRjq-zTrN6vWSzK4OWAAZ7vnHVAAA= + message_user: + simple: 3fa9f28b-eb0e-463a-ba7b-8089fe9991e2 + recipient_email: + simple: avishai@demistodev.onmicrosoft.com + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 370 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "11": + id: "11" + taskid: c6bfb4e2-0e8d-49b6-8201-0636fe97052b + type: condition + task: + id: c6bfb4e2-0e8d-49b6-8201-0636fe97052b + version: -1 + name: Check outputs + type: condition + iscommand: false + brand: "" + nexttasks: + "yes": + - "12" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: isEqualString + left: + value: + simple: MSGraphMail.MailAssessment.ContentType + iscontext: true + right: + value: + simple: mail + - - operator: isEqualString + left: + value: + simple: MSGraphMail.MailAssessment.MessageID + iscontext: true + right: + value: + simple: AAMkAGY3OTQyMzMzLWYxNjktNDE0My05NmZhLWQ5MGY1YjIyNzBkNABGAAAAAACYCKjWAnXBTrnhgWJCcLX7BwDrxRwRjq-zTrN6vWSzK4OWAAAAAAEMAADrxRwRjq-zTrN6vWSzK4OWAAZ7vnHVAAA= + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 545 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "12": + id: "12" + taskid: ba0d17cb-eda5-4d3d-88a4-15de07975701 + type: regular + task: + id: ba0d17cb-eda5-4d3d-88a4-15de07975701 + version: -1 + name: Create email file assessment request + description: Create email file assessment request. + script: '|||msg-create-email-file-assessment-request' + type: regular + iscommand: true + brand: "" + nexttasks: + '#none#': + - "13" + scriptarguments: + category: + simple: phishing + content_data: + simple: UmVjZWl2ZWQ6IGZyb20gVkkxUFIwN01CMTAwNjUuZXVycHJkMDcucHJvZC5vdXRsb29rLmNvbQ0KICgyNjAzOjEwYTY6ODAwOjExOTo6MjIpIGJ5IFBBWFBSMDdNQjgzOTguZXVycHJkMDcucHJvZC5vdXRsb29rLmNvbSB3aXRoDQogSFRUUFM7IFN1biwgMTMgQXVnIDIwMjMgMTU6MjA6NTAgKzAwMDANClJlY2VpdmVkOiBmcm9tIFBBWFBSMDdNQjgzOTguZXVycHJkMDcucHJvZC5vdXRsb29rLmNvbSAoMjYwMzoxMGE2OjEwMjoyYmM6OjYpDQogYnkgVkkxUFIwN01CMTAwNjUuZXVycHJkMDcucHJvZC5vdXRsb29rLmNvbSAoMjYwMzoxMGE2OjgwMDoxMTk6OjIyKSB3aXRoDQogTWljcm9zb2Z0IFNNVFAgU2VydmVyICh2ZXJzaW9uPVRMUzFfMiwNCiBjaXBoZXI9VExTX0VDREhFX1JTQV9XSVRIX0FFU18yNTZfR0NNX1NIQTM4NCkgaWQgMTUuMjAuNjY3OC4yNDsgU3VuLCAxMyBBdWcNCiAyMDIzIDE1OjIwOjQ4ICswMDAwDQpSZWNlaXZlZDogZnJvbSBQQVhQUjA3TUI4Mzk4LmV1cnByZDA3LnByb2Qub3V0bG9vay5jb20NCiAoW2ZlODA6OmFiOTE6NWFhMDo5YzVlOjRlYTFdKSBieSBQQVhQUjA3TUI4Mzk4LmV1cnByZDA3LnByb2Qub3V0bG9vay5jb20NCiAoW2ZlODA6OmFiOTE6NWFhMDo5YzVlOjRlYTElNF0pIHdpdGggbWFwaSBpZCAxNS4yMC42Njc4LjAyMjsgU3VuLCAxMyBBdWcgMjAyMw0KIDE1OjIwOjQ4ICswMDAwDQpGcm9tOiBBdmlzaGFpIEJyYW5kZWlzIDxhdmlzaGFpQGRlbWlzdG9kZXYub25taWNyb3NvZnQuY29tPg0KVG86IEF2aXNoYWkgQnJhbmRlaXMgPGF2aXNoYWlAZGVtaXN0b2Rldi5vbm1pY3Jvc29mdC5jb20+DQpTdWJqZWN0OiBGdzogdGVzdCBtYWlsIHRvIHJhdGUgdGVzdA0KVGhyZWFkLVRvcGljOiB0ZXN0IG1haWwgdG8gcmF0ZSB0ZXN0DQpUaHJlYWQtSW5kZXg6IEFRSFp6Zm04SnA3OFRSZVFDa21sa0FxUnlOZWJydz09DQpEYXRlOiBTdW4sIDEzIEF1ZyAyMDIzIDE1OjIwOjQ4ICswMDAwDQpNZXNzYWdlLUlEOg0KCTxQQVhQUjA3TUI4Mzk4OERERjRDNTU1RjMxQzU5NDY3QkM5OTE2QUBQQVhQUjA3TUI4Mzk4LmV1cnByZDA3LnByb2Qub3V0bG9vay5jb20+DQpBY2NlcHQtTGFuZ3VhZ2U6IGVuLVVTDQpDb250ZW50LUxhbmd1YWdlOiBlbi1VUw0KWC1NUy1FeGNoYW5nZS1Pcmdhbml6YXRpb24tQXV0aEFzOiBJbnRlcm5hbA0KWC1NUy1FeGNoYW5nZS1Pcmdhbml6YXRpb24tQXV0aE1lY2hhbmlzbTogMDQNClgtTVMtRXhjaGFuZ2UtT3JnYW5pemF0aW9uLUF1dGhTb3VyY2U6IFBBWFBSMDdNQjgzOTguZXVycHJkMDcucHJvZC5vdXRsb29rLmNvbQ0KWC1NUy1IYXMtQXR0YWNoOg0KWC1NUy1FeGNoYW5nZS1Pcmdhbml6YXRpb24tTmV0d29yay1NZXNzYWdlLUlkOg0KCTgwMTMzY2Y3LWI0OTMtNGMwYS1mOTZhLTA4ZGI5YzEwZGY1Yg0KWC1NUy1FeGNoYW5nZS1Pcmdhbml6YXRpb24tU0NMOiAxDQpYLU1TLVRORUYtQ29ycmVsYXRvcjoNClgtTVMtRXhjaGFuZ2UtT3JnYW5pemF0aW9uLVJlY29yZFJldmlld0NmbVR5cGU6IDANCm1zaXBfbGFiZWxzOg0KeC1tcy1wdWJsaWN0cmFmZmljdHlwZTogRW1haWwNCngtZm9yZWZyb250LWFudGlzcGFtLXJlcG9ydDoNCglDSVA6MjU1LjI1NS4yNTUuMjU1O0NUUlk6O0xBTkc6ZW47U0NMOjE7U1JWOjtJUFY6TkxJO1NGVjpOU1BNO0g6UEFYUFIwN01CODM5OC5ldXJwcmQwNy5wcm9kLm91dGxvb2suY29tO1BUUjo7Q0FUOk5PTkU7U0ZTOjtESVI6SU5UOw0KYXV0aGVudGljYXRpb24tcmVzdWx0czogZGtpbT1ub25lIChtZXNzYWdlIG5vdCBzaWduZWQpDQogaGVhZGVyLmQ9bm9uZTtkbWFyYz1ub25lIGFjdGlvbj1ub25lIGhlYWRlci5mcm9tPWRlbWlzdG9kZXYub25taWNyb3NvZnQuY29tOw0KeC1taWNyb3NvZnQtYW50aXNwYW06IEJDTDowOw0KeC1tcy1vZmZpY2UzNjUtZmlsdGVyaW5nLWNvcnJlbGF0aW9uLWlkOiA4MDEzM2NmNy1iNDkzLTRjMGEtZjk2YS0wOGRiOWMxMGRmNWINCngtbXMtdHJhZmZpY3R5cGVkaWFnbm9zdGljOg0KCVBBWFBSMDdNQjgzOTg6RUVffFZJMVBSMDdNQjEwMDY1OkVFX3xQQVhQUjA3TUI4Mzk4OkVFXw0KeC1tcy1leGNoYW5nZS1jcm9zc3RlbmFudC1uZXR3b3JrLW1lc3NhZ2UtaWQ6DQoJODAxMzNjZjctYjQ5My00YzBhLWY5NmEtMDhkYjljMTBkZjViDQp4LW1zLWV4Y2hhbmdlLWNyb3NzdGVuYW50LWZyb21lbnRpdHloZWFkZXI6IEhvc3RlZA0KeC1tcy1leGNoYW5nZS1jcm9zc3RlbmFudC1pZDogZWJhYzFhMTYtODFiZi00NDliLThkNDMtNTczMmMzYzFkOTk5DQp4LW1zLWV4Y2hhbmdlLWNyb3NzdGVuYW50LW9yaWdpbmFsYXJyaXZhbHRpbWU6IDEzIEF1ZyAyMDIzIDE1OjIwOjQ4LjMzMzQgKFVUQykNCngtbXMtZXhjaGFuZ2UtdHJhbnNwb3J0LWNyb3NzdGVuYW50aGVhZGVyc3N0YW1wZWQ6IFZJMVBSMDdNQjEwMDY1DQp4LW1zLWV4Y2hhbmdlLWNyb3NzdGVuYW50LW1haWxib3h0eXBlOiBIT1NURUQNCngtbXMtZXhjaGFuZ2UtY3Jvc3N0ZW5hbnQtdXNlcnByaW5jaXBhbG5hbWU6DQoJL2h0ZTdnODBaOFFZWjlqZDk0eGE5QzRaMytmb3dNTkk1NWFwVWo0ZzJOelk5UVJpTCtkRGR0WFRjMFpWdEFsYXFmK0xObVVkRWw3SFo2NEcxeTViRjVvZGxpZ2RQYUc1bElqNEIvZFI1dktLUC9Ic2FhVkNvQ0l1MTZNM0R1Nm4NCngtbXMtZXhjaGFuZ2UtdHJhbnNwb3J0LWVuZHRvZW5kbGF0ZW5jeTogMDA6MDA6MDIuNjQxMzc1MA0KeC1tcy1leGNoYW5nZS1hdHBtZXNzYWdlcHJvcGVydGllczogU0wNCngtbXMtZXhjaGFuZ2UtcHJvY2Vzc2VkLWJ5LWJjY2ZvbGRlcmluZzogMTUuMjAuNjY3OC4wMjINCngtbXMtZXhjaGFuZ2UtY3Jvc3N0ZW5hbnQtYXV0aGFzOiBJbnRlcm5hbA0KeC1tcy1leGNoYW5nZS1jcm9zc3RlbmFudC1hdXRoc291cmNlOiBQQVhQUjA3TUI4Mzk4LmV1cnByZDA3LnByb2Qub3V0bG9vay5jb20NClgtTWljcm9zb2Z0LUFudGlzcGFtLU1haWxib3gtRGVsaXZlcnk6DQoJdWNmOjA7am1yOjA7YXV0aDowO2Rlc3Q6STtFTkc6KDkxMDAwMSkoOTQ0NTA2NDc4KSg5NDQ2MjY2MDQpKDkyMDA5NykoNDI1MDAxKSg5MzAwOTcpKDE0MDAwMykoMTQyMDEwMyk7DQpYLU1pY3Jvc29mdC1BbnRpc3BhbS1NZXNzYWdlLUluZm86DQoJOUkvZnlpRm9pSlNzaittanR0aEZvZEdzdkRMQzVmOVA4eVpDUmovT0NWdXFLQ294SFpqY0tFR2JGcU1rT1QyUFJFV3VSRnNCQnh5TFEzY2xhUkxhQVoyNEw2WGNKQXZ4MnUvZG02NjluRk5halNHeEprUDlMTHpvQUFpVTRzQUxtN1YxMmpyYVRjcDNOaFM5UHpXZlBLRUlBS3NNT3ZDcUdmeURNd29uSjVveTJBOHUxT2dVNnQ1QlkyK0FDR2ZZVERPS1lhOXBUMUgwbFBBS1VTL0ZzYmgydVE5UmhUYVJhOVV4UkFtakhuTUh1UmxxS0JtSGRQQXV1MEl1STVWV01aRThkMFFnSnExbmFNOXFDOTM5MmxsKzd0eFRDa0dlSlZhbGovaExjdlVOa3dnSlZrMW5LREJkOWROTm8vV0FQYzVjaU9Hb3FSclAzNUxDREpsSVdraGdHQ25RSy9NNzAzSjBRTVBteFpRN2FrcEE3a2VoeTAxb21iYmhGOUxhQmIwTDVyYVlTbWZhWmNDVlNKY1ViYnIyaWw0SU82UG0xRWVFMnREMnFCSXlYcHU3dCs5V0pSRlFhTHZueFoyMnh1bDZoMllaMzdidW5Ocm5KZFdNZ0lMa1ZETnB1Und3VTd0dmk4Q1h3blBrSUlGK2dOWnBsaS85b0U4encySFV0U25vaEhFSERvTXMyRE1hSHh2d2VOU1oyTmJkbzNUb1dPbXJCSDV6cGlaWnVzbWJkN294RDBKTm1HeFNGRzhtNjdrZ2pFbnJWRUgwQUl0RjJTMmRoU0l1WVpGZUo5SWgrc1hsZzNXNDdZSmw0eTlGK1FITDMyc2NKd3FHMTg1MVBJVjEyVFBHWHhkWDBVZUMreWkvQlZrTDI0em42akNBeEJwUnp0eVArNEw3akVNK1dXcWlXdWgxK0NmU0Q3bDBWeG1VdHBQbWxUYndxdGpKK1pscEk3WGNwdEV6ZnNoR3pVejNkUEhXSWFTWmRTWGxBQXdXMDRlaEtWbHUvdEtEDQpDb250ZW50LVR5cGU6IG11bHRpcGFydC9hbHRlcm5hdGl2ZTsNCglib3VuZGFyeT0iXzAwMF9QQVhQUjA3TUI4Mzk4OERERjRDNTU1RjMxQzU5NDY3QkM5OTE2QVBBWFBSMDdNQjgzOThldXJwXyINCk1JTUUtVmVyc2lvbjogMS4wDQoNCi0tXzAwMF9QQVhQUjA3TUI4Mzk4OERERjRDNTU1RjMxQzU5NDY3QkM5OTE2QVBBWFBSMDdNQjgzOThldXJwXw0KQ29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PSJpc28tODg1OS0xIg0KQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogcXVvdGVkLXByaW50YWJsZQ0KDQoNCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpGcm9tOiBBdmlzaGFpIEJyYW5kZWlzDQpTZW50OiBTdW5kYXksIEF1Z3VzdCAxMywgMjAyMyA1OjU1IFBNDQpUbzogcmF0ZSB0ZXN0IDEgPHJhdGV0ZXN0MUBkZW1pc3RvZGV2Lm9ubWljcm9zb2Z0LmNvbT4NCkNjOiBDb250ZW50IFRlc3QgPENvbnRlbnRUZXN0QGRlbWlzdG9kZXYub25taWNyb3NvZnQuY29tPg0KU3ViamVjdDogdGVzdCBtYWlsIHRvIHJhdGUgdGVzdA0KDQp0ZXN0IG1haWwgdG8gcmF0ZSB0ZXN0ICAxDQpsaW5rIHRvIGNoZWNrIHlvdXIgY3JlZGl0IGNhcmQNCmh0dHBzOi8vd3d3Lmhvb2tzZWN1cml0eS5jby9waGlzaGluZy1lbWFpbC1leGFtcGxlczxodHRwczovL2V1cjAxLnNhZmVsaW5rcz0NCi5wcm90ZWN0aW9uLm91dGxvb2suY29tLz91cmw9M0RodHRwcyUzQSUyRiUyRnd3dy5ob29rc2VjdXJpdHkuY28lMkZwaGlzaGluZz0NCi1lbWFpbC1leGFtcGxlcyZkYXRhPTNEMDUlN0MwMSU3Q2F2aXNoYWklNDBkZW1pc3RvZGV2Lm9ubWljcm9zb2Z0LmNvbSU3QzgwMT0NCjMzY2Y3YjQ5MzRjMGFmOTZhMDhkYjljMTBkZjViJTdDZWJhYzFhMTY4MWJmNDQ5YjhkNDM1NzMyYzNjMWQ5OTklN0MxJTdDMCU3Qz0NCjYzODI3NTM2ODUxMTE1MzE2NiU3Q1Vua25vd24lN0NUV0ZwYkdac2IzZDhleUpXSWpvaU1DNHdMakF3TURBaUxDSlFJam9pVjJsdT0NCk16SWlMQ0pCVGlJNklrMWhhV3dpTENKWFZDSTZNbjAlM0QlN0MzMDAwJTdDJTdDJTdDJnNkYXRhPTNEVUlBSkYzdjBJbWNTNTJyNT0NCnRNQUx5UndxNTMyRENZZU44Q2lMSVVyMEloUSUzRCZyZXNlcnZlZD0zRDA+DQo1MCsgUGhpc2hpbmcgRW1haWwgRXhhbXBsZXMgLSBDb21tb24gVHlwZXMgYW5kIEV4YW1wbGVzIG9mIFBoaXNoaW5nPGh0dHBzOi89DQovZXVyMDEuc2FmZWxpbmtzLnByb3RlY3Rpb24ub3V0bG9vay5jb20vP3VybD0zRGh0dHBzJTNBJTJGJTJGd3d3Lmhvb2tzZWN1cmk9DQp0eS5jbyUyRnBoaXNoaW5nLWVtYWlsLWV4YW1wbGVzJmRhdGE9M0QwNSU3QzAxJTdDYXZpc2hhaSU0MGRlbWlzdG9kZXYub25taWM9DQpyb3NvZnQuY29tJTdDODAxMzNjZjdiNDkzNGMwYWY5NmEwOGRiOWMxMGRmNWIlN0NlYmFjMWExNjgxYmY0NDliOGQ0MzU3MzJjM2M9DQoxZDk5OSU3QzElN0MwJTdDNjM4Mjc1MzY4NTExMzA5ODQ0JTdDVW5rbm93biU3Q1RXRnBiR1pzYjNkOGV5SldJam9pTUM0d0xqQXc9DQpNREFpTENKUUlqb2lWMmx1TXpJaUxDSkJUaUk2SWsxaGFXd2lMQ0pYVkNJNk1uMCUzRCU3QzMwMDAlN0MlN0MlN0Mmc2RhdGE9M0Q9DQp3dnBiaWtad1NHd3ZzdGpmV3ZUaTBrRFQ5OEtKV3dDcyUyQmFmU3FuUEZYQW8lM0QmcmVzZXJ2ZWQ9M0QwPg0KVmlldyBvdXIgbGFyZ2UgY29sbGVjdGlvbiBvZiBwaGlzaGluZyBlbWFpbCBleGFtcGxlcywgZnJvbSBVYmVyIHRvIFBheXBhbCBhPQ0KbmQgbW9yZSwgYW5kIGxlYXJuIGhvdyB0byB1c2UgdGhlIGNvbW1vbiByZWQgZmxhZ3Mgb2YgcGhpc2hpbmcgdG8gYXZvaWQgY2xpPQ0KY2tpbmcgb24gcmVhbCBwaGlzaGluZyBlbWFpbHMuDQp3d3cuaG9va3NlY3VyaXR5LmNvDQoNCg0KDQotLV8wMDBfUEFYUFIwN01CODM5ODhEREY0QzU1NUYzMUM1OTQ2N0JDOTkxNkFQQVhQUjA3TUI4Mzk4ZXVycF8NCkNvbnRlbnQtVHlwZTogdGV4dC9odG1sOyBjaGFyc2V0PSJpc28tODg1OS0xIg0KQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogcXVvdGVkLXByaW50YWJsZQ0KDQo8aHRtbD4NCjxoZWFkPg0KPG1ldGEgaHR0cC1lcXVpdj0zRCJDb250ZW50LVR5cGUiIGNvbnRlbnQ9M0QidGV4dC9odG1sOyBjaGFyc2V0PTNEaXNvLTg4NTktPQ0KMSI+DQo8c3R5bGUgdHlwZT0zRCJ0ZXh0L2NzcyIgc3R5bGU9M0QiZGlzcGxheTpub25lOyI+IFAge21hcmdpbi10b3A6MDttYXJnaW4tYm89DQp0dG9tOjA7fSA8L3N0eWxlPg0KPC9oZWFkPg0KPGJvZHkgZGlyPTNEImx0ciI+DQo8ZGl2IHN0eWxlPTNEImZvbnQtZmFtaWx5OiBDYWxpYnJpLCBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOyBmb250LXNpemU9DQo6IDEycHQ7IGNvbG9yOiByZ2IoMCwgMCwgMCk7IiBjbGFzcz0zRCJlbGVtZW50VG9Qcm9vZiI+DQo8YnI+DQo8L2Rpdj4NCjxkaXYgaWQ9M0QiYXBwZW5kb25zZW5kIj48L2Rpdj4NCjxociBzdHlsZT0zRCJkaXNwbGF5OmlubGluZS1ibG9jazt3aWR0aDo5OCUiIHRhYmluZGV4PTNEIi0xIj4NCjxkaXYgaWQ9M0QiZGl2UnBseUZ3ZE1zZyIgZGlyPTNEImx0ciI+PGZvbnQgZmFjZT0zRCJDYWxpYnJpLCBzYW5zLXNlcmlmIiBzdD0NCnlsZT0zRCJmb250LXNpemU6MTFwdCIgY29sb3I9M0QiIzAwMDAwMCI+PGI+RnJvbTo8L2I+IEF2aXNoYWkgQnJhbmRlaXM8YnI+DQo8Yj5TZW50OjwvYj4gU3VuZGF5LCBBdWd1c3QgMTMsIDIwMjMgNTo1NSBQTTxicj4NCjxiPlRvOjwvYj4gcmF0ZSB0ZXN0IDEgJmx0O3JhdGV0ZXN0MUBkZW1pc3RvZGV2Lm9ubWljcm9zb2Z0LmNvbSZndDs8YnI+DQo8Yj5DYzo8L2I+IENvbnRlbnQgVGVzdCAmbHQ7Q29udGVudFRlc3RAZGVtaXN0b2Rldi5vbm1pY3Jvc29mdC5jb20mZ3Q7PGJyPg0KPGI+U3ViamVjdDo8L2I+IHRlc3QgbWFpbCB0byByYXRlIHRlc3Q8L2ZvbnQ+DQo8ZGl2PiZuYnNwOzwvZGl2Pg0KPC9kaXY+DQo8c3R5bGUgdHlwZT0zRCJ0ZXh0L2NzcyIgc3R5bGU9M0QiZGlzcGxheTpub25lIj4NCjwhLS0NCnANCgl7bWFyZ2luLXRvcDowOw0KCW1hcmdpbi1ib3R0b206MH0NCi0tPg0KPC9zdHlsZT4NCjxkaXYgZGlyPTNEImx0ciI+DQo8ZGl2IGNsYXNzPTNEInhfZWxlbWVudFRvUHJvb2YiIHN0eWxlPTNEImZvbnQtZmFtaWx5OkNhbGlicmksQXJpYWwsSGVsdmV0aWM9DQphLHNhbnMtc2VyaWY7IGZvbnQtc2l6ZToxMnB0OyBjb2xvcjpyZ2IoMCwwLDApIj4NCnRlc3QgbWFpbCB0byByYXRlIHRlc3QmbmJzcDsgMSZuYnNwOzwvZGl2Pg0KPGRpdiBjbGFzcz0zRCJ4X2VsZW1lbnRUb1Byb29mIiBzdHlsZT0zRCJmb250LWZhbWlseTpDYWxpYnJpLEFyaWFsLEhlbHZldGljPQ0KYSxzYW5zLXNlcmlmOyBmb250LXNpemU6MTJwdDsgY29sb3I6cmdiKDAsMCwwKSI+DQpsaW5rIHRvIGNoZWNrIHlvdXIgY3JlZGl0IGNhcmQ8L2Rpdj4NCjxkaXYgY2xhc3M9M0QieF9lbGVtZW50VG9Qcm9vZiB4X0NvbnRlbnRQYXN0ZWQwIiBzdHlsZT0zRCJmb250LWZhbWlseTpDYWxpYj0NCnJpLEFyaWFsLEhlbHZldGljYSxzYW5zLXNlcmlmOyBmb250LXNpemU6MTJwdDsgY29sb3I6cmdiKDAsMCwwKSI+DQo8YSBocmVmPTNEImh0dHBzOi8vZXVyMDEuc2FmZWxpbmtzLnByb3RlY3Rpb24ub3V0bG9vay5jb20vP3VybD0zRGh0dHBzJTNBJTI9DQpGJTJGd3d3Lmhvb2tzZWN1cml0eS5jbyUyRnBoaXNoaW5nLWVtYWlsLWV4YW1wbGVzJmFtcDtkYXRhPTNEMDUlN0MwMSU3Q2F2aXM9DQpoYWklNDBkZW1pc3RvZGV2Lm9ubWljcm9zb2Z0LmNvbSU3QzgwMTMzY2Y3YjQ5MzRjMGFmOTZhMDhkYjljMTBkZjViJTdDZWJhYzE9DQphMTY4MWJmNDQ5YjhkNDM1NzMyYzNjMWQ5OTklN0MxJTdDMCU3QzYzODI3NTM2ODUxMTE1MzE2NiU3Q1Vua25vd24lN0NUV0ZwYkc9DQpac2IzZDhleUpXSWpvaU1DNHdMakF3TURBaUxDSlFJam9pVjJsdU16SWlMQ0pCVGlJNklrMWhhV3dpTENKWFZDSTZNbjAlM0QlN0M9DQozMDAwJTdDJTdDJTdDJmFtcDtzZGF0YT0zRFVJQUpGM3YwSW1jUzUycjV0TUFMeVJ3cTUzMkRDWWVOOENpTElVcjBJaFElM0QmYW09DQpwO3Jlc2VydmVkPTNEMCIgb3JpZ2luYWxzcmM9M0QiaHR0cHM6Ly93d3cuaG9va3NlY3VyaXR5LmNvL3BoaXNoaW5nLWVtYWlsLWU9DQp4YW1wbGVzIiBzaGFzaD0zRCJyVng2eWNUUXFpaFRla3k1UG9xT3A2UnpFaTVoTmlqL1E3UFFnYUlWRUJjckQvQW1sNVlMcXprQ1E9DQpFSldpcU9uMEtUTVl4RTZNTytFUWIxUUcrNEw0aHZPaTRuM2lHVHV0NXRTaFBYa0xSM0RXc1JNNG5UOUFsekRzOXR3MHpEOU91WGQ9DQoyU3MxYzNTSDg1R3R3MkFWZ1lqNkg0KzJwRnVBb3hPalkrN250Nm89M0QiIGlkPTNEIkxQbG5rT1dBTGlua1ByZXZpZXciPmh0dHA9DQpzOi8vd3d3Lmhvb2tzZWN1cml0eS5jby9waGlzaGluZy1lbWFpbC1leGFtcGxlczwvYT48YnI+DQo8L2Rpdj4NCjxkaXYgY2xhc3M9M0QieF9fRW50aXR5IHhfX0VUeXBlX09XQUxpbmtQcmV2aWV3IHhfX0VJZF9PV0FMaW5rUHJldmlldyB4X19FUj0NCmVhZG9ubHlfMSI+DQo8ZGl2IGlkPTNEIkxQQm9yZGVyX0dUYUhSMGNITTZMeTkzZDNjdWFHOXZhM05sWTNWeWFYUjVMbU52TDNCb2FYTm9hVzVuTFdWdFk9DQpXbHNMV1Y0WVcxd2JHVnoiIGNsYXNzPTNEInhfTFBCb3JkZXIxNTk0OTkiIHN0eWxlPTNEIndpZHRoOjEwMCU7IG1hcmdpbi10b3A9DQo6MTZweDsgbWFyZ2luLWJvdHRvbToxNnB4OyBtYXgtd2lkdGg6ODAwcHg7IG1pbi13aWR0aDo0MjRweCI+DQo8dGFibGUgaWQ9M0QiTFBDb250YWluZXIxNTk0OTkiIHJvbGU9M0QicHJlc2VudGF0aW9uIiBzdHlsZT0zRCJwYWRkaW5nOjEycHg9DQogMzZweCAxMnB4IDEycHg7IHdpZHRoOjEwMCU7IGJvcmRlci13aWR0aDoxcHg7IGJvcmRlci1zdHlsZTpzb2xpZDsgYm9yZGVyLWM9DQpvbG9yOnJnYigyMDAsMjAwLDIwMCk7IGJvcmRlci1yYWRpdXM6MnB4Ij4NCjx0Ym9keT4NCjx0ciB2YWxpZ249M0QidG9wIiBzdHlsZT0zRCJib3JkZXItc3BhY2luZzowcHgiPg0KPHRkIHN0eWxlPTNEIndpZHRoOjEwMCUiPg0KPGRpdiBpZD0zRCJMUFRpdGxlMTU5NDk5IiBzdHlsZT0zRCJmb250LXNpemU6MjFweDsgZm9udC13ZWlnaHQ6MzAwOyBtYXJnaW4tPQ0KcmlnaHQ6OHB4OyBmb250LWZhbWlseTp3Zl9zZWdvZS11aV9saWdodCwmcXVvdDtTZWdvZSBVSSBMaWdodCZxdW90OywmcXVvdDtTPQ0KZWdvZSBXUCBMaWdodCZxdW90OywmcXVvdDtTZWdvZSBVSSZxdW90OywmcXVvdDtTZWdvZSBXUCZxdW90OyxUYWhvbWEsQXJpYWwsPQ0Kc2Fucy1zZXJpZjsgbWFyZ2luLWJvdHRvbToxMnB4Ij4NCjxhIHRhcmdldD0zRCJfYmxhbmsiIGlkPTNEIkxQVXJsQW5jaG9yMTU5NDk5IiBocmVmPTNEImh0dHBzOi8vZXVyMDEuc2FmZWxpbj0NCmtzLnByb3RlY3Rpb24ub3V0bG9vay5jb20vP3VybD0zRGh0dHBzJTNBJTJGJTJGd3d3Lmhvb2tzZWN1cml0eS5jbyUyRnBoaXNoaT0NCm5nLWVtYWlsLWV4YW1wbGVzJmFtcDtkYXRhPTNEMDUlN0MwMSU3Q2F2aXNoYWklNDBkZW1pc3RvZGV2Lm9ubWljcm9zb2Z0LmNvbT0NCiU3QzgwMTMzY2Y3YjQ5MzRjMGFmOTZhMDhkYjljMTBkZjViJTdDZWJhYzFhMTY4MWJmNDQ5YjhkNDM1NzMyYzNjMWQ5OTklN0MxJT0NCjdDMCU3QzYzODI3NTM2ODUxMTMwOTg0NCU3Q1Vua25vd24lN0NUV0ZwYkdac2IzZDhleUpXSWpvaU1DNHdMakF3TURBaUxDSlFJaj0NCm9pVjJsdU16SWlMQ0pCVGlJNklrMWhhV3dpTENKWFZDSTZNbjAlM0QlN0MzMDAwJTdDJTdDJTdDJmFtcDtzZGF0YT0zRHd2cGJpaz0NClp3U0d3dnN0amZXdlRpMGtEVDk4S0pXd0NzJTJCYWZTcW5QRlhBbyUzRCZhbXA7cmVzZXJ2ZWQ9M0QwIiBvcmlnaW5hbHNyYz0zRD0NCiJodHRwczovL3d3dy5ob29rc2VjdXJpdHkuY28vcGhpc2hpbmctZW1haWwtZXhhbXBsZXMiIHNoYXNoPTNEIlQyUTU1M0YzeWNQTT0NCk80b2dnZVVWNE9vOGFhWEVNMHNKUmdmdFRPSU1WRzlkQ2JMVklKdmlvT1ZxaEx6T3Jxa3BnV09nVzUzTXh2dk9UUE1rRWVwOVZXdD0NCnY4TG85ZXFseC9iY1ZCdytnR2paYkZSZFJmc3JGSVRZWlJCVDk4OWpDeDFZRFh3am5aZGo0MEZ3ZS9HSzZhKzI4REVNLzBTUEw4Tj0NClJ4Zkk1VFJrQT0zRCIgc3R5bGU9M0QidGV4dC1kZWNvcmF0aW9uOm5vbmUiPjUwKw0KIFBoaXNoaW5nIEVtYWlsIEV4YW1wbGVzIC0gQ29tbW9uIFR5cGVzIGFuZCBFeGFtcGxlcyBvZiBQaGlzaGluZzwvYT48L2Rpdj4NCjxkaXYgaWQ9M0QiTFBEZXNjcmlwdGlvbjE1OTQ5OSIgc3R5bGU9M0QiZm9udC1zaXplOjE0cHg7IG1heC1oZWlnaHQ6MTAwcHg7ID0NCmZvbnQtZmFtaWx5OndmX3NlZ29lLXVpX25vcm1hbCwmcXVvdDtTZWdvZSBVSSZxdW90OywmcXVvdDtTZWdvZSBXUCZxdW90OyxUYT0NCmhvbWEsQXJpYWwsc2Fucy1zZXJpZjsgbWFyZ2luLWJvdHRvbToxMnB4OyBtYXJnaW4tcmlnaHQ6OHB4OyBvdmVyZmxvdzpoaWRkZT0NCm47IGNvbG9yOnJnYigxMDIsMTAyLDEwMikiPg0KVmlldyBvdXIgbGFyZ2UgY29sbGVjdGlvbiBvZiBwaGlzaGluZyBlbWFpbCBleGFtcGxlcywgZnJvbSBVYmVyIHRvIFBheXBhbCBhPQ0KbmQgbW9yZSwgYW5kIGxlYXJuIGhvdyB0byB1c2UgdGhlIGNvbW1vbiByZWQgZmxhZ3Mgb2YgcGhpc2hpbmcgdG8gYXZvaWQgY2xpPQ0KY2tpbmcgb24gcmVhbCBwaGlzaGluZyBlbWFpbHMuPC9kaXY+DQo8ZGl2IGlkPTNEIkxQTWV0YWRhdGExNTk0OTkiIHN0eWxlPTNEImZvbnQtc2l6ZToxNHB4OyBmb250LXdlaWdodDo0MDA7IGZvbnQ9DQotZmFtaWx5OndmX3NlZ29lLXVpX25vcm1hbCwmcXVvdDtTZWdvZSBVSSZxdW90OywmcXVvdDtTZWdvZSBXUCZxdW90OyxUYWhvbWE9DQosQXJpYWwsc2Fucy1zZXJpZjsgY29sb3I6cmdiKDE2NiwxNjYsMTY2KSI+DQp3d3cuaG9va3NlY3VyaXR5LmNvPC9kaXY+DQo8L3RkPg0KPC90cj4NCjwvdGJvZHk+DQo8L3RhYmxlPg0KPC9kaXY+DQo8L2Rpdj4NCjxkaXYgc3R5bGU9M0QiZm9udC1mYW1pbHk6Q2FsaWJyaSxBcmlhbCxIZWx2ZXRpY2Esc2Fucy1zZXJpZjsgZm9udC1zaXplOjEycD0NCnQ7IGNvbG9yOnJnYigwLDAsMCkiPg0KPGJyPg0KPC9kaXY+DQo8ZGl2IGNsYXNzPTNEInhfZWxlbWVudFRvUHJvb2YiIHN0eWxlPTNEImZvbnQtZmFtaWx5OkNhbGlicmksQXJpYWwsSGVsdmV0aWM9DQphLHNhbnMtc2VyaWY7IGZvbnQtc2l6ZToxMnB0OyBjb2xvcjpyZ2IoMCwwLDApIj4NCjxicj4NCjwvZGl2Pg0KPC9kaXY+DQo8L2JvZHk+DQo8L2h0bWw+DQoNCi0tXzAwMF9QQVhQUjA3TUI4Mzk4OERERjRDNTU1RjMxQzU5NDY3QkM5OTE2QVBBWFBSMDdNQjgzOThldXJwXy0tDQo= + expected_assessment: + simple: unblock + recipient_email: + simple: avishai@demistodev.onmicrosoft.com + separatecontext: false + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 720 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false + "13": + id: "13" + taskid: f4d525b2-4641-4538-8c73-2af8170f8885 + type: condition + task: + id: f4d525b2-4641-4538-8c73-2af8170f8885 + version: -1 + name: Check outputs + type: condition + iscommand: false + brand: "" + nexttasks: + "yes": + - "2" + separatecontext: false + conditions: + - label: "yes" + condition: + - - operator: isEqualString + left: + value: + simple: MSGraphMail.EmailAssessment.ContentType + iscontext: true + right: + value: + simple: mail + - - operator: isEqualString + left: + value: + simple: MSGraphMail.EmailAssessment.RecipientEmail + iscontext: true + right: + value: + simple: avishai@demistodev.onmicrosoft.com + continueonerrortype: "" + view: |- + { + "position": { + "x": 50, + "y": 895 + } + } + note: false + timertriggers: [] + ignoreworker: false + skipunavailable: false + quietmode: 0 + isoversize: false + isautoswitchedtoquietmode: false +view: |- + { + "linkLabelsPosition": {}, + "paper": { + "dimensions": { + "height": 2310, + "width": 380, + "x": 50, + "y": 50 + } + } + } +inputs: [] +outputs: [] diff --git a/Packs/MicrosoftGraphSecurity/TestPlaybooks/Microsoft_Graph_security_test_ediscovery.yml b/Packs/MicrosoftGraphSecurity/TestPlaybooks/Microsoft_Graph_security_test_ediscovery.yml index 0c6cd7359f38..3701576601ae 100644 --- a/Packs/MicrosoftGraphSecurity/TestPlaybooks/Microsoft_Graph_security_test_ediscovery.yml +++ b/Packs/MicrosoftGraphSecurity/TestPlaybooks/Microsoft_Graph_security_test_ediscovery.yml @@ -1670,6 +1670,9 @@ tasks: nexttasks: '#none#': - "38" + scriptarguments: + permission_type: + simple: ediscovery separatecontext: false continueonerrortype: "" view: |- diff --git a/Packs/MicrosoftGraphSecurity/pack_metadata.json b/Packs/MicrosoftGraphSecurity/pack_metadata.json index 0e452364813c..3d6d74907324 100644 --- a/Packs/MicrosoftGraphSecurity/pack_metadata.json +++ b/Packs/MicrosoftGraphSecurity/pack_metadata.json @@ -2,7 +2,7 @@ "name": "Microsoft Graph Security", "description": "Unified gateway to security insights - all from a unified Microsoft Graph\n Security API.", "support": "xsoar", - "currentVersion": "2.2.5", + "currentVersion": "2.2.6", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", diff --git a/Tests/conf.json b/Tests/conf.json index cf25852046b4..f979650ee4ab 100644 --- a/Tests/conf.json +++ b/Tests/conf.json @@ -2233,6 +2233,11 @@ "instance_names": "ms_graph_security_client_cred_v2", "is_mockable": false }, + { + "integrations": "Microsoft Graph", + "playbookID": "MSG-Threat-Assessment-test", + "instance_names": "ms_graph_security_ediscovery" + }, { "integrations": "Microsoft Graph User", "playbookID": "Microsoft Graph User - Test", @@ -5791,7 +5796,8 @@ "Microsoft Defender Advanced Threat Protection - Test self deployed": "Issue CIAC-7527", "Microsoft Defender Advanced Threat Protection - Test": "Issue CIAC-7527", "OpsGenieV3TestPlaybook": "Issue CIAC-7649", - "ThreatStream-Test": "Issue CRTX-96526" + "ThreatStream-Test": "Issue CRTX-96526", + "MSG-Threat-Assessment-test": "API limitation" }, "skipped_integrations": { "CiscoWSAv2": "No instance - No license",