Ejemplo n.º 1
0
def jira_req(method, resource_url, body='', link=False):
    url = resource_url if link else (BASE_URL + resource_url)
    result = requests.request(
        method=method,
        url=url,
        data=body,
        headers=HEADERS,
        verify=USE_SSL,
        params=OAUTH,
    )
    if not result.ok:
        demisto.debug(result.text)
        try:
            rj = result.json()
            if rj.get('errorMessages'):
                return_error(f'Status code: {result.status_code}\nMessage: {",".join(rj["errorMessages"])}')
            elif rj.get('errors'):
                return_error(f'Status code: {result.status_code}\nMessage: {",".join(rj["errors"].values())}')
            else:
                return_error(f'Status code: {result.status_code}\nError text: {result.text}')
        except ValueError as ve:
            demisto.debug(str(ve))
            if result.status_code == 401:
                return_error('Unauthorized request, please check authentication related parameters.')
            elif result.status_code == 404:
                return_error("Could not connect to the Jira server. Verify that the server URL is correct.")
            else:
                return_error(
                    f"Failed reaching the server. status code: {result.status_code}")

    return result
Ejemplo n.º 2
0
def http_request(method, url, params=None):
    """
    HTTP request helper function
    """
    if params is None:
        params = DEF_PARAMS
    else:
        params.update(DEF_PARAMS)
    res = requests.request(
        method=method,
        url=url,
        params=params,
        verify=VERIFY_CERTIFICATE
    )

    if not res.ok:
        demisto.debug(res.text)
        return_error('Could not execute the request')

    try:
        res_json = res.json()
        return res_json
    except Exception as ex:
        demisto.debug(str(ex))
        return_error(str(ex))
Ejemplo n.º 3
0
def add_entries_command():
    resource_id = demisto.args().get('resourceId')
    entries = demisto.args().get('entries')
    query_path = 'www/manager-service/services/ActiveListService/'
    if not isinstance(entries, dict):
        try:
            entries = json.loads(entries)
        except ValueError as ex:
            demisto.debug(str(ex))
            return_error('Entries must be in JSON format. Must be array of objects.')
        if not all([entry.keys() == entries[0].keys() for entry in entries[1:]]):
            return_error('All entries must have the same fields')

    columns = ''.join(COLUMN(column) for column in entries[0])  # the fields in the entryList matrix are the columns
    entry_list = BODY(columns + ''.join(ENTRY_LIST(''.join(ENTRY(v) for v in en.values())) for en in entries))
    body = REQ_SOAP_BODY(function='addEntries', auth_token=AUTH_TOKEN, resource_id=resource_id, entryList=entry_list)
    res = send_request(query_path, body=body)

    if not res.ok:
        demisto.debug(res.text)
        return_error("Failed to add entries. Please make sure to enter Active List resource ID"
                     "\nResource ID: {}\nStatus Code: {}\nRequest Body: {}\nResponse: {}".format(resource_id,
                                                                                                 res.status_code, body,
                                                                                                 res.text))

    demisto.results("Success")
Ejemplo n.º 4
0
def login():
    query_path = 'www/core-service/rest/LoginService/login'
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Accept': 'application/json'
    }
    params = {
        'login': demisto.get(demisto.params(), 'credentials.identifier'),
        'password': demisto.get(demisto.params(), 'credentials.password'),
        'alt': 'json'
    }
    res = send_request(query_path, headers=headers, params=params, is_login=True)
    if not res.ok:
        demisto.debug(res.text)
        return_error('Failed to login, check integration parameters.')

    try:
        res_json = res.json()
        if 'log.loginResponse' in res_json and 'log.return' in res_json.get('log.loginResponse'):
            auth_token = res_json.get('log.loginResponse').get('log.return')
            if demisto.command() not in ['test-module', 'fetch-incidents']:
                # this is done to bypass setting integration context outside of the cli
                demisto.setIntegrationContext({'auth_token': auth_token})
            return auth_token

        return_error('Failed to login. Have not received token after login')
    except ValueError:
        return_error('Failed to login. Please check integration parameters')
Ejemplo n.º 5
0
def send_request(query_path, body=None, params=None, json=None, headers=None, method='post', is_login=False):
    if headers is None:
        headers = HEADERS
    full_url = BASE_URL + query_path
    try:
        res = requests.request(
            method,
            full_url,
            headers=headers,
            verify=VERIFY_CERTIFICATE,
            data=body,
            params=params,
            json=json
        )

        if not res.ok and not is_login:
            if params and not body:
                params['authToken'] = login()
            else:
                body = body.replace(demisto.getIntegrationContext().get('auth_token'), login())
            return requests.request(
                method,
                full_url,
                headers=headers,
                verify=VERIFY_CERTIFICATE,
                data=body,
                params=params,
                json=json
            )
        return res

    except Exception as ex:
        demisto.debug(str(ex))
        return_error('Connection Error. Please check integration parameters')
Ejemplo n.º 6
0
def fetch_incidents():
    last_run = demisto.getLastRun()
    # Get the last fetch time, if exists
    last_fetch = last_run.get('time')

    # Handle first time fetch, fetch incidents retroactively
    if last_fetch is None:
        last_fetch, _ = parse_date_range(FETCH_TIME, date_format='%Y-%m-%dT%H:%M:%S')

    latest = datetime.strptime(last_fetch, '%Y-%m-%dT%H:%M:%S')

    demisto.debug('getting alarms since {}'.format(last_fetch))
    incidents = []
    items = list_alerts(time_frame='Custom', start_time=last_fetch)
    demisto.debug('got {} new alarms'.format(len(items)))
    for item in items:
        incident_date = datetime.strptime(item['ALERT_TIME'], '%Y-%m-%d %H:%M:%S')
        incident = {
            'Type': 'Fidelis',
            'name': '{} {}'.format(item['ALERT_ID'], item['SUMMARY']),
            'occurred': incident_date.strftime('%Y-%m-%dT%H:%M:%SZ'),
            'rawJSON': json.dumps(item),
        }
        latest = max(latest, incident_date)
        incidents.append(incident)

    if latest != last_fetch:
        last_fetch = (latest + timedelta(seconds=1)).strftime('%Y-%m-%dT%H:%M:%S')
        demisto.setLastRun({'time': last_fetch})

    demisto.incidents(incidents)
Ejemplo n.º 7
0
def update_case(case_id, stage, severity):
    # get the case from arcsight
    case = get_case(case_id)
    case['stage'] = stage
    case['consequenceSeverity'] = severity if severity else case['consequenceSeverity']

    # update its stage and send it back to arcsight
    query_path = 'www/manager-service/rest/CaseService/update'
    params = {
        'alt': 'json'
    }
    json_ = {
        "cas.update": {
            "cas.authToken": AUTH_TOKEN,
            "cas.resource": case,
        }
    }
    res = send_request(query_path, json=json_, params=params)

    if not res.ok:
        demisto.debug(res.text)
        return_error('Failed to get security update case {}. \nPlease make sure user have edit permissions,'
                     ' or case is unlocked. \nStatus Code: {}\nResponse Body: {}'.format(case_id, res.status_code,
                                                                                         res.text))

    res_json = res.json()
    if 'cas.updateResponse' in res_json and 'cas.return' in res_json.get('cas.updateResponse'):
        return case

    return_error('Failed to update case, fail to parse response. Response Body: {}'.format(res.text))
Ejemplo n.º 8
0
def get_case(resource_id, fetch_base_events=False):
    query_path = 'www/manager-service/rest/CaseService/getResourceById'
    params = {
        'authToken': AUTH_TOKEN,
        'resourceId': resource_id,
    }
    res = send_request(query_path, params=params, method='get')

    if not res.ok:
        demisto.debug(res.text)
        if 'InvalidResourceIDException: Invalid resource ID' in res.text and 'for Case' in res.text:
            return_error('Invalid resource ID {} for Case'.format(resource_id))
        else:
            return_error('Failed to get case. StatusCode: {}'.format(res.status_code))

    res_json = res.json()
    if 'cas.getResourceByIdResponse' in res_json and 'cas.return' in res_json.get('cas.getResourceByIdResponse'):
        case = res_json.get('cas.getResourceByIdResponse').get('cas.return')

        if case.get('eventIDs') and not isinstance(case['eventIDs'], list):
            # if eventIDs is single id then convert to list
            case['eventIDs'] = [case['eventIDs']]

        if case.get('eventIDs') and fetch_base_events:
            case['events'] = decode_arcsight_output(get_security_events(case['eventIDs'], ignore_empty=True),
                                                    remove_nones=False)

        return case

    return_error('Case {} not found'.format(resource_id))
Ejemplo n.º 9
0
def delete_case_command():
    case_id = demisto.args().get('caseId')

    query_path = 'www/manager-service/rest/CaseService/deleteByUUID'
    req_body = json.dumps({
        'cas.deleteByUUID': {
            'cas.authToken': AUTH_TOKEN,
            'cas.id': case_id
        }
    })
    params = {
        'alt': 'json'
    }
    res = send_request(query_path, params=params, body=req_body)
    if not res.ok:
        demisto.debug(res.text)
        return_error("Failed to delete case.\nStatus Code: {}\nResponse: {}".format(res.status_code, res.text))

    entry_context = {
        'resourceid': case_id,
        'deleted': 'True'
    }
    contents = 'Case {}  was deleted successfully'.format(case_id)
    human_readable = 'Case {} successfully deleted'.format(case_id)
    outputs = {'ArcSightESM.Cases(val.resourceid===obj.resourceid)': entry_context}
    return_outputs(readable_output=human_readable, outputs=outputs, raw_response=contents)
Ejemplo n.º 10
0
def get_case_event_ids_command():
    case_id = demisto.args().get('caseId')
    with_correlated_events = demisto.args().get('withCorrelatedEvents') == 'true'
    query_path = 'www/manager-service/rest/CaseService/getCaseEventIDs'
    params = {
        'authToken': AUTH_TOKEN,
        'caseId': case_id
    }

    res = send_request(query_path, params=params, method='get')
    if not res.ok:
        demisto.debug(res.text)
        return_error("Failed to get Event IDs with:\nStatus Code: {}\nResponse: {}".format(res.status_code, res.text))

    res_json = res.json()
    if 'cas.getCaseEventIDsResponse' in res_json and 'cas.return' in res_json.get('cas.getCaseEventIDsResponse'):
        event_ids = res_json.get('cas.getCaseEventIDsResponse').get('cas.return')
        if not isinstance(event_ids, list):
            event_ids = [event_ids]

        if with_correlated_events:
            event_ids = get_correlated_events_ids(event_ids)

        contents = decode_arcsight_output(res_json)
        human_readable = tableToMarkdown(name='', headers='Case {} Event IDs'.format(case_id), t=event_ids,
                                         removeNull=True)
        outputs = {'ArcSightESM.CaseEvents': event_ids}
        return_outputs(readable_output=human_readable, outputs=outputs, raw_response=contents)
    else:
        demisto.results('No result returned')
Ejemplo n.º 11
0
def http_request(method, url_suffix, params=None, body=None, do_not_refresh_token=False):
    """
    Generic request to Microsoft Graph
    """
    token = get_token()
    response = requests.request(
        method,
        BASE_URL + url_suffix,
        headers={
            'Authorization': 'Bearer ' + token,
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        },
        params=params,
        data=body,
        verify=USE_SSL,
    )
    try:
        data = response.json() if response.text else {}
        if not response.ok:
            if demisto.get(data, "error.message") == 'InvalidAuthenticationToken' and not do_not_refresh_token:
                get_token(refresh_token=True)  # try refreshing the token only once (avoid endless loop)
                return http_request(method, url_suffix, params, body, do_not_refresh_token=True)
            return_error(f'API call to MS Graph failed [{response.status_code}] - {demisto.get(data, "error.message")}')
        elif response.status_code == 206:  # 206 indicates Partial Content, reason will be in the warning header
            demisto.debug(str(response.headers))

        return data

    except TypeError as ex:
        demisto.debug(str(ex))
        return_error(f'Error in API call to Microsoft Graph, could not parse result [{response.status_code}]')
Ejemplo n.º 12
0
def get_all_query_viewers_command():
    query_path = 'www/manager-service/rest/QueryViewerService/findAllIds'
    params = {
        'authToken': AUTH_TOKEN,
        'alt': 'json'
    }
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Accept': 'application/json'
    }
    res = send_request(query_path, headers=headers, params=params)
    if not res.ok:
        demisto.debug(res.text)
        return_error("Failed to get query viewers:\nStatus Code: {}\nResponse: {}".format(res.status_code, res.text))

    res_json = res.json()
    if 'qvs.findAllIdsResponse' in res_json and 'qvs.return' in res_json.get('qvs.findAllIdsResponse'):
        query_viewers = res_json.get('qvs.findAllIdsResponse').get('qvs.return')

        contents = decode_arcsight_output(query_viewers)
        outputs = {'ArcSightESM.AllQueryViewers': contents}
        human_readable = tableToMarkdown(name='', t=query_viewers, headers='Query Viewers', removeNull=True)
        return_outputs(readable_output=human_readable, outputs=outputs, raw_response=contents)

    else:
        demisto.results('No Query Viewers were found')
Ejemplo n.º 13
0
def rasterize():
    global return_code, error_message
    return_code = 0
    error_message = ''
    url = demisto.args()['url']
    if not (url.startswith("http")):
        url = "http://" + url
    friendly_name = 'url.png'
    if demisto.get(demisto.args(), 'type') == 'pdf':
        friendly_name = 'url.pdf'
    proxy_flag = ""
    if proxy:
        if url.startswith("https"):
            proxy_flag = "--proxy=" + https_proxy
        else:
            proxy_flag = "--proxy=" + http_proxy
    demisto.debug('rasterize proxy settings: ' + proxy_flag)
    command = ['phantomjs', proxy_flag, '/usr/local/bin/rasterize.js', url, friendly_name]
    if demisto.get(demisto.args(), 'width') and demisto.get(demisto.args(), 'height'):
        command.append(demisto.get(demisto.args(), 'width') + '*' + demisto.get(demisto.args(), 'height'))
    try:
        error_message = subprocess.check_output(command)
    except subprocess.CalledProcessError:
        return_code = -1
        error_message = "Can't access the URL. It might be malicious, or unreachable for one of several reasons."
    if return_code == 0:
        file = file_result_existing_file(friendly_name)
        file['Type'] = entryTypes['image']
        demisto.results(file)
    else:
        demisto.results({'ContentsFormat': 'text', 'Type': entryTypes['error'],
                         'Contents': 'PhantomJS returned - ' + error_message})
