Beispiel #1
0
    def run(self, params={}):

        domains = params.get("domains")
        if len(domains) == 1:
            domains = str(domains[0])

        try:
            remoteCategories = self.connection.investigate.categorization(
                domains, labels=True)
        except Exception as e:
            raise PluginException(preset=PluginException.Preset.UNKNOWN,
                                  data=e)

        categories = []
        for key, value in remoteCategories.items():
            categories.append({
                "name":
                key,
                "status":
                value.get("status"),
                "security_categories":
                value.get("security_categories"),
                "content_categories":
                value.get("content_categories"),
            })

        return {"categories": categories}
    def run(self, params={}):
        """Run action"""
        opts = params.get(Input.OPTIONS) or {}
        push_info = opts.get("pushinfo")

        if push_info:
            push_info = urllib.parse.urlencode(push_info)

        user_id = None
        if params.get(Input.USER_ID):
            user_id = params.get(Input.USER_ID)

        username = None
        if params.get(Input.USERNAME):
            username = params.get(Input.USERNAME)

        if (username and user_id) or (user_id is None and username is None):
            raise PluginException(
                cause="Wrong input",
                assistance="Only user_id or username should be used. Not both."
            )

        response = self.connection.auth_api.auth(
            factor=params[Input.FACTOR],
            username=username,
            user_id=user_id,
            ipaddr=params.get(Input.IPADDR),
            async_txn=params.get(Input.ASYNC),
            type=opts.get("type"),
            display_username=username,
            pushinfo=push_info,
            device=params.get(Input.DEVICE),
            passcode=opts.get("passcode"),
        )
        return response
Beispiel #3
0
def extract_json_data(response: requests.Response) -> Dict:
    try:
        dct = response.json()
    except json.decoder.JSONDecodeError:
        raise PluginException(preset=PluginException.Preset.INVALID_JSON,
                              data=response.text)
    return dct
    def dn_escape_and_split(dn):
        """
        This method will split a dn into it's component peaces and then escape the needed characters
        :param dn:
        :return: Will return a list of the dn component peaces
        """
        dn_list = re.split(r',..=', dn)
        attribute = re.findall(r',..=', dn)

        # Ensure that special characters are escaped
        character_list = ['\\', ',', '#', '+', '<', '>', ';', '"', '/']
        for idx, value in enumerate(dn_list):
            for escaped_char in character_list:
                if f'\{escaped_char}' not in value:
                    dn_list[idx] = dn_list[idx].replace(
                        escaped_char, f'\{escaped_char}')

        # Re add the removed ,..= to temp  list strings then remove the unneeded comma
        try:
            for idx, value in enumerate(attribute):
                dn_list[idx + 1] = f'{value}{dn_list[idx+1]}'[1:]
        except PluginException as e:
            raise PluginException(
                cause='The input DN was invalid. ',
                assistance='Please double check input. Input was:{dn}') from e
        return dn_list
Beispiel #5
0
    def run(self, params={}):
        try:
            self.connection.bucket_session.headers.update(
                {"Content-Type": "application/json"})
            user = self.connection.bucket_session.get(
                f"{self.connection.base_api}/users/{params.get(Input.USERNAME)}"
            )
            user_obj = user.json()
            if user.status_code == 200:
                user_info = helpers.clean_json({
                    "username":
                    user_obj["username"]
                    if "username" in user_obj else params.get(Input.USERNAME),
                    "url":
                    "https://bitbucket.org/" + params.get(Input.USERNAME),
                    "display name":
                    user_obj["display_name"]
                    if "display_name" in user_obj else "",
                    "website":
                    user_obj["website"] if "website" in user_obj else "",
                    "location":
                    user_obj["location"] if "location" in user_obj else "",
                })
                return {Output.USER: user_info}

            return {"error": user_obj["error"]["message"]}
        except requests.exceptions.RequestException as e:
            raise PluginException(cause="User repository error", data=e)
