def wrapper(self, *args, **kwargs): if not has_admin_rights(self): LOGGER.warning('User %s tried to access admin REST service %s', get_audit_name(self), self.request.path) raise tornado.web.HTTPError(403, 'Access denied') return func(self, *args, **kwargs)
def start_script(self, config, values, user_id, all_audit_names): audit_name = audit_utils.get_audit_name(all_audit_names) executor = ScriptExecutor(config, values) execution_id = self._id_generator.next_id() audit_command = executor.get_secure_command() LOGGER.info('Calling script #%s: %s', execution_id, audit_command) executor.start() self._executors[execution_id] = executor self._execution_infos[execution_id] = _ExecutionInfo( execution_id=execution_id, owner=user_id, audit_name=audit_name, audit_command=audit_command, config=config, all_audit_names=all_audit_names) self._active_executor_ids.add(execution_id) self._add_post_finish_handling(execution_id, executor) self._fire_execution_started(execution_id) return execution_id
def create_filename(self, execution_id, all_audit_names, script_name, start_time): audit_name = get_audit_name(all_audit_names) audit_name = file_utils.to_filename(audit_name) date_string = ms_to_datetime(start_time).strftime(self._date_format) username = get_first_existing(all_audit_names, audit_utils.AUTH_USERNAME, audit_utils.PROXIED_USERNAME) mapping = { 'ID': execution_id, 'USERNAME': username, 'HOSTNAME': get_first_existing(all_audit_names, audit_utils.PROXIED_HOSTNAME, audit_utils.HOSTNAME, default='unknown-host'), 'IP': get_first_existing(all_audit_names, audit_utils.PROXIED_IP, audit_utils.IP), 'DATE': date_string, 'AUDIT_NAME': audit_name, 'SCRIPT': script_name } filename = self._filename_template.safe_substitute(mapping) if not filename.lower().endswith('.log'): filename += '.log' filename = filename.replace(" ", "_") return filename
def open(self, process_id): auth = self.application.auth if not auth.is_authenticated(self): return None logger = logging.getLogger("scriptServer") self.process_wrapper = running_scripts.get(int(process_id)) if not self.process_wrapper: raise Exception("Couldn't find corresponding process") self.write_message(wrap_to_server_event("input", "your input >>")) self.write_message(wrap_script_output(" --- OUTPUT --- \n")) audit_name = get_audit_name(self, logger) output_logger = self.create_script_output_logger(audit_name, logger) output_logger.open() reading_thread = threading.Thread(target=pipe_process_to_http, args=( self.process_wrapper, output_logger, self.safe_write )) reading_thread.start() web_socket = self process_wrapper = self.process_wrapper class FinishListener(object): def finished(self): reading_thread.join() output_logger.close() try: downloadable_files = file_download_feature.prepare_downloadable_files( process_wrapper.get_config(), process_wrapper.get_full_output(), process_wrapper.execution_info.param_values, audit_name, get_tornado_secret(), TEMP_FOLDER) for file in downloadable_files: filename = os.path.basename(file) relative_path = file_utils.relative_path(file, TEMP_FOLDER) web_socket.safe_write(wrap_to_server_event( 'file', {'url': relative_path.replace(os.path.sep, '/'), 'filename': filename})) except: logger.exception("Couldn't prepare downloadable files") tornado.ioloop.IOLoop.current().add_callback(web_socket.close) self.process_wrapper.add_finish_listener(FinishListener())
def open(self, execution_id): auth = self.application.auth if not auth.is_authenticated(self): return None executor = self.application.execution_service.get_active_executor( execution_id) # type: ScriptExecutor if not executor: raise Exception("Couldn't find corresponding process") self.executor = executor self.ioloop = tornado.ioloop.IOLoop.current() self.write_message(wrap_to_server_event("input", "your input >>")) self.write_message(wrap_script_output(" --- OUTPUT --- \n")) audit_name = get_audit_name(self) output_stream = executor.get_unsecure_output_stream() bash_formatting = executor.config.is_bash_formatting() pipe_output_to_http(output_stream, bash_formatting, self.safe_write) web_socket = self file_download_feature = self.application.file_download_feature class FinishListener(object): def finished(self): output_stream.wait_close() script_output = ''.join(output_stream.get_old_data()) try: downloadable_files = file_download_feature.prepare_downloadable_files( executor.config, script_output, executor.parameter_values, audit_name) for file in downloadable_files: filename = os.path.basename(file) relative_path = file_utils.relative_path( file, TEMP_FOLDER) web_socket.safe_write( wrap_to_server_event( 'file', { 'url': relative_path.replace( os.path.sep, '/'), 'filename': filename })) except: LOGGER.exception("Couldn't prepare downloadable files") web_socket.ioloop.add_callback(web_socket.close) executor.add_finish_listener(FinishListener())
def validate_absolute_path(self, root, absolute_path): logger = logging.getLogger('scriptServer') audit_name = get_audit_name(self, logger) file_path = file_utils.relative_path(absolute_path, os.path.abspath(root)) if not file_download_feature.allowed_to_download(file_path, audit_name, get_tornado_secret()): logger.warning('Access attempt from ' + audit_name + ' to ' + absolute_path) raise tornado.web.HTTPError(404) return super(AuthorizedStaticFileHandler, self).validate_absolute_path(root, absolute_path)
def validate_absolute_path(self, root, absolute_path): if not self.application.auth.is_enabled() and ( absolute_path.endswith("/login.html")): raise tornado.web.HTTPError(404) relative_path = file_utils.relative_path(absolute_path, root) if self.is_admin_file(relative_path): if not has_admin_rights(self): LOGGER.warning('User %s tried to access admin static file %s', get_audit_name(self), relative_path) raise tornado.web.HTTPError(403) return super(AuthorizedStaticFileHandler, self).validate_absolute_path(root, absolute_path)
def validate_absolute_path(self, root, absolute_path): audit_name = get_audit_name(self) file_download_feature = self.application.file_download_feature file_path = file_utils.relative_path(absolute_path, os.path.abspath(root)) if not file_download_feature.allowed_to_download( file_path, audit_name): LOGGER.warning('Access attempt from ' + audit_name + ' to ' + absolute_path) raise tornado.web.HTTPError(404) return super(AuthorizedStaticFileHandler, self).validate_absolute_path(root, absolute_path)
def finished(self): return_code = request_handler_self.process_wrapper.get_return_code() if return_code != 0: script = str(script_name) audit_name = get_audit_name(request_handler_self, script_logger) title = script + ' FAILED' body = 'The script "' + script + '", started by ' + audit_name + \ ' exited with return code ' + str(return_code) + '.' + \ ' Usually this means an error, occurred during the execution.' + \ ' Please check the corresponding logs' send_alerts(alerts_config, title, body)
def _get_paths(self, execution_id, predicate): config = self.config if is_empty(config.output_files): return [] paths = [_extract_path(f) for f in config.output_files if predicate(f)] paths = [p for p in paths if p] parameter_values = self.execution_service.get_user_parameter_values( execution_id) all_audit_names = self.execution_service.get_all_audit_names( execution_id) audit_name = audit_utils.get_audit_name(all_audit_names) username = audit_utils.get_audit_username(all_audit_names) return substitute_variable_values(config.parameters, paths, parameter_values, audit_name, username)
def get_audit_name(request_handler): logger = logging.getLogger('tests') return audit_utils.get_audit_name(request_handler, logger)
def get_audit_name(request_handler): return audit_utils.get_audit_name(request_handler)
def post(self): script_name = None audit_name = get_audit_name(self) try: arguments = tornado_utils.get_form_arguments(self) execution_info = external_model.to_execution_info(arguments) script_name = execution_info.script config = load_config(script_name) if not config: message = 'Script with name "' + str( script_name) + '" not found' LOGGER.error(message) respond_error(self, 400, message) return file_upload_feature = self.application.file_upload_feature if self.request.files: for key, value in self.request.files.items(): file_info = value[0] file_path = file_upload_feature.save_file( file_info.filename, file_info.body, audit_name) execution_info.param_values[key] = file_path valid_parameters = model_helper.validate_parameters( execution_info.param_values, config) if not valid_parameters: message = 'Received invalid parameters' LOGGER.error(message) respond_error(self, 400, message) return executor = ScriptExecutor(config, execution_info.param_values, audit_name) audit_command = executor.get_secure_command() LOGGER.info('Calling script: ' + audit_command) LOGGER.info('User info: ' + str(get_all_audit_names(self))) process_id = executor.start() running_scripts[process_id] = executor self.write(str(process_id)) secure_output_stream = executor.get_secure_output_stream() self.start_script_output_logger(audit_name, script_name, secure_output_stream) alerts_config = self.application.alerts_config if alerts_config: self.subscribe_fail_alerter(script_name, alerts_config, audit_name, executor, secure_output_stream) except Exception as e: LOGGER.exception("Error while calling the script") if hasattr(e, "strerror") and e.strerror: error_output = e.strerror else: error_output = "Unknown error occurred, contact the administrator" result = " --- ERRORS --- \n" result += error_output if script_name: script = str(script_name) else: script = "Some script" audit_name = audit_name send_alerts( self.application.alerts_config, script + ' NOT STARTED', "Couldn't start the script " + script + ' by ' + audit_name + '.\n\n' + result) respond_error(self, 500, result)
def on_close(self): if self.executor.config.kill_on_disconnect: self.executor.kill() audit_name = get_audit_name(self) LOGGER.info(audit_name + ' disconnected')
def get_audit_name(request_handler): audit_name = audit_utils.get_audit_name(request_handler) return normalize_hostname(audit_name)
def get_audit_name(self): return audit_utils.get_audit_name(self.audit_names)
def post(self): script_name = None try: request_data = self.request.body execution_info = external_model.to_execution_info(request_data.decode("UTF-8")) script_name = execution_info.script config = load_config(script_name) if not config: respond_error(self, 400, "Script with name '" + str(script_name) + "' not found") return working_directory = config.get_working_directory() if working_directory is not None: working_directory = file_utils.normalize_path(working_directory) script_logger = logging.getLogger("scriptServer") valid_parameters = model_helper.validate_parameters(execution_info.param_values, config) if not valid_parameters: respond_error(self, 400, 'Received invalid parameters') return script_base_command = process_utils.split_command(config.get_script_command(), working_directory) script_args = build_command_args(execution_info.param_values, config) command = script_base_command + script_args audit_script_args = build_command_args( execution_info.param_values, config, model_helper.value_to_str) audit_command = script_base_command + audit_script_args script_logger.info('Calling script: ' + ' '.join(audit_command)) script_logger.info('User info: ' + str(get_all_audit_names(self, script_logger))) run_pty = config.is_requires_terminal() if run_pty and not pty_supported: script_logger.warning( "Requested PTY mode, but it's not supported for this OS (" + sys.platform + "). Falling back to POpen") run_pty = False if run_pty: self.process_wrapper = execution_pty.PtyProcessWrapper(command, config.get_name(), working_directory, config, execution_info) else: self.process_wrapper = execution_popen.POpenProcessWrapper(command, config.get_name(), working_directory, config, execution_info) self.process_wrapper.start() process_id = self.process_wrapper.get_process_id() running_scripts[process_id] = self.process_wrapper self.write(str(process_id)) alerts_config = self.application.alerts_config if alerts_config: self.subscribe_fail_alerter(script_name, script_logger, alerts_config) except Exception as e: script_logger = logging.getLogger("scriptServer") script_logger.exception("Error while calling the script") if hasattr(e, "strerror") and e.strerror: error_output = e.strerror else: error_output = "Unknown error occurred, contact the administrator" result = " --- ERRORS --- \n" result += error_output if script_name: script = str(script_name) else: script = "Some script" audit_name = get_audit_name(self, script_logger) send_alerts(self.application.alerts_config, script + ' NOT STARTED', "Couldn't start the script " + script + ' by ' + audit_name + '.\n\n' + result) respond_error(self, 500, result)
def has_admin_rights(self): audit_name = get_audit_name(self) return self.application.authorizer.is_admin(audit_name)