class DSTestConnectivityConnector(object):

    def __init__(self, connector):
        """
        :param connector: DigitalShadowsConnector
        """
        self._connector = connector
        self._handle_exception_object = ExceptionHandling()
        config = connector.get_config()
        self._ds_api_key = config[DS_API_KEY_CFG]
        self._ds_api_secret_key = config[DS_API_SECRET_KEY_CFG]

    def test_connectivity(self):
        self._connector.save_progress(DS_TEST_CONNECTIVITY_MSG.format(self._ds_api_key))

        try:
            ds_service = DSBaseService(self._ds_api_key, self._ds_api_secret_key)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(e)
            return self._connector.set_status(phantom.APP_ERROR, "{0} {1}".format(DS_TEST_CONNECTIVITY_MSG_FAIL, error_message))
        try:
            if ds_service.valid_credentials():
                return self._connector.set_status(phantom.APP_SUCCESS, DS_TEST_CONNECTIVITY_MSG_PASS)
            else:
                return self._connector.set_status(phantom.APP_ERROR, DS_TEST_CONNECTIVITY_MSG_FAIL)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(e)
            return self._connector.set_status(phantom.APP_ERROR, "{0}. {1}".format(DS_TEST_CONNECTIVITY_MSG_FAIL, error_message))
 def __init__(self, connector):
     """
     :param connector: DigitalShadowsConnector
     """
     self._connector = connector
     self._handle_exception_object = ExceptionHandling()
     config = connector.get_config()
     self._ds_api_key = config[DS_API_KEY_CFG]
     self._ds_api_secret_key = config[DS_API_SECRET_KEY_CFG]
Beispiel #3
0
 def __init__(self, connector):
     """
     :param connector: DigitalShadowsConnector
     """
     self._connector = connector
     self._handle_exception_object = ExceptionHandling()
     config = connector.get_config()
     self._ds_api_key = config[DS_API_KEY_CFG]
     self._ds_api_secret_key = config[DS_API_SECRET_KEY_CFG]
     self._poll_interval = config['ingest'].get('interval_mins')
     self._container_label = config['ingest']['container_label']
     self._history_days_interval = config['history_days_interval']
     self._global_incident = config.get('global_incident', False)
     self._private_incident = config.get('private_incident', False)
     self._inc_typ_data_leakage = config.get('inc_typ_data_leakage', False)
     self._inc_typ_brand_protection = config.get('inc_typ_brand_protection',
                                                 False)
     self._inc_typ_infrastructure = config.get('inc_typ_infrastructure',
                                               False)
     self._inc_typ_physical_security = config.get(
         'inc_typ_physical_security', False)
     self._inc_typ_social_media_compliance = config.get(
         'inc_typ_social_media_compliance', False)
     self._inc_typ_cyber_threat = config.get('inc_typ_cyber_threat', False)
Beispiel #4
0
class DSSearchEntitiesConnector(object):

    def __init__(self, connector):
        """
        :param connector: DigitalShadowsConnector
        """
        self._connector = connector

        config = connector.get_config()
        self._handle_exception_object = ExceptionHandling()
        self._ds_api_key = config[DS_API_KEY_CFG]
        self._ds_api_secret_key = config[DS_API_SECRET_KEY_CFG]

    def search_entities(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)

        self._connector.save_progress("process started...!!! ")

        # type = param.get('types').split(',')
        type = ["CLIENT_INCIDENT", "DATA_BREACH", "AGGREGATE_DATA_BREACH", "INTELLIGENCE", "TECHNICAL_SOURCE", "WEB_SOURCE"]
        date_range = param.get('date_range')
        query = param.get('query')
        """
        incident_types = param.get('incident_types')
        incident_subtypes = param.get('incident_subtypes')
        incident_severities = param.get('incident_severities')
        web_page_networks = param.get('web_page_networks')
        forum_post_networks = param.get('forum_post_networks')
        marketplace_listing_networks = param.get('marketplace_listing_networks')
        market_places = param.get('marketplaces')
        chat_protocols = param.get('chat_protocols')
        chat_servers = param.get('chat_servers')
        chat_channels = param.get('chat_channels')
        threat_level_types = param.get('threat_level_types')
        web_page_site_categories = param.get('web_page_site_categories')
        forum_post_site_categories = param.get('forum_post_site_categories')
        blog_names = param.get('blog_names')
        date_period = param.get('date_period')
        start_date = param.get('from')
        end_date = param.get('until')
        """

        try:
            search_service = SearchEntitiesService(self._ds_api_key, self._ds_api_secret_key)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(e)
            return action_result.set_status(phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG, error_message))

        try:
            search_view = search_service.search_entity_view(dateRange=date_range, query_string=query, types=type)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(e)
            return action_result.set_status(phantom.APP_ERROR, "Error Connecting to server. {0}".format(error_message))
        """
        search_view = search_service.search_entity_view(types=type, dateRange=date_range, incidentTypes=incident_types, incidentSubtypes=incident_subtypes,
                                                        incidentSeverities=incident_severities, webPageNetworks=web_page_networks,
                                                        forumPostNetworks=forum_post_networks, marketplaceListingNetworks=marketplace_listing_networks,
                                                        marketplaces=market_places, chatProtocols=chat_protocols, chatServers=chat_servers,
                                                        chatChannels=chat_channels, threatLevelTypes=threat_level_types,
                                                        webPageSiteCategories=web_page_site_categories, forumPostSiteCategories=forum_post_site_categories,
                                                        blogNames=blog_names, datePeriod=date_period, from_date=start_date,
                                                        until=end_date, query_string=query)
        """
        self._connector.save_progress("View: {}".format(search_view))
        try:
            search_entity_pages = search_service.find_all_pages(view=search_view)
            # self._connector.save_progress("entity: " + str(search_entity_pages))
            entity_total = len(search_entity_pages)
        except StopIteration:
            error_message = 'No Search Entity objects retrieved from the Digital Shadows API in page groups'
            return action_result.set_status(phantom.APP_ERROR, "Error Details: {0}".format(error_message))
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(e)
            return action_result.set_status(phantom.APP_ERROR, "Error Connecting to server. {}".format(error_message))
        if entity_total > 0:
            summary = {
                'entity_count': entity_total,
                'entity_found': True
            }
            action_result.update_summary(summary)
            for entity_page in search_entity_pages:
                for entity in entity_page:
                    # self._connector.save_progress("entity payload: " + str(entity.payload))
                    action_result.add_data(entity.payload)
            action_result.set_status(phantom.APP_SUCCESS, 'String search entities are fetched')
        else:
            summary = {
                'entity_count': 0,
                'entity_found': False
            }
            action_result.update_summary(summary)
            action_result.set_status(phantom.APP_SUCCESS, 'Entities not found for search string')
        return action_result.get_status()