Beispiel #6
0
    def run(self, params={}):
        policy_name = params.get(Input.ACCESS_POLICY)
        rule_name = params.get(Input.RULE_NAME)

        with fmcapi.FMC(host=self.connection.host,
                        username=self.connection.username,
                        password=self.connection.password,
                        autodeploy=True,
                        limit=10) as fmc1:
            urls = {'objects': []}
            for url in params.get(Input.URL_OBJECTS):
                if len(url['url']) > 400:
                    raise PluginException(
                        cause='URL exceeds max length of 400.',
                        assistance='Please shorten the URL or try another.')

                url_id = self.make_url_object(fmc=fmc1,
                                              name=url['name'],
                                              fqdn=url['url'])
                urls['objects'].append({
                    'type': 'URL',
                    'id': url_id,
                    'name': url['name']
                })
            policy = self.make_policy(fmc=fmc1, policy_name=policy_name)
            acr_id = self.make_rule(fmc=fmc1,
                                    policy=policy,
                                    rule_name=rule_name,
                                    urls=urls)

        return {Output.SUCCESS: True}
Beispiel #7
0
    def op(self, cmd: str) -> dict:
        querystring = {"type": "op", "key": self.key, "cmd": cmd}

        response = self.session.get(self.url,
                                    params=querystring,
                                    verify=self.verify_cert)
        try:
            output = xmltodict.parse(response.text)
        except TypeError:
            raise ServerException(
                cause='The response from PAN-OS was not the correct data type.',
                assistance='Contact support for help.',
                data=response.text)
        except SyntaxError:
            raise ServerException(
                cause='The response from PAN-OS was malformed.',
                assistance='Contact support for help.',
                data=response.text)
        except BaseException as e:
            raise PluginException(
                cause=
                'An unknown error occurred when parsing the PAN-OS response.',
                assistance='Contact support for help.',
                data=f'{response.text}, error {e}')

        if output['response']['@status'] == 'error':
            error = output['response']['msg']
            error = json.dumps(error)
            raise ServerException(
                cause='PAN-OS returned an error in response to the request.',
                assistance=
                'Double that check inputs are valid. Contact support if this issue persists.',
                data=error)
        return output
    def run(self, params={}):
        # Generate unique identifier for report names
        identifier = uuid.uuid4()
        scan_id = params.get(Input.SCAN_ID)

        # Report to collect site ID and asset IDs of scan
        report_payload = {
            'name': f"Rapid7-ScanAssets-InsightConnect-{identifier}",
            'format': 'sql-query',
            'query': 'SELECT site_id, asset_id '
                     'FROM dim_site_scan AS dss '
                     'JOIN dim_asset_scan AS das ON das.scan_id = dss.scan_id',
            'version': '2.3.0',
            'scope': {'scan': scan_id}
        }

        report_contents = util.adhoc_sql_report(self.connection, self.logger, report_payload)
        self.logger.info(f"Processing Assets of Scan ID {scan_id}")

        # Extract site ID and asset IDs
        scan_asset_ids = set()
        scan_site_id = None

        try:
            csv_report = csv.DictReader(io.StringIO(report_contents['raw']))
        except Exception as e:
            raise PluginException(cause=f"Error: Failed to process query response for assets returned for "
                                        f"scan ID {scan_id}.",
                                  assistance=f"Exception returned was {e}")

        for row in csv_report:
            scan_asset_ids.add(int(row["asset_id"]))

            # Assign site ID for scan
            if scan_site_id is None:
                scan_site_id = row["site_id"]

        # Get assets of site of scan
        resource_helper = ResourceRequests(self.connection.session, self.logger)
        search_criteria = {
            "filters": [
                {
                    "field": "site-id",
                    "operator": "in",
                    "values": [scan_site_id]
                }
            ],
            "match": "all"
        }
        self.logger.info("Performing filtered asset search with criteria %s" % search_criteria)
        endpoint = endpoints.Asset.search(self.connection.console_url)

        site_assets = resource_helper.paged_resource_request(endpoint=endpoint,
                                                             method='post',
                                                             payload=search_criteria)

        # Filter assets to specific scan assets
        filtered_assets = [asset for asset in site_assets if asset["id"] in scan_asset_ids]

        return {Output.ASSETS: filtered_assets}
