コード例 #1
0
    def test_delete_object(self, rest_api, example_object, full_access_user,
                           none_access_user):
        # Test default route
        rest_api.post(f'{self.ROUTE_URL}/',
                      json=CmdbObject.to_json(example_object))

        default_response = rest_api.delete(
            f'{self.ROUTE_URL}/{example_object.public_id}')
        assert default_response.status_code == HTTPStatus.OK

        default_response = rest_api.post(
            f'{self.ROUTE_URL}/', json=CmdbObject.to_json(example_object))
        assert default_response.status_code == HTTPStatus.OK

        # ACCESS OK
        access_update_types_response = rest_api.delete(
            f'{self.ROUTE_URL}/{example_object.public_id}',
            user=full_access_user)
        assert access_update_types_response.status_code != (
            HTTPStatus.FORBIDDEN or HTTPStatus.UNAUTHORIZED)
        validate_response = rest_api.get(
            f'{self.ROUTE_URL}/{example_object.public_id}')
        assert validate_response.status_code == HTTPStatus.NOT_FOUND

        # ACCESS FORBIDDEN
        none_update_types_response = rest_api.delete(
            f'{self.ROUTE_URL}/{example_object.public_id}',
            user=none_access_user)
        assert none_update_types_response.status_code == HTTPStatus.FORBIDDEN

        # ACCESS UNAUTHORIZED
        un_get_types_response = rest_api.delete(
            f'{self.ROUTE_URL}/{example_object.public_id}', unauthorized=True)
        assert un_get_types_response.status_code == HTTPStatus.UNAUTHORIZED
コード例 #2
0
    def get(self,
            public_id: Union[PublicID, int],
            user: UserModel = None,
            permission: AccessControlPermission = None) -> CmdbObject:
        """
        Get a single object by its id.

        Args:
            public_id (int): ID of the object.
            user: Request user
            permission: ACL permission

        Returns:
            CmdbObject: Instance of CmdbObject with data.
        """
        cursor_result = self._get(self.collection,
                                  filter={'public_id': public_id},
                                  limit=1)
        for resource_result in cursor_result.limit(-1):
            resource = CmdbObject.from_data(resource_result)
            type_ = TypeManager(database_manager=self._database_manager).get(
                resource.type_id)
            verify_access(type_, user, permission)
            return resource
        else:
            raise ManagerGetError(f'Object with ID: {public_id} not found!')
コード例 #3
0
    def test_get_object(self, rest_api, example_object, full_access_user,
                        none_access_user):
        default_response = rest_api.get(
            f'{self.ROUTE_URL}/{example_object.public_id}/{"native"}')
        assert default_response.status_code == HTTPStatus.OK

        # Response parsable
        response_dict = default_response.get_json()
        test_object = CmdbObject.from_data(response_dict)
        assert isinstance(test_object, CmdbObject)

        # Not Found
        not_found_response = rest_api.get(f'{self.ROUTE_URL}/{-1}')
        assert not_found_response.status_code == HTTPStatus.NOT_FOUND

        # ACCESS OK
        access_get_types_response = rest_api.get(
            f'{self.ROUTE_URL}/{example_object.public_id}',
            user=full_access_user)
        assert access_get_types_response.status_code != (
            HTTPStatus.FORBIDDEN or HTTPStatus.UNAUTHORIZED)

        # ACCESS FORBIDDEN
        none_get_types_response = rest_api.get(
            f'{self.ROUTE_URL}/{example_object.public_id}',
            user=none_access_user)
        assert none_get_types_response.status_code == HTTPStatus.FORBIDDEN

        # ACCESS UNAUTHORIZED
        none_get_types_response = rest_api.get(
            f'{self.ROUTE_URL}/{example_object.public_id}', unauthorized=True)
        assert none_get_types_response.status_code == HTTPStatus.UNAUTHORIZED
