Beispiel #1
0
    def _create_or_update_workspace(self, request, create):
        context = RequestContext.from_rest_request(request)
        payload = json.loads(request[PAYLOAD])

        workspace_proto = augmented_reality_pb2.ARWorkspaceData()
        if WORKSPACE_ID_LABEL in payload:
            workspace_proto.arWorkspaceId = payload[WORKSPACE_ID_LABEL]
        if WORKSPACE_TITLE_LABEL in payload:
            workspace_proto.title = payload[WORKSPACE_TITLE_LABEL]
        if KVSTORE_DATA_LABEL in payload:
            # We probably should update this API to accept an ARWorkspaceData in JSON format so we only have one way
            # to set things. I.e. if the ID or title is set in the following payload, it will overwrite the ID and title
            # set above.
            workspace_data = json.loads(payload[KVSTORE_DATA_LABEL]).get(
                WORKSPACE_DATA_LABEL, {})
            if isinstance(workspace_data, dict):
                workspace_data = json.dumps(workspace_data)
            workspace_proto = Parse(workspace_data, workspace_proto)

        if create:
            affected_workspace_id = yield ar_workspace_request_processor.create_ar_workspace(
                context, self.async_splunk_client, self.async_kvstore_client,
                self.async_ar_permissions_client, workspace_proto)
        else:
            affected_workspace_id = yield ar_workspace_request_processor.update_ar_workspace(
                context, self.async_client_factory.kvstore_client(),
                self.async_client_factory.ar_permissions_client(),
                workspace_proto)

        defer.returnValue({
            PAYLOAD: {
                WORKSPACE_ID_LABEL: affected_workspace_id
            },
            STATUS: http.OK
        })
Beispiel #2
0
    def async_get(self, request):
        """
        Serves role and capability information relative to the user by default or a specific role if one is specified.

        Query Parameters:
        * role: if specified, this will return which capability this particular role grants

        Example Response:
        {
            "read": {
                "asset": ["asset_1", "asset_2"],
                "workspace": ["workspace_1", "workspace_2", "workspace_3"],
                "geofence": "ALL"
            },
            "write": {
                "note": ["note_1", "note_2"],
                "playbook": ["playbook_1"]
            },
            general: ["workspace_write", "asset_manage", "note_manage", "beacon_view"],
        }

        If the user has access to all objects of a specific type, the value for the object type key in "read" or "write"
        will have the value "ALL" instead of an actual list.

        :param request: a dictionary representing the HTTP request
        """
        context = RequestContext.from_rest_request(request)
        query = request.get(QUERY, {})

        if ROLE in query:
            capabilities, accesses = yield self._permissions.get_capabilities_granted_by_role(context, query[ROLE])
        else:
            capabilities, accesses = yield self._permissions.get_user_capabilities(context)

        read, write = collections.defaultdict(set), collections.defaultdict(set)
        for capability in Capabilities.read_capabilities() + Capabilities.write_capabilities():
            access = accesses.get(capability, Access(quantity=AccessQuantity.NONE))
            object_type = capability.type.value
            if access.quantity == AccessQuantity.ALL:
                read[object_type] = ALL_ACCESS
                write[object_type] = ALL_ACCESS
            elif capability.level == LEVEL_READ:
                read[object_type] |= access.ids
            elif capability.level == LEVEL_WRITE:
                read[object_type] |= access.ids
                write[object_type] |= access.ids

        for object_type in read:
            read[object_type] = list(read[object_type]) if isinstance(read[object_type], set) else read[object_type]
        for object_type in write:
            write[object_type] = list(write[object_type]) if isinstance(write[object_type], set) else write[object_type]

        defer.returnValue({
            STATUS: http.OK,
            PAYLOAD: {
                CAPABILITIES: sorted(capabilities),
                READ: dict(read),
                WRITE: dict(write)
            }
        })