Beispiel #9
0
    def get_users_in_group(self, api_url):
        returned_data = []
        response = self.connection.session.get(api_url)
        next_link = None
        links = response.headers.get("Link", "").split(", ")
        for link in links:
            if 'rel="next"' in link:
                matched_link = re.match("<(.*?)>", link)
                if matched_link:
                    next_link = matched_link.group(1)

        if next_link:
            returned_data.extend(self.get_users_in_group(next_link))

        try:
            data = response.json()
        except ValueError:
            raise PluginException(
                cause="Returned data was not in JSON format.",
                assistance="Double-check that group ID's are all valid.",
                data=response.text,
            )

        helpers.raise_based_on_error_code(response)
        returned_data.extend(komand.helper.clean(data))
        return returned_data
    def run(self, params={}):
        """Run the trigger"""
        self.jql = params.get(Input.JQL) or ''
        self.get_attachments = params.get(Input.GET_ATTACHMENTS, False)
        self.project = params.get(Input.PROJECT)

        valid_project = look_up_project(self.project, self.connection.client)
        if not valid_project:
            raise PluginException(
                cause=f"Project {self.project} does not exist or the user does not have permission to access the project.",
                assistance='Please provide a valid project ID/name or make sure the project is accessible to the user.')

        if self.project:
            if self.jql:
                self.jql = 'project=' + self.project + ' and ' + self.jql
            else:
                self.jql = 'project=' + self.project

        self.logger.info('Querying %s', self.jql)

        self.initialize()

        while True:
            self.poll()
            time.sleep(params.get(Input.POLL_TIMEOUT, 60))
    def run(self, params={}):
        try:
            domain = params.get(Input.DOMAIN).strip('https://').split('/')[0]
            comment = params.get(Input.COMMENT)
            fields = [
                "analystNotes",
                "counts",
                "enterpriseLists",
                "entity",
                "intelCard",
                "metrics",
                "relatedEntities",
                "risk",
                "sightings",
                "threatLists",
                "timestamps"
            ]

            if not comment:
                comment = None
            domain_report = self.connection.client.lookup_domain(domain, fields=fields, comment=comment)
            if domain_report.get("warnings", False):
                self.logger.warning(f"Warning: {domain_report.get('warnings')}")
            return komand.helper.clean(domain_report["data"])
        except Exception as e:
            PluginException(cause=f"Error: {e}", assistance="Review exception")