コード例 #4
0
    def test_update_object(self, rest_api, example_object, full_access_user,
                           none_access_user):
        example_object.editor_id = 1
        example_object.creation_time = None

        # Test default
        default_response = rest_api.put(
            f'{self.ROUTE_URL}/{example_object.public_id}',
            json=CmdbObject.to_json(example_object))
        assert default_response.status_code == HTTPStatus.ACCEPTED

        validate_response = rest_api.get(
            f'{self.ROUTE_URL}/{example_object.public_id}/{"native"}')
        assert validate_response.status_code == HTTPStatus.OK

        response_dict = validate_response.get_json()
        test_object = CmdbObject.from_data(response_dict)
        assert isinstance(test_object, CmdbObject)
        assert test_object.last_edit_time is not None

        # ACCESS OK
        access_update_types_response = rest_api.put(
            f'{self.ROUTE_URL}/{example_object.public_id}',
            json=CmdbObject.to_json(example_object),
            user=full_access_user)
        assert access_update_types_response.status_code != (
            HTTPStatus.FORBIDDEN or HTTPStatus.UNAUTHORIZED)
        validate_response = rest_api.get(
            f'{self.ROUTE_URL}/{example_object.public_id}')
        assert validate_response.status_code == HTTPStatus.OK
        rest_api.delete(f'{self.ROUTE_URL}/{example_object.public_id}')

        # ACCESS FORBIDDEN
        none_update_types_response = rest_api.put(
            f'{self.ROUTE_URL}/{example_object.public_id}',
            json=CmdbObject.to_json(example_object),
            user=none_access_user)
        assert none_update_types_response.status_code == HTTPStatus.FORBIDDEN

        # ACCESS UNAUTHORIZED
        un_get_types_response = rest_api.put(
            f'{self.ROUTE_URL}/{example_object.public_id}',
            json=CmdbObject.to_json(example_object),
            unauthorized=True)
        assert un_get_types_response.status_code == HTTPStatus.UNAUTHORIZED
        example_object.public_id = 1
        example_object.name = 'test'
コード例 #5
0
def example_object():
    return CmdbObject(public_id=1,
                      type_id=1,
                      status=True,
                      creation_time=datetime.now(timezone.utc),
                      author_id=1,
                      active=True,
                      fields=[],
                      version='1.0.0')
コード例 #6
0
def example_object():
    return CmdbObject(public_id=1,
                      type_id=1,
                      status=True,
                      creation_time=datetime.now(timezone.utc),
                      author_id=1,
                      active=True,
                      fields=[{
                          "name": "dummy-field-1",
                          "value": 'dummy-value'
                      }, {
                          "name": "dummy-field-2",
                          "value": ''
                      }],
                      version='1.0.0')
コード例 #7
0
    def test_get_objects(self, rest_api, full_access_user, none_access_user):
        default_response = rest_api.get(f'{self.ROUTE_URL}/')
        assert default_response.status_code == HTTPStatus.OK

        # Response parsable
        response_dict = default_response.get_json()
        test_object_json = response_dict['results'][0]
        test_object = CmdbObject.from_data(test_object_json)

        assert len(response_dict['results']) == int(
            default_response.headers['X-Total-Count'])
        assert len(response_dict['results'])
        assert isinstance(test_object, CmdbObject)

        # Test filter
        filter_response = rest_api.get(
            f'{self.ROUTE_URL}/',
            query_string={'filter': dumps({'public_id': 1})})
        assert filter_response.status_code == HTTPStatus.OK
        assert int(filter_response.headers['X-Total-Count']) == 1

        # Test empty filter
        empty_filter_response = rest_api.get(
            f'{self.ROUTE_URL}/',
            query_string={'filter': dumps({'public_id': 2})})
        assert empty_filter_response.status_code == HTTPStatus.OK
        assert int(empty_filter_response.headers['X-Total-Count']) == 0

        # Test wrong filter
        wrong_filter_response = rest_api.get(f'{self.ROUTE_URL}/',
                                             query_string={'filter': '\xE9'})
        assert wrong_filter_response.status_code == HTTPStatus.BAD_REQUEST

        # ACCESS OK
        access_get_types_response = rest_api.get(f'{self.ROUTE_URL}/',
                                                 user=full_access_user)
        assert access_get_types_response.status_code != (
            HTTPStatus.FORBIDDEN or HTTPStatus.UNAUTHORIZED)

        # ACCESS FORBIDDEN
        none_get_types_response = rest_api.get(f'{self.ROUTE_URL}/',
                                               user=none_access_user)
        assert none_get_types_response.status_code == HTTPStatus.FORBIDDEN

        # ACCESS UNAUTHORIZED
        none_get_types_response = rest_api.get(f'{self.ROUTE_URL}/',
                                               unauthorized=True)
        assert none_get_types_response.status_code == HTTPStatus.UNAUTHORIZED