Ejemplo n.º 14
0
def extract_text(image_path: str, languages: List[str] = None) -> str:
    exe_params = [TESSERACT_EXE, image_path, 'stdout']
    if languages:
        exe_params.extend(['-l', '+'.join(languages)])
    res = subprocess.run(exe_params, capture_output=True, check=True, text=True)
    if res.stderr:
        demisto.debug('tesseract returned ok but stderr contains warnings: {}'.format(res.stderr))
    return res.stdout
Ejemplo n.º 15
0
def get_entries_command():
    resource_id = demisto.args().get('resourceId')
    entry_filter = demisto.args().get('entryFilter')

    query_path = 'www/manager-service/services/ActiveListService/'
    body = REQ_SOAP_BODY(function='getEntries', auth_token=AUTH_TOKEN, resource_id=resource_id, entryList=None)

    res = send_request(query_path, body=body)

    if not res.ok:
        demisto.debug(res.text)
        return_error("Failed to get entries:\nResource ID: {}\nStatus Code: {}\nRequest Body: {}\nResponse: {}".format(
            resource_id, res.status_code, body, res.text))

    res_json = json.loads(xml2json(res.text))
    raw_entries = demisto.get(res_json, 'Envelope.Body.getEntriesResponse.return')

    # retrieve columns
    cols = demisto.get(raw_entries, 'columns')
    if cols:
        hr_columns = tableToMarkdown(name='', headers=['Columns'], t=cols,
                                     removeNull=True) if cols else 'Active list has no columns'
        contents = cols
        return_outputs(readable_output=hr_columns, outputs={}, raw_response=contents)

    if 'entryList' in raw_entries:
        entry_list = raw_entries['entryList'] if isinstance(raw_entries['entryList'], list) else [
            raw_entries['entryList']]
        entry_list = [d['entry'] for d in entry_list if 'entry' in d]
        keys = raw_entries.get('columns')
        entries = [dict(zip(keys, values)) for values in entry_list]

        # if the user wants only entries that contain certain 'field:value' sets (filters)
        # e.g., "name:myName,eventId:0,:ValueInUnknownField"
        # if the key is empty, search in every key
        filtered = entries
        if entry_filter:
            for f in entry_filter.split(','):
                k, v = f.split(':')
                filtered = [entry for entry in filtered if ((entry.get(k) == v) if k else (v in entry.values()))]

        contents = decode_arcsight_output(filtered)
        ActiveListContext = {
            'ResourceID': resource_id,
            'Entries': contents,
        }
        outputs = {
            'ArcSightESM.ActiveList.{id}'.format(id=resource_id): contents,
            'ArcSightESM.ActiveList(val.ResourceID===obj.ResourceID)': ActiveListContext
        }
        human_readable = tableToMarkdown(name='Active List entries: {}'.format(resource_id), t=filtered,
                                         removeNull=True)
        return_outputs(readable_output=human_readable, outputs=outputs, raw_response=contents)

    else:
        demisto.results('Active List has no entries')
Ejemplo n.º 16
0
def parse_timestamp_to_datestring(timestamp):
    if timestamp and timestamp > 0:
        try:
            return datetime.fromtimestamp(timestamp / 1000.0).strftime("%Y-%m-%dT%H:%M:%S.000Z")
        except (ValueError, TypeError) as e:
            demisto.debug(str(e))
            if timestamp == '31 Dec 1969 19:00:00 EST':
                # Unix epoch 00:00:00 UTC
                return 'None'
            return timestamp
Ejemplo n.º 17
0
def clear_entries_command():
    resource_id = demisto.args().get('resourceId')
    query_path = 'www/manager-service/services/ActiveListService/'
    body = REQ_SOAP_BODY(function='clearEntries', auth_token=AUTH_TOKEN, resource_id=resource_id, entryList=None)
    res = send_request(query_path, body=body)

    if not res.ok:
        demisto.debug(res.text)
        return_error(
            "Failed to clear entries.\nResource ID: {}\nStatus Code: {}\nRequest Body: {}\nResponse: {}".format(
                resource_id, res.status_code, body, res.text))

    demisto.results("Success")
Ejemplo n.º 18
0
def get_command_examples(entry_id):
    commands = []  # type: list
    errors = []  # type: list
    if entry_id is None:
        return commands, errors

    if re.match(r'[\d]+@[0-9a-fA-F]+', entry_id) is not None:
        examples_path = demisto.getFilePath(entry_id)['path']
        with open(examples_path, 'r') as examples_file:
            commands = examples_file.read().split('\n')
    else:
        demisto.debug('failed to open command file, tried parsing as free text')
        commands = entry_id.split('\n')

    return commands, errors
Ejemplo n.º 19
0
def test_module():
    try:
        res = requests.request('GET', SERVER + 'ping', params=DEF_PARAMS, verify=VERIFY_CERTIFICATE)
        if not res.ok:
            try:
                res_json = res.json()
                return_error('Could not connect, reason: {}'.format(res_json.get('message')))

            except Exception as ex:
                demisto.debug(str(ex))
                return_error('Could not parse server response, please verify instance parameters')
        demisto.results('ok')
    except Exception as ex:
        demisto.debug(str(ex))
        return_error('Failed to establish new connection, please verify instance parameters')
Ejemplo n.º 20
0
def get_all_cases_command():
    query_path = 'www/manager-service/rest/CaseService/findAllIds'
    params = {
        'authToken': AUTH_TOKEN,
        'alt': 'json'
    }
    res = send_request(query_path, params=params, method='get')

    if not res.ok:
        demisto.debug(res.text)
        return_error('Failed to get case list. StatusCode: {}'.format(res.status_code))

    contents = res.json().get('cas.findAllIdsResponse').get('cas.return')
    human_readable = tableToMarkdown(name='All cases', headers='caseID', t=contents, removeNull=True)
    outputs = {'ArcSightESM.AllCaseIDs': contents}
    return_outputs(readable_output=human_readable, outputs=outputs, raw_response=contents)
Ejemplo n.º 21
0
def fetch_incidents(query, id_offset=None, fetch_by_created=None, **_):
    last_run = demisto.getLastRun()
    demisto.debug(f"last_run: {last_run}" if last_run else 'last_run is empty')
    id_offset = last_run.get("idOffset") if (last_run and last_run.get("idOffset")) else id_offset

    incidents, max_results = [], 50
    if id_offset:
        query = f'{query} AND id >= {id_offset}'
    if fetch_by_created:
        query = f'{query} AND created>-1m'
    res = run_query(query, '', max_results)
    for ticket in res.get('issues'):
        id_offset = max(id_offset, ticket.get("id"))
        incidents.append(create_incident_from_ticket(ticket))

    demisto.setLastRun({"idOffset": id_offset})
    demisto.incidents(incidents)
Ejemplo n.º 22
0
def extract_text_command() -> dict:
    langs = argToList(demisto.getArg('langs')) or argToList(demisto.getParam('langs'))
    demisto.debug("Using langs settings: {}".format(langs))
    entry_id = demisto.args()['entryid']
    file_path = demisto.getFilePath(entry_id)
    if not file_path:
        return_error("Couldn't find entry id: {}".format(entry_id))
    demisto.debug('Extracting text from file: {}'.format(file_path))
    res = extract_text(file_path['path'], langs)
    file_entry = {'EntryID': entry_id, 'Text': res}
    return {
        'Type': entryTypes['note'],
        'Contents': res,
        'ContentsFormat': formats['text'],
        'ReadableContentsFormat': formats['markdown'],
        'HumanReadable': "## Image OCR Extracted Text\n\n" + res,
        "EntryContext": {"File(val.EntryID == obj.EntryID)": file_entry},
    }
Ejemplo n.º 23
0
def get_query_viewer_results_command():
    resource_id = demisto.args().get('id')
    only_columns = demisto.args().get('onlyColumns')
    columns, query_results = get_query_viewer_results(query_viewer_id=resource_id)

    demisto.debug('printing Query Viewer column headers')
    demisto.results({
        'Type': entryTypes['note'],
        'ContentsFormat': formats['json'],
        'Contents': columns,
        'HumanReadable': tableToMarkdown(name='', headers='Column Headers', t=columns, removeNull=True)
    })
    if only_columns == 'false':
        demisto.debug('printing Query Viewer results')

        contents = query_results
        human_readable = tableToMarkdown(name='Query Viewer Results: {}'.format(resource_id), t=contents,
                                         removeNull=True)
        outputs = {'ArcSightESM.QueryViewerResults': contents}
        return_outputs(readable_output=human_readable, outputs=outputs, raw_response=contents)
Ejemplo n.º 24
0
def rasterize_email_request(html, friendly_name):
    global return_code, error_message

    f = open('htmlBody.html', 'w')
    f.write('<html style="background:white";>' + html + '</html>')
    f.close()

    proxy_flag = ""
    if proxy:
        proxy_flag = "--proxy=" + http_proxy
    demisto.debug('rasterize proxy settings: ' + proxy_flag)

    command = ['phantomjs', proxy_flag, '/usr/local/bin/rasterize.js', 'htmlBody.html', friendly_name]
    if demisto.get(demisto.args(), 'width') and demisto.get(demisto.args(), 'height'):
        command.append(demisto.get(demisto.args(), 'width') + '*' + demisto.get(demisto.args(), 'height'))
    try:
        error_message = subprocess.check_output(command)
    except Exception as e:
        return_code = -1
        error_message = e.message
Ejemplo n.º 25
0
def run_query(query, start_at='', max_results=None):
    # EXAMPLE
    """
    request = {
        "jql": "project = HSP",
        "startAt": 0,
        "maxResults": 15,
        "fields": [    <-- not supported yet, but easily attainable
            "summary",
            "status",
            "assignee"
        ]
    }
    """
    demisto.debug(f'querying with: {query}')
    url = BASE_URL + 'rest/api/latest/search/'
    query_params = {
        'jql': query,
        "startAt": start_at,
        "maxResults": max_results,
    }
    if OAUTH:
        query_params.update(OAUTH)  # type: ignore

    result = requests.get(
        url=url,
        headers=HEADERS,
        verify=USE_SSL,
        params=query_params
    )
    try:
        rj = result.json()
        if rj.get('issues'):
            return rj

        errors = ",".join(rj.get("errorMessages", ['could not fetch any issues, please check your query']))
        return_error(f'No issues were found, error message from Jira: {errors}')

    except ValueError as ve:
        demisto.debug(str(ve))
        return_error(f'Failed to send request, reason: {result.reason}')
Ejemplo n.º 26
0
def initialize_server(host, port, secure_connection, unsecure):
    """
    uses the instance configuration to initialize the LDAP server

    :param host: host or ip
    :type host: string
    :param port: port or None
    :type port: number
    :param secure_connection: SSL or None
    :type secure_connection: string
    :param unsecure: trust any cert
    :type unsecure: boolean
    :return: ldap3 Server
    :rtype: Server
    """

    if secure_connection == "SSL":
        # intialize server with ssl
        # port is configured by default as 389 or as 636 for LDAPS if not specified in configuration
        demisto.debug("initializing sever with ssl (unsecure: {}). port: {}". format(unsecure, port or 'default(636)'))
        if not unsecure:
            demisto.debug("will require server certificate.")
            tls = Tls(validate=ssl.CERT_REQUIRED)
            if port:
                return Server(host, port=port, use_ssl=True, tls=tls)
            return Server(host, use_ssl=True, tls=tls)
        if port:
            return Server(host, port=port, use_ssl=True)
        return Server(host, use_ssl=True)
    demisto.debug("initializing server without secure connection. port: {}". format(port or 'default(389)'))
    if port:
        return Server(host, port=port)
    return Server(host)
Ejemplo n.º 27
0
def decode_ip(address_by_bytes):
    """ Decodes the enigmatic ways IPs are stored in ArcSight DB into IPv4/6 format """
    if isinstance(address_by_bytes, int):
        return int_to_ip(address_by_bytes)

    try:
        # if it's not an int, it should be Base64 encoded string
        decoded_string = base64.b64decode(address_by_bytes).encode('hex')
        if len(address_by_bytes) >= 20:
            # split the IPv6 address into 8 chunks of 4
            decoded_string = [decoded_string[i:i + 4] for i in range(0, len(decoded_string), 4)]  # type: ignore
            return "{}:{}:{}:{}:{}:{}:{}:{}".format(*decoded_string)
        elif len(address_by_bytes) >= 6:
            decoded_string = int(decoded_string, 16)  # type: ignore
            return int_to_ip(decoded_string)
        else:
            return address_by_bytes

    except Exception as ex:
        # sometimes ArcSight would not encode IPs, this will cause the decoder to
        # throw an exception, and in turn, we will return the input in its original form.
        demisto.debug(str(ex))
        return address_by_bytes
Ejemplo n.º 28
0
def get_security_events(event_ids, last_date_range=None, ignore_empty=False):
    start_time, end_time = -1, -1
    if last_date_range:
        # Must of format 'number date_range_unit'
        # Examples: (2 hours, 4 minutes, 6 month, 1 day, etc.)
        start_time, end_time = parse_date_range(last_date_range, to_timestamp=True)

    query_path = 'www/manager-service/rest/SecurityEventService/getSecurityEvents'
    params = {
        'alt': 'json'
    }
    json_ = {
        "sev.getSecurityEvents": {
            "sev.authToken": AUTH_TOKEN,
            "sev.ids": event_ids,
            "sev.startMillis": start_time,
            "sev.endMillis": end_time
        }
    }
    res = send_request(query_path, json=json_, params=params)

    if not res.ok:
        demisto.debug(res.text)
        return_error(
            'Failed to get security events with ids {}.\nFull URL: {}\nStatus Code: {}\nResponse Body: {}'.format(
                event_ids, BASE_URL + query_path, res.status_code, res.text))

    res_json = res.json()
    if res_json.get('sev.getSecurityEventsResponse') and res_json.get('sev.getSecurityEventsResponse').get(
            'sev.return'):
        events = res_json.get('sev.getSecurityEventsResponse').get('sev.return')
        return events if isinstance(events, list) else [events]

    demisto.debug(res.text)
    if not ignore_empty:
        demisto.results('No events were found')
