def set_last_contact_time(self, *args, **kwargs):
        """
        Restricts the devices that this query is performed on to the specified last contact time.

        Args:
            *args (list): Not used, retained for compatibility.
            **kwargs (dict): Keyword arguments to this function.  The critical ones are "start" (the start time),
                             "end" (the end time), and "range" (the range value).

        Returns:
            DeviceSearchQuery: This instance.

        Raises:
            ApiError: If an invalid combination of keyword parameters are specified.
        """
        if kwargs.get("start", None) and kwargs.get("end", None):
            if kwargs.get("range", None):
                raise ApiError(
                    "cannot specify range= in addition to start= and end=")
            stime = kwargs["start"]
            if not isinstance(stime, str):
                stime = stime.isoformat()
            etime = kwargs["end"]
            if not isinstance(etime, str):
                etime = etime.isoformat()
            self._time_filter = {"start": stime, "end": etime}
        elif kwargs.get("range", None):
            if kwargs.get("start", None) or kwargs.get("end", None):
                raise ApiError(
                    "cannot specify start= or end= in addition to range=")
            self._time_filter = {"range": kwargs["range"]}
        else:
            raise ApiError("must specify either start= and end= or range=")
        return self
Пример #2
0
    def _lr_post_command(self, data):
        retries = self.MAX_RETRY_COUNT

        if "name" in data and data["name"] not in self.session_data[
                "supported_commands"]:
            raise ApiError("Command {0} not supported by this device".format(
                data["name"]))

        while retries:
            try:
                data["session_id"] = self.session_id
                resp = self._cb.post_object(
                    "{cblr_base}/sessions/{0}/commands".format(
                        self.session_id, cblr_base=self.cblr_base), data)
            except ObjectNotFoundError as e:
                try:
                    error_message = json.loads(e.message)
                    if error_message["error_code"] == "NOT_FOUND":
                        self.session_id, self.session_data = \
                            self._cblr_manager._get_or_create_session(self.device_id)
                        retries -= 1
                        continue
                except Exception:
                    pass
                raise ApiError("Received 404 error from server: {0}".format(
                    e.message))
            else:
                return resp

        raise TimeoutError(
            message="Command {0} failed after {1} retries".format(
                data["name"], self.MAX_RETRY_COUNT))
Пример #3
0
    def set_create_time(self, *args, **kwargs):
        """
        Restricts the alerts that this query is performed on to the specified creation time.

        The time may either be specified as a start and end point or as a range.

        Args:
            *args (list): Not used.
            **kwargs (dict): Used to specify start= for start time, end= for end time, and range= for range.

        Returns:
            BaseAlertSearchQuery: This instance.
        """
        if kwargs.get("start", None) and kwargs.get("end", None):
            if kwargs.get("range", None):
                raise ApiError("cannot specify range= in addition to start= and end=")
            stime = kwargs["start"]
            if not isinstance(stime, str):
                stime = stime.isoformat()
            etime = kwargs["end"]
            if not isinstance(etime, str):
                etime = etime.isoformat()
            self._time_filters["create_time"] = {"start": stime, "end": etime}
        elif kwargs.get("range", None):
            if kwargs.get("start", None) or kwargs.get("end", None):
                raise ApiError("cannot specify start= or end= in addition to range=")
            self._time_filters["create_time"] = {"range": kwargs["range"]}
        else:
            raise ApiError("must specify either start= and end= or range=")
        return self