コード例 #8
0
    def test_insert_object(self, rest_api, example_object, full_access_user):
        """
        Prepare data for mass change with access control
        """
        i = 0
        while i < 3:
            i = i + 1
            data = copy.copy(CmdbObject.to_json(example_object))
            data['public_id'] = i
            data['active'] = i % 2 != 0
            data['fields'][0]['value'] = f'dummy-value-{i}'
            access_insert_types_response = rest_api.post(f'{self.ROUTE_URL}/',
                                                         json=data,
                                                         user=full_access_user)
            assert access_insert_types_response.status_code != (
                HTTPStatus.FORBIDDEN or HTTPStatus.UNAUTHORIZED)

        assert len(
            rest_api.get(f'{self.ROUTE_URL}/').get_json()['results']) == 3
コード例 #9
0
def update_object(public_id: int, request_user: UserModel):
    object_ids = request.args.getlist('objectIDs')

    if len(object_ids) > 0:
        object_ids = list(map(int, object_ids))
    else:
        object_ids = [public_id]

    update_ack = None

    for obj_id in object_ids:
        # get current object state
        try:
            current_object_instance = object_manager.get_object(obj_id)
            current_type_instance = object_manager.get_type(
                current_object_instance.get_type_id())
            current_object_render_result = CmdbRender(
                object_instance=current_object_instance,
                type_instance=current_type_instance,
                render_user=request_user,
                object_manager=object_manager,
                ref_render=True).result()
        except ObjectManagerGetError as err:
            LOGGER.error(err)
            return abort(404)
        except RenderError as err:
            LOGGER.error(err)
            return abort(500)

        update_comment = ''
        # load put data
        try:
            # get data as str
            add_data_dump = json.dumps(request.json)

            # convert into python dict
            put_data = json.loads(add_data_dump, object_hook=object_hook)
            # check for comment
            try:
                put_data['public_id'] = obj_id
                put_data[
                    'creation_time'] = current_object_instance.creation_time
                put_data['author_id'] = current_object_instance.author_id

                old_fields = list(
                    map(
                        lambda x:
                        {k: v
                         for k, v in x.items() if k in ['name', 'value']},
                        current_type_instance.get_fields()))
                new_fields = put_data['fields']
                for item in new_fields:
                    for old in old_fields:
                        if item['name'] == old['name']:
                            old['value'] = item['value']
                put_data['fields'] = old_fields

                if 'active' not in put_data:
                    put_data['active'] = current_object_instance.active
                if 'version' not in put_data:
                    put_data['version'] = current_object_instance.version

                update_comment = put_data['comment']
                del put_data['comment']
            except (KeyError, IndexError, ValueError):
                update_comment = ''
        except TypeError as e:
            LOGGER.warning(e)
            return abort(400)

        # update edit time
        put_data['last_edit_time'] = datetime.now(timezone.utc)

        try:
            update_object_instance = CmdbObject(**put_data)
        except ObjectManagerUpdateError as err:
            LOGGER.error(err)
            return abort(400)

        # calc version

        changes = current_object_instance / update_object_instance

        if len(changes['new']) == 1:
            update_object_instance.update_version(
                update_object_instance.VERSIONING_PATCH)
        elif len(changes['new']) == len(update_object_instance.fields):
            update_object_instance.update_version(
                update_object_instance.VERSIONING_MAJOR)
        elif len(changes['new']) > (len(update_object_instance.fields) / 2):
            update_object_instance.update_version(
                update_object_instance.VERSIONING_MINOR)
        else:
            update_object_instance.update_version(
                update_object_instance.VERSIONING_PATCH)

        # insert object
        try:
            update_ack = object_manager.update_object(
                update_object_instance, request_user,
                AccessControlPermission.UPDATE)

        except ManagerGetError as err:
            return abort(404, err.message)
        except AccessDeniedError as err:
            return abort(403, err.message)
        except CMDBError as e:
            LOGGER.warning(e)
            return abort(500)

        try:
            # generate log
            log_data = {
                'object_id':
                obj_id,
                'version':
                current_object_render_result.object_information['version'],
                'user_id':
                request_user.get_public_id(),
                'user_name':
                request_user.get_display_name(),
                'comment':
                update_comment,
                'changes':
                changes,
                'render_state':
                json.dumps(current_object_render_result,
                           default=default).encode('UTF-8')
            }
            log_manager.insert(action=LogAction.EDIT,
                               log_type=CmdbObjectLog.__name__,
                               **log_data)
        except (CMDBError, LogManagerInsertError) as err:
            LOGGER.error(err)

    return make_response(update_ack)