Beispiel #12
0
    def _create_user(self, params, passwd):
        account_enabled = params.get(Input.ACCOUNT_ENABLED, True)
        display_name = params.get(Input.DISPLAY_NAME)
        mail_nickname = params.get(Input.MAIL_NICKNAME, display_name)
        user_principal_name = params.get(Input.USER_PRINCIPAL_NAME)

        user = {
            "accountEnabled": account_enabled,
            "displayName": display_name,
            "mailNickname": mail_nickname,
            "userPrincipalName": user_principal_name,
            "passwordProfile": {
                "forceChangePasswordNextSignIn": True,
                "password": passwd
            },
        }

        headers = self.connection.get_headers(self.connection.get_auth_token())
        endpoint_formatted = f"https://graph.microsoft.com/v1.0/{self.connection.tenant}/users/"
        result = requests.post(endpoint_formatted, headers=headers, json=user)

        try:
            result.raise_for_status()
        except Exception as e:
            raise PluginException(preset=PluginException.Preset.UNKNOWN,
                                  data=result.text) from e

        # 201 Created is the response according to MS.
        # https://docs.microsoft.com/en-us/graph/api/user-post-users?view=graph-rest-1.0&tabs=http#response-1
        return result.status_code == 201
    def run(self, params={}):
        with tempfile.TemporaryDirectory() as tempdir:
            chrome_options = Options()
            chrome_options.add_argument("--headless")
            chrome_options.add_argument("--window-size=%s" % self.WINDOW_SIZE)
            chrome_options.add_argument("--no-sandbox")
            chrome_options.add_argument("--disable-dev-shm-usage")
            chrome_options.add_argument("--disable-gpu")
            chrome_options.add_argument(f"--user-data-dir={tempdir}")
            chrome_options.binary_location = self.CHROME_PATH

            url = params.get(Input.URL, "")
            delay = params.get(Input.DELAY, 0)
            if not url.lower().startswith('http'):
                raise PluginException(
                    cause="Input Error:",
                    assistance="URLs need to start with 'http'")
            driver = webdriver.Chrome(executable_path=self.CHROMEDRIVER_PATH,
                                      options=chrome_options)
            driver.get(url)
            time.sleep(delay)
            full_page = params.get(Input.FULL_PAGE, False)
            if full_page:
                try:
                    body = driver.find_element_by_tag_name('body')
                    img_str = body.screenshot_as_base64
                except Exception:
                    img_str = self.screenshot_to_file(driver)
            else:
                img_str = self.screenshot_to_file(driver)
            driver.quit()
        return {Output.SCREENSHOT: img_str}
Beispiel #14
0
    def run(self, params={}):
        """TODO: Run action"""
        client = self.connection.client
        _file = io.BytesIO(base64.b64decode(params.get('file')))
        filename = params.get('filename')

        out = {}
        try:
            if filename:
                self.logger.info('Filename specified: %s', filename)
                out = client.submit_file(_file, filename)
            else:
                out = client.submit_file(_file)
            out['supported_file_type'] = True
        except pyldfire.WildFireException as e:
            if e.args and "Unsupport File type" in e.args[
                    0]:  # Yes, that's the error, not a typo
                out['supported_file_type'] = False
            else:
                raise PluginException(PluginException.Preset.UNKNOWN) from e

        if 'filename' not in out.keys():
            out['filename'] = 'Unknown'

        if 'url' not in out.keys():
            out['url'] = 'Unknown'

        return {'submission': komand.helper.clean(out)}
Beispiel #15
0
 def http_errors(self, response: dict, status_code: int) -> None:
     """
     Will look for and handle non 2XX status codes
     :param response: The JSON response from the API call
     :param status_code: The API calls status code
     """
     if status_code in self._STATUS_CODES:
         raise PluginException(
             cause=self._STATUS_CODES[status_code]["cause"],
             assistance=self._STATUS_CODES[status_code]["assistance"],
             data=f"Raw response data: {response}")
     if status_code not in range(200, 299):
         raise PluginException(
             cause="An undocumented response code was returned.",
             assistance="Contact support for assistance",
             data=f"Raw response data: {response}")
    def run(self, params={}):
        group_ids = params.get(Input.GROUP_ID)
        user_id = params.get(Input.USER_ID)

        self.logger.info(f"Getting user info: {user_id}")
        user_response = get_user_info(self.connection, user_id, self.logger)
        user_object = user_response.json()
        user = {
            "@odata.id":
            f"https://graph.microsoft.com/v1.0/{self.connection.tenant}/users/{user_object.get('id')}"
        }

        headers = self.connection.get_headers(self.connection.get_auth_token())

        for group_id in group_ids:
            add_to_group_endpoint = f"https://graph.microsoft.com/v1.0/{self.connection.tenant}/groups/{group_id}/members/$ref"
            result = requests.post(add_to_group_endpoint,
                                   json=user,
                                   headers=headers)
            if not result.status_code == 204:
                raise PluginException(
                    cause=
                    f"Add User to Group call returned an unexpected response: {result.status_code}",
                    assistance=
                    f"Check that the group id {group_id} and user id {user_id} are correct.",
                    data=result.text)
        return {Output.SUCCESS: True}
    def resource_request(self, endpoint: str, method: str = "get", params: dict = None, payload: dict = None) -> dict:
        """
        Sends a request to API with the provided endpoint and optional method/payload
        :param endpoint: Endpoint for the API call defined in endpoints.py
        :param method: HTTP method for the API request
        :param params: URL parameters to append to the request
        :param payload: JSON body for the API request if required
        :return: Dict containing the JSON response body
        """
        try:
            request_method = getattr(self.session, method.lower())

            if not params:
                params = {}
            if not payload:
                response = request_method(url=endpoint, params=params, verify=False)
            else:
                response = request_method(url=endpoint, params=params, json=payload, verify=False)
        except requests.RequestException as e:
            self.logger.error(e)
            raise

        if response.status_code in range(200, 299):
            resource = response.text
            return {"resource": resource, "status": response.status_code}
        else:
            try:
                error = response.json()["message"]
            except KeyError:
                self.logger.error(f"Code: {response.status_code}, message: {error}")
                error = "Unknown error occurred. Please contact support or try again later."

            status_code_message = self._ERRORS.get(response.status_code, self._ERRORS[000])
            self.logger.error(f"{status_code_message} ({response.status_code}): {error}")
            raise PluginException(f"InsightIDR returned a status code of {response.status_code}: {status_code_message}")