Пример #4
0
    def set_time_range(self, key, **kwargs):
        """
        Restricts the alerts that this query is performed on to the specified time range.

        The time may either be specified as a start and end point or as a range.

        Args:
            key (str): The key to use for criteria one of create_time,
                       first_event_time, last_event_time, or last_update_time
            **kwargs (dict): Used to specify start= for start time, end= for end time, and range= for range.

        Returns:
            BaseAlertSearchQuery: This instance.
        """
        if key not in ["create_time", "first_event_time", "last_event_time", "last_update_time"]:
            raise ApiError("key must be one of create_time, first_event_time, last_event_time, or last_update_time")
        if kwargs.get("start", None) and kwargs.get("end", None):
            if kwargs.get("range", None):
                raise ApiError("cannot specify range= in addition to start= and end=")
            stime = kwargs["start"]
            if not isinstance(stime, str):
                stime = stime.isoformat()
            etime = kwargs["end"]
            if not isinstance(etime, str):
                etime = etime.isoformat()
            self._time_filters[key] = {"start": stime, "end": etime}
        elif kwargs.get("range", None):
            if kwargs.get("start", None) or kwargs.get("end", None):
                raise ApiError("cannot specify start= or end= in addition to range=")
            self._time_filters[key] = {"range": kwargs["range"]}
        else:
            raise ApiError("must specify either start= and end= or range=")
        return self
Пример #5
0
    def create(cls, cb, template=None, **kwargs):
        """
        Returns either a new Grant, or a GrantBuilder to begin the process of creating a new grant.

        Args:
            cb (CBCloudAPI): A reference to the CBCloudAPI object.
            template (dict): Optional template to use for creating the grant object.
            kwargs (dict): Additional arguments to be used to specify the principal, if template is None.
                           The arguments to be used are 'org_key' and 'userid' for the two parts of the ID.

        Returns:
            Grant: The new grant object, if the template is specified.
            GrantBuilder: If template was None, returns a GrantBuilder object.  Call methods on it to set
                            up the new grant, and then call build() to create the new grant.

        Raises:
            ApiError: If the principal is inadequately specified (whether for the Grant or GrantBuilder).
        """
        if template:
            if not template.get('principal', None):
                raise ApiError('principal must be specified in Grant template')
            t = copy.deepcopy(template)
            grant = Grant(cb, t['principal'], t)
            grant._update_object()
            return grant
        if not all([key in kwargs for key in ['org_key', 'userid']]):
            raise ApiError(
                'orgid and userid must be specified as keyword arguments to create'
            )
        return Grant.GrantBuilder(
            cb, f"psc:user:{kwargs['org_key']}:{kwargs['userid']}")
    def set_rows(self, rows):
        """
        Sets the 'rows' query body parameter to the 'start search' API call, determining how many rows to request.

        Args:
            rows (int): How many rows to request.
        """
        if not isinstance(rows, int):
            raise ApiError(
                f"Rows must be an integer. {rows} is a {type(rows)}.")
        if rows > 10000:
            raise ApiError("Maximum allowed value for rows is 10000")
        super(EnrichedEventQuery, self).set_rows(rows)
        return self
Пример #7
0
    def change_role(self, role_urn, org=None):
        """
        Add the specified role to the user (either to the grant or the profiles).

        Args:
            role_urn (str): URN of the role to be added.
            org (str): If specified, only profiles that match this organization will have the role added.  Organization
                       may be specified as either an org key or a URN.

        Raises:
            ApiError: If the user is a "legacy" user that has no grant.
        """
        my_org = None if org is None else normalize_org(org)
        grant = self.grant()
        if grant:
            prof_list = grant.profiles_
            if len(prof_list) > 0:
                for profile in prof_list:
                    add_role = True
                    if my_org and my_org not in profile.allowed_orgs:
                        add_role = False
                    if add_role and role_urn not in profile.roles:
                        profile.roles += [role_urn]
                        grant.touch()
            elif role_urn not in grant.roles:
                grant.roles += [role_urn]
                grant.touch()
            grant.save()
        else:
            raise ApiError("legacy user has no grant")
    def download(self):
        """
        Uses the query parameters that have been set to download all device listings in CSV format.

        Example:
            >>> cb.select(Device).set_status(["ALL"]).download()

        Returns:
            str: The CSV raw data as returned from the server.

        Raises:
            ApiError: If status values have not been set before calling this function.
        """
        tmp = self._criteria.get("status", [])
        if not tmp:
            raise ApiError("at least one status must be specified to download")
        query_params = {"status": ",".join(tmp)}
        tmp = self._criteria.get("ad_group_id", [])
        if tmp:
            query_params["ad_group_id"] = ",".join([str(t) for t in tmp])
        tmp = self._criteria.get("policy_id", [])
        if tmp:
            query_params["policy_id"] = ",".join([str(t) for t in tmp])
        tmp = self._criteria.get("target_priority", [])
        if tmp:
            query_params["target_priority"] = ",".join(tmp)
        tmp = self._query_builder._collapse()
        if tmp:
            query_params["query_string"] = tmp
        if self._sortcriteria:
            query_params["sort_field"] = self._sortcriteria["field"]
            query_params["sort_order"] = self._sortcriteria["order"]
        url = self._build_url("/_search/download")
        return self._cb.get_raw_data(url, query_params)
    def get_vulnerability_summary(self, category=None):
        """
        Get the vulnerabilities associated with this device

        Args:
            category (string): (optional) vulnerabilty category (OS, APP)

        Returns:
            dict: summary for the vulnerabilities for this device
        """
        VALID_CATEGORY = ["OS", "APP"]

        query_params = {}

        url = '/vulnerability/assessment/api/v1/orgs/{}'

        if category and category not in VALID_CATEGORY:
            raise ApiError("Invalid category provided")
        elif category:
            query_params["category"] = category

        req_url = url.format(self._cb.credentials.org_key
                             ) + '/devices/{}/vulnerabilities/summary'.format(
                                 self.id)
        return self._cb.get_object(req_url, query_params)