Beispiel #3
0
    def async_post(self, request):
        """Handles updates to asset groups."""
        context = RequestContext.from_rest_request(request)
        params = json.loads(request[PAYLOAD])
        if ACTION not in params or params[ACTION] not in {
                CREATE, UPDATE, DELETE
        }:
            raise SpacebridgeApiRequestError(message='Must provide an action',
                                             status_code=http.BAD_REQUEST)

        if params[ACTION] == DELETE:
            asset_group_ids = params[ASSET_GROUP_IDS]
            deleted_ids = yield delete_asset_groups(context, asset_group_ids,
                                                    self._kvstore,
                                                    self._permissions)
            defer.returnValue({
                PAYLOAD: {
                    ASSET_GROUP_IDS: deleted_ids
                },
                STATUS: http.OK
            })

        if ASSET_GROUPS not in params:
            raise SpacebridgeApiRequestError(
                'Must provide asset groups to update',
                status_code=http.BAD_REQUEST)
        asset_groups = params[ASSET_GROUPS]
        for asset_group in asset_groups:
            validate_asset_or_group_objects(
                asset_group.get(ASSET_GROUP_OBJECTS), new_workspace_title=None)
            if ASSET_GROUP_ID in asset_group:
                asset_group[KEY] = asset_group[ASSET_GROUP_ID]

        asset_group_data = []
        for asset_group in asset_groups:
            parsed_group = AssetGroup.from_json(asset_group)
            if NEW_WORKSPACE_TITLE in asset_group:
                # Today the only time NEW_WORKSPACE_TITLE will be specified is when there is only one asset group being
                # updated so it's safe to assume that this will not spawn many KV store requests.
                created_workspace_id = yield create_ar_workspace(
                    context,
                    self._splunk,
                    self._kvstore,
                    self._permissions,
                    ARWorkspaceData(title=asset_group[NEW_WORKSPACE_TITLE]),
                    dashboard_id=parsed_group.dashboard_id)
                parsed_group.workspace_id = created_workspace_id
            asset_group_data.append(parsed_group)

        affected_groups = yield bulk_update_asset_groups(
            context, asset_group_data, self._kvstore, self._permissions)
        defer.returnValue({
            PAYLOAD: {
                ASSET_GROUP_IDS_RESPONSE_KEY: affected_groups
            },
            STATUS:
            http.OK if params[ACTION] == UPDATE else http.CREATED
        })
Beispiel #4
0
 def async_delete(self, request):
     context = RequestContext.from_rest_request(request)
     role = request.get(QUERY, {}).get(ROLE)
     if not role:
         raise SpacebridgeApiRequestError('Delete role request must specify the URL encoded parameter "role".',
                                          status_code=http.BAD_REQUEST)
     yield self._permissions.delete_role(context, role)
     defer.returnValue({
         PAYLOAD: {ROLE: role},
         STATUS: http.OK
     })
Beispiel #5
0
    def async_get(self, request):
        context = RequestContext.from_rest_request(request)
        location_based_assets = yield wait_for_all(
            [self._get_beacons(context),
             self._get_geofences(context)],
            raise_on_first_exception=True)

        payload = []
        for grouping in location_based_assets:
            payload.extend(grouping)

        defer.returnValue({STATUS: http.OK, PAYLOAD: payload})
Beispiel #6
0
 def _create_or_update_role(self, request, role_operation_fn):
     context = RequestContext.from_rest_request(request)
     payload = json.loads(request[PAYLOAD]) if PAYLOAD in request else None
     if not payload or not payload.get(ROLE):
         raise SpacebridgeApiRequestError('Request payload must contain the "role" parameter.',
                                          status_code=http.BAD_REQUEST)
     role = yield role_operation_fn(
         request_context=context,
         name=payload[ROLE],
         parent_roles=payload.get(IMPORTED_ROLES),
         general_capabilities=payload.get(GENERAL_CAPABILITIES),
         object_capabilities=[ObjectCapability.from_dict(oc) for oc in payload.get(OBJECT_CAPABILITIES, [])])
     defer.returnValue(role)