Beispiel #18
0
    def run(self, params={}):
        add = util.ExternalList()
        name = params.get("name")
        list_type = params.get("list_type")
        description = params.get("description")
        source = params.get("source")
        repeat = params.get("repeat")
        time = params.get("time")
        day = params.get("day")

        xpath = "/config/devices/entry/vsys/entry/external-list/entry[@name='{}']".format(
            name)
        element = add.element_for_create_external_list(
            self._LIST_TYPE_KEY[list_type],
            description,
            source,
            self._REPEAT_KEY[repeat],
            time,
            day.lower,
        )

        output = self.connection.request.set_(xpath=xpath, element=element)
        try:
            status = output["response"]["@status"]
            code = output["response"]["@code"]
            message = output["response"]["msg"]
            return {"status": status, "code": code, "message": message}
        except KeyError:
            raise PluginException(
                cause="The output did not contain expected keys.",
                assistance="Contact support for help.",
                data=output,
            )
Beispiel #19
0
    def run(self, params={}):
        query = params.get(Input.QUERY)
        log_set_name = params.get(Input.LOG_SET)
        timeout = params.get(Input.TIMEOUT)

        time_from_string = params.get(Input.TIME_FROM)
        relative_time_from = params.get(Input.RELATIVE_TIME)
        time_to_string = params.get(Input.TIME_TO)

        # Time To is optional, if not specified, time to is set to now
        time_from, time_to = parse_dates(time_from_string, time_to_string, relative_time_from)

        if time_from > time_to:
            raise PluginException(
                cause="Time To input was chronologically behind Time From.",
                assistance="Please edit the step so Time From is chronologically behind (in the past) relative to Time To.\n",
                data=f"\nTime From: {time_from}\nTime To:{time_to}",
            )

        log_set_id = self.get_log_set_id(log_set_name)

        # The IDR API will SOMETIMES return results immediately.
        # It will return results if it gets them. If not, we'll get a call back URL to work on
        callback_url, log_entries = self.maybe_get_log_entries(log_set_id, query, time_from, time_to)

        if not log_entries:
            log_entries = self.get_results_from_callback(callback_url, timeout)

        log_entries = komand.helper.clean(log_entries)

        for log_entry in log_entries:
            log_entry["message"] = json.loads(log_entry.get("message", "{}"))

        self.logger.info(f"Sending results to orchestrator.")
        return {Output.RESULTS: log_entries, Output.COUNT: len(log_entries)}