Пример #10
0
    def stop(self):
        """Stop a running query.

        Returns:
            (bool): True if query was stopped successfully, False otherwise.

        Raises:
            ServerError: If the server response cannot be parsed as JSON.
        """
        if self._is_deleted:
            raise ApiError("cannot stop a deleted query")
        url = self.urlobject_single.format(self._cb.credentials.org_key,
                                           self.id) + "/status"
        result = self._cb.put_object(url, {'status': 'CANCELLED'})
        if (result.status_code == 200):
            try:
                self._info = result.json()
                self._last_refresh_time = time.time()
                return True
            except Exception:
                raise ServerError(
                    result.status_code,
                    "Cannot parse response as JSON: {0:s}".format(
                        result.content))
        return False
Пример #11
0
    def update(self, **kwargs):
        """Updates this watchlist with the given arguments.

        Arguments:
            **kwargs (dict(str, str)): The fields to update.

        Raises:
            InvalidObjectError: If `id` is missing or Watchlist.validate() fails.
            ApiError: If `report_ids` is given and is empty.

        Example:

        >>> watchlist.update(name="New Name")


        """
        if not self.id:
            raise InvalidObjectError("missing Watchlist ID")

        # NOTE(ww): Special case, according to the docs.
        if "report_ids" in kwargs and not kwargs["report_ids"]:
            raise ApiError(
                "can't update a watchlist to have an empty report list")

        for key, value in kwargs.items():
            if key in self._info:
                self._info[key] = value

        self.validate()

        url = "/threathunter/watchlistmgr/v3/orgs/{}/watchlists/{}".format(
            self._cb.credentials.org_key, self.id)
        new_info = self._cb.put_object(url, self._info).json()
        self._info.update(new_info)
Пример #12
0
 def _perform_query(self, cls, **kwargs):
     if hasattr(cls, "_query_implementation"):
         return cls._query_implementation(self, **kwargs)
     else:
         raise ApiError(
             "All Carbon Black Cloud models must provide _query_implementation"
         )
Пример #13
0
    def _perform_query(self, start=0, rows=0):
        if self._run_id is None:
            raise ApiError("Can't retrieve results without a run ID")

        url = self._doc_class.urlobject.format(
            self._cb.credentials.org_key, self._run_id
        )
        current = start
        numrows = 0
        still_querying = True
        while still_querying:
            request = self._build_request(start, rows)
            resp = self._cb.post_object(url, body=request)
            result = resp.json()

            self._total_results = result["num_found"]
            if self._total_results > MAX_RESULTS_LIMIT:
                self._total_results = MAX_RESULTS_LIMIT
            self._count_valid = True

            results = result.get("results", [])
            for item in results:
                yield self._doc_class(self._cb, item)
                current += 1
                numrows += 1

                if rows and numrows == rows:
                    still_querying = False
                    break

            start = current
            if current >= self._total_results:
                still_querying = False
                break
