def __init__(self, master=None, controller_mailbox=None): self.master = master if master else Master.get_master(mailbox=controller_mailbox) self.controller_mailbox = controller_mailbox self.config_handler = ConfigHandler() initialize_storage_db() check_tool_availability() self.access_handler = AccessHandler() acl_parser = ACLConfigHandler() #database access authorization self.table_to_class = dict(workspaces=Workspaces, storages=Storage) self.cls_to_identifier_method = { Workspaces: Workspaces.get_by_full_name, Storage: Storage.get_storage_by_name} self.cls_to_acl = {Workspaces: acl_parser.get_workspaces_setter_acl, Storage: acl_parser.get_storages_setter_acl}
def extract_action_log(): if not g.munge: return if not g.payload.get('action_log'): print('WARNING: ACTION LOG WASN\'T GENERATED') return log_entry = g.payload.pop('action_log') with open(ConfigHandler().action_log_path, 'a+') as f: s = ','.join([g.username, g.pop('source_ip'), log_entry]) + '\n' f.write(s)
def __init__(self, username, label, storage, max_extension_period, max_extensions, counter): self.username = username self.label = label self.counter = counter self.full_name = ConfigHandler().assemble_workspace_full_name( username, label, counter) self.storage = storage self.time_created = datetime.now() self.max_extension_period = max_extension_period self.max_extensions = max_extensions self.times_extended = 0 self.expiration_date = datetime.now() + timedelta( days=max_extension_period) workspace_options = ConfigHandler().get_workspace_options() for option in workspace_options: for key in option: setattr(self, key, option[key]) session = meta.get_session(self) session.add(self) session.commit()
def test_get_emails_for_errors(): """Test getters""" c_handler1 = ConfigHandler(path + '/src/tests/application/config.ini') #assert c_handler1.get_emails_for_errors() == ['*****@*****.**', '*****@*****.**', '*****@*****.**'] assert c_handler1.get_logs_storage_duration() == 30 assert c_handler1.get_max_tasks_number_for_user() == 3 assert c_handler1.get_administrators() == ['ldap1', 'ldap2', 'ldap3'] assert c_handler1.get_search_address() == 'klmno'
class NotificationHandler: """ Handles notification, that have to be resolved with MessageService """ MESSAGE = "\n\nAutomatically generated message from DMD\n" + datetime.datetime.now( ).strftime("%d.%m.%Y %H:%M:%S") _config_handler = ConfigHandler() def __init__(self): self._message_service = EmailService( self._config_handler.get_email_domain()) def resolve_notification(self, job): """ Resolves notification. :param job: Job with changed status """ job_id = "Task ID " + str(job.get_job_id()) if job.get_status() == JobStatus.ACTIVE and job.has_start_notification( ): self._message_service.mail([job.get_user()], job_id + " has been started." + self.MESSAGE) if job.get_status() == JobStatus.DONE and job.has_end_notification(): self._message_service.mail([job.get_user()], job_id + " has been completed." + self.MESSAGE) if job.get_status() == JobStatus.PAUSED and job.has_error_notification( ): self._message_service.mail([job.get_user()], job_id + " has been paused." + self.MESSAGE) if job.get_error() is not None and job.get_status( ) == JobStatus.PAUSED: error_emails = self._config_handler.get_emails_for_errors() self._message_service.mail( None, job_id + " has been paused because of following error: " + job.get_error(), error_emails) return def resolve_exception_notification(self, exception): """ Resolves error notification :param exception: exception with message """ self._message_service.send( None, "Exception occurred: " + exception.message + self.MESSAGE) return
def patch(self, full_name): '''Use this to modify the files's acl''' pa = patch_access_schema(g.payload) if not is_plausible_entry(pa['tag_type'], pa['name']): raise SyntaxError('Bad Request.') role = current_app.config['APPLICATION'].get_user_type(g.username) # not specifying caller indicates full authority and access rights caller = (None if role == 'Administrator' else g.username) username, label, counter = ConfigHandler().disassemble_workspace_full_name(full_name) req = { 'username': username, 'label': label, 'counter': counter, 'caller': caller, 'tag_type': pa['tag_type'], 'name': pa['name'], 'instruction': pa['instruction'], } current_app.config['APPLICATION'].put_workspace_permission(**req) return '', 204
class Application: """ Represents adapter pattern. Adapts json input from Controller to ApplicationFacade """ def __init__(self, master=None, controller_mailbox=None): self.master = master if master else Master.get_master(mailbox=controller_mailbox) self.controller_mailbox = controller_mailbox self.config_handler = ConfigHandler() initialize_storage_db() check_tool_availability() self.access_handler = AccessHandler() acl_parser = ACLConfigHandler() #database access authorization self.table_to_class = dict(workspaces=Workspaces, storages=Storage) self.cls_to_identifier_method = { Workspaces: Workspaces.get_by_full_name, Storage: Storage.get_storage_by_name} self.cls_to_acl = {Workspaces: acl_parser.get_workspaces_setter_acl, Storage: acl_parser.get_storages_setter_acl} def create_job(self, user, for_user, workspace, target, email): """ :return: ID of a new Job :raises UserNotFoundException: if 'for_user' or 'user' doesn't exist in database :raises SearchException: Search raises an exception. See exception's message for details :raises StorageNotAcceptingException: if one of the referenced Storages doesn't accept jobs currently :raises NoAdministratorRightsException: if 'user' can not create jobs for 'for_user' :raises PermissionException: if 'for_user' reached his max. amount of jobs :raises MasterPausedException: if Master is paused """ caller = User.get_user_by_username(user) for_user = User.get_user_by_username(for_user) if for_user else caller target_storj = Storage.get_storage_by_name(target) src_workspace = Workspaces.get_by_full_name(workspace) if src_workspace.username != caller.name and caller.get_user_type() != UserRole.Administrator: raise PermissionError('Unauthorized to move workspaces of other users.') src_storj = Storage.get_storage_by_name(src_workspace.storage) source = src_workspace.full_path addr = search_class.verify_job(source, target) target_path = target_storj.mountpoint + addr['source_relative_path'] copy_options = determine_copytool(src_storj, target_storj) job = Job(addr['source_alias'], target, source, email, for_user, target_path=target_path, copy_options=json.dumps(copy_options)) self.access_handler.check_create_job(job, caller) self.master.add_to_queue(job) return job.get_job_id() def cancel_job(self, job_id, user): """ :raises JobNotFoundException: if there is no job with 'job_id' :raises UserNotFoundException: if 'user' doesn't exist :raises PermissionException: if 'user' is not permitted to cancel given job :raises SemanticException: if 'job' is already cancelled or done """ job = Job.get_job_by_id(job_id) calling_user = User.get_user_by_username(user) self.access_handler.check_cancel_job(job, calling_user) self.master.cancel_job(job) def get_jobs(self, days, user=None, for_user=None, statuses=None): """ :raises UserNotFoundException: if given 'user' or 'for_user' doesn't exist :raises NoProjectManagerRightsException: @see access_handler """ calling_user = User.get_user_by_username(user) if user else None team = True if for_user == "team" else False for_user = None if for_user in [None, "team"] else User.get_user_by_username(for_user) if team: self.access_handler.check_read_rights(None, calling_user) jobs = Job.get_jobs(calling_user.get_team_members(), statuses, days) elif for_user is not None and calling_user is not None: self.access_handler.check_read_rights(for_user, calling_user) jobs = Job.get_jobs([for_user.get_username()], statuses, days) else: jobs = Job.get_jobs(None, statuses) return build_log(jobs) def get_directory_list(self, storage=None, user=None, for_user=None): """ Routes get_directory_list request to ApplicationFacade and builds JSON :raises UserNotFoundException: if given 'user' or 'for_user' doesn't exist :raises NoProjectManagerRightsException: @see access_handler :raises StorageAliasNotFoundException: if 'storage' is not found. :raises StorageNotMountedException: if a Storage to be worked on is not currently mounted. :raises NoResponseFromSearchException: if Search is not reachable """ calling_user = User.get_user_by_username(user) if user else None team = True if for_user == "team" else False for_user = None if for_user in [None, "team"] else User.get_user_by_username(for_user) if team: self.access_handler.check_read_rights(None, calling_user) users = calling_user.get_team_members() elif self.has_read_permission(calling_user, for_user): users = [for_user.get_username()] if for_user else None else: raise PermissionError("You have no access to this data!") return search_class.get_directory_list(storage_alias=storage, usernames=users) def get_storage_alias_list(self): """ :return: list of available storages :raises NoResponseFromSearchException: if Search is not reachable """ storage_aliases = [s.alias for s in Storage.get_storages()] return dict(storages=storage_aliases) def get_storages(self): return build_storages(Storage.get_storages()) def get_storage(self, alias): return build_storages([Storage.get_storage_by_name(alias)]) def get_job(self, user, job_id): """ Routes get_job request to ApplicationFacade :raises UserNotFoundException: if given 'user' doesn't exist :raises NoProjectManagerRightsException: @see access_handler """ calling_user = User.get_user_by_username(user) job = Job.get_job_by_id(job_id) for_user = job.get_user() self.access_handler.check_read_rights(for_user, calling_user) return build_job(job) def set_rights(self, user, role): """ Routes set_rights request to ApplicationFacade. :raises UserNotFoundException: if given 'user' doesn't exist :raises PermissionException: @see access_handler """ for_user = User.get_user_by_username(user) role = UserRole(role) self.access_handler.check_set_rights(for_user, role) for_user.set_user_type(role) def add_user_to_team(self, for_user, to_manager): """ Routes add_user_to_team request to ApplicationFacade of another user (to_manager) """ for_user = User.get_user_by_username(for_user) manager = User.get_user_by_username(to_manager) # @Todo test inheritance of get_user_by_username self.access_handler.check_add_user_to_team(for_user, manager) manager.add_user_to_team(for_user) def get_team_list(self): """ Routes get_team_list request to ApplicationFacade """ result = dict managers = User.get_users([UserRole.ProjectManager]) for manager in managers: result.update({manager.get_username(): manager.get_team_members()}) return build_team_list(result) def set_priority(self, job_id, priority): """ Routes set_priority request to ApplicationFacade :raises JobNotFoundException: job with 'job_id' doesn't exist :raises PermissionException: job is not in the queue :raises MasterPausedException: if master is paused """ job = Job.get_job_by_id(job_id) self.access_handler.check_set_priority(job) self.master.set_priority(job, priority) def get_workers(self): return build_workers(self.master.get_workers()) def resume(self, job_id): """ Routes resume request to ApplicationFacade """ job = Job.get_job_by_id(job_id) self.access_handler.check_resume(job) self.master.resume_job(job) def verify_user_via_token(self, user, token): return self.access_handler.verify_user_via_token(user, token) def ensure_existance(self, user): return self.access_handler.ensure_existance(user) def get_user_type(self, user, as_string=True): user = User.get_user_by_username(user) if not as_string: return user.get_user_type() return user.get_user_type().name def enable_worker(self, worker_id): self.master.enable_worker(worker_id) def disable_worker(self, worker_id): self.master.disable_worker(worker_id) def get_credentials_by_user(self, user): user = User.get_user_by_username(user) self.access_handler.verify_user_via_token(user.name, None) token = user.get_token() return dict(token=token) def enable_master(self): self.master.is_active = True def disable_master(self, ): self.master.is_active = False def put_workspace_permission(self, username, label, counter, caller, tag_type, name, instruction): w = Workspaces.get_by_triple(username, label, counter) p = Posix(w.full_path) if caller is not None: if caller != p.get_owner(): raise PermissionError('Insufficient permissions.') Posix(w.full_path).put_permission(tag_type, name, instruction) def get_workspace_permission(self, username, label, counter): w = Workspaces.get_by_triple(username, label, counter) return Posix(w.full_path).get_permission() def has_read_permission(self, calling_user, for_user): return (calling_user.get_user_type() == UserRole.Administrator or calling_user.get_username() == for_user.get_username()) def get_workspaces(self, for_user): if for_user: return build_workspaces(Workspaces.get_by_username(for_user)) else: return build_workspaces(Workspaces.get_all()) def create_workspace(self, username, ws_label, storage_alias=None): if not storage_alias: storage_alias = self.config_handler.workspace_default_storage storj = Storage.get_storage_by_name(storage_alias) counter = Workspaces.calc_counter(ws_label, username) filename = self.config_handler.assemble_workspace_full_name(username, ws_label, counter) mnt = storj.mountpoint path = mnt + filename + '/' if os.path.exists(path): raise FileExistsError('workspace full_name naming collision, directory still exists') Workspaces( username=username, label=ws_label, storage=storage_alias, max_extension_period=storj.max_extension_period, max_extensions=storj.max_extensions, counter=counter ) os.mkdir(path) uid = pwd.getpwnam(username).pw_uid os.chmod(path, 0o755) os.chown(path, uid, uid) w = Workspaces.get_by_triple(username, ws_label, counter) w.set_full_path(path) return w.full_name def remove_workspace(self, user, user_type, name): w = Workspaces.get_by_full_name(name) full_path = w.full_path full_name = w.full_name # if w.username == user or user_type is UserRole.Administrator: # pass # else: # raise PermissionError('Not allowed to remove workspace ' + w.full_name + '.') if not w.username == user and user_type is not UserRole.Administrator: raise PermissionError('Not allowed to remove workspace ' + w.full_name + '.') #remove ws from DB w.remove() #remove ws from fs if os.path.exists(full_path): try: shutil.rmtree(full_path) pass except OSError as e: return (full_name, "error: "+ e) else: return (full_name, "not found") return (w.full_name, "removed") def extend_workspace(self, user, user_type, name): w = Workspaces.get_by_full_name(name) if not w.username == user and user_type is not UserRole.Administrator: raise PermissionError('Not allowed to extend workspace ' + w.full_name + '.') w.extend() return (w.full_name, str(w.time_remaining)) def set_in_database(self, table, key, value, identifier, user): # Strip down value to max 1024, probably should be improved value = value[:1024] user = User.get_user_by_username(user) cls = self.table_to_class[table] acl = self.cls_to_acl[cls]() if not key in acl[user.get_user_type()]: raise PermissionError('Users of type ' + user.get_user_type().name + ' are not allowed to set the ' + key + ' attribute in ' +table) meth = self.cls_to_identifier_method[cls] obj = meth(identifier) if not obj: raise AttributeError('No ' + table + ' with identifier ' + identifier + ' was found.') # Check if this operation, changing a users property (workspace), is authorized if cls.__name__ == 'Workspaces' and user.name != obj.username and user.get_user_type() != UserRole.Administrator: raise PermissionError('You are not allowed to modify the workspace ' + obj.full_name) obj.set_value(key, value)
def get(self, full_name): username, label, counter = ConfigHandler().disassemble_workspace_full_name(full_name) perms = current_app.config['APPLICATION'].get_workspace_permission(username, label, counter) return jsonify(perms)
def test_wrong_logs_duration(): """Test wrong _logs_storage_duration value (not int)""" with pytest.raises(ConfigurationException): c_handler = ConfigHandler( path + '/src/tests/application/config_with_wrong_logs_duration.ini')
def test_wrong_max_number(): """Test wrong max_tasks_number_for_user value (not int)""" with pytest.raises(ConfigurationException): c_handler = ConfigHandler( path + '/src/tests/application/config_with_wrong_max_tasks_number.ini')