Beispiel #20
0
    def run(self, params={}):
        """Run the trigger"""
        # send a test event
        self.jql = params.get('jql') or ''
        self.get_attachments = params.get('get_attachments', False)
        self.project = params.get('project')

        # Check if project exists
        valid_project = look_up_project(self.project, self.connection.client)
        if not valid_project:
            raise PluginException(
                cause=
                f"Project {self.project} does not exist or user don't have permission to access the project.",
                assistance=
                'Please provide a valid project ID/name or make sure project is accessible to user.'
            )

        if self.project:
            if self.jql:
                self.jql = 'project=' + self.project + ' and ' + self.jql
            else:
                self.jql = 'project=' + self.project

        self.logger.info('Querying %s', self.jql)

        self.initialize()

        while True:
            self.poll()
            time.sleep(60)
 def host_formatter(self, host: str) -> str:
     """
     Formats The host as needed for the connection
     """
     colons = host.count(":")
     if colons > 0:
         host = host.split(":")
         if colons == 1:
             if host[1].find("//") != -1:
                 host = host[1][2:]
             else:
                 self.logger.info(
                     "Port was provided in hostname, using value from Port field instead"
                 )
                 host = host[0]
         elif colons == 2:
             self.logger.info(
                 "Port was provided in hostname, using value from Port field instead"
             )
             host = host[1]
             if host.find("//") != -1:
                 host = host[2:]
         else:
             raise PluginException(
                 cause=
                 f"There are too many colons ({colons}) in the host name ({host}).",
                 assistance="Check that the host name is correct",
                 data=host,
             )
     backslash = host.find("/")
     if backslash != -1:
         host = host[:backslash]
     return host
Beispiel #22
0
    def run(self, params={}):
        policy_name = params.get(Input.ACCESS_POLICY)
        rule_name = params.get(Input.RULE_NAME)

        with fmcapi.FMC(
            host=self.connection.host,
            username=self.connection.username,
            password=self.connection.password,
            autodeploy=True,
            limit=10,
        ) as fmc1:
            urls = {"objects": []}
            for url in params.get(Input.URL_OBJECTS):
                if len(url["url"]) > 400:
                    raise PluginException(
                        cause="URL exceeds max length of 400.",
                        assistance="Please shorten the URL or try another.",
                    )

                url_id = self.make_url_object(fmc=fmc1, name=url["name"], fqdn=url["url"])
                urls["objects"].append({"type": "URL", "id": url_id, "name": url["name"]})
            policy = self.make_policy(fmc=fmc1, policy_name=policy_name)
            acr_id = self.make_rule(fmc=fmc1, policy=policy, rule_name=rule_name, urls=urls)

        return {Output.SUCCESS: True}
Beispiel #23
0
    def run(self, params={}):
        headers = {'Content-Type': 'application/json'}
        params['token'] = self.connection.token

        priorities = {
                        'Lowest': -2,
                        'Low': -1,
                        'Normal': 0,
                        'High': 1,
                        'Emergency': 2
                        }
        params['priority'] = priorities[params.get('priority','Normal')]

        if(params.get('priority', 0) == 2):
            if(params.get('retry', 0) < 30):
                self.logger.info("SendMessage: retry interval too short - setting to 30 seconds")
                params['retry'] = 30
            if(params.get('expire', 0) == 0):
                self.logger.info("SendMessage: emergency priority set but expiry not defined, setting expiry to 1 hour")
                params['expiry'] = 3600
        else:
            params.pop('retry', None)
            params.pop('expire', None)

        if(params.get('timestamp', '000').startswith("000")):
            params.pop('timestamp', None)

        res = requests.post(self.connection.api_url, data=json.dumps(params), headers=headers)
        if(res.status_code != 200):
            raise PluginException(preset=PluginException.Preset.UNKNOWN)
        try:
            return res.json()
        except json.decoder.JSONDecodeError:
            raise ConnectionTestException(preset=PluginException.Preset.INVALID_JSON, data=res.text)
    def run(self, params={}):
        url = f"https://{self.connection.server_ip}:{self.connection.server_port}/web_api/show-access-rulebase"
        headers = self.connection.get_headers()
        payload = {
            "offset": 0,
            "limit": params.get(Input.LIMIT, 1),
            "name": params.get(Input.LAYER_NAME),
            "details-level": "full",
            "use-object-dictionary": True
        }

        result = requests.post(url,
                               headers=headers,
                               json=payload,
                               verify=self.connection.ssl_verify)

        try:
            result.raise_for_status()
        except Exception as e:
            raise PluginException(
                cause=f"Show Access Rules from {url} failed.\n",
                assistance=f"{result.text}\n",
                data=e)

        return {Output.ACCESS_RULES: komand.helper.clean(result.json())}