Ejemplo n.º 29
0
def test_function():
    token = get_token()
    response = requests.get(
        BASE_URL + 'users',
        headers={
            'Authorization': 'Bearer ' + token,
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        },
        params={'$select': 'displayName'},
        verify=USE_SSL
    )
    try:
        data = response.json() if response.text else {}
        if not response.ok:
            return_error(f'API call to MS Graph failed. Please check authentication related parameters.'
                         f' [{response.status_code}] - {demisto.get(data, "error.message")}')

        demisto.results('ok')

    except TypeError as ex:
        demisto.debug(str(ex))
        return_error(f'API call to MS Graph failed, could not parse result. '
                     f'Please check authentication related parameters. [{response.status_code}]')
Ejemplo n.º 30
0
def get_remote_data_command(client, args):
    """
    get-remote-data command: Returns an updated remote incident.
    Args:
        client: The client object.
        args:
            id: incident id to retrieve.
            lastUpdate: when was the last time we retrieved data.

    Returns:
        GetRemoteDataResponse object, which contain the incident data to update.
    """
    remote_args = GetRemoteDataArgs(args)
    demisto.debug(
        'Performing get-remote-data command with incident id: {} and last_update: {}'
        .format(remote_args.remote_incident_id, remote_args.last_update))

    incident_data = {}
    try:
        incident_data = client.get_incident_by_id(
            remote_args.remote_incident_id)
        delta = {
            field: incident_data.get(field)
            for field in INCOMING_MIRRORED_FIELDS if incident_data.get(field)
        }

        last_update_date = dateparser.parse(remote_args.last_update,
                                            settings={'TIMEZONE': 'UTC'})
        assert last_update_date is not None, f'could not parse {remote_args.last_update}'
        if not delta or date_to_timestamp(incident_data.get('updated_at'), '%Y-%m-%dT%H:%M:%S.%fZ') \
                <= int(last_update_date.timestamp()):
            demisto.debug("Nothing new in the incident.")
            delta = {
                'id': remote_args.remote_incident_id,
                'in_mirror_error': ""
            }

            return GetRemoteDataResponse(mirrored_object=delta, entries=[])

        entries = []

        state = delta and delta.get('state')
        if state and state.lower() == 'closed':
            if demisto.params().get('close_incident'):

                demisto.debug(
                    f'Incident is closed: {remote_args.remote_incident_id}')
                entries.append({
                    'Type': EntryType.NOTE,
                    'Contents': {
                        'dbotIncidentClose':
                        True,
                        'closeReason':
                        f'From SaasSecurity: {delta.get("category")}'
                    },
                    'ContentsFormat': EntryFormat.JSON
                })

        demisto.debug(
            f"Update incident {remote_args.remote_incident_id} with fields: {delta}"
        )
        return GetRemoteDataResponse(mirrored_object=delta, entries=entries)

    except Exception as e:
        demisto.debug(
            f"Error in Saas Security incoming mirror for incident {remote_args.remote_incident_id} \n"
            f"Error message: {str(e)}")

        if incident_data:
            incident_data['in_mirror_error'] = str(e)

        else:
            incident_data = {
                'id': remote_args.remote_incident_id,
                'in_mirror_error': str(e)
            }

        return GetRemoteDataResponse(mirrored_object=incident_data, entries=[])
Ejemplo n.º 31
0
def get_incidents_batch_by_time_request(params):
    """Perform an API request to get incidents from ProofPoint in batches to prevent a timeout.

    As the api does not return the results in an specific order, we query the api on specific time frames using
    created_before and created_after using the fetch delta parameter.
    Args:
        params(dict): The params of the request

    Returns:
        list. The incidents returned from the API call
    """
    incidents_list = []  # type:list

    fetch_delta = params.get('fetch_delta', '6 hours')
    fetch_limit = int(params.get('fetch_limit', '50'))
    last_fetched_id = int(params.get('last_fetched_id', '0'))

    current_time = datetime.now()

    time_delta = get_time_delta(fetch_delta)

    created_after = datetime.strptime(params.get('created_after'), TIME_FORMAT)
    created_before = created_after + time_delta

    request_params = {
        'state': params.get('state'),
        'created_after': created_after.isoformat().split('.')[0] + 'Z',
        'created_before': created_before.isoformat().split('.')[0] + 'Z'
    }

    # while loop relevant for fetching old incidents
    while created_before < current_time and len(incidents_list) < fetch_limit:
        demisto.debug(
            "Entered the batch loop , with fetch_limit {} and incidents list {} and incident length {} "
            "with created_after {} and created_before {}.".format(
                str(fetch_limit), str([incident.get('id') for incident in incidents_list]), str(len(incidents_list)),
                str(request_params['created_after']), str(request_params['created_before'])))

        new_incidents = get_new_incidents(request_params, last_fetched_id)
        incidents_list.extend(new_incidents)

        # advancing fetch time by given fetch delta time
        created_after = created_before
        created_before = created_before + time_delta

        # updating params according to the new times
        request_params['created_after'] = created_after.isoformat().split('.')[0] + 'Z'
        request_params['created_before'] = created_before.isoformat().split('.')[0] + 'Z'
        demisto.debug("End of the current batch loop with {} incidents".format(str(len(incidents_list))))

    # fetching the last batch when created_before is bigger then current time = fetching new incidents
    if len(incidents_list) < fetch_limit:
        # fetching the last batch
        request_params['created_before'] = current_time.isoformat().split('.')[0] + 'Z'
        new_incidents = get_new_incidents(request_params, last_fetched_id)
        incidents_list.extend(new_incidents)

        demisto.debug(
            "Finished the last batch, with fetch_limit {} and incidents list {} and incident length {}".format(
                str(fetch_limit), str([incident.get('id') for incident in incidents_list]), str(len(incidents_list))))

    incidents_list_limit = incidents_list[:fetch_limit]
    return incidents_list_limit
Ejemplo n.º 32
0
 def _get_refresh_token_from_auth_code_param(self) -> str:
     refresh_prefix = "refresh_token:"
     if self.auth_code.startswith(refresh_prefix):  # for testing we allow setting the refresh token directly
         demisto.debug("Using refresh token set as auth_code")
         return self.auth_code[len(refresh_prefix):]
     return ''
Ejemplo n.º 33
0
def get_issue_fields(issue_creating=False, **issue_args):
    """
    refactor issues's argument as received from demisto into jira acceptable format, and back.
    :param issue_creating: flag that indicates this function is called when creating an issue
    :param issue_args: issue argument
    """
    issue = {}  # type: dict
    if 'issueJson' in issue_args:
        try:
            issue = json.loads(issue_args['issueJson'])
        except TypeError as te:
            demisto.debug(str(te))
            return_error("issueJson must be in a valid json format")

    if not issue.get('fields'):
        issue['fields'] = {}

    if not issue['fields'].get('issuetype') and issue_creating:
        issue['fields']['issuetype'] = {}

    if issue_args.get('summary'):
        issue['fields']['summary'] = issue_args['summary']

    if not issue['fields'].get('project') and (issue_args.get('projectKey') or
                                               issue_args.get('projectName')):
        issue['fields']['project'] = {}

    if issue_args.get('projectKey'):
        issue['fields']['project']['key'] = issue_args.get('projectKey', '')
    if issue_args.get('projectName'):
        issue['fields']['project']['name'] = issue_args.get('projectName', '')

    if issue_creating:
        # make sure the key & name are right, and get the corresponding project id & key
        project_id = get_project_id(issue['fields']['project'].get('key', ''),
                                    issue['fields']['project'].get('name', ''))
        issue['fields']['project']['id'] = project_id

    if issue_args.get('issueTypeName'):
        issue['fields']['issuetype']['name'] = issue_args['issueTypeName']

    if issue_args.get('issueTypeId'):
        issue['fields']['issuetype']['id'] = issue_args['issueTypeId']

    if issue_args.get('parentIssueId'):
        if not issue['fields'].get('parent'):
            issue['fields']['parent'] = {}
        issue['fields']['parent']['id'] = issue_args['parentIssueId']

    if issue_args.get('parentIssueKey'):
        if not issue['fields'].get('parent'):
            issue['fields']['parent'] = {}
        issue['fields']['parent']['key'] = issue_args['parentIssueKey']

    if issue_args.get('description'):
        issue['fields']['description'] = issue_args['description']

    if issue_args.get('labels'):
        issue['fields']['labels'] = issue_args['labels'].split(",")

    if issue_args.get('priority'):
        if not issue['fields'].get('priority'):
            issue['fields']['priority'] = {}
        issue['fields']['priority']['name'] = issue_args['priority']

    if issue_args.get('duedate'):
        issue['fields']['duedate'] = issue_args['duedate']

    if issue_args.get('assignee'):
        if not issue['fields'].get('assignee'):
            issue['fields']['assignee'] = {}
        issue['fields']['assignee']['name'] = issue_args['assignee']

    if issue_args.get('reporter'):
        if not issue['fields'].get('reporter'):
            issue['fields']['reporter'] = {}
        issue['fields']['reporter']['name'] = issue_args['reporter']

    return issue
Ejemplo n.º 34
0
def main() -> None:
    try:
        params = demisto.params()
        base_url = urljoin(params['url'], '/api')
        if not params.get('credentials') or not (api_token := params.get(
                'credentials', {}).get('password')):
            raise DemistoException(
                'Missing API Key. Fill in a valid key in the integration configuration.'
            )
        verify_certificate = not params.get('insecure', False)
        proxy = params.get('proxy', False)
        command = demisto.command()
        args = demisto.args() if demisto.args() else {}
        demisto.debug(f'Command being called is {command}')

        client = Client(base_url=base_url,
                        use_ssl=verify_certificate,
                        use_proxy=proxy,
                        apitoken=api_token)
        commands: Dict[str, Callable] = {
            'cb-edr-processes-search': processes_search_command,
            'cb-edr-process-get': process_get_command,
            'cb-edr-process-segments-get': process_segments_get_command,
            'cb-edr-process-events-list': process_events_list_command,
            'cb-edr-binary-search': binary_search_command,
            'cb-edr-binary-download': binary_download_command,
            'cb-edr-binary-summary': binary_summary_command,
            'cb-edr-alert-search': alert_search_command,
            'cb-edr-alert-update': alert_update_command,
            'cb-edr-binary-bans-list': binary_bans_list_command,
            'cb-edr-binary-ban': binary_ban_command,
            'cb-edr-watchlists-list': get_watchlist_list_command,
            'cb-edr-watchlist-create': watchlist_create_command,
            'cb-edr-watchlist-update': watchlist_update_command,
            'cb-edr-watchlist-delete': watchlist_delete_command,
            'cb-edr-sensors-list': sensors_list_command,
            'cb-edr-quarantine-device': quarantine_device_command,
            'cb-edr-unquarantine-device': unquarantine_device_command,
            'cb-edr-sensor-installer-download':
            sensor_installer_download_command,
            'endpoint': endpoint_command
        }

        if command == 'test-module':
            result = test_module(client, params)
            return_results(result)

        elif command == 'fetch-incidents':

            next_run, incidents = fetch_incidents(
                client=client,
                max_results=params.get('max_fetch'),
                last_run=demisto.getLastRun(),
                first_fetch_time=params.get('first_fetch', '3 days'),
                status=params.get('alert_status', None),
                feedname=params.get('alert_feed_name', None),
                query=params.get('alert_query', None))
            demisto.setLastRun(next_run)
            demisto.incidents(incidents)

        elif command in commands:
            return_results(commands[command](client, **args))
        else:
            raise NotImplementedError(
                f'command {command} was not implemented in this integration.')
Ejemplo n.º 35
0
def fetch_incidents(client: Client,
                    max_results: int,
                    last_run: dict,
                    first_fetch_time: str,
                    status: str = None,
                    feedname: str = None,
                    query: str = None):
    if (status or feedname) and query:
        raise Exception(
            f'{INTEGRATION_NAME} - Search is not permitted with both query and filter parameters.'
        )

    max_results = arg_to_number(arg=max_results,
                                arg_name='max_fetch',
                                required=False) if max_results else 50

    # How much time before the first fetch to retrieve incidents
    first_fetch_time = dateparser.parse(first_fetch_time)
    first_fetch_timestamp_ms = int(
        first_fetch_time.timestamp()) if first_fetch_time else None
    last_fetch = last_run.get('last_fetch', None)
    # Handle first fetch time
    if last_fetch is None:
        last_fetch = first_fetch_timestamp_ms
    else:
        last_fetch = int(last_fetch)

    latest_created_time = last_fetch

    incidents: List[Dict[str, Any]] = []

    # multiple statuses are not supported by api. If status provided, gets the incidents for each status.
    # Otherwise will run without status.
    alerts = []
    if status:
        for current_status in argToList(status):
            res = client.get_alerts(status=current_status, feedname=feedname)
            alerts += res.get('results', [])
    else:
        res = client.get_alerts(feedname=feedname, query=query)
        alerts += res.get('results', [])

    for alert in alerts[:max_results]:
        incident_created_time = dateparser.parse(alert.get('created_time'))
        incident_created_time_ms = int(incident_created_time.timestamp()
                                       ) if incident_created_time else '0'

        # to prevent duplicates, adding incidents with creation_time > last fetched incident
        if last_fetch:
            if incident_created_time_ms <= last_fetch:
                continue

        alert_id = alert.get('unique_id', '')
        alert_name = alert.get('process_name', '')
        incident_name = f'{INTEGRATION_NAME}: {alert_id} {alert_name}'
        if not alert_id or not alert_name:
            demisto.debug(f'Alert details are missing. {str(alert)}')

        incident = {
            'name': incident_name,
            'occurred': timestamp_to_datestring(incident_created_time_ms),
            'rawJSON': json.dumps(alert),
        }

        incidents.append(incident)

        # Update last run and add incident if the incident is newer than last fetch
        if incident_created_time_ms > latest_created_time:
            latest_created_time = incident_created_time_ms

    demisto.debug(
        f'Fetched {len(alerts)} alerts. Saving {len(incidents)} as incidents.')
    # Save the next_run as a dict with the last_fetch key to be stored
    next_run = {'last_fetch': latest_created_time}
    return next_run, incidents
 async def set_access_token(self, refresh_token: 'RefreshToken') -> None:
     await refresh_token.set_access_token(self)
     demisto.debug('Set access token successfully')