コード例 #10
0
def update_object(public_id: int, data: dict, request_user: UserModel):
    object_ids = request.args.getlist('objectIDs')

    if len(object_ids) > 0:
        object_ids = list(map(int, object_ids))
    else:
        object_ids = [public_id]

    manager = ObjectManager(database_manager=current_app.database_manager,
                            event_queue=current_app.event_queue)
    results: [dict] = []
    failed = []

    for obj_id in object_ids:
        # deep copy
        active_state = request.get_json().get('active', None)
        new_data = copy.deepcopy(data)
        try:
            current_object_instance = manager.get(
                obj_id,
                user=request_user,
                permission=AccessControlPermission.READ)
            current_type_instance = type_manager.get(
                current_object_instance.get_type_id())
            current_object_render_result = CmdbRender(
                object_instance=current_object_instance,
                object_manager=object_manager,
                type_instance=current_type_instance,
                render_user=request_user).result()
            update_comment = ''
            try:
                # check for comment
                new_data['public_id'] = obj_id
                new_data[
                    'creation_time'] = current_object_instance.creation_time
                new_data['author_id'] = current_object_instance.author_id
                new_data[
                    'active'] = active_state if active_state else current_object_instance.active

                if 'version' not in data:
                    new_data['version'] = current_object_instance.version

                old_fields = list(
                    map(
                        lambda x:
                        {k: v
                         for k, v in x.items() if k in ['name', 'value']},
                        current_object_render_result.fields))
                new_fields = data['fields']
                for item in new_fields:
                    for old in old_fields:
                        if item['name'] == old['name']:
                            old['value'] = item['value']
                new_data['fields'] = old_fields

                update_comment = data['comment']
                del new_data['comment']

            except (KeyError, IndexError, ValueError):
                update_comment = ''
            except TypeError as err:
                LOGGER.error(
                    f'Error: {str(err.args)} Object: {json.dumps(new_data, default=default)}'
                )
                failed.append(
                    ResponseFailedMessage(error_message=str(err.args),
                                          status=400,
                                          public_id=obj_id,
                                          obj=new_data).to_dict())
                continue

            # update edit time
            new_data['last_edit_time'] = datetime.now(timezone.utc)
            new_data['editor_id'] = request_user.public_id

            update_object_instance = CmdbObject(
                **json.loads(json.dumps(new_data, default=json_util.default),
                             object_hook=object_hook))

            # calc version
            changes = current_object_instance / update_object_instance

            if len(changes['new']) == 1:
                new_data['version'] = update_object_instance.update_version(
                    update_object_instance.VERSIONING_PATCH)
            elif len(changes['new']) == len(update_object_instance.fields):
                new_data['version'] = update_object_instance.update_version(
                    update_object_instance.VERSIONING_MAJOR)
            elif len(
                    changes['new']) > (len(update_object_instance.fields) / 2):
                new_data['version'] = update_object_instance.update_version(
                    update_object_instance.VERSIONING_MINOR)
            else:
                new_data['version'] = update_object_instance.update_version(
                    update_object_instance.VERSIONING_PATCH)

            manager.update(obj_id, new_data, request_user,
                           AccessControlPermission.UPDATE)
            results.append(new_data)

            # Generate log entry
            try:
                log_data = {
                    'object_id':
                    obj_id,
                    'version':
                    update_object_instance.get_version(),
                    'user_id':
                    request_user.get_public_id(),
                    'user_name':
                    request_user.get_display_name(),
                    'comment':
                    update_comment,
                    'changes':
                    changes,
                    'render_state':
                    json.dumps(update_object_instance,
                               default=default).encode('UTF-8')
                }
                log_manager.insert(action=LogAction.EDIT,
                                   log_type=CmdbObjectLog.__name__,
                                   **log_data)
            except (CMDBError, LogManagerInsertError) as err:
                LOGGER.error(err)

        except AccessDeniedError as err:
            LOGGER.error(err)
            return abort(403)
        except ObjectManagerGetError as err:
            LOGGER.error(err)
            failed.append(
                ResponseFailedMessage(error_message=err.message,
                                      status=400,
                                      public_id=obj_id,
                                      obj=new_data).to_dict())
            continue
        except (ManagerGetError, ObjectManagerUpdateError) as err:
            LOGGER.error(err)
            failed.append(
                ResponseFailedMessage(error_message=err.message,
                                      status=404,
                                      public_id=obj_id,
                                      obj=new_data).to_dict())
            continue
        except (CMDBError, RenderError) as e:
            LOGGER.warning(e)
            failed.append(
                ResponseFailedMessage(error_message=str(e.__repr__),
                                      status=500,
                                      public_id=obj_id,
                                      obj=new_data).to_dict())
            continue

    api_response = UpdateMultiResponse(results=results,
                                       failed=failed,
                                       url=request.url,
                                       model=CmdbObject.MODEL)
    return api_response.make_response()
