def verify_import_access(user: UserModel, _type: TypeModel, _manager: TypeManager): """Validate if a user has access to objects of this type.""" location = 'acl.groups.includes.' + str(user.group_id) query = {'$and': [{'$or': [ {'$or': [ {'acl': {'$exists': False}}, {'acl.activated': False}] }, {'$and': [ {'acl.activated': True}, {'$and': [ {location: {'$exists': True}}, {location: {'$all': [ AccessControlPermission.READ.value, AccessControlPermission.CREATE.value, AccessControlPermission.UPDATE.value] } } ] } ] }] }, {'public_id': _type.public_id}]} types_ = _manager.iterate(filter=query, limit=1, skip=0, sort='public_id', order=1) if len([TypeModel.to_json(_) for _ in types_.results]) == 0: raise AccessDeniedError(f'The objects of the type `{_type.name}` are protected by ACL permission!')
def delete_object(self, public_id: int, user: UserModel, permission: AccessControlPermission = None): type_id = self.get_object(public_id=public_id).type_id type_ = self._type_manager.get(type_id) if not type_.active: raise AccessDeniedError( f'Objects cannot be removed because type `{type_.name}` is deactivated.' ) verify_access(type_, user, permission) try: if self._event_queue: event = Event( "cmdb.core.object.deleted", { "id": public_id, "type_id": self.get_object(public_id).get_type_id(), "user_id": user.get_public_id(), "event": 'delete' }) self._event_queue.put(event) ack = self._delete(CmdbObject.COLLECTION, public_id) return ack except (CMDBError, Exception): raise ObjectDeleteError(msg=public_id)
def verify_access(model: TypeModel, user: UserModel = None, permission: AccessControlPermission = None): """Validate if a user has access to objects of this type.""" if not user or not permission: return verify = has_access_control(model, user, permission) if not verify: raise AccessDeniedError('Protected by ACL permission!')
def insert_object(self, data: (CmdbObject, dict), user: UserModel = None, permission: AccessControlPermission = None) -> int: """ Insert new CMDB Object Args: data: init data user: current user, to detect who triggered event permission: extended user acl rights Returns: Public ID of the new object in database """ new_object = None if isinstance(data, dict): try: new_object = CmdbObject(**data) except CMDBError as e: LOGGER.debug( f'Error while inserting object - error: {e.message}') raise ObjectManagerInsertError(e) elif isinstance(data, CmdbObject): new_object = data type_ = self._type_manager.get(new_object.type_id) if not type_.active: raise AccessDeniedError( f'Objects cannot be created because type `{type_.name}` is deactivated.' ) verify_access(type_, user, permission) try: ack = self.dbm.insert(collection=CmdbObject.COLLECTION, data=new_object.__dict__) if self._event_queue: event = Event( "cmdb.core.object.added", { "id": new_object.get_public_id(), "type_id": new_object.get_type_id(), "user_id": new_object.author_id, "event": 'insert' }) self._event_queue.put(event) except (CMDBError, PublicIDAlreadyExists) as e: raise ObjectInsertError(e) return ack
def update_object(self, data: (dict, CmdbObject), user: UserModel = None, permission: AccessControlPermission = None) -> str: if isinstance(data, dict): update_object = CmdbObject(**data) elif isinstance(data, CmdbObject): update_object = data else: raise ObjectManagerUpdateError( 'Wrong CmdbObject init format - expecting CmdbObject or dict') update_object.last_edit_time = datetime.now(timezone.utc) if user: update_object.editor_id = user.public_id type_ = self._type_manager.get(update_object.type_id) if not type_.active: raise AccessDeniedError( f'Objects cannot be updated because type `{type_.name}` is deactivated.' ) verify_access(type_, user, permission) ack = self._update(collection=CmdbObject.COLLECTION, public_id=update_object.get_public_id(), data=update_object.__dict__) if self._event_queue and user: event = Event( "cmdb.core.object.updated", { "id": update_object.get_public_id(), "type_id": update_object.get_type_id(), "user_id": user.get_public_id(), 'event': 'update' }) self._event_queue.put(event) return ack.acknowledged
def import_objects(request_user: UserModel): # Check if file exists if not request.files: return abort(400, 'No import file was provided') request_file: FileStorage = get_file_in_request('file', request.files) filename = secure_filename(request_file.filename) working_file = f'/tmp/{filename}' request_file.save(working_file) # Load file format file_format = request.form.get('file_format', None) # Load parser config parser_config: dict = get_element_from_data_request('parser_config', request) or {} if parser_config == {}: LOGGER.info('No parser config was provided - using default parser config') # Check for importer config importer_config_request: dict = get_element_from_data_request('importer_config', request) or None if not importer_config_request: return abort(400, 'No import config was provided') # Check if type exists try: type_manager = TypeManager(database_manager=current_app.database_manager) type_ = type_manager.get(importer_config_request.get('type_id')) if not type_.active: raise AccessDeniedError(f'Objects cannot be created because type `{type_.name}` is deactivated.') verify_import_access(user=request_user, _type=type_, _manager=type_manager) except ObjectManagerGetError as err: return abort(404, err.message) except AccessDeniedError as err: return abort(403, err.message) # Load parser try: parser_class = load_parser_class('object', file_format) except ParserLoadError as ple: return abort(406, ple.message) parser = parser_class(parser_config) LOGGER.info(f'Parser {parser_class} was loaded') # Load importer config try: importer_config_class = load_importer_config_class('object', file_format) except ImporterLoadError as ile: return abort(406, ile.message) importer_config = importer_config_class(**importer_config_request) LOGGER.debug(importer_config_request) # Load importer try: importer_class = load_importer_class('object', file_format) except ImporterLoadError as ile: return abort(406, ile.message) importer = importer_class(working_file, importer_config, parser, object_manager, request_user) LOGGER.info(f'Importer {importer_class} was loaded') try: import_response: ImporterObjectResponse = importer.start_import() except ImportRuntimeError as ire: LOGGER.error(f'Error while importing objects: {ire.message}') return abort(500, ire.message) except AccessDeniedError as err: return abort(403, err.message) # close request file request_file.close() # log all successful imports for message in import_response.success_imports: try: # get object state of every imported object current_type_instance = object_manager.get_type(importer_config_request.get('type_id')) current_object = object_manager.get_object(message.public_id) current_object_render_result = CmdbRender(object_instance=current_object, type_instance=current_type_instance, render_user=request_user, object_manager=object_manager).result() # insert object create log log_params = { 'object_id': message.public_id, 'user_id': request_user.get_public_id(), 'user_name': request_user.get_display_name(), 'comment': 'Object was imported', 'render_state': json.dumps(current_object_render_result, default=default).encode('UTF-8'), 'version': current_object.version } log_manager.insert(action=LogAction.CREATE, log_type=CmdbObjectLog.__name__, **log_params) except ObjectManagerGetError as err: LOGGER.error(err) return abort(404) except RenderError as err: LOGGER.error(err) return abort(500) except LogManagerInsertError as err: LOGGER.error(err) return make_response(import_response)