Ejemplo n.º 37
0
def update_remote_system_command(client: Client, args: Dict[str, Any],
                                 mirror_tags: Set[str]) -> str:
    """update-remote-system command: pushes local changes to the remote system

    :type client: ``Client``
    :param client: XSOAR client to use

    :type args: ``Dict[str, Any]``
    :param args:
        all command arguments, usually passed from ``demisto.args()``.
        ``args['data']`` the data to send to the remote system
        ``args['entries']`` the entries to send to the remote system
        ``args['incidentChanged']`` boolean telling us if the local incident indeed changed or not
        ``args['remoteId']`` the remote incident id

    :type mirror_tags: ``Optional[str]``
    :param mirror_tags:
        The tag that you will mirror out of the incident.

    :return:
        ``str`` containing the remote incident id - really important if the incident is newly created remotely

    :rtype: ``str``
    """
    parsed_args = UpdateRemoteSystemArgs(args)
    if parsed_args.delta:
        demisto.debug(
            f'Got the following delta keys {str(list(parsed_args.delta.keys()))}'
        )

    demisto.debug(
        f'Sending incident with remote ID [{parsed_args.remote_incident_id}] to remote system\n'
    )

    new_incident_id: str = parsed_args.remote_incident_id  # type: ignore
    updated_incident = {}
    if not parsed_args.remote_incident_id or parsed_args.incident_changed:
        if parsed_args.remote_incident_id:
            # First, get the incident as we need the version
            old_incident = client.get_incident(
                incident_id=parsed_args.remote_incident_id)
            for changed_key in parsed_args.delta.keys():
                old_incident[changed_key] = parsed_args.delta[
                    changed_key]  # type: ignore

            parsed_args.data = old_incident

        else:
            parsed_args.data['createInvestigation'] = True
            # This is used to identify the custom field, so that we will know the source of the incident
            # and will not mirror it in afterwards
            parsed_args.data['CustomFields'] = {'frompong': 'true'}

        updated_incident = client.update_incident(incident=parsed_args.data)
        new_incident_id = updated_incident['id']
        demisto.debug(f'Got back ID [{new_incident_id}]')

    else:
        demisto.debug(
            f'Skipping updating remote incident fields [{parsed_args.remote_incident_id}] as it is '
            f'not new nor changed.')

    if parsed_args.entries:
        for entry in parsed_args.entries:
            demisto.info(f"this is the tag {entry.get('tags', [])}")
            if mirror_tags.intersection(set(entry.get('tags', []))):
                demisto.debug(f'Sending entry {entry.get("id")}')
                client.add_incident_entry(incident_id=new_incident_id,
                                          entry=entry)

    # Close incident if relevant
    if updated_incident and parsed_args.inc_status == IncidentStatus.DONE:
        demisto.debug(f'Closing remote incident {new_incident_id}')
        client.close_incident(
            new_incident_id,
            updated_incident.get('version'),  # type: ignore
            parsed_args.data.get('closeReason'),
            parsed_args.data.get('closeNotes'))

    return new_incident_id
Ejemplo n.º 38
0
def url_command():
    url = demisto.args().get('url')
    try:
        url_information = query_url_information(url).json()

        ec = {
            'URL': {
                'Data': url
            },
            'DBotScore': {
                'Type': 'url',
                'Vendor': 'URLhaus',
                'Indicator': url
            }
        }

        if url_information['query_status'] == 'ok':
            # URLhaus output
            blacklist_information = []
            blacklists = url_information.get('blacklists', {})
            for bl_name, bl_status in blacklists.items():
                blacklist_information.append({
                    'Name': bl_name,
                    'Status': bl_status
                })

            date_added = reformat_date(url_information.get('date_added'))
            urlhaus_data = {
                'ID': url_information.get('id', ''),
                'Status': url_information.get('url_status', ''),
                'Host': url_information.get('host', ''),
                'DateAdded': date_added,
                'Threat': url_information.get('threat', ''),
                'Blacklist': blacklist_information,
                'Tags': url_information.get('tags', [])
            }

            payloads = []
            for payload in url_information.get('payloads', []):
                vt_data = payload.get('virustotal', None)
                vt_information = None
                if vt_data:
                    vt_information = {
                        'Result': float(vt_data.get('percent', 0)),
                        'Link': vt_data.get('link', '')
                    }
                payloads.append({
                    'Name': payload.get('filename', 'unknown'),
                    'Type': payload.get('file_type', ''),
                    'MD5': payload.get('response_md5', ''),
                    'VT': vt_information
                })

            urlhaus_data['Payload'] = payloads

            # DBot score calculation
            dbot_score, description = calculate_dbot_score(
                url_information.get('blacklists', {}), THRESHOLD,
                COMPROMISED_IS_MALICIOUS)

            ec['DBotScore']['Score'] = dbot_score
            if dbot_score == 3:
                ec['URL']['Malicious'] = {
                    'Vendor': 'URLhaus',
                    'Description': description
                }

            ec['URLhaus.URL(val.ID && val.ID === obj.ID)'] = urlhaus_data

            human_readable = tableToMarkdown(
                f'URLhaus reputation for {url}', {
                    'URLhaus link':
                    url_information.get("urlhaus_reference", "None"),
                    'Description':
                    description,
                    'URLhaus ID':
                    urlhaus_data['ID'],
                    'Status':
                    urlhaus_data['Status'],
                    'Threat':
                    url_information.get("threat", ""),
                    'Date added':
                    date_added
                })
            demisto.results({
                'Type': entryTypes['note'],
                'ContentsFormat': formats['json'],
                'Contents': url_information,
                'HumanReadable': human_readable,
                'HumanReadableFormat': formats['markdown'],
                'EntryContext': ec
            })
        elif url_information['query_status'] == 'no_results':
            ec['DBotScore']['Score'] = 0

            human_readable = f'## URLhaus reputation for {url}\n' \
                f'No results!'

            demisto.results({
                'Type': entryTypes['note'],
                'ContentsFormat': formats['json'],
                'Contents': url_information,
                'HumanReadable': human_readable,
                'HumanReadableFormat': formats['markdown'],
                'EntryContext': ec
            })
        elif url_information['query_status'] == 'invalid_url':
            human_readable = f'## URLhaus reputation for {url}\n' \
                f'Invalid URL!'

            demisto.results({
                'Type': entryTypes['note'],
                'ContentsFormat': formats['json'],
                'Contents': url_information,
                'HumanReadable': human_readable,
                'HumanReadableFormat': formats['markdown'],
                'EntryContext': ec
            })
        else:
            demisto.results({
                'Type':
                entryTypes['error'],
                'ContentsFormat':
                formats['text'],
                'Contents':
                f'Query results = {url_information["query_status"]}'
            })

    except Exception:
        demisto.debug(traceback.format_exc())
        return_error(
            'Failed getting url data, please verify the arguments and parameters'
        )
Ejemplo n.º 39
0
def domain_command():
    domain = demisto.args()['domain']

    try:
        domain_information = query_host_information(domain).json()

        ec = {
            'Domain': {
                'Name': domain
            },
            'DBotScore': {
                'Type': 'domain',
                'Vendor': 'URLhaus',
                'Indicator': domain
            }
        }

        if domain_information['query_status'] == 'ok':
            # URLHaus output
            blacklist_information = []
            blacklists = domain_information.get('blacklists', {})
            for bl_name, bl_status in blacklists.items():
                blacklist_information.append({
                    'Name': bl_name,
                    'Status': bl_status
                })

            first_seen = reformat_date(domain_information.get('firstseen'))

            urlhaus_data = {
                'FirstSeen': first_seen,
                'Blacklist': blacklists,
                'URL': domain_information.get('urls', [])
            }

            # DBot score calculation
            dbot_score, description = calculate_dbot_score(
                domain_information.get('blacklists', {}), THRESHOLD,
                COMPROMISED_IS_MALICIOUS)

            ec['DBotScore']['Score'] = dbot_score
            if dbot_score == 3:
                ec['domain']['Malicious'] = {
                    'Vendor': 'URLhaus',
                    'Description': description
                }

            ec['URLhaus.Domain(val.Name && val.Name === obj.Name)'] = urlhaus_data

            human_readable = tableToMarkdown(
                f'URLhaus reputation for {domain}', {
                    'URLhaus link':
                    domain_information.get('urlhaus_reference', 'None'),
                    'Description':
                    description,
                    'First seen':
                    first_seen,
                })
            demisto.results({
                'Type': entryTypes['note'],
                'ContentsFormat': formats['json'],
                'Contents': domain_information,
                'HumanReadable': human_readable,
                'HumanReadableFormat': formats['markdown'],
                'EntryContext': ec
            })
        elif domain_information['query_status'] == 'no_results':
            ec['DBotScore']['Score'] = 0

            human_readable = f'## URLhaus reputation for {domain}\n' \
                f'No results!'

            demisto.results({
                'Type': entryTypes['note'],
                'ContentsFormat': formats['json'],
                'Contents': domain_information,
                'HumanReadable': human_readable,
                'HumanReadableFormat': formats['markdown'],
                'EntryContext': ec
            })
        elif domain_information['query_status'] == 'invalid_host':
            human_readable = f'## URLhaus reputation for {domain}\n' \
                f'Invalid domain!'

            demisto.results({
                'Type': entryTypes['note'],
                'ContentsFormat': formats['json'],
                'Contents': domain_information,
                'HumanReadable': human_readable,
                'HumanReadableFormat': formats['markdown'],
                'EntryContext': ec
            })
        else:
            demisto.results({
                'Type':
                entryTypes['error'],
                'ContentsFormat':
                formats['text'],
                'Contents':
                f'Query results = {domain_information["query_status"]}'
            })

    except Exception:
        demisto.debug(traceback.format_exc())
        return_error(
            'Failed getting domain data, please verify the arguments and parameters'
        )
Ejemplo n.º 40
0
def file_command():
    hash = demisto.args()['file']
    if len(hash) == 32:
        hash_type = 'md5'
    elif len(hash) == 64:
        hash_type = 'sha256'
    else:
        return_error(
            'Only accepting MD5 (32 bytes) or SHA256 (64 bytes) hash types')

    try:
        file_information = query_payload_information(hash_type, hash).json()

        if file_information['query_status'] == 'ok' and file_information[
                'md5_hash']:
            # URLhaus output
            first_seen = reformat_date(file_information.get('firstseen'))
            last_seen = reformat_date(file_information.get('lastseen'))

            urlhaus_data = {
                'MD5': file_information.get('md5_hash', ''),
                'SHA256': file_information.get('sha256_hash', ''),
                'Type': file_information.get('file_type', ''),
                'Size': int(file_information.get('file_size', '')),
                'Signature': file_information.get('signature', ''),
                'FirstSeen': first_seen,
                'LastSeen': last_seen,
                'DownloadLink': file_information.get('urlhaus_download', ''),
                'URL': file_information.get('urls', [])
            }

            virus_total_data = file_information.get('virustotal')
            if virus_total_data:
                urlhaus_data['VirusTotal'] = {
                    'Percent':
                    float(
                        file_information.get('virustotal',
                                             {'percent': 0})['percent']),
                    'Link':
                    file_information.get('virustotal', {'link': ''})['link']
                }

            ec = {
                'File': {
                    'Size': urlhaus_data.get('Size', 0),
                    'MD5': urlhaus_data.get('MD5', ''),
                    'SHA256': urlhaus_data.get('SHA256')
                },
                'URLhaus.File(val.MD5 && val.MD5 === obj.MD5)': urlhaus_data
            }

            human_readable = tableToMarkdown(
                f'URLhaus reputation for {hash_type.upper()} : {hash}', {
                    'URLhaus link': urlhaus_data.get('DownloadLink', ''),
                    'Signature': urlhaus_data.get('Signature', ''),
                    'MD5': urlhaus_data.get('MD5', ''),
                    'SHA256': urlhaus_data.get('SHA256', ''),
                    'First seen': first_seen,
                    'Last seen': last_seen
                })
            demisto.results({
                'Type': entryTypes['note'],
                'ContentsFormat': formats['json'],
                'Contents': file_information,
                'HumanReadable': human_readable,
                'HumanReadableFormat': formats['markdown'],
                'EntryContext': ec
            })
        elif (file_information['query_status'] == 'ok' and not file_information['md5_hash']) or \
                file_information['query_status'] == 'no_results':
            human_readable = f'## URLhaus reputation for {hash_type.upper()} : {hash}\n' \
                f'No results!'

            demisto.results({
                'Type': entryTypes['note'],
                'ContentsFormat': formats['json'],
                'Contents': file_information,
                'HumanReadable': human_readable,
                'HumanReadableFormat': formats['markdown'],
            })
        elif file_information['query_status'] in [
                'invalid_md5', 'invalid_sha256'
        ]:
            human_readable = f'## URLhaus reputation for {hash_type.upper()} : {hash}\n' \
                f'Invalid {file_information["query_status"].lstrip("invalid_").upper()}!'

            demisto.results({
                'Type': entryTypes['note'],
                'ContentsFormat': formats['json'],
                'Contents': file_information,
                'HumanReadable': human_readable,
                'HumanReadableFormat': formats['markdown'],
            })
        else:
            demisto.results({
                'Type':
                entryTypes['error'],
                'ContentsFormat':
                formats['text'],
                'Contents':
                f'Query results = {file_information["query_status"]}'
            })

    except Exception:
        print(traceback.format_exc())
        demisto.debug(traceback.format_exc())
        return_error(
            'Failed getting file data, please verify the arguments and parameters'
        )