Beispiel #7
0
 def async_get(self, request):
     """Returns a list of asset groups. If no asset group IDs are specified, all will be returned."""
     context = RequestContext.from_rest_request(request)
     asset_group_ids = request[QUERY].get(ASSET_GROUP_IDS)
     asset_groups = yield get_asset_groups(context, asset_group_ids,
                                           self._kvstore, self._permissions)
     defer.returnValue({
         PAYLOAD: {
             ASSET_GROUPS:
             [asset_group.to_dict() for asset_group in asset_groups]
         },
         STATUS: http.OK
     })
Beispiel #8
0
 def async_delete(self, request):
     """Deletes a workspace by ID."""
     context = RequestContext.from_rest_request(request)
     workspace_id = extract_parameter(request[QUERY], WORKSPACE_ID_LABEL,
                                      QUERY)
     deleted_ids = yield ar_workspace_request_processor.delete_ar_workspace(
         context, self.async_client_factory.kvstore_client(),
         self.async_client_factory.ar_permissions_client(), [workspace_id])
     defer.returnValue({
         PAYLOAD: {
             WORKSPACE_ID_LABEL: deleted_ids
         },
         STATUS: http.OK,
     })
Beispiel #9
0
 def async_get(self, request):
     """Looks up assets from KV store."""
     context = RequestContext.from_rest_request(request)
     asset_ids = request[QUERY].get(ASSET_IDS)
     assets = yield get_assets(context,
                               asset_ids,
                               self._kvstore,
                               self._permissions,
                               ungroup_assets=False)
     defer.returnValue({
         PAYLOAD: {
             ASSETS: [asset.to_dict() for asset in assets]
         },
         STATUS: http.OK
     })
 def async_get(self, request):
     context = RequestContext.from_rest_request(request)
     try:
         phantom_metadata = yield get_phantom_metadata(
             context, self._kvstore)
         defer.returnValue({
             STATUS: http.OK,
             PAYLOAD: phantom_metadata.to_dict()
         })
     except NoRegisteredPhantomInstanceException:
         defer.returnValue({
             STATUS: http.NO_CONTENT,
             PAYLOAD:
             'No existing configuration'  # The payload attribute is required for all responses.
         })
    async def get(self, request):
        """
        Lists one or more dashboards in the form of JSON formatted DashboardDescription messages.

        Request Parameters
            offset         the number of dashboards to skip
            max_results    the maximum number of dashboards to return
            dashboard_ids  one or more dashboard IDs to query
            minimal_list   0 for verbose descriptions and 1 for minimal descriptions
        """
        context = RequestContext.from_rest_request(request)
        response = await dashboard_list_request(request,
                                                self.async_client_factory,
                                                context)
        return {
            PAYLOAD:
            response,
            STATUS:
            HTTPStatus.INTERNAL_SERVER_ERROR
            if 'error' in response else HTTPStatus.OK,
        }
Beispiel #12
0
    def async_get(self, request):
        """Returns workspaces from KV store.

        If no workspace IDs are provided in the request, data for all workspaces is returned.
        """
        context = RequestContext.from_rest_request(request)
        workspace_ids = request[QUERY].get(WORKSPACE_ID_LABEL) or []
        if not isinstance(workspace_ids, list):
            workspace_ids = [workspace_ids]
        workspaces = yield ar_workspace_request_processor.get_ar_workspaces(
            context,
            self.async_kvstore_client,
            self.async_ar_permissions_client,
            workspace_ids,
            json_format=True)
        defer.returnValue({
            PAYLOAD: {
                'ar_workspaces': workspaces
            },
            STATUS: http.OK
        })
    def async_post(self, request):
        context = RequestContext.from_rest_request(request)
        if PAYLOAD not in request:
            raise SpacebridgeApiRequestError(
                'Request must contain a JSON payload containing the field "hostname" set '
                'to the Phantom hostname to use.',
                status_code=http.BAD_REQUEST)
        request_payload = json.loads(request[PAYLOAD])
        if 'username' not in request_payload or 'password' not in request_payload:
            raise SpacebridgeApiRequestError(
                'Request must include a Phantom username and password.',
                status_code=http.BAD_REQUEST)
        phantom_metadata = PhantomMetadata.from_json(request_payload)
        username, password = request_payload['username'], request_payload[
            'password']

        if request_payload.get('health_check_only', False):
            response = yield self._health_check(phantom_metadata, username,
                                                password)
        else:
            response = yield self._set_phantom_metadata(
                context, phantom_metadata, username, password)

        defer.returnValue(response)