Beispiel #5
0
class DSIntelligenceIncidentsConnector(object):
    def __init__(self, connector):
        """
        :param connector: DigitalShadowsConnector
        """
        self._connector = connector

        config = connector.get_config()
        self._handle_exception_object = ExceptionHandling()
        self._ds_api_key = config[DS_API_KEY_CFG]
        self._ds_api_secret_key = config[DS_API_SECRET_KEY_CFG]

    def get_intelligence_incident_by_id(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)
        try:
            intelligence_incident_service = IntelligenceIncidentService(
                self._ds_api_key, self._ds_api_secret_key)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG,
                                                    error_message))
        intel_incident_id = param['intel_incident_id']
        # validate 'intel_incident_id' action parameter
        ret_val, intel_incident_id = self._handle_exception_object.validate_integer(
            action_result, intel_incident_id, INTEL_INCIDENT_ID_KEY)
        if phantom.is_fail(ret_val):
            return action_result.get_status()
        try:
            intelligence_incident = intelligence_incident_service.find_intel_incident_by_id(
                intel_incident_id)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error Connecting to server. {0}".format(error_message))
        # intelligence_incident_total = len(intelligence_incident_pages)
        # if intelligence_incident_total > 0:
        if 'id' in intelligence_incident:
            summary = {
                'intelligence_incident_count': 1,
                'intelligence_incident_found': True
            }
            action_result.update_summary(summary)
            action_result.add_data(intelligence_incident)
            """
            for intelligence_incident_page in intelligence_incident_pages:
                for intelligence_incident in intelligence_incident_page:
                    data = {
                        'incident_id': intelligence_incident.id,
                        'type': intelligence_incident.payload['type'],
                        'severity': intelligence_incident.payload['severity'],
                        'title': intelligence_incident.payload['title'],
                        'summary': unidecode(intelligence_incident.payload['summary']),
                        'published': intelligence_incident.payload['published'],
                        'modified': intelligence_incident.payload['modified'],
                        'occurred': intelligence_incident.payload['occurred'],
                        'verified': intelligence_incident.payload['verified'],
                        'description': unidecode(intelligence_incident.payload['description']),
                        'entitysummary': {
                            'source': intelligence_incident.payload['entitySummary']['source'],
                            'summarytext': intelligence_incident.payload['entitySummary']['summarytext'] if 'summarytext' in intelligence_incident.payload['entitySummary'] else '',
                            'domain': intelligence_incident.payload['entitySummary']['domain'],
                            'sourceDate': intelligence_incident.payload['entitySummary']['sourceDate'],
                            'type': intelligence_incident.payload['entitySummary']['type']
                        }
                    }

                    action_result.add_data(data)
            """
            action_result.set_status(phantom.APP_SUCCESS,
                                     DS_GET_INTELLIGENCE_INCIDENT_SUCCESS)
        return action_result.get_status()

    def get_intel_incident_ioc_by_id(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)

        param_types = None if 'types' not in param else param.get(
            'types').split(',')

        try:
            intelligence_incident_service = IntelligenceIncidentService(
                self._ds_api_key, self._ds_api_secret_key)
            intelligence_incident_view = IntelligenceIncidentService.intelligence_incident_ioc_view(
                types=param_types)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG,
                                                    error_message))
        intel_incident_id = param['intel_incident_id']
        # validate 'intel_incident_id' action parameter
        ret_val, intel_incident_id = self._handle_exception_object.validate_integer(
            action_result, intel_incident_id, INTEL_INCIDENT_ID_KEY)
        if phantom.is_fail(ret_val):
            return action_result.get_status()

        try:
            intelligence_incident_ioc_pages = intelligence_incident_service.find_intel_incident_ioc_by_id(
                intel_incident_id=intel_incident_id,
                view=intelligence_incident_view)
            intelligence_incident_ioc_total = len(
                intelligence_incident_ioc_pages)
            self._connector.save_progress(
                "II IoC Total: {}".format(intelligence_incident_ioc_total))
        except StopIteration:
            error_message = 'No Incident review objects retrieved from the Digital Shadows API'
            return action_result.set_status(
                phantom.APP_ERROR, "Error Details: {0}".format(error_message))
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error Connecting to server. {}".format(error_message))
        if intelligence_incident_ioc_total > 0:
            summary = {
                'intelligence_incident_ioc_count':
                intelligence_incident_ioc_total,
                'intelligence_incident_ioc_found': True
            }
            action_result.update_summary(summary)

            for intelligence_incident_ioc_page in intelligence_incident_ioc_pages:
                for intelligence_incident_ioc in intelligence_incident_ioc_page:
                    self._connector.save_progress("loop id: {}".format(
                        intelligence_incident_ioc.payload))
                    action_result.add_data(intelligence_incident_ioc.payload)

            action_result.set_status(phantom.APP_SUCCESS,
                                     DS_GET_INTELLIGENCE_INCIDENT_SUCCESS)
        return action_result.get_status()

    def get_intelligence_incident(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)

        # interval_startdate = date.today() - timedelta(int(param['date_range']))
        date_ranges = param.get('date_range')
        incident_types = []
        if param.get('incident_types') is not None:
            param_incident_types = param.get('incident_types').split(',')

            for inc_type in param_incident_types:
                if inc_type == "DATA_LEAKAGE":
                    incident_types.append({
                        'type': 'DATA_LEAKAGE',
                        'subTypes': DS_DL_SUBTYPE
                    })
                if inc_type == "BRAND_PROTECTION":
                    incident_types.append({
                        'type': 'BRAND_PROTECTION',
                        'subTypes': DS_BP_SUBTYPE
                    })
                if inc_type == "INFRASTRUCTURE":
                    incident_types.append({
                        'type': 'INFRASTRUCTURE',
                        'subTypes': DS_INFR_SUBTYPE
                    })
                if inc_type == "PHYSICAL_SECURITY":
                    incident_types.append({
                        'type': 'PHYSICAL_SECURITY',
                        'subTypes': DS_PS_SUBTYPE
                    })
                if inc_type == "SOCIAL_MEDIA_COMPLIANCE":
                    incident_types.append({
                        'type': 'SOCIAL_MEDIA_COMPLIANCE',
                        'subTypes': DS_SMC_SUBTYPE
                    })
                if inc_type == "CYBER_THREAT":
                    incident_types.append({'type': 'CYBER_THREAT'})
        else:
            param_incident_types = None

        try:
            intelligence_incident_service = IntelligenceIncidentService(
                self._ds_api_key, self._ds_api_secret_key)
            intelligence_incident_view = IntelligenceIncidentService.intelligence_incidents_view(
                date_range=date_ranges,
                date_range_field='published',
                types=incident_types)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG,
                                                    error_message))
        try:
            intelligence_incident_pages = intelligence_incident_service.find_all_pages(
                view=intelligence_incident_view)
            intelligence_incident_total = len(intelligence_incident_pages)
        except StopIteration:
            error_message = 'No IntelligenceIncident objects retrieved from the Digital Shadows API in page groups'
            return action_result.set_status(
                phantom.APP_ERROR, "Error Details: {0}".format(error_message))
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error Connecting to server. {}".format(error_message))
        if intelligence_incident_total > 0:
            summary = {
                'intelligence_incident_count': intelligence_incident_total,
                'intelligence_incident_found': True
            }
            action_result.update_summary(summary)
            for intelligence_incident_page in intelligence_incident_pages:
                for intelligence_incident in intelligence_incident_page:
                    action_result.add_data(intelligence_incident.payload)

            action_result.set_status(phantom.APP_SUCCESS,
                                     DS_GET_INTELLIGENCE_INCIDENT_SUCCESS)
        return action_result.get_status()