Ejemplo n.º 41
0
def main() -> None:
    api_key = demisto.params().get('apikey')
    base_url = demisto.params().get('url')
    verify_certificate = not demisto.params().get('insecure', False)

    # How much time before the first fetch to retrieve incidents
    first_fetch_time = dateparser.parse(demisto.params().get('first_fetch', '3 days')) \
        .strftime(XSOAR_DATE_FORMAT)  # type: ignore[union-attr]
    proxy = demisto.params().get('proxy', False)
    demisto.debug(f'Command being called is {demisto.command()}')
    mirror_tags = set(demisto.params().get('mirror_tag', '').split(',')) \
        if demisto.params().get('mirror_tag') else set([])

    query = demisto.params().get('query', '') or ''
    disable_from_same_integration = demisto.params().get(
        'disable_from_same_integration')
    if disable_from_same_integration:
        query += ' -sourceBrand:"XSOAR Mirroring"'

    max_results = arg_to_number(arg=demisto.params().get('max_fetch'),
                                arg_name='max_fetch')
    if not max_results or max_results > MAX_INCIDENTS_TO_FETCH:
        max_results = MAX_INCIDENTS_TO_FETCH

    try:
        headers = {'Authorization': api_key}
        client = Client(base_url=base_url,
                        verify=verify_certificate,
                        headers=headers,
                        proxy=proxy)

        if demisto.command() == 'test-module':
            if demisto.params().get('isFetch'):
                fetch_incidents(
                    client=client,
                    max_results=max_results,
                    last_run=demisto.getLastRun(),
                    first_fetch_time=first_fetch_time,
                    query=query,
                    mirror_direction=demisto.params().get('mirror_direction'),
                    mirror_tag=list(mirror_tags))

            return_results(test_module(client, first_fetch_time))

        elif demisto.command() == 'fetch-incidents':
            next_run, incidents = fetch_incidents(
                client=client,
                max_results=max_results,
                last_run=demisto.getLastRun(),
                first_fetch_time=first_fetch_time,
                query=query,
                mirror_direction=demisto.params().get('mirror_direction'),
                mirror_tag=list(mirror_tags))
            demisto.setLastRun(next_run)
            demisto.incidents(incidents)

        elif demisto.command() == 'xsoar-search-incidents':
            return_results(search_incidents_command(client, demisto.args()))

        elif demisto.command() == 'xsoar-get-incident':
            return_results(get_incident_command(client, demisto.args()))

        elif demisto.command() == 'get-mapping-fields':
            return_results(get_mapping_fields_command(client))

        elif demisto.command() == 'get-remote-data':
            return_results(
                get_remote_data_command(client, demisto.args(),
                                        demisto.params()))

        elif demisto.command() == 'update-remote-system':
            return_results(
                update_remote_system_command(client, demisto.args(),
                                             mirror_tags))

        else:
            raise NotImplementedError('Command not implemented')

    except NotImplementedError:
        raise
    except Exception as e:
        return_error(
            f'Failed to execute {demisto.command()} command.\nError:\n{str(e)}'
        )
Ejemplo n.º 42
0
def fetch_mails(client: IMAPClient,
                time_to_fetch_from: datetime = None,
                permitted_from_addresses: str = '',
                permitted_from_domains: str = '',
                include_raw_body: bool = False,
                limit: int = 200,
                save_file: bool = False,
                message_id: int = None,
                uid_to_fetch_from: int = 1) -> Tuple[list, list, int]:
    """
    This function will fetch the mails from the IMAP server.

    Args:
        client: IMAP client
        time_to_fetch_from: Fetch all incidents since first_fetch_time
        include_raw_body: Whether to include the raw body of the mail in the incident's body
        permitted_from_addresses: A string representation of list of mail addresses to fetch from
        permitted_from_domains: A string representation list of domains to fetch from
        limit: The maximum number of incidents to fetch each time, if the value is -1 all
               mails will be fetched (used with list-messages command)
        save_file: Whether to save the .eml file of the incident's mail
        message_id: A unique message ID with which a specific mail can be fetched
        uid_to_fetch_from: The email message UID to start the fetch from as offset

    Returns:
        mails_fetched: A list of Email objects
        messages_fetched: A list of the ids of the messages fetched
        last_message_in_current_batch: The UID of the last message fetchedd
    """
    if message_id:
        messages_uids = [message_id]
    else:
        messages_query = generate_search_query(time_to_fetch_from,
                                               permitted_from_addresses,
                                               permitted_from_domains,
                                               uid_to_fetch_from)
        demisto.debug(
            f'Searching for email messages with criteria: {messages_query}')
        messages_uids = client.search(messages_query)[:limit]
    mails_fetched = []
    messages_fetched = []
    demisto.debug(f'Messages to fetch: {messages_uids}')
    for mail_id, message_data in client.fetch(messages_uids, 'RFC822').items():
        message_bytes = message_data.get(b'RFC822')
        if not message_bytes:
            continue
        email_message_object = Email(message_bytes, include_raw_body,
                                     save_file, mail_id)
        if (not time_to_fetch_from or time_to_fetch_from < email_message_object.date) and \
                int(email_message_object.id) > int(uid_to_fetch_from):
            mails_fetched.append(email_message_object)
            messages_fetched.append(email_message_object.id)
        else:
            demisto.debug(
                f'Skipping {email_message_object.id} with date {email_message_object.date}. '
                f'uid_to_fetch_from: {uid_to_fetch_from}, first_fetch_time: {time_to_fetch_from}'
            )
    last_message_in_current_batch = uid_to_fetch_from
    if messages_uids:
        last_message_in_current_batch = messages_uids[-1]

    return mails_fetched, messages_fetched, last_message_in_current_batch
Ejemplo n.º 43
0
def main():
    """
    Intercept and execute commands.
    """

    # IdentityIQ Base URL (https://identityiq-server.com/identityiq)
    base_url = demisto.params().get('identityiq_url')

    # OAuth 2.0 Credentials
    client_id = demisto.params().get('client_id')
    client_secret = demisto.params().get('client_secret')
    grant_type = 'client_credentials'

    # Convert the argument to an int or set to MAX_INCIDENTS_TO_FETCH
    max_results = int(demisto.params().get('max_fetch'))
    if not max_results or max_results > MAX_INCIDENTS_TO_FETCH:
        max_results = MAX_INCIDENTS_TO_FETCH

    first_fetch_str = demisto.params().get('first_fetch', '3 days')

    # Other configs
    verify_certificate = not demisto.params().get('insecure', False)
    proxy = handle_proxy()
    request_timeout = 10

    demisto.debug(f'Command being called is {demisto.command()}')
    try:
        headers = get_headers(base_url, client_id, client_secret, grant_type,
                              verify_certificate)
        client = Client(base_url=base_url,
                        verify=verify_certificate,
                        proxy=proxy,
                        headers=headers,
                        max_results=max_results,
                        request_timeout=request_timeout)
        results = None
        if demisto.command() == 'test-module':
            # This is the call made when pressing the integration Test button.
            results = test_connection(client)

        elif demisto.command() == 'fetch-incidents':
            next_run, incidents = fetch_incidents(client, demisto.getLastRun(),
                                                  first_fetch_str)
            demisto.setLastRun(next_run)
            demisto.incidents(incidents)

        elif demisto.command() == 'identityiq-search-identities':
            id = demisto.args().get('id', None)
            email = demisto.args().get('email', None)
            risk = demisto.args().get('risk', 0)
            active = demisto.args().get('active', True)
            response = search_identities(client, id, email, risk, active)
            results = build_results('IdentityIQ.Identity', 'id', response)

        elif demisto.command() == 'identityiq-get-policyviolations':
            id = demisto.args().get('id', None)
            response = get_policy_violations(client, id)
            results = build_results('IdentityIQ.PolicyViolation', 'policyName',
                                    response)

        elif demisto.command() == 'identityiq-get-taskresults':
            id = demisto.args().get('id', None)
            response = get_task_results(client, id)
            results = build_results('IdentityIQ.TaskResult', 'id', response)

        elif demisto.command() == 'identityiq-get-accounts':
            id = demisto.args().get('id', None)
            display_name = demisto.args().get('display_name', None)
            last_refresh = demisto.args().get('last_refresh', None)
            native_identity = demisto.args().get('native_identity', None)
            last_target_agg = demisto.args().get('last_target_agg')
            identity_name = demisto.args().get('identity_name', None)
            application_name = demisto.args().get('application_name', None)
            response = get_accounts(client, id, display_name, last_refresh,
                                    native_identity, last_target_agg,
                                    identity_name, application_name)
            results = build_results('IdentityIQ.Account', 'id', response)

        elif demisto.command() == 'identityiq-disable-account':
            id = demisto.args().get('id', None)
            response = change_account_status(client, id, False)
            results = build_results('IdentityIQ.Account', 'id', response)

        elif demisto.command() == 'identityiq-enable-account':
            id = demisto.args().get('id', None)
            response = change_account_status(client, id, True)
            results = build_results('IdentityIQ.Account', 'id', response)

        elif demisto.command() == 'identityiq-delete-account':
            id = demisto.args().get('id', None)
            results = delete_account(client, id)

        elif demisto.command() == 'identitytiq-get-launched-workflows':
            id = demisto.args().get('id', None)
            response = get_launched_workflows(client, id)
            results = build_results('IdentityIQ.Workflow', 'id', response)

        elif demisto.command() == 'identityiq-get-roles':
            id = demisto.args().get('id', None)
            response = get_roles(client, id)
            results = build_results('IdentityIQ.Role', 'name', response)

        elif demisto.command() == 'identityiq-get-entitlements':
            id = demisto.args().get('id', None)
            response = get_entitlements(client, id)
            results = build_results('IdentityIQ.Entitlement', 'id', response)

        elif demisto.command() == 'identityiq-get-alerts':
            id = demisto.args().get('id', None)
            response = get_alerts(client, id)
            results = build_results('IdentityIQ.Alert', 'id', response)

        elif demisto.command() == 'identityiq-create-alert':
            display_name = demisto.args().get('display_name', None)
            attribute = demisto.args().get('attribute', None)
            response = create_alert(client, display_name, attribute)
            results = build_results('IdentityIQ.Alert', 'id', response)

        return_results(results)

    # Log exceptions and return errors
    except Exception as e:
        demisto.error(traceback.format_exc())
        return_error(
            f'Failed to execute {demisto.command()} command.\nError:\n{str(e)}'
        )
Ejemplo n.º 44
0
def main():
    esm = NitroESM(ESM_URL, USERNAME, PASSWORD)
    try:
        esm.login()
        final_result = 'No result set'

        if demisto.command() == 'fetch-incidents':
            last_run = demisto.getLastRun()
            demisto.debug('\n\nlast run:\n{}\n'.format(last_run))
            # for backward compatibility uses
            if 'value' in last_run and 'alarms' not in last_run:
                last_run['alarms'] = last_run['value']
            configuration_last_case = int(demisto.params().get(
                'startingCaseID', 0))

            start_alarms = last_run.get('alarms')
            if start_alarms is None:
                start_alarms, _ = parse_date_range(
                    demisto.params()['alarm_fetch_time'],
                    date_format='%Y-%m-%dT%H:%M:%S.%f',
                    timezone=TIMEZONE)

            last_case = last_run.get('cases', 0)
            # if last_case < configuration_last_case:
            last_case = max(last_case, configuration_last_case)

            incidents = []  # type: list
            mode = demisto.params().get('fetchTypes', 'alarms').lower(
            )  # alarms is default for backward compatibility

            next_run = None
            if mode in ('alarms', 'both'):
                end = (datetime.now() + timedelta(hours=TIMEZONE)).isoformat()

                demisto.debug("alarms: start - {} , end - {}".format(
                    start_alarms, end))

                alarms = esm.fetch_alarms('CUSTOM', start_alarms, end, '')
                demisto.debug('alarms found:\n{}\n'.format(alarms))

                incidents = []
                for alarm in alarms:
                    triggered_date = alarm['triggeredDate']
                    if next_run is None or next_run < triggered_date:
                        next_run = triggered_date
                    alarm['events'] = esm.list_alarm_events(alarm['ID'])
                    incidents.append({
                        'name':
                        alarm['summary'],
                        'details':
                        'Alarm {} , ID : {} , was triggered by condition type: {}'
                        .format(alarm['alarmName'], alarm['ID'],
                                alarm['conditionType']),
                        'severity':
                        severity_to_level(alarm['severity']),
                        'rawJSON':
                        json.dumps(alarm)
                    })

            if mode in ('cases', 'both'):
                # get new cases
                cases = [
                    case for case in esm.get_cases()
                    if case['id']['value'] > last_case
                ]
                cases.sort(key=lambda c: c['id']['value'])
                cases = cases[:MAX_CASES_PER_FETCH]

                if cases:
                    last_case = cases[-1]['id']['value']

                # update last run info
                last_run['cases'] = last_case

                demisto.debug('adding %d more cases, last id is: %d' % (
                    len(cases),
                    last_run['cases'],
                ))
                if cases:
                    incidents.extend(cases_to_incidents(cases))

            if next_run is not None:
                next_run_datetime = datetime.strptime(next_run,
                                                      parse_time(next_run))
                next_run = (next_run_datetime +
                            timedelta(seconds=1)).isoformat()
            else:
                next_run = start_alarms

            last_run['value'] = next_run
            last_run['alarms'] = next_run

            demisto.incidents(incidents)
            demisto.setLastRun(last_run)
            sys.exit(0)

        elif demisto.command() == 'test-module':
            if VERSION not in ['10.0', '10.1', '10.2', '10.3', '11.1']:
                final_result = 'version must be one of 10.x, got %s' % (
                    VERSION, )
            else:
                esm.fetch_all_fields()
                final_result = 'ok'

        elif demisto.command() == 'esm-fetch-fields':
            res = esm.fetch_all_fields()
            final_result = res

        elif demisto.command() == 'esm-search':
            args = demisto.args()
            res = esm.search(demisto.get(args, 'timeRange'),
                             demisto.get(args, 'customStart'),
                             demisto.get(args, 'customEnd'),
                             json.loads(args.get('filters')),
                             args.get('fields'),
                             demisto.get(args, 'queryType') or 'EVENT',
                             demisto.get(args, 'maxWait') or 30)
            final_result = res

        elif demisto.command() == 'esm-get-case-list':
            since_date_range = demisto.args().get('since')
            res = esm.get_cases(since_date_range)
            final_result = cases_to_entry(esm, 'All cases:', res)

        elif demisto.command() == 'esm-get-case-detail':
            args = demisto.args()
            case_id = int(demisto.get(args, 'id'))
            res = esm.get_case_detail(case_id)
            final_result = cases_to_entry(esm, 'Case %d:' % (case_id, ), [res])

        elif demisto.command() == 'esm-add-case':
            args = demisto.args()
            res = esm.add_case(
                demisto.get(args, 'summary'),
                int(demisto.get(args, 'severity')),
                demisto.get(args, 'status'),
                demisto.get(args, 'assignee'),
                demisto.get(args, 'organization'),
            )
            case = esm.get_case_detail(res)
            final_result = cases_to_entry(esm, 'New Case:', [case])

        elif demisto.command() == 'esm-edit-case':
            args = demisto.args()
            case_id = int(demisto.get(args, 'id'))
            severity = demisto.get(args, 'severity')
            esm.edit_case(
                case_id,
                demisto.get(args, 'summary'),
                int(severity) if severity else None,
                demisto.get(args, 'status'),
                demisto.get(args, 'assignee'),
                demisto.get(args, 'organization'),
            )
            case = esm.get_case_detail(case_id)
            final_result = cases_to_entry(esm, 'Edited Case:', [case])

        elif demisto.command() == 'esm-get-case-statuses':
            res = esm.get_case_statuses()
            final_result = case_statuses_to_entry(res)

        elif demisto.command() == 'esm-add-case-status':
            args = demisto.args()
            res = esm.add_case_status(
                demisto.get(args, 'name'),
                bool(strtobool(demisto.get(args, 'show_in_case_pane'))),
            )
            final_result = res

        elif demisto.command() == 'esm-edit-case-status':
            args = demisto.args()
            should_show = demisto.get(args, 'show_in_case_pane')
            res = esm.edit_case_status(
                demisto.get(args, 'original_name'),
                demisto.get(args, 'new_name'),
                bool(strtobool(should_show)) if should_show else None,
            )
            final_result = res

        elif demisto.command() == 'esm-delete-case-status':
            args = demisto.args()
            res = esm.delete_case_status(demisto.get(args, 'name'))
            final_result = res

        elif demisto.command() == 'esm-get-case-event-list':
            args = demisto.args()
            event_ids = demisto.get(args, 'ids').split(',')
            res = esm.get_case_event_list(event_ids)
            final_result = case_events_to_entry(res)

        elif demisto.command() == 'esm-get-organization-list':
            res = esm.get_organizations()
            final_result = organizations_to_entry(res)

        elif demisto.command() == 'esm-get-user-list':
            res = esm.get_users()
            final_result = users_to_entry(res)

        elif demisto.command() == 'esm-fetch-alarms':
            args = demisto.args()
            res = esm.fetch_alarms(demisto.get(args, 'timeRange'),
                                   demisto.get(args, 'customStart'),
                                   demisto.get(args, 'customEnd'),
                                   demisto.get(args, 'assignedUser'))
            final_result = alarms_to_entry(res)

        elif demisto.command() == 'esm-acknowledge-alarms':
            args = demisto.args()
            res = esm.acknowledge_alarms(
                argToList(demisto.get(args, 'alarmIds')))
            final_result = res

        elif demisto.command() == 'esm-unacknowledge-alarms':
            args = demisto.args()
            res = esm.unacknowledge_alarms(
                argToList(demisto.get(args, 'alarmIds')))
            final_result = res

        elif demisto.command() == 'esm-delete-alarms':
            args = demisto.args()
            res = esm.delete_alarms(argToList(demisto.get(args, 'alarmIds')))
            final_result = res

        elif demisto.command() == 'esm-get-alarm-event-details':
            args = demisto.args()
            res = esm.get_alarm_event_details(demisto.get(args, 'eventId'))
            final_result = alarm_events_to_entry(esm, [res])

        elif demisto.command() == 'esm-list-alarm-events':
            args = demisto.args()
            res = esm.list_alarm_events(demisto.get(args, 'alarmId'))
            final_result = alarm_events_to_entry(esm, res['events'])
        demisto.results(final_result)

    except Exception as ex:
        demisto.error('#### error in McAfee ESM v10: ' + str(ex))
        if demisto.command() == 'fetch-incidents':
            LOG(traceback.format_exc())
            LOG.print_log()
            raise
        else:
            return_error(str(ex), error=traceback.format_exc())
    finally:
        esm.logout()
 def set_auth_headers(self, token: str) -> None:
     self._headers = {'Authorization': f'Bearer {token}'}
     demisto.debug('Set auth headers successfully')