Пример #14
0
    def or_(self, **kwargs):
        """Unsupported. Will raise if called.

        Raises:
            ApiError: .or_() cannot be called on Endpoint Standard queries.
        """
        raise ApiError(".or_() cannot be called on Endpoint Standard queries.")
 def _get_query_parameters(self):
     args = self._default_args.copy()
     if not (self._facet_fields or self._ranges):
         raise ApiError(
             "Event Facet Queries require at least one field or range to be requested. "
             "Use add_facet_field(['my_facet_field']) to add fields to the request, "
             "or use add_range({}) to add ranges to the request.")
     terms = {}
     if self._facet_fields:
         terms["fields"] = self._facet_fields
     if self._facet_rows:
         terms["rows"] = self._facet_rows
     args["terms"] = terms
     if self._ranges:
         args["ranges"] = self._ranges
     if self._criteria:
         args["criteria"] = self._criteria
     if self._exclusions:
         args["exclusions"] = self._exclusions
     if self._time_range:
         args["time_range"] = self._time_range
     args['query'] = self._query_builder._collapse()
     if self._query_builder._process_guid is not None:
         args["process_guid"] = self._query_builder._process_guid
     if 'process_guid:' in args['query']:
         q = args['query'].split('process_guid:', 1)[1].split(' ', 1)[0]
         args["process_guid"] = q
     return args
Пример #16
0
    def _bulk_threat_update_status(self, threat_ids, status, remediation,
                                   comment):
        """
        Update the status of alerts associated with multiple threat IDs, past and future.

        Args:
            threat_ids (list): List of string threat IDs.
            status (str): The status to set for all alerts, either "OPEN" or "DISMISSED".
            remediation (str): The remediation state to set for all alerts.
            comment (str): The comment to set for all alerts.

        Returns:
            str: The request ID of the pending request, which may be used to select a WorkflowStatus object.
        """
        if not all(isinstance(t, str) for t in threat_ids):
            raise ApiError("One or more invalid threat ID values")
        request = {"state": status, "threat_id": threat_ids}
        if remediation is not None:
            request["remediation_state"] = remediation
        if comment is not None:
            request["comment"] = comment
        url = "/appservices/v6/orgs/{0}/threat/workflow/_criteria".format(
            self.credentials.org_key)
        resp = self.post_object(url, body=request)
        output = resp.json()
        return output["request_id"]
Пример #17
0
    def set_rows(self, rows):
        """
        Sets the 'rows' query body parameter to the 'start search' API call, determining how many rows to request.

        Args:
            rows (int): How many rows to request.
        """
        if not isinstance(rows, int):
            raise ApiError(
                f"Rows must be an integer. {rows} is a {type(rows)}.")
        if rows > 10000:
            raise ApiError("Maximum allowed value for rows is 10000")

        self._rows = rows
        self._default_args["rows"] = self._rows
        return self
Пример #18
0
    def or_(self, **kwargs):
        """Unsupported. Will raise if called.

        Raises:
            APIError: TreeQueries do not support _or() filters.
        """
        raise ApiError(".or_() cannot be called on Tree queries")
Пример #19
0
 def _refresh(self):
     if self._is_deleted:
         raise ApiError("cannot refresh a deleted query")
     url = self.urlobject_single.format(self._cb.credentials.org_key, self.id)
     resp = self._cb.get_object(url)
     self._info = resp
     self._last_refresh_time = time.time()
     return True
Пример #20
0
        def _refresh(self):
            """
            Throws an error, since Profile data cannot be refreshed.

            Raises:
                ApiError: Always.
            """
            raise ApiError("Profile cannot be refreshed")