Beispiel #25
0
    def run(self, params={}):
        payload_notes = ''
        user_notes = params.get(Input.NOTES)
        if user_notes:
            payload_notes = user_notes
        payload_scan_action = params.get(Input.SCAN_ACTION)
        payload_filename = params.get(Input.FILE).get('filename')
        payload_file_contents = params.get(Input.FILE).get('content')

        payload = {
            "file_name": payload_filename,
            "file_content_base64_string": payload_file_contents,
            "file_scan_action": payload_scan_action,
            "note": payload_notes
        }
        json_payload = json.dumps(payload)
        self.connection.create_jwt_token(self.api_path, self.api_http_method, json_payload)
        request_url = self.connection.url + self.api_path

        response = None
        try:
            response = requests.put(request_url, headers=self.connection.header_dict, data=json_payload, verify=False)
            response.raise_for_status()
            return {Output.SUCCESS: response is not None}
        except RequestException as rex:
            if response:
                self.logger.error(f"Received status code: {response.status_code}")
                self.logger.error(f"Response was: {response.text}")
            raise PluginException(assistance="Please verify the connection details and input data.",
                                  cause=f"Error processing the Apex request: {rex}")

        return {Output.SUCCESS : False}
Beispiel #26
0
    def run(self, params={}):
        table = "sys_journal_field"
        url = f'{self.connection.table_url}{table}'
        system_id = params.get(Input.SYSTEM_ID)
        type_ = "work_notes" if params.get(Input.TYPE) == "work notes" else params.get(Input.TYPE)
        fields = "sys_id,sys_created_on,name,element_id,sys_tags,value,sys_created_by,element"

        if type_ == "all":
            url = f'{url}?sysparm_query=element_id={system_id}&sysparm_fields={fields}'
        elif type_ == "comments":
            url = f'{url}?sysparm_query=element_id={system_id}^element={type_}&sysparm_fields={fields}'
        elif type_ == "work_notes":
            url = f'{url}?sysparm_query=element_id={system_id}^element={type_}&sysparm_fields={fields}'

        method = "get"

        response = self.connection.request.make_request(url, method)

        try:
            result = response["resource"].get("result")
        except KeyError as e:
            raise PluginException(preset=PluginException.Preset.UNKNOWN,
                                  data=response.text) from e

        return {
            Output.INCIDENT_COMMENTS_WORKNOTES: result
        }
Beispiel #27
0
    def search(self, pattern, start=None, limit=None, include_category=None):
        '''Searches for domains that match a given pattern'''

        params = dict()

        if start is None:
            start = datetime.timedelta(days=30)

        if isinstance(start, datetime.timedelta):
            params['start'] = int(
                time.mktime(
                    (datetime.datetime.utcnow() - start).timetuple()) * 1000)
        elif isinstance(start, datetime.datetime):
            params['start'] = int(time.mktime(start.timetuple()) * 1000)
        else:
            raise PluginException(
                cause='Unable to retrieve domains for search.',
                assistance=Investigate.SEARCH_ERR)

        if limit is not None and isinstance(limit, int):
            params['limit'] = limit
        if include_category is not None and isinstance(include_category, bool):
            params['includeCategory'] = str(include_category).lower()

        uri = self._uris['search'].format(urllib.parse.quote_plus(pattern))

        return self.get_parse(uri, params)