Ejemplo n.º 46
0
def get_remote_data_command(client: Client, args: Dict[str, Any],
                            params: Dict[str, Any]) -> GetRemoteDataResponse:
    """get-remote-data command: Returns an updated incident and entries

    :type client: ``Client``
    :param Client: XSOAR client to use

    :type args: ``Dict[str, Any]``
    :param args:
        all command arguments, usually passed from ``demisto.args()``.
        ``args['id']`` incident id to retrieve
        ``args['lastUpdate']`` when was the last time we retrieved data

    :return:
        A ``List[Dict[str, Any]]`` first entry is the incident (which can be completely empty) and others are the new entries

    :rtype: ``List[Dict[str, Any]]``
    """
    demisto_debug(f'##### get-remote-data args: {json.dumps(args, indent=4)}')
    incident = None
    try:
        args['lastUpdate'] = arg_to_timestamp(
            arg=args.get('lastUpdate'),  # type: ignore
            arg_name='lastUpdate',
            required=True)
        remote_args = GetRemoteDataArgs(args)
        demisto_debug(
            f'Getting update for remote [{remote_args.remote_incident_id}]')

        categories = params.get('categories', None)
        if categories:
            categories = categories.split(',')
        else:
            categories = None
        tags = params.get('tags', None)
        if tags:
            tags = tags.split(',')
        else:
            tags = None

        incident = client.get_incident(
            incident_id=remote_args.remote_incident_id)  # type: ignore
        # If incident was modified before we last updated, no need to return it
        modified = arg_to_timestamp(
            arg=incident.get('modified'),  # type: ignore
            arg_name='modified',
            required=False)
        occurred = arg_to_timestamp(
            arg=incident.get('occurred'),  # type: ignore
            arg_name='occurred',
            required=False)

        if (datetime.fromtimestamp(modified) - datetime.fromtimestamp(occurred)
                < timedelta(minutes=1)
                and datetime.fromtimestamp(remote_args.last_update) -
                datetime.fromtimestamp(modified) < timedelta(minutes=1)):
            remote_args.last_update = occurred + 1
            # in case new entries created less than a minute after incident creation

        demisto_debug(f'tags: {tags}')
        demisto_debug(f'tags: {categories}')
        entries = client.get_incident_entries(
            incident_id=remote_args.remote_incident_id,  # type: ignore
            from_date=remote_args.last_update * 1000,
            max_results=100,
            categories=categories,
            tags=tags,
            tags_and_operator=True)

        formatted_entries = []
        # file_attachments = []

        if entries:
            for entry in entries:
                if 'file' in entry and entry.get('file'):
                    file_entry_content = client.get_file_entry(
                        entry.get('id'))  # type: ignore
                    file_result = fileResult(entry['file'], file_entry_content)

                    formatted_entries.append(file_result)
                else:
                    formatted_entries.append({
                        'Type':
                        entry.get('type'),
                        'Category':
                        entry.get('category'),
                        'Contents':
                        entry.get('contents'),
                        'ContentsFormat':
                        entry.get('format'),
                        'Tags':
                        entry.get(
                            'tags'),  # the list of tags to add to the entry
                        'Note':
                        entry.get(
                            'note')  # boolean, True for Note, False otherwise
                    })

        # Handle if the incident closed remotely
        if incident.get('status') == IncidentStatus.DONE:
            formatted_entries.append({
                'Type': EntryType.NOTE,
                'Contents': {
                    'dbotIncidentClose': True,
                    'closeReason': incident.get('closeReason'),
                    'closeNotes': incident.get('closeNotes')
                },
                'ContentsFormat': EntryFormat.JSON
            })

        incident['in_mirror_error'] = ''

        if remote_args.last_update >= modified and not formatted_entries:
            demisto.debug(
                f'Nothing new in the incident, incident id {remote_args.remote_incident_id}'
            )
            incident = {
            }  # this empties out the incident, which will result in not updating the local one

        incident['dbotMirrorInstance'] = demisto.integrationInstance()
        incident['id'] = remote_args.remote_incident_id
        # incident['attachment'] = file_attachments
        mirror_data = GetRemoteDataResponse(mirrored_object=incident,
                                            entries=formatted_entries)
        return mirror_data

    except Exception as e:
        demisto.error(
            f"Error in XSOAR incoming mirror for incident {args['id']} \nError message: {str(e)}"
        )
        incident = {'id': args['id'], 'in_mirror_error': str(e)}

        return GetRemoteDataResponse(mirrored_object=incident, entries=[])
    async def fetch_event(self, offset: int = 0, event_type: str = '') -> AsyncGenerator[Dict, None]:
        """Retrieves events from a CrowdStrike Falcon stream starting from given offset.

        Args:
            offset (int): Stream offset to start the fetch from.
            event_type (str): Stream event type to fetch.

        Yields:
            AsyncGenerator[Dict, None]: Event fetched from the stream.
        """
        demisto.debug('Fetching event')
        event = Event()
        create_task(self._discover_refresh_stream(event))
        demisto.debug('Waiting for stream discovery or refresh')
        await event.wait()
        demisto.debug('Done waiting for stream discovery or refresh')
        async with ClientSession(
            connector=TCPConnector(ssl=self.verify_ssl),
            headers={'Authorization': f'Token {self.session_token}'},
            trust_env=self.proxy
        ) as session:
            try:
                async with session.get(self.data_feed_url, params={'offset': offset, 'eventType': event_type}) as res:
                    demisto.debug(f'Fetched event: {res.content}')
                    async for line in res.content:
                        stripped_line = line.strip()
                        if stripped_line:
                            try:
                                yield json.loads(stripped_line)
                            except json.decoder.JSONDecodeError:
                                demisto.debug(f'Failed decoding event (skipping it) - {str(stripped_line)}')
            except Exception as e:
                demisto.debug(f'Failed to fetch event: {e} - Going to sleep for 10 seconds and then retry')
                await sleep(10)
Ejemplo n.º 48
0
    res = run_query(query, '', max_results)
    curr_id = id_offset
    for ticket in res.get('issues'):
        ticket_id = int(ticket.get("id"))
        if ticket_id == curr_id:
            continue

        id_offset = max(int(id_offset), ticket_id)
        incidents.append(create_incident_from_ticket(ticket))

    demisto.setLastRun({"idOffset": id_offset})
    demisto.incidents(incidents)


''' COMMANDS MANAGER / SWITCH PANEL '''
demisto.debug('Command being called is %s' % (demisto.command()))
try:
    # Remove proxy if not set to true in params
    handle_proxy()

    if demisto.command() == 'test-module':
        # This is the call made when pressing the integration test button.
        test_module()

    elif demisto.command() == 'fetch-incidents':
        # Set and define the fetch incidents command to run after activated via integration settings.
        fetch_incidents(**snakify(demisto.params()))

    elif demisto.command() == 'jira-get-issue':
        get_issue(**snakify(demisto.args()))
Ejemplo n.º 49
0
def fetch_incidents(
        client: Client, max_results: int, last_run: Dict[str, Union[str, int]],
        first_fetch_time: Union[int, str], query: Optional[str],
        mirror_direction: str,
        mirror_tag: List[str]) -> Tuple[Dict[str, str], List[dict]]:
    """This function retrieves new incidents every interval (default is 1 minute).

    :type client: ``Client``
    :param client: XSOAR client to use

    :type max_results: ``int``
    :param max_results: Maximum numbers of incidents per fetch

    :type last_run: ``Optional[Dict[str, str]]``
    :param last_run:
        A dict with a key containing the latest incident created time we got
        from last fetch

    :type first_fetch_time: ``Optional[int, str]``
    :param first_fetch_time:
        If last_run is None (first time we are fetching), it contains
        the timestamp in milliseconds on when to start fetching incidents

    :type query: ``Optional[str]``
    :param query:
        query to fetch the relevant incidents

    :type mirror_direction: ``str``
    :param mirror_direction:
        Mirror direction for the fetched incidents

    :type mirror_tag: ``List[str]``
    :param mirror_tag:
        The tags that you will mirror out of the incident.

    :return:
        A tuple containing two elements:
            next_run (``Dict[str, int]``): Contains the timestamp that will be
                    used in ``last_run`` on the next fetch.
            incidents (``List[dict]``): List of incidents that will be created in XSOAR

    :rtype: ``Tuple[Dict[str, int], List[dict]]``
    """

    last_fetch = last_run.get('last_fetch')
    if not last_fetch:
        last_fetch = first_fetch_time  # type: ignore
    else:
        demisto.debug(
            'Trying to convert the last_fetch to int, and convert it to date string if succeed. '
            'This is for preventing backward compatibility breakage.')
        try:
            last_fetch = int(last_fetch)
            last_fetch = datetime.fromtimestamp(last_fetch).strftime(
                XSOAR_DATE_FORMAT)
        except Exception:
            pass

    latest_created_time = dateparser.parse(
        last_fetch)  # type: ignore[arg-type]
    incidents_result: List[Dict[str, Any]] = []
    if query:
        query += f' and created:>="{last_fetch}"'
    else:
        query = f'created:>="{last_fetch}"'

    demisto.debug(f'Fetching incidents since last fetch: {last_fetch}')
    incidents = client.search_incidents(query=query,
                                        max_results=max_results,
                                        start_time=last_fetch)

    for incident in incidents:
        incident_result: Dict[str, Any] = dict()
        incident_result['dbotMirrorDirection'] = MIRROR_DIRECTION[
            mirror_direction]  # type: ignore
        incident['dbotMirrorInstance'] = demisto.integrationInstance()
        incident_result[
            'dbotMirrorTags'] = mirror_tag if mirror_tag else None  # type: ignore
        incident_result['dbotMirrorId'] = incident['id']

        for key, value in incident.items():
            if key in FIELDS_TO_COPY_FROM_REMOTE_INCIDENT:
                incident_result[key] = value

        incident_result['rawJSON'] = json.dumps(incident)

        file_attachments = []
        if incident.get('attachment') and len(incident.get(
                'attachment', [])) > 0 and incident.get('investigationId'):
            entries = client.get_incident_entries(
                incident_id=incident['investigationId'],  # type: ignore
                from_date=0,
                max_results=10,
                categories=['attachments'],
                tags=None,
                tags_and_operator=False)

            for entry in entries:
                if 'file' in entry and entry.get('file'):
                    file_entry_content = client.get_file_entry(
                        entry.get('id'))  # type: ignore
                    file_result = fileResult(entry['file'], file_entry_content)
                    if any(
                            attachment.get('name') == entry['file']
                            for attachment in incident.get('attachment', [])):
                        if file_result['Type'] == EntryType.ERROR:
                            raise Exception(
                                f"Error getting attachment: {str(file_result.get('Contents', ''))}"
                            )

                        file_attachments.append({
                            'path':
                            file_result.get('FileID', ''),
                            'name':
                            file_result.get('File', '')
                        })

        incident_result['attachment'] = file_attachments
        incidents_result.append(incident_result)
        incident_created_time = dateparser.parse(
            incident.get('created'))  # type: ignore[arg-type]

        # Update last run and add incident if the incident is newer than last fetch
        if incident_created_time > latest_created_time:  # type: ignore[operator]
            latest_created_time = incident_created_time

    # Save the next_run as a dict with the last_fetch key to be stored
    next_run = {
        'last_fetch': (latest_created_time + timedelta(microseconds=1)
                       )  # type: ignore[operator]
        .strftime(XSOAR_DATE_FORMAT)
    }  # type: ignore[union-attr,operator]

    return next_run, incidents_result