class DSDataBreachConnector(object):
    def __init__(self, connector):
        """
        :param connector: DigitalShadowsConnector
        """
        self._connector = connector

        config = connector.get_config()
        self._handle_exception_object = ExceptionHandling()
        self._ds_api_key = config[DS_API_KEY_CFG]
        self._ds_api_secret_key = config[DS_API_SECRET_KEY_CFG]

    def get_data_breach_by_id(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)
        try:
            breach_service = DataBreachService(self._ds_api_key,
                                               self._ds_api_secret_key)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG,
                                                    error_message))

        breach_id = param['breach_id']
        # validate 'breach_id' action parameter
        ret_val, breach_id = self._handle_exception_object.validate_integer(
            action_result, breach_id, BREACH_ID_KEY)
        if phantom.is_fail(ret_val):
            return action_result.get_status()
        try:
            breach = breach_service.find_data_breach_by_id(breach_id)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error Connecting to server. {0}".format(error_message))

        if 'id' in breach:
            summary = {'data_breach_count': 1, 'data_breach_found': True}
            action_result.update_summary(summary)
            action_result.add_data(breach)
            action_result.set_status(phantom.APP_SUCCESS,
                                     DS_GET_BREACH_SUCCESS)
        else:
            summary = {'data_breach_count': 0, 'data_breach_found': False}
            action_result.update_summary(summary)
            action_result.set_status(phantom.APP_SUCCESS,
                                     DS_GET_BREACH_NOT_FOUND)
        return action_result.get_status()

    def get_data_breach(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)

        date_range = param['date_range']
        param_reposted_credentials = None if 'reposted_credentials' not in param else param[
            'reposted_credentials'].split(',')
        param_severities = None if 'severities' not in param else param.get(
            'severities').split(',')
        param_statuses = None if 'statuses' not in param else param.get(
            'statuses').split(',')
        param_user_name = None if 'user_name' not in param else param.get(
            'user_name').split(',')

        try:
            breach_service = DataBreachService(self._ds_api_key,
                                               self._ds_api_secret_key)
            breach_view = DataBreachService.data_breach_view(
                published=date_range,
                reposted_credentials=param_reposted_credentials,
                severities=param_severities,
                statuses=param_statuses,
                username=param_user_name)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG,
                                                    error_message))
        try:
            breach_pages = breach_service.find_all_pages(view=breach_view)
            breach_total = len(breach_pages)
        except StopIteration:
            error_message = 'No DataBreach objects retrieved from the Digital Shadows API in page groups'
            return action_result.set_status(
                phantom.APP_ERROR, "Error Details: {0}".format(error_message))
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error Connecting to server. {}".format(error_message))
        if breach_total > 0:
            summary = {
                'data_breach_count': breach_total,
                'data_breach_found': True
            }
            action_result.update_summary(summary)

            for breach_page in breach_pages:
                for breach in breach_page:
                    action_result.add_data(breach.payload)
            action_result.set_status(phantom.APP_SUCCESS,
                                     DS_GET_BREACH_SUCCESS)
        else:
            summary = {'data_breach_count': 0, 'data_breach_found': False}
            action_result.update_summary(summary)
            action_result.set_status(phantom.APP_SUCCESS,
                                     DS_GET_BREACH_NOT_FOUND)
        return action_result.get_status()

    def get_data_breach_record(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)

        date_range = param['date_range']
        if 'domain_names' in param:
            param_domain_names = param['domain_names'].split(',')
        else:
            param_domain_names = None

        if 'review_statuses' in param:
            param_review_statuses = param['review_statuses'].split(',')
        else:
            param_review_statuses = None

        param_distinction = param.get('distinction')
        param_user_name = param.get('user_name')
        param_password = param.get('password')

        try:
            breach_record_service = DataBreachRecordService(
                self._ds_api_key, self._ds_api_secret_key)
            breach_record_view = DataBreachRecordService.data_breach_records_view(
                published=date_range,
                domain_names=param_domain_names,
                username=param_user_name,
                password=param_password,
                review_statuses=param_review_statuses,
                distinction=param_distinction)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG,
                                                    error_message))
        self._connector.save_progress(str(breach_record_view))
        try:
            breach_record_pages = breach_record_service.read_all_records(
                view=breach_record_view)
            breach_record_total = len(breach_record_pages)
        except StopIteration:
            error_message = 'No DataBreach objects retrieved from the Digital Shadows API in page groups'
            return action_result.set_status(
                phantom.APP_ERROR, "Error Details: {0}".format(error_message))
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error Connecting to server. {}".format(error_message))
        if breach_record_total > 0:
            summary = {
                'data_breach_record_count': breach_record_total,
                'data_breach_record_found': True
            }
            action_result.update_summary(summary)
            for breach_record_page in breach_record_pages:
                for breach_record in breach_record_page:
                    action_result.add_data(breach_record.payload)
            action_result.set_status(
                phantom.APP_SUCCESS,
                "Digital Shadows data breach records fetched")
        else:
            summary = {
                'data_breach_record_count': 0,
                'data_breach_record_found': False
            }
            action_result.update_summary(summary)
            action_result.set_status(
                phantom.APP_SUCCESS,
                "Data breach record not found in Digital Shadows")
        return action_result.get_status()

    def get_data_breach_record_by_id(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)
        try:
            breach_record_service = DataBreachRecordService(
                self._ds_api_key, self._ds_api_secret_key)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG,
                                                    error_message))
        breach_id = param['breach_id']
        # validate 'breach_id' action parameter
        ret_val, breach_id = self._handle_exception_object.validate_integer(
            action_result, breach_id, BREACH_ID_KEY)
        if phantom.is_fail(ret_val):
            return action_result.get_status()
        try:
            breach_record_pages = breach_record_service.find_all_pages(
                breach_id)
            breach_record_total = len(breach_record_pages)
        except StopIteration:
            error_message = 'No data breach record retrieved from the Digital Shadows API in page groups'
            return action_result.set_status(
                phantom.APP_ERROR, "Error Details: {0}".format(error_message))
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error Connecting to server. {}".format(error_message))
        if breach_record_total > 0:
            summary = {
                'data_breach_record_count': breach_record_total,
                'data_breach_record_found': True
            }
            action_result.update_summary(summary)
            for breach_record_page in breach_record_pages:
                for breach_record in breach_record_page:
                    action_result.add_data(breach_record.payload)
            action_result.set_status(
                phantom.APP_SUCCESS,
                "Digital Shadows data breach records fetched")
        else:
            summary = {
                'data_breach_record_count': 0,
                'data_breach_record_found': False
            }
            action_result.update_summary(summary)
            action_result.set_status(
                phantom.APP_SUCCESS,
                "Data breach record not found in Digital Shadows")
        return action_result.get_status()

    def get_data_breach_record_by_username(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)

        try:
            breach_record_service = DataBreachRecordService(
                self._ds_api_key, self._ds_api_secret_key)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG,
                                                    error_message))

        user_name = param['user_name']
        domain_names_param = None if 'domain_names' not in param else param[
            'domain_names'].split(',')
        review_statuses_param = None if 'review_statuses' not in param else param[
            'review_statuses'].split(',')
        published_date_range = param.get('published_date_range', 'ALL')

        try:
            breach_record_view = DataBreachRecordService.data_breach_records_view(
                username=user_name,
                published=published_date_range,
                domain_names=domain_names_param,
                review_statuses=review_statuses_param)
            self._connector.save_progress(
                "Breach record View: {}".format(breach_record_view))
            breach_record_pages = breach_record_service.read_all_records(
                view=breach_record_view)
        except StopIteration:
            error_message = 'No DataBreach objects retrieved from the Digital Shadows API in page groups'
            return action_result.set_status(
                phantom.APP_ERROR, "Error Details: {0}".format(error_message))
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error Connecting to server. {}".format(error_message))

        breach_record_total = len(breach_record_pages)
        if breach_record_total > 0:
            summary = {
                'data_breach_record_count': breach_record_total,
                'data_breach_record_found': True
            }
            action_result.update_summary(summary)
            for breach_record_page in breach_record_pages:
                for breach_record in breach_record_page:
                    action_result.add_data(breach_record.payload)
            action_result.set_status(
                phantom.APP_SUCCESS,
                "Digital Shadows data breach records fetched")
        else:
            summary = {
                'data_breach_record_count': 0,
                'data_breach_record_found': False
            }
            action_result.update_summary(summary)
            action_result.set_status(
                phantom.APP_SUCCESS,
                "Data breach record not found in Digital Shadows")
        return action_result.get_status()

    def get_data_breach_record_reviews(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)
        try:
            breach_record_service = DataBreachRecordService(
                self._ds_api_key, self._ds_api_secret_key)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG,
                                                    error_message))
        breach_record_id = param['breach_record_id']
        # validate 'breach_record_id' action parameter
        ret_val, breach_record_id = self._handle_exception_object.validate_integer(
            action_result, breach_record_id, BREACH_RECORD_ID_KEY)
        if phantom.is_fail(ret_val):
            return action_result.get_status()
        try:
            breach_record_reviews = breach_record_service.find_data_breach_record_reviews(
                breach_record_id)
            breach_record_reviews_total = len(breach_record_reviews)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error Connecting to server. {0}".format(error_message))
        if breach_record_reviews_total > 0:
            summary = {
                'breach_record_reviews_count': breach_record_reviews_total,
                'breach_record_reviews_found': True
            }
            action_result.update_summary(summary)
            for breach_record_review in breach_record_reviews:
                action_result.add_data(breach_record_review)
            action_result.set_status(
                phantom.APP_SUCCESS,
                "Digital Shadows breach record reviews fetched for the Breach Record ID: {}"
                .format(breach_record_id))
        return action_result.get_status()

    def post_breach_record_review(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)
        try:
            breach_record_service = DataBreachRecordService(
                self._ds_api_key, self._ds_api_secret_key)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG,
                                                    error_message))
        post_data = {
            'note': param.get('review_note'),
            'status': param.get('review_status')
        }
        breach_record_id = param.get('breach_record_id')
        # validate 'breach_record_id' action parameter
        ret_val, breach_record_id = self._handle_exception_object.validate_integer(
            action_result, breach_record_id, BREACH_RECORD_ID_KEY)
        if phantom.is_fail(ret_val):
            return action_result.get_status()
        try:
            response = breach_record_service.post_data_breach_record_review(
                post_data, breach_record_id=breach_record_id)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error Connecting to server. {0}".format(error_message))
        summary = {
            'breach_record_reviews_status_code': response['status'],
            'breach_record_reviews_message': response['message']
        }
        action_result.update_summary(summary)
        if response['message'] == "SUCCESS":
            action_result.set_status(
                phantom.APP_SUCCESS,
                "Digital Shadows breach record review posted successfully")
        else:
            action_result.set_status(
                phantom.APP_SUCCESS,
                "Error in breach record review post request")