Beispiel #28
0
    def run(self, params={}):
        min_time = params.get(Input.MINTIME, 1000000000000)

        auth_logs = []
        try:
            results = self.connection.admin_api.get_authentication_log(
                api_version=2,
                mintime=min_time,
                limit=str(self.PAGE_SIZE)
            )
            auth_logs.extend(results[self.AUTH_LOGS])

            total_objects_left = results[self.METADATA][self.TOTAL_OBJECTS] - self.PAGE_SIZE

            next_offset = results[self.METADATA][self.NEXT_OFFSET]
            while total_objects_left > 0:
                results = self.connection.admin_api.get_authentication_log(
                    api_version=2,
                    mintime=min_time,
                    limit=str(self.PAGE_SIZE),
                    next_offset=next_offset
                )

                next_offset = results[self.METADATA][self.NEXT_OFFSET]
                total_objects_left -= self.PAGE_SIZE
                auth_logs.extend(results[self.AUTH_LOGS])

            auth_logs = komand.helper.clean(auth_logs)
            return {Output.AUTHLOGS: auth_logs}
        except KeyError as e:
            raise PluginException(
                preset=PluginException.Preset.SERVER_ERROR,
                data=f"Error: API response was missing required fields necessary for proper functioning. {str(e)}"
            )
    def make_request(self,
                     endpoint,
                     method,
                     payload=None,
                     params=None,
                     content_type="application/json"):
        try:
            request_method = getattr(self.session, method.lower())

            headers = {
                "Content-Type": content_type,
                "Accept": "application/json"
            }

            if not params:
                params = {}
            response = request_method(url=endpoint,
                                      headers=headers,
                                      params=params,
                                      json=payload,
                                      verify=False)
        except requests.RequestException as e:
            self.logger.error(e)
            raise

        if response.status_code in range(200, 299):
            try:
                resource = None if response.status_code == 204 else response.json(
                )
            except json.decoder.JSONDecodeError:
                raise PluginException(
                    preset=PluginException.Preset.INVALID_JSON,
                    data=response.text)

            return {'resource': resource, 'status': response.status_code}
        else:
            try:
                error = response.json()
            except json.decoder.JSONDecodeError:
                raise PluginException(
                    preset=PluginException.Preset.INVALID_JSON,
                    data=response.text)

            raise PluginException(
                cause=f'Error in API request to ServiceNow. ',
                assistance=
                f'Status code: {response.status_code}, Error: {error}')
    def run(self, params={}):
        formatter = ADUtils()
        conn = self.connection.conn
        dn = params.get('distinguished_name')
        group_dn = params.get('group_dn')
        add_remove = params.get('add_remove')

        # Normalize dn
        dn = formatter.format_dn(dn)[0]
        dn = formatter.unescape_asterisk(dn)
        self.logger.info(f'Escaped DN {dn}')
        # Normalize group dn
        group_dn = formatter.format_dn(group_dn)[0]
        group_dn = formatter.unescape_asterisk(group_dn)
        self.logger.info(f'Escaped group DN {group_dn}')

        if add_remove == 'add':
            try:
                group = extend.ad_add_members_to_groups(conn, dn, group_dn)
            except LDAPInvalidDnError as e:
                raise PluginException(
                    cause=
                    'Either the user or group distinguished name was not found.',
                    assistance=
                    'Please check that the distinguished names are correct',
                    data=e)
        else:
            try:
                group = extend.ad_remove_members_from_groups(conn,
                                                             dn,
                                                             group_dn,
                                                             fix=True)
            except LDAPInvalidDnError as e:
                raise PluginException(
                    cause=
                    'Either the user or group distinguished name was not found.',
                    assistance=
                    'Please check that the distinguished names are correct',
                    data=e)

        if group is False:
            self.logger.error(
                'ModifyGroups: Unexpected result for group. Group was ' +
                str(group))
            raise PluginException(preset=PluginException.Preset.UNKNOWN)

        return {'success': group}