Ejemplo n.º 50
0
def demisto_debug(msg):
    if demisto.params().get('debug_mode'):
        demisto.info(msg)
    else:
        demisto.debug(msg)
Ejemplo n.º 51
0
def aws_session(service='lambda',
                region=None,
                roleArn=None,
                roleSessionName=None,
                roleSessionDuration=None,
                rolePolicy=None):
    kwargs = {}
    config = CONFIG
    command_config: Dict[str, Any] = {}
    retries = demisto.getArg('retries')
    if retries:
        command_config['retries'] = dict(max_attempts=int(retries))
    timeout = demisto.getArg('timeout')
    if timeout:
        (read_timeout, connect_timeout) = get_timeout(timeout)
        command_config['read_timeout'] = read_timeout
        command_config['connect_timeout'] = connect_timeout
    if retries or timeout:
        demisto.debug(f'Merging client config settings: {command_config}')
        config = CONFIG.merge(Config(**command_config))
    if roleArn and roleSessionName is not None:
        kwargs.update({
            'RoleArn': roleArn,
            'RoleSessionName': roleSessionName,
        })
    elif AWS_ROLE_ARN and AWS_ROLE_SESSION_NAME is not None:
        kwargs.update({
            'RoleArn': AWS_ROLE_ARN,
            'RoleSessionName': AWS_ROLE_SESSION_NAME,
        })

    if roleSessionDuration is not None:
        kwargs.update({'DurationSeconds': int(roleSessionDuration)})
    elif AWS_ROLE_SESSION_DURATION is not None:
        kwargs.update({'DurationSeconds': int(AWS_ROLE_SESSION_DURATION)})

    if rolePolicy is not None:
        kwargs.update({'Policy': rolePolicy})
    elif AWS_ROLE_POLICY is not None:
        kwargs.update({'Policy': AWS_ROLE_POLICY})
    if kwargs and not AWS_ACCESS_KEY_ID:

        if not AWS_ACCESS_KEY_ID:
            sts_client = boto3.client('sts',
                                      config=config,
                                      verify=VERIFY_CERTIFICATE,
                                      region_name=AWS_DEFAULT_REGION)
            sts_response = sts_client.assume_role(**kwargs)
            if region is not None:
                client = boto3.client(
                    service_name=service,
                    region_name=region,
                    aws_access_key_id=sts_response['Credentials']
                    ['AccessKeyId'],
                    aws_secret_access_key=sts_response['Credentials']
                    ['SecretAccessKey'],
                    aws_session_token=sts_response['Credentials']
                    ['SessionToken'],
                    verify=VERIFY_CERTIFICATE,
                    config=config)
            else:
                client = boto3.client(
                    service_name=service,
                    region_name=AWS_DEFAULT_REGION,
                    aws_access_key_id=sts_response['Credentials']
                    ['AccessKeyId'],
                    aws_secret_access_key=sts_response['Credentials']
                    ['SecretAccessKey'],
                    aws_session_token=sts_response['Credentials']
                    ['SessionToken'],
                    verify=VERIFY_CERTIFICATE,
                    config=config)
    elif AWS_ACCESS_KEY_ID and AWS_ROLE_ARN:
        sts_client = boto3.client(service_name='sts',
                                  aws_access_key_id=AWS_ACCESS_KEY_ID,
                                  aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
                                  verify=VERIFY_CERTIFICATE,
                                  config=config)
        kwargs.update({
            'RoleArn': AWS_ROLE_ARN,
            'RoleSessionName': AWS_ROLE_SESSION_NAME,
        })
        sts_response = sts_client.assume_role(**kwargs)
        client = boto3.client(
            service_name=service,
            region_name=AWS_DEFAULT_REGION,
            aws_access_key_id=sts_response['Credentials']['AccessKeyId'],
            aws_secret_access_key=sts_response['Credentials']
            ['SecretAccessKey'],
            aws_session_token=sts_response['Credentials']['SessionToken'],
            verify=VERIFY_CERTIFICATE,
            config=config)
    else:
        if region is not None:
            client = boto3.client(service_name=service,
                                  region_name=region,
                                  aws_access_key_id=AWS_ACCESS_KEY_ID,
                                  aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
                                  verify=VERIFY_CERTIFICATE,
                                  config=config)
        else:
            client = boto3.client(service_name=service,
                                  region_name=AWS_DEFAULT_REGION,
                                  aws_access_key_id=AWS_ACCESS_KEY_ID,
                                  aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
                                  verify=VERIFY_CERTIFICATE,
                                  config=config)
    return client
Ejemplo n.º 52
0
def main() -> None:
    params = demisto.params()
    client_id: str = params['credentials']['identifier']
    client_secret: str = params['credentials']['password']
    base_url: str = params['url'].rstrip('/')
    verify_certificate = not params.get('insecure', False)
    proxy = params.get('proxy', False)

    # Fetch incident related params:
    first_fetch_time = params.get('first_fetch', '3 days')
    fetch_limit = arg_to_number(params.get('max_fetch', LIMIT_DEFAULT))
    fetch_state = params.get('state')
    fetch_severity = params.get('severity')
    fetch_status = ','.join(
        STATUS_MAP.get(x)
        for x in argToList(params.get('status', [])))  # type: ignore[misc]
    fetch_app_ids = ','.join(argToList(params.get('app_ids', [])))

    mirror_direction = MIRROR_DIRECTION.get(
        params.get('mirror_direction', 'None'), None)
    instance = demisto.integrationInstance()

    commands = {
        'saas-security-incidents-get': get_incidents_command,
        'saas-security-incident-get-by-id': get_incident_by_id_command,
        'saas-security-incident-state-update': update_incident_state_command,
        'saas-security-get-apps': get_apps_command,
        'saas-security-asset-remediate': remediate_asset_command,
        'saas-security-remediation-status-get': get_remediation_status_command,
        'get-remote-data': get_remote_data_command,
        'get-modified-remote-data': get_modified_remote_data_command,
        'update-remote-system': update_remote_system_command,
    }
    command = demisto.command()
    demisto.debug(f'Command being called is {command}')

    try:
        client = Client(
            base_url=base_url,
            client_id=client_id,
            client_secret=client_secret,
            verify=verify_certificate,
            proxy=proxy,
        )

        if command == 'test-module':
            return_results(
                test_module(client, params.get('isFetch'), first_fetch_time,
                            fetch_state, fetch_severity, fetch_status,
                            fetch_app_ids))
        elif command == 'fetch-incidents':
            fetch_incidents(client, first_fetch_time, fetch_limit, fetch_state,
                            fetch_severity, fetch_status, fetch_app_ids,
                            mirror_direction, instance)
        elif command == 'get-mapping-fields':
            return_results(get_mapping_fields_command())

        elif command in commands:
            return_results(commands[command](client, demisto.args()))

        else:
            raise NotImplementedError(
                f'Command "{command}" is not implemented.')

    except Exception as e:
        return_error(f'Failed to execute {command} command.\nError:\n{str(e)}')
Ejemplo n.º 53
0
def get_issue_fields(issue_creating=False, **issue_args):
    """
    refactor issues's argument as received from demisto into jira acceptable format, and back.
    :param issue_creating: flag that indicates this function is called when creating an issue
    :param issue_args: issue argument
    """
    issue = {}  # type: dict
    if 'issueJson' in issue_args:
        try:
            issue = json.loads(issue_args['issueJson'])
        except TypeError as te:
            demisto.debug(str(te))
            return_error("issueJson must be in a valid json format")

    if not issue.get('fields'):
        issue['fields'] = {}

    if not issue['fields'].get('issuetype') and issue_creating:
        issue['fields']['issuetype'] = {}

    if issue_args.get('summary'):
        issue['fields']['summary'] = issue_args['summary']

    if not issue['fields'].get('project'):
        issue['fields']['project'] = {}

    if issue_args.get('projectKey'):
        issue['fields']['project']['key'] = issue_args.get('projectKey', '')
    if issue_args.get('projectName'):
        issue['fields']['project']['name'] = issue_args.get('projectName', '')

    if issue_creating:
        # make sure the key & name are right, and get the corresponding project id & key
        project_id = get_project_id(issue['fields']['project'].get('key', ''),
                                    issue['fields']['project'].get('name', ''))
        issue['fields']['project']['id'] = project_id

    if issue_args.get('issueTypeName'):
        issue['fields']['issuetype']['name'] = issue_args['issueTypeName']

    if issue_args.get('issueTypeId'):
        issue['fields']['issuetype']['id'] = issue_args['issueTypeId']

    if issue_args.get('parentIssueId'):
        if not issue['fields'].get('parent'):
            issue['fields']['parent'] = {}
        issue['fields']['parent']['id'] = issue_args['parentIssueId']

    if issue_args.get('parentIssueKey'):
        if not issue['fields'].get('parent'):
            issue['fields']['parent'] = {}
        issue['fields']['parent']['key'] = issue_args['parentIssueKey']

    if issue_args.get('description'):
        issue['fields']['description'] = issue_args['description']

    if issue_args.get('labels'):
        issue['fields']['labels'] = issue_args['labels'].split(",")

    if issue_args.get('priority'):
        if not issue['fields'].get('priority'):
            issue['fields']['priority'] = {}
        issue['fields']['priority']['name'] = issue_args['priority']

    if issue_args.get('duedate'):
        issue['fields']['duedate'] = issue_args['duedate']

    if issue_args.get('assignee'):
        if not issue['fields'].get('assignee'):
            issue['fields']['assignee'] = {}
        issue['fields']['assignee']['name'] = issue_args['assignee']

    if issue_args.get('reporter'):
        if not issue['fields'].get('reporter'):
            issue['fields']['reporter'] = {}
        issue['fields']['reporter']['name'] = issue_args['reporter']

    return issue
Ejemplo n.º 54
0
def update_remote_system_command(client: Client, args: Dict[str, Any]) -> str:
    """
    update-remote-system command: pushes local changes to the remote system.
    Since the API limitation doesn't allow to update the category when the incident state is open,
    The only use cases the update-remote-system can update are:
     1. When the incident were closed in XSOAR, so this command will close the mirror remote incident as well.
     2. If the category of an incident which was already closed in the remote and fetched was changed.

    :type client: ``Client``
    :param client: XSOAR client to use

    :type args: ``Dict[str, Any]``
    :param args:
        all command arguments, usually passed from ``demisto.args()``.
        ``args['data']`` the data to send to the remote system
        ``args['entries']`` the entries to send to the remote system
        ``args['incidentChanged']`` boolean telling us if the local incident indeed changed or not
        ``args['remoteId']`` the remote incident id

    :return:
        ``str`` containing the remote incident id - really important if the incident is newly created remotely
    :rtype: ``str``
    """
    parsed_args = UpdateRemoteSystemArgs(args)
    if parsed_args.delta:
        demisto.debug(
            f'Got the following delta keys {str(list(parsed_args.delta.keys()))}'
        )

    if parsed_args.incident_changed:
        # Check if the incident were closed in XSOAR,
        # or the category of an incident which was already closed in the remote was changed,
        # since these are the only use cases we wanna mirror out.
        if parsed_args.inc_status == IncidentStatus.DONE or (
                parsed_args.data.get('state') == 'closed'
                and 'category' in parsed_args.data):

            category = parsed_args.data.get('category').replace(' ', '_').lower() \
                if 'category' in parsed_args.data else None
            if category in POSSIBLE_CATEGORIES_TO_MIRROR_OUT:

                try:
                    demisto.debug(
                        f'Sending incident with remote ID {parsed_args.remote_incident_id} to remote system.'
                    )
                    result = client.update_incident_state(
                        inc_id=parsed_args.remote_incident_id,
                        category=category)
                    demisto.debug(
                        f'Incident updated successfully. Result: {result}')

                except Exception as e:
                    demisto.error(
                        f"Error in Saas Security outgoing mirror for incident {parsed_args.remote_incident_id} \n"
                        f"Error message: {str(e)}")
            else:
                demisto.debug(
                    f'The value of category {parsed_args.data.get("category")} is invalid.'
                    f' The category can be one of the following {POSSIBLE_CATEGORIES_TO_MIRROR_OUT}.'
                )
        else:
            demisto.debug(
                'Skipping updating the remote incident since the incident is not closed. '
                'Could not update the category for open incident due to an API limitation.'
            )
    else:
        demisto.debug(
            f'Skipping updating remote incident fields [{parsed_args.remote_incident_id}] '
            f'as it is not new nor changed.')

    return parsed_args.remote_incident_id
Ejemplo n.º 55
0
    def http_request(
            self, *args, resp_type='json', headers=None,
            return_empty_response=False, scope: Optional[str] = None,
            resource: str = '', **kwargs):
        """
        Overrides Base client request function, retrieves and adds to headers access token before sending the request.

        Args:
            resp_type: Type of response to return. will be ignored if `return_empty_response` is True.
            headers: Headers to add to the request.
            return_empty_response: Return the response itself if the return_code is 206.
            scope: A scope to request. Currently will work only with self-deployed app.
            resource (str): The resource identifier for which the generated token will have access to.
        Returns:
            Response from api according to resp_type. The default is `json` (dict or list).
        """
        if 'ok_codes' not in kwargs and not self._ok_codes:
            kwargs['ok_codes'] = (200, 201, 202, 204, 206, 404)
        token = self.get_access_token(resource=resource, scope=scope)
        default_headers = {
            'Authorization': f'Bearer {token}',
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        }

        if headers:
            default_headers.update(headers)

        if self.timeout:
            kwargs['timeout'] = self.timeout

        response = super()._http_request(  # type: ignore[misc]
            *args, resp_type="response", headers=default_headers, **kwargs)

        # 206 indicates Partial Content, reason will be in the warning header.
        # In that case, logs with the warning header will be written.
        if response.status_code == 206:
            demisto.debug(str(response.headers))
        is_response_empty_and_successful = (response.status_code == 204)
        if is_response_empty_and_successful and return_empty_response:
            return response

        # Handle 404 errors instead of raising them as exceptions:
        if response.status_code == 404:
            try:
                error_message = response.json()
            except Exception:
                error_message = 'Not Found - 404 Response'
            raise NotFoundError(error_message)

        try:
            if resp_type == 'json':
                return response.json()
            if resp_type == 'text':
                return response.text
            if resp_type == 'content':
                return response.content
            if resp_type == 'xml':
                ET.parse(response.text)
            return response
        except ValueError as exception:
            raise DemistoException('Failed to parse json object from response: {}'.format(response.content), exception)