Beispiel #7
0
class DSOnPollConnector(object):
    def __init__(self, connector):
        """
        :param connector: DigitalShadowsConnector
        """
        self._connector = connector
        self._handle_exception_object = ExceptionHandling()
        config = connector.get_config()
        self._ds_api_key = config[DS_API_KEY_CFG]
        self._ds_api_secret_key = config[DS_API_SECRET_KEY_CFG]
        self._poll_interval = config['ingest'].get('interval_mins')
        self._container_label = config['ingest']['container_label']
        self._history_days_interval = config['history_days_interval']
        self._global_incident = config.get('global_incident', False)
        self._private_incident = config.get('private_incident', False)
        self._inc_typ_data_leakage = config.get('inc_typ_data_leakage', False)
        self._inc_typ_brand_protection = config.get('inc_typ_brand_protection',
                                                    False)
        self._inc_typ_infrastructure = config.get('inc_typ_infrastructure',
                                                  False)
        self._inc_typ_physical_security = config.get(
            'inc_typ_physical_security', False)
        self._inc_typ_social_media_compliance = config.get(
            'inc_typ_social_media_compliance', False)
        self._inc_typ_cyber_threat = config.get('inc_typ_cyber_threat', False)

    def on_poll(self, param):  # noqa

        self._connector.debug_print(param)
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)

        start_time, end_time = self._phantom_daterange(param)
        if start_time is None or end_time is None:
            action_result.set_status(
                phantom.APP_ERROR,
                status_message='start time or end time not specified')
        else:
            self._connector.save_progress("Start creating incident")
            # Validate 'history_days_interval' configuration parameter
            ret_val, self._history_days_interval = self._handle_exception_object.validate_integer(
                action_result, self._history_days_interval,
                HISTORY_DAYS_INTERVAL_KEY)
            if phantom.is_fail(ret_val):
                return action_result.get_status()
            date_range = "P{}D".format(self._history_days_interval)

            incident_types = []
            if self._inc_typ_data_leakage:
                incident_types.append({
                    'type': 'DATA_LEAKAGE',
                    'subTypes': DS_DL_SUBTYPE
                })
            if self._inc_typ_brand_protection:
                incident_types.append({
                    'type': 'BRAND_PROTECTION',
                    'subTypes': DS_BP_SUBTYPE
                })
            if self._inc_typ_infrastructure:
                incident_types.append({
                    'type': 'INFRASTRUCTURE',
                    'subTypes': DS_INFR_SUBTYPE
                })
            if self._inc_typ_physical_security:
                incident_types.append({
                    'type': 'PHYSICAL_SECURITY',
                    'subTypes': DS_PS_SUBTYPE
                })
            if self._inc_typ_social_media_compliance:
                incident_types.append({
                    'type': 'SOCIAL_MEDIA_COMPLIANCE',
                    'subTypes': DS_SMC_SUBTYPE
                })
            if self._inc_typ_cyber_threat:
                incident_types.append({'type': 'CYBER_THREAT'})

            if self._private_incident:
                try:
                    incident_service = IncidentService(self._ds_api_key,
                                                       self._ds_api_secret_key)

                    incident_view = IncidentService.incidents_view(
                        date_range=date_range,
                        date_range_field='published',
                        statuses=['READ', 'UNREAD'],
                        types=incident_types)
                    self._connector.save_progress(
                        "incident req view: {}".format(
                            json.dumps(incident_view, ensure_ascii=False)))
                except Exception as e:
                    error_message = self._handle_exception_object.get_error_message_from_exception(
                        e)
                    return action_result.set_status(
                        phantom.APP_ERROR,
                        "{0} {1}".format(SERVICE_ERR_MSG, error_message))

                try:
                    incident_pages = incident_service.find_all_pages(
                        view=incident_view)
                    j = 0
                    incident_total = len(incident_pages)
                except StopIteration:
                    error_message = 'No Incident objects retrieved from the Digital Shadows API in page groups'
                    return action_result.set_status(
                        phantom.APP_ERROR,
                        "Error Details: {0}".format(error_message))
                except Exception as e:
                    error_message = self._handle_exception_object.get_error_message_from_exception(
                        e)
                    return action_result.set_status(
                        phantom.APP_ERROR,
                        "Error Connecting to server. {}".format(error_message))
                for incident_page in incident_pages:
                    for incident in incident_page:
                        status, message = self._save_incident(incident)
                        if status == phantom.APP_SUCCESS:
                            j += 1
                            self._connector.save_progress(
                                DS_POLL_INCIDENT_COMPLETE.format(
                                    incident.id, j, incident_total))
                        else:
                            self._connector.error_print(
                                "Did not ingest incident {}".format(
                                    incident.id))
                            action_result.set_status(phantom.APP_ERROR,
                                                     message)
                            self._connector.add_action_result(action_result)
                            return action_result.get_status()
                self._connector.save_progress(
                    "Ingesting DS Incidents Completed.")

                if j != incident_total:
                    action_result.set_status(
                        phantom.APP_ERROR,
                        status_message=
                        'Did not receive all the incident from Digital Shadows'
                    )
                else:
                    action_result.set_status(phantom.APP_SUCCESS)

            if self._global_incident:
                try:
                    intelligence_incident_service = IntelligenceIncidentService(
                        self._ds_api_key, self._ds_api_secret_key)
                    intelligence_incident_view = IntelligenceIncidentService.intelligence_incidents_view(
                        date_range=date_range,
                        date_range_field='published',
                        types=incident_types)
                    self._connector.save_progress(
                        'intelligence_incident_view: {}'.format(
                            json.dumps(intelligence_incident_view,
                                       ensure_ascii=False)))
                except Exception as e:
                    error_message = self._handle_exception_object.get_error_message_from_exception(
                        e)
                    return action_result.set_status(
                        phantom.APP_ERROR,
                        "{0} {1}".format(SERVICE_ERR_MSG, error_message))

                try:
                    intelligence_incident_pages = intelligence_incident_service.find_all_pages(
                        view=intelligence_incident_view)
                    k = 0
                    intelligence_incident_total = len(
                        intelligence_incident_pages)
                except StopIteration:
                    error_message = 'No IntelligenceIncident objects retrieved from the Digital Shadows API in page groups'
                    return action_result.set_status(
                        phantom.APP_ERROR,
                        "Error Details: {0}".format(error_message))
                except Exception as e:
                    error_message = self._handle_exception_object.get_error_message_from_exception(
                        e)
                    return action_result.set_status(
                        phantom.APP_ERROR,
                        "Error Connecting to server. {}".format(error_message))

                for intelligence_incident_page in intelligence_incident_pages:
                    for intelligence_incident in intelligence_incident_page:
                        self._connector.save_progress('count: {}'.format(k))
                        status, message = self._save_intel_incident(
                            intelligence_incident)
                        if status == phantom.APP_SUCCESS:
                            k += 1
                            self._connector.save_progress(
                                DS_POLL_INCIDENT_COMPLETE.format(
                                    intelligence_incident.id, k,
                                    intelligence_incident_total))
                        else:
                            self._connector.error_print(
                                "Did not ingest intel-incident {}".format(
                                    intelligence_incident.id))
                            action_result.set_status(phantom.APP_ERROR,
                                                     message)
                            self._connector.add_action_result(action_result)
                            return action_result.get_status()

                if k != intelligence_incident_total:
                    action_result.set_status(
                        phantom.APP_ERROR,
                        status_message=
                        'Did not receive all the intelligence incident from Digital Shadows'
                    )
                else:
                    action_result.set_status(phantom.APP_SUCCESS)

                self._connector.save_progress(
                    "Ingesting DS Intelligence Incidents Completed.")
            """
            self._connector.save_progress("Ingesting Data Breaches from {} until {}".format(start_time, end_time))
            published_filter = '{}/{}'.format(start_time.isoformat(), end_time.isoformat())

            breach_service = DataBreachService(self._ds_api_key, self._ds_api_secret_key)

            view = DataBreachService.data_breach_view(published=published_filter)
            breach_pages = breach_service.find_all_pages(view=view)

            i = 0
            total = len(breach_pages)
            for breach_page in breach_pages:
                for breach in breach_page:
                    status, message = self._save_data_breach(breach)
                    if status == phantom.APP_SUCCESS:
                        i += 1
                        self._connector.save_progress(DS_POLL_BREACH_COMPLETE.format(breach.id, i, total))
                    else:
                        self._connector.error_print("Did not ingest Data Breach {}".format(breach.id))
                        action_result.set_status(phantom.APP_ERROR, message)
                        self._connector.add_action_result(action_result)
                        return action_result.get_status()

            if i != total:
                action_result.set_status(phantom.APP_ERROR,
                                         status_message='Did not receive all data breaches from Digital Shadows')
            else:
                action_result.set_status(phantom.APP_SUCCESS)
            """

        return action_result.get_status()

    def _phantom_daterange(self, param):
        """
        Extract Phantom start time and end time as datetime objects.
        Divide by 1000 to resolve milliseconds.

        :param param: dict
        :return: start_time, end_time
        """
        try:
            start_time_param = float(param.get('start_time'))
            end_time_param = float(param.get('end_time'))
        except TypeError:
            self._connector.error_print("start time or end time not specified")
            return None, None

        return datetime.fromtimestamp(
            start_time_param / 1000.0), datetime.fromtimestamp(end_time_param /
                                                               1000.0)

    def _save_data_breach(self, breach):

        container = self._prepare_container(breach)
        status, message, container_id = self._connector.save_container(
            container)

        if status == phantom.APP_SUCCESS:
            breach_record_service = DataBreachRecordService(
                self._ds_api_key, self._ds_api_secret_key)

            for breach_record_page in breach_record_service.find_all_pages(
                    breach.id):
                artifacts = list(
                    map(
                        lambda breach_record: self._prepare_artifact(
                            container_id, container['severity'], breach,
                            breach_record), breach_record_page))
                self._connector.save_artifacts(artifacts)

            return status, message
        else:
            return status, message

    def _save_intel_incident(self, intelligence_incident):
        container = self._prepare_intel_incident_container(
            intelligence_incident)
        status, message, container_id = self._connector.save_container(
            container)
        if status == phantom.APP_SUCCESS and message != 'Duplicate container found':
            intel_incident_artifacts = self._prepare_intel_incident_artifact(
                container_id, container['severity'], intelligence_incident)
            self._connector.save_artifact(intel_incident_artifacts)
            self._connector.save_progress(
                "Created the intelligence incident successfully")
            return status, message
        else:
            return status, message

    def _prepare_intel_incident_container(self, intelligence_incident):
        """
        Create a container from Digital Shadows incident.
        """
        # now = datetime.now()
        container = dict()
        # self._connector.save_progress(" print container: " + str(container))
        container['label'] = self._container_label
        container['name'] = '{} - {}'.format(
            intelligence_incident.payload['type'].title().replace('_', ' '),
            unidecode(intelligence_incident.payload['title']))
        intel_incident_desc = unidecode(intelligence_incident.payload['title'])
        # intel_incident_desc = intel_incident_desc.replace( u'\u201c', u'"').replace( u'\u201d', u'"')
        container['description'] = '{}'.format(intel_incident_desc)
        container['custom_fields'] = dict()
        container['custom_fields']['IncidentType'] = str(
            intelligence_incident.payload['type'])
        if 'subType' in intelligence_incident.payload:
            container['custom_fields']['IncidentSubType'] = str(
                intelligence_incident.payload['subType'])
        container['custom_fields'][
            'IncidentURL'] = 'https://portal-digitalshadows.com/client/intelligence/incident/{}'.format(
                intelligence_incident.payload['id'])
        container['severity'] = self._ds_to_phantom_severity_transform(
            intelligence_incident.payload['severity'])
        container['source_data_identifier'] = intelligence_incident.id
        container['start_time'] = intelligence_incident.payload['published']
        container['ingest_app_id'] = self._connector.get_app_id()
        return container

    def _prepare_intel_incident_artifact(self, container_id,
                                         container_severity,
                                         intelligence_incident):
        """
        Create an artifact from Digital Shadows Intelligence Incidents.

        :param container_id: int
        :param incident: DS Incident
        :return: dict
        """
        now = datetime.now()
        artifact = dict()
        artifact['container_id'] = container_id
        artifact['label'] = ' '
        artifact['name'] = 'Intelligence Incident details'
        artifact['description'] = 'Details provided by Digital Shadows'
        artifact['severity'] = container_severity
        artifact['type'] = ' '
        artifact['start_time'] = now.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
        artifact['source_data_identifier'] = intelligence_incident.id
        artifact['run_automation'] = False
        artifact['cef'] = dict()
        artifact['cef']['externalId'] = intelligence_incident.id
        artifact['cef'][
            'deviceAddress'] = 'https://portal-digitalshadows.com/client/intelligence/incident/{}'.format(
                intelligence_incident.id)
        artifact['cef']['   Title'] = intelligence_incident.payload['title']
        # artifact['cef']['   Type'] = intelligence_incident.payload['type'].title().replace('_', ' ')
        artifact['cef']['deviceEventCategory'] = intelligence_incident.payload[
            'type']
        if 'subType' in intelligence_incident.payload:
            # artifact['cef']['   SubType'] = intelligence_incident.payload['subType'].title().replace('_', ' ')
            artifact['cef']['deviceFacility'] = intelligence_incident.payload[
                'subType']
        artifact['cef']['  Description'] = intelligence_incident.payload[
            'description']
        # artifact['cef']['  Impact'] = intelligence_incident.payload['impactDescription']
        # artifact['cef']['  Mitigation'] = intelligence_incident.payload['mitigation']
        artifact['cef']['  Summary'] = dict()
        # artifact['cef']['  Summary'] = intelligence_incident.payload['entitySummary']
        if 'domain' in intelligence_incident.payload['entitySummary']:
            # artifact['cef']['  Summary']['domain'] = intelligence_incident.payload['entitySummary']['domain']
            artifact['cef']['deviceDnsDomain'] = intelligence_incident.payload[
                'entitySummary']['domain']
        if 'contentRemoved' in intelligence_incident.payload['entitySummary']:
            artifact['cef']['  Summary'][
                'contentRemoved'] = intelligence_incident.payload[
                    'entitySummary']['contentRemoved']
        if 'source' in intelligence_incident.payload['entitySummary']:
            artifact['cef']['  Summary'][
                'source'] = intelligence_incident.payload['entitySummary'][
                    'source']
        if 'sourceDate' in intelligence_incident.payload['entitySummary']:
            artifact['cef']['  Summary'][
                'sourceDate'] = intelligence_incident.payload['entitySummary'][
                    'sourceDate']
        if 'summaryText' in intelligence_incident.payload['entitySummary']:
            artifact['cef']['  Summary'][
                'summaryText'] = intelligence_incident.payload[
                    'entitySummary']['summaryText']
        if 'type' in intelligence_incident.payload['entitySummary']:
            # artifact['cef']['  Summary']['type'] = intelligence_incident.payload['entitySummary']['type']
            artifact['cef']['fileType'] = intelligence_incident.payload[
                'entitySummary']['type']

        if 'dataBreach' in intelligence_incident.payload['entitySummary']:
            # artifact['cef']['  Summary']['DataBreach ID'] = intelligence_incident.payload['entitySummary']['dataBreach']['id']
            artifact['cef'][
                'deviceExternalId'] = intelligence_incident.payload[
                    'entitySummary']['dataBreach']['id']
        artifact['cef'][' Internal'] = intelligence_incident.payload[
            'internal']
        artifact['cef'][' Restricted'] = intelligence_incident.payload[
            'restrictedContent']
        artifact['cef']['Dates'] = dict()
        if 'alerted' in intelligence_incident.payload:
            artifact['cef']['Dates'][
                'alerted'] = intelligence_incident.payload['alerted']
        artifact['cef']['Dates']['verified'] = intelligence_incident.payload[
            'verified']
        artifact['cef']['Dates']['occurred'] = intelligence_incident.payload[
            'occurred']
        artifact['cef']['Dates']['modified'] = intelligence_incident.payload[
            'modified']
        # artifact['cef']['Dates']['published'] = intelligence_incident.payload['published']
        artifact['cef']['deviceCustomeDate1'] = intelligence_incident.payload[
            'published']

        artifact['cef_types'] = dict()
        artifact['cef_types']['deviceAddress'] = ['url']

        return artifact

    def _save_incident(self, incident):
        container = self._prepare_incident_container(incident)
        status, message, container_id = self._connector.save_container(
            container)

        if status == phantom.APP_SUCCESS and message != 'Duplicate container found':
            incident_artifacts = self._prepare_incident_artifact(
                container_id, container['severity'], incident)
            self._connector.save_artifact(incident_artifacts)
            self._connector.save_progress("Created the incident successfully")
            return status, message
        else:
            return status, message

    def _prepare_incident_container(self, incident):
        """
        Create a container from Digital Shadows incident.
        """
        # now = datetime.now()
        container = dict()
        container['label'] = self._container_label
        container['name'] = '{} - {}'.format(
            incident.payload['type'].title().replace('_', ' '),
            unidecode(incident.payload['title']))
        incident_desc = unidecode(incident.payload['title'])
        container['description'] = '{}'.format(incident_desc)
        container['custom_fields'] = dict()
        container['custom_fields']['IncidentType'] = str(
            incident.payload['type'])
        if 'subType' in incident.payload:
            container['custom_fields']['IncidentSubType'] = str(
                incident.payload['subType'])
        container['custom_fields'][
            'IncidentURL'] = 'https://www.portal-digitalshadows.com/client/incidents/{}'.format(
                incident.payload['id'])
        container['severity'] = self._ds_to_phantom_severity_transform(
            incident.payload['severity'])
        container['source_data_identifier'] = incident.id
        container['start_time'] = incident.payload['published']
        container['ingest_app_id'] = self._connector.get_app_id()
        return container

    def _prepare_incident_artifact(self, container_id, container_severity,
                                   incident):
        """
        Create an artifact from Digital Shadows Incidents.

        :param container_id: int
        :param incident: DS Incident
        :return: dict
        """
        now = datetime.now()
        artifact = dict()
        artifact['container_id'] = container_id
        artifact['label'] = ' '
        artifact['name'] = 'Incident details'
        artifact['description'] = 'Details provided by Digital Shadows'
        artifact['severity'] = container_severity
        artifact['type'] = ' '
        artifact['start_time'] = now.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
        artifact['source_data_identifier'] = incident.id
        artifact['run_automation'] = False
        artifact['cef'] = dict()
        artifact['cef']['externalId'] = incident.id
        artifact['cef'][
            'deviceAddress'] = 'https://www.portal-digitalshadows.com/client/incidents/{}'.format(
                incident.payload['id'])
        artifact['cef']['   Title'] = incident.payload['title']
        # artifact['cef']['   Type'] = incident.payload['type'].title().replace('_', ' ')
        artifact['cef']['deviceEventCategory'] = incident.payload['type']
        if 'subType' in incident.payload:
            # artifact['cef']['  Sub Type'] = incident.payload['subType'].title().replace('_', ' ')
            artifact['cef']['deviceFacility'] = incident.payload['subType']
        artifact['cef']['  Description'] = incident.payload['description']
        artifact['cef']['  Impact'] = incident.payload['impactDescription']
        artifact['cef']['  Mitigation'] = incident.payload['mitigation']
        artifact['cef']['  Summary'] = dict()
        # artifact['cef']['  Summary'] = incident.payload['entitySummary']
        if 'domain' in incident.payload['entitySummary']:
            artifact['cef']['deviceDnsDomain'] = incident.payload[
                'entitySummary']['domain']
        if 'type' in incident.payload['entitySummary']:
            artifact['cef']['fileType'] = incident.payload['entitySummary'][
                'type']
        if 'contentRemoved' in incident.payload['entitySummary']:
            artifact['cef']['  Summary']['contentRemoved'] = incident.payload[
                'entitySummary']['contentRemoved']
        if 'source' in incident.payload['entitySummary']:
            artifact['cef']['  Summary']['source'] = incident.payload[
                'entitySummary']['source']
        if 'sourceDate' in incident.payload['entitySummary']:
            artifact['cef']['  Summary']['sourceDate'] = incident.payload[
                'entitySummary']['sourceDate']
        if 'summaryText' in incident.payload['entitySummary']:
            artifact['cef']['  Summary']['summaryText'] = incident.payload[
                'entitySummary']['summaryText']
        if 'type' in incident.payload['entitySummary']:
            artifact['cef']['fileType'] = incident.payload['entitySummary'][
                'type']

        if 'dataBreach' in incident.payload['entitySummary']:
            artifact['cef']['deviceExternalId'] = incident.payload[
                'entitySummary']['dataBreach']['id']

        if 'internal' in incident.payload:
            artifact['cef'][' Internal'] = incident.payload['internal']
        if 'restrictedContent' in incident.payload:
            artifact['cef'][' Restricted'] = incident.payload[
                'restrictedContent']
        artifact['cef']['Dates'] = dict()
        if 'alerted' in incident.payload:
            artifact['cef']['Dates']['alerted'] = incident.payload['alerted']
        if 'verified' in incident.payload:
            artifact['cef']['Dates']['verified'] = incident.payload['verified']
        if 'occurred' in incident.payload:
            artifact['cef']['Dates']['occurred'] = incident.payload['occurred']
        if 'modified' in incident.payload:
            artifact['cef']['Dates']['modified'] = incident.payload['modified']
        # artifact['cef']['Dates']['published'] = incident.payload['published']
        artifact['cef']['deviceCustomeDate1'] = incident.payload['published']

        artifact['cef_types'] = dict()
        artifact['cef_types']['deviceAddress'] = ['url']

        return artifact

    def _prepare_container(self, breach):
        """
        Create a container from Digital Shadows Data Breach.

        :param breach: DataBreach
        :return: dict
        """
        container = dict()
        container['label'] = self._container_label
        container['name'] = 'Digital Shadows Data Breach {}'.format(breach.id)
        container['description'] = '{}'.format(breach.incident_title)
        container['severity'] = self._ds_to_phantom_severity_transform(
            breach.incident_severity)
        container['source_data_identifier'] = breach.id
        container['start_time'] = breach.published
        container['ingest_app_id'] = self._connector.get_app_id()
        return container

    def _prepare_artifact(self, container_id, container_severity, breach,
                          breach_record):
        """
        Create an artifact from Digital Shadows Data Breach Record.

        :param container_id: int
        :param breach: DataBreach
        :param breach_record: DataBreachRecord
        :return: dict
        """
        source_host_name = urlparse(
            breach.source_url
        ).hostname if breach.source_url is not None else None
        link_to_incident = "{}/client/incidents/{}".format(
            ds_api_host, breach.incident_id)

        artifact = dict()
        artifact['container_id'] = container_id
        artifact['label'] = self._container_label
        artifact['name'] = 'Digital Shadows Data Breach Record {}'.format(
            breach_record.id)
        artifact['type'] = 'data breach record'
        artifact['severity'] = container_severity
        artifact['start_time'] = breach_record.published
        artifact['source_data_identifier'] = breach_record.id
        artifact['cef'] = {
            'suser': '******'.format(breach_record.username),
            'sourceHostName': '{}'.format(source_host_name),
            'cs1Label': 'Password',
            'cs1': '{}'.format(breach_record.password),
            'cs2Label': 'Source Url',
            'cs2': '{}'.format(breach.source_url),
            'cs3Label': 'Link to Incident',
            'cs3': link_to_incident,
            'cn1Label': 'Digital Shadows Incident Id',
            'cn1': '{}'.format(breach.incident_id)
        }
        return artifact

    def _ds_to_phantom_severity_transform(self, severity):
        """
        Map Digital Shadows severity to Phantom severity.

        :param severity: DS Severity: VERY_HIGH, HIGH, MEDIUM, LOW, VERY_LOW, NONE
        :return: Phantom Severity: high, medium, low
        """
        return {
            'VERY_HIGH': 'high',
            'HIGH': 'high',
            'MEDIUM': 'medium',
            'LOW': 'low',
            'VERY_LOW': 'low',
            'NONE': 'low'
        }.get(severity)