Beispiel #14
0
    def async_post(self, request):
        """Handles creating and modifying assets.

        The payload parameters used by this handler include:
            - action: determines what to do with the given assets. Either update, create, or delete.
            - assets: a list of JSON document assets to update or create.
            - asset_objects: a list of objects to associate with the given asset or asset group.
            - asset_group_id: the ID of an existing asset group to associate with the above assets.
            - asset_group_name: the name of a new asset group to create and associate with the above assets.
            - new_workspace_title: the name of a new workspace to create and associate with the given assets or asset
                                   group.
            - overwrite: bool indicating whether to overwrite existing asset data.
        """
        context = RequestContext.from_rest_request(request)
        params = json.loads(request[PAYLOAD])
        if ACTION not in params or params[ACTION] not in {
                CREATE, UPDATE, DELETE
        }:
            raise SpacebridgeApiRequestError(message='Must provide an action',
                                             status_code=http.BAD_REQUEST)

        if params.get(ACTION) == DELETE:
            deleted_ids = yield delete_assets(context, params.get(ASSET_IDS),
                                              self._kvstore, self._permissions)
            defer.returnValue({
                PAYLOAD: {
                    ASSET_IDS: deleted_ids
                },
                STATUS: http.OK
            })

        yield self._check_user_can_do_update(context, params)

        # Create a workspace if the user specifies a new workspace title
        dashboard_id, workspace_id = _get_asset_object_ids(params)
        if params.get(NEW_WORKSPACE_TITLE):
            workspace_id = yield create_ar_workspace(
                context,
                self._splunk,
                self._kvstore,
                self._permissions,
                ARWorkspaceData(title=params.get(NEW_WORKSPACE_TITLE)),
                dashboard_id=dashboard_id)
            LOGGER.debug('Created workspace_id=%s', workspace_id)

        # Create an asset group if the user specifies a new group name
        asset_group_id = params.get(ASSET_GROUP_ID)
        if params.get(ASSET_GROUP_NAME):
            asset_group = AssetGroup(name=params.get(ASSET_GROUP_NAME),
                                     key=asset_group_id,
                                     dashboard_id=dashboard_id,
                                     workspace_id=workspace_id)
            try:
                asset_group_id = yield create_asset_group(
                    context, asset_group, self._kvstore, self._permissions)
            except AssetGroupAlreadyExists as e:
                LOGGER.debug(e)

        assets = [
            AssetData(asset_name=asset.get(ASSET_NAME),
                      asset_id=asset.get(ASSET_ID),
                      asset_group=asset_group_id,
                      is_splunk_generated=asset.get(ASSET_TYPE)
                      or ASSET_ID in asset,
                      dashboard_description_pb=DashboardDescription(
                          dashboardId=dashboard_id),
                      ar_workspace_data_pb=ARWorkspaceData(
                          arWorkspaceId=workspace_id))
            for asset in params.get(ASSETS, [])
        ]
        affected_ids = yield self._kvstore.async_batch_save_request(
            auth_header=context.auth_header,
            collection=ASSETS_COLLECTION_NAME,
            entries=[asset.to_dict(jsonify_objects=True) for asset in assets])
        if not asset_group_id:
            yield self._permissions.register_objects(
                context,
                ARObjectType.ASSET,
                affected_ids,
                check_if_objects_exist=True)

        # Return the IDs that were affected by this request
        defer.returnValue({
            PAYLOAD: {
                'asset_ids': affected_ids or [],
                'workspace_id': workspace_id,
                'asset_group_id': asset_group_id,
            },
            STATUS:
            http.OK if params[ACTION] == UPDATE else http.CREATED
        })
 def async_delete(self, request):
     context = RequestContext.from_rest_request(request)
     yield delete_phantom_metadata(context, self._kvstore)
     defer.returnValue({STATUS: http.OK, PAYLOAD: {'success': True}})