コード例 #11
0
    def test_insert_object(self, rest_api, example_object, full_access_user,
                           none_access_user):
        # Test default
        default_response = rest_api.post(
            f'{self.ROUTE_URL}/', json=CmdbObject.to_json(example_object))
        assert default_response.status_code == HTTPStatus.OK

        example_object.public_id = 2
        example_object.type_id = 2
        example_object.fields = [{
            "name": "test-field",
            "value": 1,
        }]

        default_response = rest_api.post(
            f'{self.ROUTE_URL}/', json=CmdbObject.to_json(example_object))
        assert default_response.status_code == HTTPStatus.OK

        validate_response = rest_api.get(
            f'{self.ROUTE_URL}/{example_object.public_id}')
        assert validate_response.status_code == HTTPStatus.OK

        double_check_response = rest_api.post(
            f'{self.ROUTE_URL}/', json=CmdbObject.to_json(example_object))
        assert double_check_response.status_code == HTTPStatus.BAD_REQUEST

        # DELETE default
        rest_api.delete(f'{self.ROUTE_URL}/{example_object.public_id}')

        # ACCESS OK
        access_insert_types_response = rest_api.post(
            f'{self.ROUTE_URL}/',
            json=CmdbObject.to_json(example_object),
            user=full_access_user)
        assert access_insert_types_response.status_code != (
            HTTPStatus.FORBIDDEN or HTTPStatus.UNAUTHORIZED)

        validate_response = rest_api.get(
            f'{self.ROUTE_URL}/{example_object.public_id}')
        assert validate_response.status_code == HTTPStatus.OK

        # DELETE default
        rest_api.delete(f'{self.ROUTE_URL}/{example_object.public_id}')

        # ACCESS FORBIDDEN
        forbidden_insert_types_response = rest_api.post(
            f'{self.ROUTE_URL}/',
            json=CmdbObject.to_json(example_object),
            user=none_access_user)
        assert forbidden_insert_types_response.status_code == HTTPStatus.FORBIDDEN

        validate_response = rest_api.get(
            f'{self.ROUTE_URL}/{example_object.public_id}')
        assert validate_response.status_code == HTTPStatus.NOT_FOUND

        # ACCESS UNAUTHORIZED
        un_insert_types_response = rest_api.post(
            f'{self.ROUTE_URL}/',
            json=CmdbObject.to_json(example_object),
            unauthorized=True)
        assert un_insert_types_response.status_code == HTTPStatus.UNAUTHORIZED
        validate_response = rest_api.get(
            f'{self.ROUTE_URL}/{example_object.public_id}')

        assert validate_response.status_code == HTTPStatus.NOT_FOUND
        example_object.public_id = 1