Beispiel #8
0
class DSIncidentsConnector(object):
    def __init__(self, connector):
        """
        :param connector: DigitalShadowsConnector
        """
        self._connector = connector

        config = connector.get_config()
        self._handle_exception_object = ExceptionHandling()
        self._ds_api_key = config[DS_API_KEY_CFG]
        self._ds_api_secret_key = config[DS_API_SECRET_KEY_CFG]

    def get_incident_by_id(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)

        try:
            incident_service = IncidentService(self._ds_api_key,
                                               self._ds_api_secret_key)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG,
                                                    error_message))
        incident_id = param['incident_id']
        # validate 'incident_id' action parameter
        ret_val, incident_id = self._handle_exception_object.validate_integer(
            action_result, incident_id, INCIDENT_ID_KEY)
        if phantom.is_fail(ret_val):
            return action_result.get_status()

        try:
            incident = incident_service.find_incident_by_id(incident_id)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error Connecting to server. {0}".format(error_message))
        if 'id' in incident:
            summary = {'incident_found': True}
            action_result.update_summary(summary)
            action_result.add_data(incident)
            action_result.set_status(phantom.APP_SUCCESS,
                                     DS_GET_INCIDENT_SUCCESS)

        return action_result.get_status()

    def get_incident_review_by_id(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)

        incident_id = param['incident_id']
        # validate 'incident_id' action parameter
        ret_val, incident_id = self._handle_exception_object.validate_integer(
            action_result, incident_id, INCIDENT_ID_KEY)
        if phantom.is_fail(ret_val):
            return action_result.get_status()

        try:
            incident_service = IncidentService(self._ds_api_key,
                                               self._ds_api_secret_key)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG,
                                                    error_message))
        try:
            incident_reviews = incident_service.find_all_reviews(incident_id)
            incident_reviews_total = len(incident_reviews)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error Connecting to server. {0}".format(error_message))
        if incident_reviews_total > 0:
            summary = {
                'incident_reviews_count': incident_reviews_total,
                'incident_reviews_found': True
            }
            action_result.update_summary(summary)
            for incident_review in incident_reviews:
                action_result.add_data(incident_review)
            action_result.set_status(
                phantom.APP_SUCCESS,
                "Digital Shadows incident reviews fetched for the Incident ID: {}"
                .format(incident_id))
        return action_result.get_status()

    def get_incident_list(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)

        # interval_startdate = date.today() - timedelta(int(param['date_range']))
        incident_types = []
        if param.get('incident_types') is not None:
            param_incident_types = str(param['incident_types']).split(',')
            for inc_type in param_incident_types:
                if inc_type == "DATA_LEAKAGE":
                    incident_types.append({
                        'type': 'DATA_LEAKAGE',
                        'subTypes': DS_DL_SUBTYPE
                    })
                if inc_type == "BRAND_PROTECTION":
                    incident_types.append({
                        'type': 'BRAND_PROTECTION',
                        'subTypes': DS_BP_SUBTYPE
                    })
                if inc_type == "INFRASTRUCTURE":
                    incident_types.append({
                        'type': 'INFRASTRUCTURE',
                        'subTypes': DS_INFR_SUBTYPE
                    })
                if inc_type == "PHYSICAL_SECURITY":
                    incident_types.append({
                        'type': 'PHYSICAL_SECURITY',
                        'subTypes': DS_PS_SUBTYPE
                    })
                if inc_type == "SOCIAL_MEDIA_COMPLIANCE":
                    incident_types.append({
                        'type': 'SOCIAL_MEDIA_COMPLIANCE',
                        'subTypes': DS_SMC_SUBTYPE
                    })
                if inc_type == "CYBER_THREAT":
                    incident_types.append({'type': 'CYBER_THREAT'})
        else:
            param_incident_types = None

        try:
            incident_service = IncidentService(self._ds_api_key,
                                               self._ds_api_secret_key)
            incident_view = IncidentService.incidents_view(
                date_range=param.get('date_range'),
                date_range_field='published',
                types=incident_types)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG,
                                                    error_message))
        self._connector.save_progress(
            "incident view: {}".format(incident_view))
        try:
            incident_pages = incident_service.find_all_pages(
                view=incident_view)
            self._connector.save_progress(
                "incident_pages next: {}".format(incident_pages))
            incident_total = len(incident_pages)
        except StopIteration:
            error_message = 'No Incident objects retrieved from the Digital Shadows API in page groups'
            return action_result.set_status(
                phantom.APP_ERROR, "Error Details: {0}".format(error_message))
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error Connecting to server. {0}".format(error_message))

        if incident_total > 0:
            summary = {
                'incident_count': incident_total,
                'incident_found': True
            }
            action_result.update_summary(summary)
            self._connector.save_progress(
                "incident_pages: {}".format(incident_pages))

            for incident_page in incident_pages:
                for incident in incident_page:
                    self._connector.save_progress('incident: {}'.format(
                        incident.payload))
                    action_result.add_data(incident.payload)

            action_result.set_status(phantom.APP_SUCCESS,
                                     DS_GET_INCIDENT_SUCCESS)
        return action_result.get_status()

    def post_incident_review(self, param):
        action_result = ActionResult(dict(param))
        self._connector.add_action_result(action_result)
        try:
            incident_service = IncidentService(self._ds_api_key,
                                               self._ds_api_secret_key)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR, "{0} {1}".format(SERVICE_ERR_MSG,
                                                    error_message))

        incident_id = param.get('incident_id')
        # validate 'incident_id' action parameter
        ret_val, incident_id = self._handle_exception_object.validate_integer(
            action_result, incident_id, INCIDENT_ID_KEY)
        if phantom.is_fail(ret_val):
            return action_result.get_status()
        post_data = {
            'note': param.get('review_note'),
            'status': param.get('review_status')
        }
        self._connector.save_progress("post_data: {}".format(post_data))
        try:
            response = incident_service.post_incident_review(
                post_data, incident_id=incident_id)
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error Connecting to server. {0}".format(error_message))
        self._connector.save_progress("response: {}".format(response))

        try:
            summary = {
                'incident_reviews_status_code': response['status'],
                'incident_reviews_message': response['message']
            }
            action_result.update_summary(summary)
            action_result.add_data(response['content'][0])
            if response['message'] == "SUCCESS":
                action_result.set_status(
                    phantom.APP_SUCCESS,
                    "Digital Shadows Incident review posted successfully")
            else:
                action_result.set_status(
                    phantom.APP_SUCCESS,
                    "Error in incident review post request")
        except Exception as e:
            error_message = self._handle_exception_object.get_error_message_from_exception(
                e)
            return action_result.set_status(
                phantom.APP_ERROR,
                "Error occurred while fetching data from response. {}".format(
                    error_message))

        return action_result.get_status()