Ejemplo n.º 56
0
def run_long_running(params, is_test=False):
    """
    Start the long running server
    :param params: Demisto params
    :param is_test: Indicates whether it's test-module run or regular run
    :return: None
    """
    certificate: str = params.get('certificate', '')
    private_key: str = params.get('key', '')

    certificate_path = str()
    private_key_path = str()

    try:
        port = get_params_port(params)
        ssl_args = dict()

        if (certificate and not private_key) or (private_key
                                                 and not certificate):
            raise DemistoException(
                'If using HTTPS connection, both certificate and private key should be provided.'
            )

        if certificate and private_key:
            certificate_file = NamedTemporaryFile(delete=False)
            certificate_path = certificate_file.name
            certificate_file.write(bytes(certificate, 'utf-8'))
            certificate_file.close()

            private_key_file = NamedTemporaryFile(delete=False)
            private_key_path = private_key_file.name
            private_key_file.write(bytes(private_key, 'utf-8'))
            private_key_file.close()
            context = SSLContext(PROTOCOL_TLSv1_2)
            context.load_cert_chain(certificate_path, private_key_path)
            ssl_args['ssl_context'] = context
            demisto.debug('Starting HTTPS Server')
        else:
            demisto.debug('Starting HTTP Server')

        server = WSGIServer(('0.0.0.0', port),
                            APP,
                            **ssl_args,
                            log=DEMISTO_LOGGER)
        if is_test:
            server_process = Process(target=server.serve_forever)
            server_process.start()
            time.sleep(5)
            server_process.terminate()
        else:
            server.serve_forever()
    except SSLError as e:
        ssl_err_message = f'Failed to validate certificate and/or private key: {str(e)}'
        demisto.error(ssl_err_message)
        raise ValueError(ssl_err_message)
    except Exception as e:
        demisto.error(f'An error occurred in long running loop: {str(e)}')
        raise ValueError(str(e))
    finally:
        if certificate_path:
            os.unlink(certificate_path)
        if private_key_path:
            os.unlink(private_key_path)
Ejemplo n.º 57
0
def main():
    sql_loggers: list = []  # saves the debug loggers
    try:
        logging.captureWarnings(True)
        for lgr_name in SQL_LOGGERS:
            lgr = logging.getLogger(lgr_name)
            level = logging.ERROR
            if is_debug_mode():
                level = logging.DEBUG
                sql_loggers.append(
                    lgr)  # in debug mode we save the logger to revert back
                demisto.debug(
                    f'setting {logging.getLevelName(level)} for logger: {repr(lgr)}'
                )
            lgr.setLevel(level)
        params = demisto.params()
        dialect = params.get('dialect')
        port = params.get('port')
        if not port:
            port = generate_default_port_by_dialect(dialect)
        user = params.get("credentials").get("identifier")
        password = params.get("credentials").get("password")
        host = params.get('host')
        database = params.get('dbname')
        ssl_connect = params.get('ssl_connect')
        connect_parameters = params.get('connect_parameters')
        use_pool = params.get('use_pool', False)
        pool_ttl = int(params.get('pool_ttl') or DEFAULT_POOL_TTL)
        if pool_ttl <= 0:
            pool_ttl = DEFAULT_POOL_TTL
        command = demisto.command()
        LOG(f'Command being called in SQL is: {command}')
        client = Client(dialect=dialect,
                        host=host,
                        username=user,
                        password=password,
                        port=port,
                        database=database,
                        connect_parameters=connect_parameters,
                        ssl_connect=ssl_connect,
                        use_pool=use_pool,
                        pool_ttl=pool_ttl)
        commands: Dict[str,
                       Callable[[Client, Dict[str, str], str],
                                Tuple[str, Dict[Any, Any], List[Any]]]] = {
                                    'test-module': test_module,
                                    'query': sql_query_execute,
                                    'pgsql-query': sql_query_execute,
                                    'sql-command': sql_query_execute
                                }
        if command in commands:
            return_outputs(*commands[command](client, demisto.args(), command))
        else:
            raise NotImplementedError(
                f'{command} is not an existing Generic SQL command')
    except Exception as err:
        return_error(
            f'Unexpected error: {str(err)} \nquery: {demisto.args().get("query")} \n{traceback.format_exc()}'
        )
    finally:
        try:
            if client.connection:
                client.connection.close()
        except Exception as ex:
            demisto.error(f'Failed closing connection: {str(ex)}')
        if sql_loggers:
            for lgr in sql_loggers:
                demisto.debug(f'setting back ERROR for logger: {repr(lgr)}')
                lgr.setLevel(logging.ERROR)
Ejemplo n.º 58
0
def main() -> None:
    """main function, parses params and runs command functions

    :return:
    :rtype:
    """

    instance = demisto.params().get('instance')
    username = demisto.params().get('username')
    password = demisto.params().get('password')
    property_name = demisto.params().get('property_name')
    property_value = demisto.params().get('property_value')
    base_url = demisto.params().get('url')
    max_fetch = demisto.params().get('max_fetch', 20)

    # if your Client class inherits from BaseClient, SSL verification is
    # handled out of the box by it, just pass ``verify_certificate`` to
    # the Client constructor
    verify_certificate = not demisto.params().get('insecure', False)

    # How much time before the first fetch to retrieve incidents
    first_fetch_time = arg_to_timestamp(
        arg=demisto.params().get('first_fetch', '3 days'),
        arg_name='First fetch time',
        required=True
    )
    # Using assert as a type guard (since first_fetch_time is always an int when required=True)
    assert isinstance(first_fetch_time, int)

    # if your Client class inherits from BaseClient, system proxy is handled
    # out of the box by it, just pass ``proxy`` to the Client constructor
    proxy = demisto.params().get('proxy', False)

    # INTEGRATION DEVELOPER TIP
    # You can use functions such as ``demisto.debug()``, ``demisto.info()``,
    # etc. to print information in the XSOAR server log. You can set the log
    # level on the server configuration
    # See: https://xsoar.pan.dev/docs/integrations/code-conventions#logging

    demisto.debug(f'Command being called is {demisto.command()}')
    try:

        to_xm_client = Client(
            base_url=base_url,
            verify=verify_certificate,
            auth=(username, password),
            proxy=proxy)

        from_xm_client = Client(
            base_url="https://" + instance,
            verify=verify_certificate,
            auth=(username, password),
            proxy=proxy)

        if demisto.command() == 'xm-trigger-workflow':
            return_results(xm_trigger_workflow_command(
                to_xm_client,
                demisto.args().get('recipients'),
                demisto.args().get('subject'),
                demisto.args().get('body'),
                demisto.args().get('incident_id'),
                demisto.args().get('close_task_id')
            ))
        elif demisto.command() == 'fetch-incidents':
            # Set and define the fetch incidents command to run after activated via integration settings.
            alert_status = demisto.params().get('status', None)
            priority = demisto.params().get('priority', None)

            next_run, incidents = fetch_incidents(
                client=from_xm_client,
                last_run=demisto.getLastRun(),  # getLastRun() gets the last run dict
                first_fetch_time=first_fetch_time,
                max_fetch=max_fetch,
                alert_status=alert_status,
                priority=priority,
                property_name=property_name,
                property_value=property_value
            )

            # saves next_run for the time fetch-incidents is invoked
            demisto.setLastRun(next_run)
            # fetch-incidents calls ``demisto.incidents()`` to provide the list
            # of incidents to crate
            demisto.incidents(incidents)
        elif demisto.command() == 'xm-get-events':
            return_results(xm_get_events_command(
                client=from_xm_client,
                request_id=demisto.args().get('request_id'),
                status=demisto.args().get('status'),
                priority=demisto.args().get('priority'),
                from_time=demisto.args().get('from'),
                to_time=demisto.args().get('to'),
                workflow=demisto.args().get('workflow'),
                form=demisto.args().get('form'),
                property_name=demisto.args().get('property_name'),
                property_value=demisto.args().get('property_value')
            ))
        elif demisto.command() == 'xm-get-event':
            return_results(xm_get_event_command(
                client=from_xm_client,
                event_id=demisto.args().get('event_id')
            ))
        elif demisto.command() == 'test-module':
            return_results(test_module(
                from_xm=from_xm_client,
                to_xm=to_xm_client,
                user=username,
                max_fetch=max_fetch
            ))

    # Log exceptions and return errors
    except Exception as e:
        demisto.error(traceback.format_exc())  # print the traceback
        return_error(f'Failed to execute {demisto.command()} command.\nError:\n{str(e)}')
Ejemplo n.º 59
0
def get_entries_command():
    resource_id = demisto.args().get('resourceId')
    entry_filter = demisto.args().get('entryFilter')

    query_path = 'www/manager-service/services/ActiveListService/'
    body = REQ_SOAP_BODY(function='getEntries',
                         auth_token=AUTH_TOKEN,
                         resource_id=resource_id,
                         entryList=None)

    res = send_request(query_path, body=body)

    if not res.ok:
        demisto.debug(res.text)
        return_error(
            "Failed to get entries:\nResource ID: {}\nStatus Code: {}\nRequest Body: {}\nResponse: {}"
            .format(resource_id, res.status_code, body, res.text))

    res_json = json.loads(xml2json((res.text).encode('utf-8')))
    raw_entries = demisto.get(res_json,
                              'Envelope.Body.getEntriesResponse.return')

    # retrieve columns
    cols = demisto.get(raw_entries, 'columns')
    if cols:
        hr_columns = tableToMarkdown(
            name='', headers=['Columns'], t=cols,
            removeNull=True) if cols else 'Active list has no columns'
        contents = cols
        return_outputs(readable_output=hr_columns,
                       outputs={},
                       raw_response=contents)

    if 'entryList' in raw_entries:
        entry_list = raw_entries['entryList'] if isinstance(
            raw_entries['entryList'], list) else [raw_entries['entryList']]
        entry_list = [
            (d['entry'] if not isinstance(d['entry'], STRING_TYPES) else
             (d['entry'], )) for d in entry_list if 'entry' in d
        ]
        keys = raw_entries.get('columns')
        entries = [dict(zip(keys, values)) for values in entry_list]

        # if the user wants only entries that contain certain 'field:value' sets (filters)
        # e.g., "name:myName,eventId:0,:ValueInUnknownField"
        # if the key is empty, search in every key
        filtered = entries
        if entry_filter:
            for f in entry_filter.split(','):
                k, v = f.split(':')
                filtered = [
                    entry for entry in filtered
                    if ((entry.get(k) == v) if k else (v in entry.values()))
                ]

        contents = decode_arcsight_output(filtered)
        ActiveListContext = {
            'ResourceID': resource_id,
            'Entries': contents,
        }
        outputs = {
            'ArcSightESM.ActiveList.{id}'.format(id=resource_id):
            contents,
            'ArcSightESM.ActiveList(val.ResourceID===obj.ResourceID)':
            ActiveListContext
        }
        human_readable = tableToMarkdown(
            name='Active List entries: {}'.format(resource_id),
            t=filtered,
            removeNull=True)
        return_outputs(readable_output=human_readable,
                       outputs=outputs,
                       raw_response=contents)

    else:
        demisto.results('Active List has no entries')
Ejemplo n.º 60
0
def get_content_modules(content_tmp_dir: str, verify_ssl: bool = True) -> None:
    """Copies the required content modules for linting from the cached dir
    The cached dir is updated once a day

    Args:
         content_tmp_dir (str): The content tmp dir to copy the content modules to
         verify_ssl (bool): Whether to verify SSL
    """
    modules = [
        {
            'file': 'CommonServerPython.py',
            'github_url': 'https://raw.githubusercontent.com/demisto/content/master/Packs/Base/Scripts'
                          '/CommonServerPython/CommonServerPython.py',
            'content_path': 'Packs/Base/Scripts/CommonServerPython',
        },
        {
            'file': 'CommonServerPowerShell.ps1',
            'github_url': 'https://raw.githubusercontent.com/demisto/content/master/Packs/Base/Scripts'
                          '/CommonServerPowerShell/CommonServerPowerShell.ps1',
            'content_path': 'Packs/Base/Scripts/CommonServerPowerShell',
        },
        {
            'file': 'demistomock.py',
            'github_url': 'https://raw.githubusercontent.com/demisto/content/master/Tests/demistomock/demistomock.py',
            'content_path': 'Tests/demistomock',
        },
        {
            'file': 'demistomock.ps1',
            'github_url': 'https://raw.githubusercontent.com/demisto/content/master/Tests/demistomock/demistomock.ps1',
            'content_path': 'Tests/demistomock',
        },
        {
            'file': 'tox.ini',
            'github_url': 'https://raw.githubusercontent.com/demisto/content/master/tox.ini',
            'content_path': '.'
        },
        {
            'file': 'conftest.py',
            'github_url': 'https://raw.githubusercontent.com/demisto/content/master/Tests/scripts/dev_envs/pytest'
                          '/conftest.py',
            'content_path': 'Tests/scripts/dev_envs/pytest'
        },

    ]
    for module in modules:
        content_path = os.path.join(content_tmp_dir, module['content_path'])
        os.makedirs(content_path, exist_ok=True)
        try:
            cached_module_path = os.path.join(CACHED_MODULES_DIR, module['file'])
            fname = Path(cached_module_path)
            modified_time = datetime.fromtimestamp(fname.stat().st_mtime) if os.path.isfile(cached_module_path) \
                else datetime(1970, 1, 1)
            if modified_time + timedelta(days=1) < datetime.utcnow():
                demisto.debug(f'Downloading {module["file"]} from git')
                res = requests.get(module['github_url'], verify=verify_ssl, timeout=10)
                res.raise_for_status()
                with open(cached_module_path, 'wb') as f:
                    f.write(res.content)
            demisto.debug(f'Copying from {cached_module_path} to {content_path}')
            copy(cached_module_path, content_path)
        except Exception as e:
            fallback_path = f'/home/demisto/{module["file"]}'
            demisto.debug(f'Failed downloading content module {module["github_url"]} - {e}. '
                          f'Copying from {fallback_path}')
            copy(fallback_path, content_path)