def init_keys(self): from cmdb.security.key.generator import KeyGenerator kg = KeyGenerator() LOGGER.info('KEY ROUTINE: Generate RSA keypair') kg.generate_rsa_keypair() LOGGER.info('KEY ROUTINE: Generate aes key') kg.generate_symmetric_aes_key() self.__check_database() from cmdb.user_management.managers.user_manager import UserManager, UserModel from cmdb.security.security import SecurityManager scm = SecurityManager(self.setup_database_manager) usm = UserManager(self.setup_database_manager) try: admin_user: UserModel = usm.get(1) LOGGER.warning('KEY ROUTINE: Admin user detected') LOGGER.info( f'KEY ROUTINE: Enter new password for user: {admin_user.user_name}' ) admin_pass = str(input('New admin password: '******'KEY ROUTINE: Password was updated for user: {admin_user.user_name}' ) except Exception as ex: LOGGER.info( f'KEY ROUTINE: Password was updated for user failed: {ex}') LOGGER.info('KEY ROUTINE: FINISHED')
def __create_user_management(self): from cmdb.user_management.models.user import UserModel from cmdb.user_management.managers.user_manager import UserManager from cmdb.user_management.managers.group_manager import GroupManager from cmdb.user_management import __FIXED_GROUPS__ from cmdb.security.security import SecurityManager scm = SecurityManager(self.setup_database_manager) group_manager = GroupManager(self.setup_database_manager) user_manager = UserManager(self.setup_database_manager) for group in __FIXED_GROUPS__: group_manager.insert(group) # setting the initial user to admin/admin as default admin_name = 'admin' admin_pass = '******' import datetime admin_user = UserModel( public_id=1, user_name=admin_name, active=True, group_id=__FIXED_GROUPS__[0].get_public_id(), registration_time=datetime.datetime.now(), password=scm.generate_hmac(admin_pass), ) user_manager.insert(admin_user) return True
def authenticate(self, user_name: str, password: str, **kwargs) -> UserModel: __dbm = DatabaseManagerMongo( **SystemConfigReader().get_all_values_from_section('Database') ) __user_manager = UserManager(__dbm) try: ldap_connection_status = self.connect() LOGGER.debug(f'[LdapAuthenticationProvider] Connection status: {ldap_connection_status}') except Exception as e: LOGGER.error(f'[LdapAuthenticationProvider] Failed to connect to LDAP server - error: {e}') raise AuthenticationError(LdapAuthenticationProvider.get_name(), e) ldap_search_filter = self.config.search['searchfilter'].replace("%username%", user_name) LOGGER.debug(f'[LdapAuthenticationProvider] Search Filter: {ldap_search_filter}') search_result = self.__ldap_connection.search(self.config.search['basedn'], ldap_search_filter) LOGGER.debug(f'[LdapAuthenticationProvider] Search result: {search_result}') if not search_result or len(self.__ldap_connection.entries) == 0: raise AuthenticationError(LdapAuthenticationProvider.get_name(), 'No matching entry') for entry in self.__ldap_connection.entries: LOGGER.debug(f'[LdapAuthenticationProvider] Entry: {entry}') entry_dn = entry.entry_dn try: entry_connection_result = LdapAuthenticationProvider.Connection(self.__ldap_server, entry_dn, password, auto_bind=True) LOGGER.debug(f'[LdapAuthenticationProvider] UserModel connection result: {entry_connection_result}') except Exception as e: LOGGER.error(f'[LdapAuthenticationProvider] UserModel auth result: {e}') raise AuthenticationError(LdapAuthenticationProvider.get_name(), e) # Check if user exists try: user_instance: UserModel = __user_manager.get_by({'user_name': user_name}) except ManagerGetError as umge: LOGGER.warning(f'[LdapAuthenticationProvider] UserModel exists on LDAP but not in database: {umge}') LOGGER.debug(f'[LdapAuthenticationProvider] Try creating user: {user_name}') try: new_user_data = dict() new_user_data['user_name'] = user_name new_user_data['active'] = True new_user_data['group_id'] = self.config.default_group new_user_data['registration_time'] = datetime.now() new_user_data['authenticator'] = LdapAuthenticationProvider.get_name() except Exception as e: LOGGER.debug(f'[LdapAuthenticationProvider] {e}') raise AuthenticationError(LdapAuthenticationProvider.get_name(), e) LOGGER.debug(f'[LdapAuthenticationProvider] New user was init') try: user_id = __user_manager.insert(new_user_data) except ManagerInsertError as umie: LOGGER.debug(f'[LdapAuthenticationProvider] {umie}') raise AuthenticationError(LdapAuthenticationProvider.get_name(), umie) try: user_instance: UserModel = __user_manager.get(public_id=user_id) except ManagerGetError as umge: LOGGER.debug(f'[LdapAuthenticationProvider] {umge}') raise AuthenticationError(LdapAuthenticationProvider.get_name(), umge) return user_instance
def _decorate(*args, **kwargs): if auth: if not auth_is_valid(): return abort(401) if auth and right: if not user_has_right(right): if excepted: with current_app.app_context(): user_manager = UserManager( current_app.database_manager) token = parse_authorization_header( request.headers['Authorization']) try: decrypted_token = TokenValidator( current_app.database_manager).decode_token( token) except ValidationError as err: return abort(401) try: user_id = decrypted_token['DATAGERRY'][ 'value']['user']['public_id'] user_dict: dict = UserModel.to_dict( user_manager.get(user_id)) if excepted: for exe_key, exe_value in excepted.items(): try: route_parameter = kwargs[exe_value] except KeyError: return abort( 403, f'User has not the required right {right}' ) if exe_key not in user_dict.keys(): return abort( 403, f'User has not the required right {right}' ) if user_dict[ exe_key] == route_parameter: return f(*args, **kwargs) except ManagerGetError: return abort(404) return abort( 403, f'User has not the required right {right}') return f(*args, **kwargs)
def authenticate(self, user_name: str, password: str, **kwargs) -> UserModel: __dbm = DatabaseManagerMongo( **SystemConfigReader().get_all_values_from_section('Database') ) __scm = SecurityManager(__dbm) __user_manager = UserManager(__dbm) LOGGER.info(f'[LocalAuthenticationProvider] Try login for user {user_name}') try: user: UserModel = __user_manager.get_by({'user_name': user_name}) except ManagerGetError as umge: raise AuthenticationError(LocalAuthenticationProvider.get_name(), umge.message) login_pass = __scm.generate_hmac(password) if login_pass == user.password: return user raise AuthenticationError(LocalAuthenticationProvider.get_name(), 'UserModel not exists')
def change_user_password(public_id: int): """ HTTP `PATCH` route for updating a single user password. Args: public_id (int): Public ID of the user. Raises: ManagerGetError: When the user with the `public_id` was not found. ManagerUpdateError: When something went wrong during the updated. Returns: UpdateSingleResponse: User with new password """ user_manager: UserManager = UserManager( database_manager=current_app.database_manager) security_manager: SecurityManager = SecurityManager( database_manager=current_app.database_manager) try: user = user_manager.get(public_id=public_id) password = security_manager.generate_hmac(request.json.get('password')) user.password = password user_manager.update(public_id=PublicID(public_id), user=user) api_response = UpdateSingleResponse(result=UserModel.to_dict(user), url=request.url, model=UserModel.MODEL) except ManagerGetError as err: return abort(404, err.message) except ManagerUpdateError as err: return abort(400, err.message) return api_response.make_response()
def delete_user(public_id: int): """ HTTP `DELETE` route for delete a single user resource. Args: public_id (int): Public ID of the user. Raises: ManagerGetError: When the user with the `public_id` was not found. ManagerDeleteError: When something went wrong during the deletion. Returns: DeleteSingleResponse: Delete result with the deleted user as data. """ user_manager: UserManager = UserManager( database_manager=current_app.database_manager) try: deleted_group = user_manager.delete(public_id=PublicID(public_id)) api_response = DeleteSingleResponse( raw=UserModel.to_dict(deleted_group), model=UserModel.MODEL) except ManagerGetError as err: return abort(404, err.message) except ManagerDeleteError as err: return abort(404, err.message) return api_response.make_response()
def update_user(public_id: int, data: dict): """ HTTP `PUT`/`PATCH` route for update a single user resource. Args: public_id (int): Public ID of the updatable user. data (UserModel.SCHEMA): New user data to update. Raises: ManagerGetError: When the user with the `public_id` was not found. ManagerUpdateError: When something went wrong during the update. Returns: UpdateSingleResponse: With update result of the new updated user. """ user_manager: UserManager = UserManager( database_manager=current_app.database_manager) try: user = UserModel.from_data(data=data) user_manager.update(public_id=PublicID(public_id), user=user) api_response = UpdateSingleResponse(result=UserModel.to_dict(user), url=request.url, model=UserModel.MODEL) except ManagerGetError as err: return abort(404, err.message) except ManagerUpdateError as err: return abort(400, err.message) return api_response.make_response()
def insert_user(data: dict): """ HTTP `POST` route for insert a single user resource. Args: data (UserModel.SCHEMA): Insert data of a new user. Raises: ManagerGetError: If the inserted user could not be found after inserting. ManagerInsertError: If something went wrong during insertion. Returns: InsertSingleResponse: Insert response with the new user and its public_id. """ user_manager: UserManager = UserManager( database_manager=current_app.database_manager) security_manager: SecurityManager = SecurityManager( database_manager=current_app.database_manager) try: data['password'] = security_manager.generate_hmac(data['password']) result_id: PublicID = user_manager.insert(data) user = user_manager.get(public_id=result_id) except ManagerGetError as err: return abort(404, err.message) except ManagerInsertError as err: return abort(400, err.message) api_response = InsertSingleResponse(result_id=result_id, raw=UserModel.to_dict(user), url=request.url, model=UserModel.MODEL) return api_response.make_response(prefix='users')
def get_user(public_id: int): """ HTTP `GET`/`HEAD` route for a single user resource. Args: public_id (int): Public ID user. Raises: ManagerGetError: When the selected user does not exists. Notes: Calling the route over HTTP HEAD method will result in an empty body. Returns: GetSingleResponse: Which includes the json data of a UserModel. """ user_manager: UserManager = UserManager( database_manager=current_app.database_manager) try: user: UserModel = user_manager.get(public_id) except ManagerGetError as err: return abort(404, err.message) api_response = GetSingleResponse(UserModel.to_dict(user), url=request.url, model=UserModel.MODEL, body=request.method == 'HEAD') return api_response.make_response()
def __init__(self, object_instance: CmdbObject, type_instance: TypeModel, render_user: UserModel, object_manager: CmdbObjectManager = None, ref_render=False): self.object_instance: CmdbObject = object_instance self.type_instance: TypeModel = type_instance self.render_user: UserModel = render_user self.object_manager = object_manager if self.object_manager: # TODO: Refactor to pass database-manager in init self.type_manager = TypeManager(self.object_manager.dbm) self.user_manager = UserManager(self.object_manager.dbm) self.ref_render = ref_render
def parse_authorization_header(header): """ Parses the HTTP Auth Header to a JWT Token Args: header: Authorization header of the HTTP Request Examples: request.headers['Authorization'] or something same Returns: Valid JWT token """ if not header: return None value = wsgi_to_bytes(header) try: auth_type, auth_info = value.split(None, 1) auth_type = auth_type.lower() except ValueError: # Fallback for old versions auth_type = b"bearer" auth_info = value if auth_type == b"basic": try: username, password = base64.b64decode(auth_info).split(b":", 1) with current_app.app_context(): username = to_unicode(username, "utf-8") password = to_unicode(password, "utf-8") user_manager: UserManager = UserManager( current_app.database_manager) auth_module = AuthModule( SystemSettingsReader(current_app.database_manager)) try: user_instance = auth_module.login(user_manager, username, password) except Exception as e: return None if user_instance: tg = TokenGenerator(current_app.database_manager) return tg.generate_token(payload={ 'user': { 'public_id': user_instance.get_public_id() } }) else: return None except Exception: return None if auth_type == b"bearer": try: tv = TokenValidator() decoded_token = tv.decode_token(auth_info) tv.validate_token(decoded_token) return auth_info except Exception: return None return None
def __init__(self, event, state=False): super(ExportdThread, self).__init__() self.job = None self.job_id = event.get_param("id") self.type_id = event.get_param("type_id") self.user_id = event.get_param("user_id") self.event = event self.is_active = state self.exception_handling = None scr = SystemConfigReader() database_options = scr.get_all_values_from_section('Database') self.__dbm = DatabaseManagerMongo(**database_options) self.log_manager = ExportdLogManager(database_manager=self.__dbm) self.exportd_job_manager = ExportdJobManagement( database_manager=self.__dbm) self.user_manager = UserManager(database_manager=self.__dbm)
def get_request_user(*args, **kwargs): from flask import request, current_app with current_app.app_context(): user_manager = UserManager(current_app.database_manager) token = parse_authorization_header(request.headers['Authorization']) try: decrypted_token = TokenValidator().decode_token(token) except ValidationError as err: return abort(401) try: user_id = decrypted_token['DATAGERRY']['value']['user'][ 'public_id'] except ValueError: return abort(401) user = user_manager.get(user_id) kwargs.update({'request_user': user}) return func(*args, **kwargs)
def __init__(self, object_list: List[CmdbObject], request_user: UserModel, database_manager: DatabaseManagerMongo, ref_render=False, object_manager: CmdbObjectManager = None): self.object_list: List[CmdbObject] = object_list self.request_user = request_user self.ref_render = ref_render self.object_manager = object_manager self.type_manager = TypeManager(database_manager=database_manager) self.user_manager = UserManager(database_manager=database_manager)
def __init__(self, event: Event, state: bool = False): scr = SystemConfigReader() database_options = scr.get_all_values_from_section('Database') database = DatabaseManagerMongo(**database_options) super(ExportdThread, self).__init__() self.job = None self.job_id = int(event.get_param("id")) self.type_id = int( event.get_param("type_id")) if event.get_param("type_id") else None self.user_id = int(event.get_param("user_id")) self.event = event self.is_active = state self.exception_handling = None self.object_manager = CmdbObjectManager(database_manager=database) self.log_manager = ExportdLogManager(database_manager=database) self.exportd_job_manager = ExportdJobManagement( database_manager=database) self.user_manager = UserManager(database_manager=database)
def delete_group(public_id: int, params: GroupDeletionParameters): """ HTTP `DELETE` route for delete a single group resource. Args: public_id (int): Public ID of the user. params (GroupDeletionParameters): Optional action parameters for handling users when the group \ is going to be deleted. Notes: Based on the params attribute. Users can be moved or deleted. Raises: ManagerGetError: When the group with the `public_id` was not found. ManagerDeleteError: When something went wrong during the deletion. Returns: DeleteSingleResponse: Delete result with the deleted group as data. """ group_manager: GroupManager = GroupManager(database_manager=current_app.database_manager, right_manager=RightManager(rights)) user_manager: UserManager = UserManager(database_manager=current_app.database_manager) # Check of action is set if params.action: users_in_group: List[UserModel] = user_manager.get_many(Query({'group_id': public_id})) if len(users_in_group) > 0: if params.action == GroupDeleteMode.MOVE.value: if params.group_id: for user in users_in_group: user.group_id = int(params.group_id) try: user_manager.update(user.public_id, user) except ManagerUpdateError as err: return abort(400, f'Could not move user: {user.public_id} to group: {params.group_id} | ' f'Error: {err.message}') if params.action == GroupDeleteMode.DELETE.value: for user in users_in_group: try: user_manager.delete(user.public_id) except ManagerDeleteError as err: return abort(400, f'Could not delete user: {user.public_id} | Error: {err.message}') try: deleted_group = group_manager.delete(public_id=PublicID(public_id)) api_response = DeleteSingleResponse(raw=UserGroupModel.to_dict(deleted_group), model=UserGroupModel.MODEL) except ManagerGetError as err: return abort(404, err.message) except ManagerDeleteError as err: return abort(404, err.message) return api_response.make_response()
def user_has_right(required_right: str) -> bool: """Check if a user has a specific right""" from flask import request, current_app with current_app.app_context(): user_manager = UserManager(current_app.database_manager) group_manager = GroupManager(current_app.database_manager, RightManager(rights)) token = parse_authorization_header(request.headers['Authorization']) try: decrypted_token = TokenValidator(database_manager=current_app.database_manager).decode_token(token) except ValidationError as err: return abort(401) try: user_id = decrypted_token['DATAGERRY']['value']['user']['public_id'] user = user_manager.get(user_id) group = group_manager.get(user.group_id) right_status = group.has_right(right_name=required_right) if not right_status: right_status = group.has_extended_right(right_name=required_right) return right_status except ManagerGetError: return False
def preset_database(database_manager, database_name): from cmdb.database.errors.database_errors import DatabaseNotExists from cmdb.security.key.generator import KeyGenerator from cmdb.security.security import SecurityManager from cmdb.user_management.managers.group_manager import GroupManager from cmdb.user_management.managers.user_manager import UserManager try: database_manager.drop_database(database_name) except DatabaseNotExists: pass from cmdb.user_management import __FIXED_GROUPS__ from datetime import datetime kg = KeyGenerator(database_manager=database_manager) kg.generate_rsa_keypair() kg.generate_symmetric_aes_key() group_manager = GroupManager(database_manager=database_manager) user_manager = UserManager(database_manager=database_manager) security_manager = SecurityManager(database_manager=database_manager) for group in __FIXED_GROUPS__: group_manager.insert(group) admin_name = 'admin' admin_pass = '******' from cmdb.user_management import UserModel admin_user = UserModel( public_id=1, user_name=admin_name, active=True, group_id=__FIXED_GROUPS__[0].public_id, registration_time=datetime.now(), password=security_manager.generate_hmac(admin_pass), ) user_manager.insert(admin_user)
def post_login(): user_manager: UserManager = UserManager(current_app.database_manager) group_manager: GroupManager = GroupManager( current_app.database_manager, right_manager=RightManager(rights)) security_manager: SecurityManager = SecurityManager( current_app.database_manager) login_data = request.json if not request.json: return abort(400, 'No valid JSON data was provided') request_user_name = login_data['user_name'] request_password = login_data['password'] auth_module = AuthModule( system_settings_reader.get_all_values_from_section( 'auth', default=AuthModule.__DEFAULT_SETTINGS__), user_manager=user_manager, group_manager=group_manager, security_manager=security_manager) user_instance = None try: user_instance = auth_module.login(request_user_name, request_password) except (AuthenticationProviderNotExistsError, AuthenticationProviderNotActivated) as err: return abort(503, err.message) except Exception as e: return abort(401) finally: # If login success generate user instance with token if user_instance: tg = TokenGenerator() token: bytes = tg.generate_token( payload={'user': { 'public_id': user_instance.get_public_id() }}) token_issued_at = int(datetime.now().timestamp()) token_expire = int(tg.get_expire_time().timestamp()) login_response = LoginResponse(user_instance, token, token_issued_at, token_expire) return login_response.make_response() # Login not success else: return abort(401, 'Could not login')
def get_users(params: CollectionParameters): """ HTTP `GET`/`HEAD` route for getting a iterable collection of resources. Args: params (CollectionParameters): Passed parameters over the http query string Returns: GetMultiResponse: Which includes a IterationResult of the UserModel. Notes: Calling the route over HTTP HEAD method will result in an empty body. Raises: ManagerIterationError: If the collection could not be iterated. ManagerGetError: If the collection/resources could not be found. """ user_manager: UserManager = UserManager( database_manager=current_app.database_manager) try: iteration_result: IterationResult[UserModel] = user_manager.iterate( filter=params.filter, limit=params.limit, skip=params.skip, sort=params.sort, order=params.order) users = [UserModel.to_dict(user) for user in iteration_result.results] api_response = GetMultiResponse(users, total=iteration_result.total, params=params, url=request.url, model=UserModel.MODEL, body=request.method == 'HEAD') except ManagerIterationError as err: return abort(400, err.message) except ManagerGetError as err: return abort(404, err.message) return api_response.make_response()
from cmdb.security.token.generator import TokenGenerator from cmdb.user_management import UserModel from cmdb.user_management.managers.user_manager import UserManager from cmdb.utils.system_reader import SystemSettingsReader from cmdb.utils.system_writer import SystemSettingsWriter try: from cmdb.utils.error import CMDBError except ImportError: CMDBError = Exception auth_blueprint = RootBlueprint('auth_rest', __name__, url_prefix='/auth') LOGGER = logging.getLogger(__name__) with current_app.app_context(): user_manager: UserManager = UserManager(current_app.database_manager) system_settings_reader: SystemSettingsReader = SystemSettingsReader( current_app.database_manager) system_setting_writer: SystemSettingsWriter = SystemSettingsWriter( current_app.database_manager) @auth_blueprint.route('/settings/', methods=['GET']) @auth_blueprint.route('/settings', methods=['GET']) @login_required @insert_request_user @right_required('base.system.view') def get_auth_settings(request_user: UserModel): auth_module = AuthModule(system_settings_reader) return make_response(auth_module.settings)
def login(self, user_manager: UserManager, user_name: str, password: str) -> Union[UserModel, None]: """ Performs a login try with given username and password If the user is not found, iterate over all installed and activated providers Args: user_manager: Usermanager instance user_name: Name of the user password: Password Returns: UserModel: instance if user was found and password was correct None: if something went wrong """ user_name = user_name.lower() user_instance = None try: founded_user = user_manager.get_by({'user_name': user_name}) provider_class_name = founded_user.authenticator LOGGER.debug( f'[AUTH] Founded user: {founded_user} with provider: {provider_class_name}' ) if not self.provider_exists(provider_class_name): raise AuthenticationProviderNotExistsError(provider_class_name) provider: ClassVar[ AuthenticationProvider] = self.get_provider_class( provider_class_name) provider_config_class: ClassVar[ str] = provider.PROVIDER_CONFIG_CLASS provider_config_settings = self.settings.get_provider_settings( provider.get_name()) provider_config_instance = provider_config_class( **provider_config_settings) provider_instance = provider(config=provider_config_instance) if not provider_instance.is_active(): raise AuthenticationProviderNotActivated( f'Provider {provider_class_name} is deactivated') if provider_instance.EXTERNAL_PROVIDER and not self.settings.enable_external: raise AuthenticationProviderNotActivated( f'External providers are deactivated') try: user_instance = provider_instance.authenticate( user_name, password) except AuthenticationError as ae: LOGGER.error(f'[LOGIN] UserModel could not login: {ae}') except ManagerGetError as umge: LOGGER.error(f'[AUTH] {user_name} not in database: {umge}') LOGGER.info( f'[AUTH] Check for other providers - request_user: {user_name}' ) # get installed providers provider_list = self.providers LOGGER.debug(f'[AUTH] Provider list: {provider_list}') external_enabled = self.settings.enable_external for provider in provider_list: LOGGER.debug(f'[AUTH] using provider: {provider}') provider_config_class = provider.PROVIDER_CONFIG_CLASS provider_settings = self.settings.get_provider_settings( provider.get_name()) provider_config_instance = provider_config_class( **provider_settings) if not provider_config_instance.is_active(): continue if provider.EXTERNAL_PROVIDER and not self.settings.enable_external: continue provider_instance = provider(config=provider_config_instance) try: user_instance = provider_instance.authenticate( user_name, password) if user_instance: break except AuthenticationError as ae: LOGGER.error( f'[AUTH] UserModel {user_name} could not validate with provider {provider}: {ae}' ) LOGGER.info(f'[AUTH] Provider instance: {provider_instance}') except Exception as e: import traceback traceback.print_exc() LOGGER.error(f'[AUTH] Error while login: {e}') return None finally: return user_instance
class ExportdThread(Thread): def __init__(self, event, state=False): super(ExportdThread, self).__init__() self.job = None self.job_id = event.get_param("id") self.type_id = event.get_param("type_id") self.user_id = event.get_param("user_id") self.event = event self.is_active = state self.exception_handling = None scr = SystemConfigReader() database_options = scr.get_all_values_from_section('Database') self.__dbm = DatabaseManagerMongo(**database_options) self.log_manager = ExportdLogManager(database_manager=self.__dbm) self.exportd_job_manager = ExportdJobManagement( database_manager=self.__dbm) self.user_manager = UserManager(database_manager=self.__dbm) def run(self): try: if self.type_id: for obj in self.exportd_job_manager.get_job_by_event_based( True): if next((item for item in obj.get_sources() if item["type_id"] == self.type_id), None): if obj.get_active( ) and obj.scheduling["event"]["active"]: self.job = obj self.worker() elif self.is_active: self.job = self.exportd_job_manager.get_job(self.job_id) self.worker() except Exception as ex: LOGGER.error(ex) return ex def worker(self): cur_user = None try: # update job for UI self.job.state = ExecuteState.RUNNING.name self.job.last_execute_date = datetime.utcnow() # get current user cur_user = self.user_manager.get(self.user_id) self.exportd_job_manager.update_job(self.job, self.user_manager.get( self.user_id), event_start=False) # execute Exportd job job = cmdb.exportd.exporter_base.ExportdManagerBase(self.job) job.execute(self.event, cur_user.get_public_id(), cur_user.get_display_name()) except Exception as err: LOGGER.error(err) self.exception_handling = err # Generate Error log try: log_params = { 'job_id': self.job.get_public_id(), 'state': False, 'user_id': cur_user.get_public_id(), 'user_name': cur_user.get_display_name(), 'event': self.event.get_type(), 'message': ['Successful'] if not err else err.args, } self.log_manager.insert_log(action=LogAction.EXECUTE, log_type=ExportdJobLog.__name__, **log_params) except LogManagerInsertError as err: LOGGER.error(err) finally: # update job for UI self.job.state = ExecuteState.SUCCESSFUL.name if not self.exception_handling else ExecuteState.FAILED.name self.exportd_job_manager.update_job(self.job, self.user_manager.get( self.user_id), event_start=False)
class CmdbRender: AUTHOR_ANONYMOUS_NAME = 'unknown' def __init__(self, object_instance: CmdbObject, type_instance: TypeModel, render_user: UserModel, object_manager: CmdbObjectManager = None, ref_render=False): self.object_instance: CmdbObject = object_instance self.type_instance: TypeModel = type_instance self.render_user: UserModel = render_user self.object_manager = object_manager if self.object_manager: # TODO: Refactor to pass database-manager in init self.type_manager = TypeManager(self.object_manager.dbm) self.user_manager = UserManager(self.object_manager.dbm) self.ref_render = ref_render @property def object_instance(self) -> CmdbObject: """ Object of the class CmdbObject that has already been instantiated. The data should come from the database and already be validated. This already happens when the object is instantiated. """ return self._object_instance @object_instance.setter def object_instance(self, object_instance: CmdbObject): """ Property setter for object_instance. The render only checks whether the passed object belongs to the correct class, not whether it is valid. """ if not isinstance(object_instance, CmdbObject): raise ObjectInstanceError() else: self._object_instance = object_instance @property def type_instance(self) -> TypeModel: """ Object of the class TypeModel that has already been instantiated. The data should come from the database and already be validated. This already happens when the object is instantiated. """ return self._type_instance @type_instance.setter def type_instance(self, type_instance: TypeModel): """ Property setter for type_instance. The render only checks whether the passed object belongs to the correct class, not whether it is valid. """ if not isinstance(type_instance, TypeModel): raise TypeInstanceError() self._type_instance = type_instance def result(self) -> RenderResult: return self._generate_result() def _generate_result(self) -> RenderResult: render_result = RenderResult() try: render_result = self.__generate_object_information(render_result) render_result = self.__generate_type_information(render_result) render_result = self.__set_fields(render_result) render_result = self.__set_sections(render_result) render_result = self.__set_summaries(render_result) render_result = self.__set_external(render_result) except CMDBError as err: import traceback traceback.print_exc() raise RenderError( f'Error while generating a CMDBResult: {str(err)}') return render_result def __generate_object_information( self, render_result: RenderResult) -> RenderResult: try: author_name = self.user_manager.get( self.object_instance.author_id).get_display_name() except CMDBError: author_name = CmdbRender.AUTHOR_ANONYMOUS_NAME if self.object_instance.editor_id: try: editor_name = self.user_manager.get( self.object_instance.editor_id).get_display_name() except CMDBError: editor_name = None else: editor_name = None render_result.object_information = { 'object_id': self.object_instance.public_id, 'creation_time': self.object_instance.creation_time, 'last_edit_time': self.object_instance.last_edit_time, 'author_id': self.object_instance.author_id, 'author_name': author_name, 'editor_id': self.object_instance.editor_id, 'editor_name': editor_name, 'active': self.object_instance.active, 'version': self.object_instance.version } return render_result def __generate_type_information( self, render_result: RenderResult) -> RenderResult: try: author_name = self.user_manager.get( self.type_instance.author_id).get_display_name() except CMDBError as err: author_name = CmdbRender.AUTHOR_ANONYMOUS_NAME try: self.type_instance.render_meta.icon except KeyError: self.type_instance.render_meta.icon = '' render_result.type_information = { 'type_id': self.type_instance.public_id, 'type_name': self.type_instance.name, 'type_label': self.type_instance.label, 'creation_time': self.type_instance.creation_time, 'author_id': self.type_instance.author_id, 'author_name': author_name, 'icon': self.type_instance.render_meta.icon, 'active': self.type_instance.active, 'version': self.type_instance.version, 'acl': self.type_instance.acl.to_json(self.type_instance.acl) } return render_result def __set_fields(self, render_result: RenderResult) -> RenderResult: render_result.fields = self.__merge_fields_value() return render_result def __set_sections(self, render_result: RenderResult) -> RenderResult: try: render_result.sections = [ section.to_json(section) for section in self.type_instance.render_meta.sections ] except (IndexError, ValueError): render_result.sections = [] return render_result def __merge_field_content_section(self, field: dict, object_: CmdbObject): curr_field = [x for x in object_.fields if x['name'] == field['name']][0] if curr_field['name'] == field['name'] and field.get('value'): field['default'] = field['value'] field['value'] = curr_field['value'] # handle dates that are stored as strings if field['type'] == 'date' and isinstance(field['value'], str) and field['value']: field['value'] = parse(field['value'], fuzzy=True) if self.ref_render and field['type'] == 'ref' and field['value']: field['reference'] = self.__merge_references(field) return field def __merge_fields_value(self) -> List[dict]: """ Checks all fields for references. Fields with references are extended by the property 'references'. All reference values are stored in the new property. """ field_map = [] for idx, section in enumerate(self.type_instance.render_meta.sections): if type(section) is TypeFieldSection and isinstance( section, TypeFieldSection): for section_field in section.fields: field = {} try: field = self.type_instance.get_field(section_field) field = self.__merge_field_content_section( field, self.object_instance) if field['type'] == 'ref' and (not self.ref_render or 'summaries' not in field): ref_field_name: str = field['name'] field = self.type_instance.get_field( ref_field_name) reference_id: int = self.object_instance.get_value( ref_field_name) field['value'] = reference_id reference_object: CmdbObject = self.object_manager.get_object( public_id=reference_id) ref_type: TypeModel = self.type_manager.get( reference_object.get_type_id()) field['reference'] = { 'type_id': ref_type.public_id, 'type_name': ref_type.name, 'type_label': ref_type.label, 'object_id': reference_id, 'summaries': [] } for ref_section_field_name in ref_type.get_fields( ): ref_section_field = ref_type.get_field( ref_section_field_name['name']) try: ref_field = self.__merge_field_content_section( ref_section_field, reference_object) except (FileNotFoundError, ValueError, IndexError): continue field['reference']['summaries'].append( ref_field) except (ValueError, IndexError, FileNotFoundError, ObjectManagerGetError): field['value'] = None field_map.append(field) elif type(section) is TypeReferenceSection and isinstance( section, TypeReferenceSection): ref_field_name: str = f'{section.name}-field' ref_field = self.type_instance.get_field(ref_field_name) reference_id: int = self.object_instance.get_value( ref_field_name) ref_field['value'] = reference_id try: reference_object: CmdbObject = self.object_manager.get_object( public_id=reference_id) except ObjectManagerGetError: reference_object = None ref_type: TypeModel = self.type_manager.get( section.reference.type_id) ref_section = ref_type.get_section( section.reference.section_name) ref_field['references'] = { 'type_id': ref_type.public_id, 'type_name': ref_type.name, 'type_label': ref_type.label, 'fields': [] } if not ref_section: continue if not section.reference.selected_fields or len( section.reference.selected_fields) == 0: selected_ref_fields = ref_section.fields section.reference.selected_fields = selected_ref_fields self.type_instance.render_meta.sections[idx] = section else: selected_ref_fields = [ f for f in ref_section.fields if f in section.reference.selected_fields ] for ref_section_field_name in selected_ref_fields: ref_section_field = ref_type.get_field( ref_section_field_name) if reference_object: try: ref_section_field = self.__merge_field_content_section( ref_section_field, reference_object) except (FileNotFoundError, ValueError, IndexError, ObjectManagerGetError): continue ref_field['references']['fields'].append(ref_section_field) field_map.append(ref_field) return field_map def __merge_references(self, current_field): # Initialise TypeReference reference = TypeReference(type_id=0, object_id=0, type_label='', line='') if current_field['value']: try: ref_object = self.object_manager.get_object( int(current_field['value']), user=self.render_user, permission=AccessControlPermission.READ) except AccessDeniedError as err: return err.message except ObjectManagerGetError: return TypeReference.to_json(reference) try: ref_type = self.object_manager.get_type( ref_object.get_type_id()) _summary_fields = [] _nested_summaries = self.type_instance.get_nested_summaries() _nested_summary_fields = ref_type.get_nested_summary_fields( _nested_summaries) _nested_summary_line = ref_type.get_nested_summary_line( _nested_summaries) reference.type_id = ref_type.get_public_id() reference.object_id = int(current_field['value']) reference.type_label = ref_type.label reference.icon = ref_type.get_icon() reference.prefix = ref_type.has_nested_prefix( _nested_summaries) _summary_fields = _nested_summary_fields \ if (_nested_summary_line or _nested_summary_fields) else ref_type.get_summary().fields summaries = [] summary_values = [] for field in _summary_fields: summary_value = str([ x for x in ref_object.fields if x['name'] == field['name'] ][0]['value']) summaries.append({ "value": summary_value, "type": field.get('type') }) summary_values.append(summary_value) reference.summaries = summaries try: # fill the summary line with summaries value data reference.line = _nested_summary_line if not reference.line_requires_fields(): reference.summaries = [] if _nested_summary_line: reference.fill_line(summary_values) except (TypeReferenceLineFillError, Exception): pass except ObjectManagerGetError: return TypeReference.to_json(reference) return TypeReference.to_json(reference) def __set_summaries(self, render_result: RenderResult) -> RenderResult: # global summary list summary_list = [] summary_line = '' default_line = f'{self.type_instance.label} #{self.object_instance.public_id}' if not self.type_instance.has_summaries(): render_result.summaries = summary_list render_result.summary_line = default_line return render_result try: summary_list = self.type_instance.get_summary().fields render_result.summaries = summary_list first = True for line in summary_list: if first: summary_line += f'{line["value"]}' first = False else: summary_line += f' | {line["value"]}' render_result.summary_line = summary_line except Exception: summary_line = default_line finally: render_result.summary_line = summary_line return render_result def __set_external(self, render_result: RenderResult) -> RenderResult: """ get filled external links Returns: list of filled external links (TypeExternalLink) """ # global external list external_list = [] # checks if type has externals defined if not self.type_instance.has_externals(): render_result.externals = [] # loop over all externals for ext_link in self.type_instance.get_externals(): # append all values for required field in this list field_list = [] # if data are missing or empty append here missing_list = [] try: # get TypeExternalLink definitions from type ext_link_instance = self.type_instance.get_external( ext_link.name) # check if link requires data - regex check for {} if ext_link_instance.link_requires_fields(): # check if has fields if not ext_link_instance.has_fields(): raise ValueError(field_list) # for every field get the value data from object_instance for ext_link_field in ext_link_instance.fields: try: if ext_link_field == 'object_id': field_value = self.object_instance.public_id else: field_value = self.object_instance.get_value( ext_link_field) if field_value is None or field_value == '': # if value is empty or does not exists raise ValueError(ext_link_field) field_list.append(field_value) except CMDBError: # if error append missing data missing_list.append(ext_link_instance) if len(missing_list) > 0: raise RuntimeError(missing_list) try: # fill the href with field value data ext_link_instance.fill_href(field_list) except ValueError: continue except (CMDBError, Exception): continue external_list.append(TypeExternalLink.to_json(ext_link_instance)) render_result.externals = external_list return render_result