Пример #21
0
    def disable_all_access(self):
        """
        Disables all access profiles held by ths user.

        Raises:
            ApiError: If the user is a "legacy" user that has no grant.
        """
        if self._disable_all_access():
            raise ApiError("legacy user has no grant")
    def _get_sensor_type(self):
        """
        Calculates the sensor type that should be installed on this compute resource.

        May also raise errors if the compute resource is ineligible or has an invalid type.

        Returns:
            str: The sensor type to be used for this compute resource.

        Raises:
            ApiError: If the compute node is not eligible or is of an invalid type.
        """
        if self.eligibility != 'ELIGIBLE':
            raise ApiError(f"device {self.name} does not allow sensor installation ({self.eligibility})")
        my_type = self.os_type
        if my_type in SensorKit.COMPUTE_RESOURCE_MAP:
            my_type = SensorKit.COMPUTE_RESOURCE_MAP[my_type]
        if my_type not in SensorKit.VALID_TYPES:
            raise ApiError(f"device {self.name} type {self.os_type} not supported for sensor installation")
        return my_type
Пример #23
0
    def __init__(self, cb, initial_data=None):
        if not initial_data:
            raise ApiError(
                "ReportSeverity can only be initialized from initial_data")

        super(ReportSeverity, self).__init__(cb,
                                             model_unique_id=initial_data.get(
                                                 self.primary_key),
                                             initial_data=initial_data,
                                             force_init=False,
                                             full_doc=True)
Пример #24
0
    def _perform_query(self, rows=0):
        if self._run_id is None:
            raise ApiError("Can't retrieve results without a run ID")

        url = self._doc_class.urlobject.format(self._cb.credentials.org_key,
                                               self._run_id)
        request = self._build_request(rows)
        resp = self._cb.post_object(url, body=request)
        result = resp.json()
        results = result.get("terms", [])
        for item in results:
            yield self._doc_class(self._cb, item)
Пример #25
0
    def set_policy_names(self, policy_names):
        """Sets the device.policy_name criteria.

        Arguments:
            policy_names ([str]): Device policy names to filter on.

        Returns:
            The FacetQuery object with specified policy_names.
        """
        if not all(isinstance(name, str) for name in policy_names):
            raise ApiError("policy_names must be a list of strings.")
        self._update_criteria("device.policy_name", policy_names)
        return self
Пример #26
0
    def set_policy_ids(self, policy_ids):
        """Sets the device.policy_id criteria.

        Arguments:
            policy_ids ([int]): Device policy ID's to filter on.

        Returns:
            The FacetQuery object with specified policy_ids.
        """
        if not all(isinstance(id, int) for id in policy_ids):
            raise ApiError("policy_ids must be a list of integers.")
        self._update_criteria("device.policy_id", policy_ids)
        return self
Пример #27
0
    def set_device_names(self, device_names):
        """Sets the device.name criteria filter.

        Arguments:
            device_names ([str]): Device names to filter on.

        Returns:
            The FacetQuery with specified device.name.
        """
        if not all(isinstance(name, str) for name in device_names):
            raise ApiError("One or more invalid device names")
        self._update_criteria("device.name", device_names)
        return self
Пример #28
0
    def set_device_ids(self, device_ids):
        """Sets the device.id criteria filter.

        Arguments:
            device_ids ([int]): Device IDs to filter on.

        Returns:
            The FacetQuery with specified device.id.
        """
        if not all(isinstance(device_id, int) for device_id in device_ids):
            raise ApiError("One or more invalid device IDs")
        self._update_criteria("device.id", device_ids)
        return self
Пример #29
0
    def set_statuses(self, statuses):
        """Sets the status criteria.

        Arguments:
            statuses ([str]): Query statuses to filter on.

        Returns:
            The ResultQuery object with specified statuses.
        """
        if not all(isinstance(status, str) for status in statuses):
            raise ApiError("statuses must be a list of strings.")
        self._update_criteria("status", statuses)
        return self
Пример #30
0
    def set_template_ids(self, template_ids):
        """Sets the template_id criteria filter.

        Arguments:
            template_ids ([str]): Template IDs to filter on.

        Returns:
            The ResultQuery with specified template_id.
        """
        if not all(isinstance(template_id, str) for template_id in template_ids):
            raise ApiError("One or more invalid template IDs")
        self._update_criteria("template_id", template_ids)
        return self