def setUp(self) -> None:
        super().setUp()

        test_utils.setup()
        self.requires_explicit_ioloop_factory = os_utils.is_win(
        ) and env_utils.is_min_version('3.8')
        self.windows = os_utils.is_win()
Beispiel #2
0
    def setUp(self) -> None:
        super().setUp()

        test_utils.setup()
        self.requires_explicit_ioloop_factory = os_utils.is_win(
        ) and env_utils.is_min_version('3.8')
        self.windows = os_utils.is_win()

        self.conf_folder = test_utils.create_dir(os.path.join('conf'))
        self.runners_folder = os.path.join(self.conf_folder, 'runners')
    def verify(self, username, password):
        if username not in self.user_passwords:
            LOGGER.warning('User ' + username + ' does not exist')
            return False

        existing_password = self.user_passwords.get(username)

        # Selects encryption algorithm depending on the password format
        # https://httpd.apache.org/docs/2.4/misc/password_encryptions.html
        if existing_password.startswith('$2y$'):
            import bcrypt
            return bcrypt.checkpw(password.encode('utf8'),
                                  existing_password.encode('utf8'))

        elif existing_password.startswith('$apr1$'):
            salt = existing_password[6:existing_password.find('$', 6)]
            hashed_password = encryption_utils.md5_apr1(salt, password)
            return hashed_password == existing_password

        elif existing_password.startswith('{SHA}'):
            expected = existing_password[5:]
            hashed_password = encryption_utils.sha1(password)
            return hashed_password == expected

        elif not os_utils.is_win():
            import crypt
            hashed_password = crypt.crypt(password, existing_password[:2])
            return hashed_password == existing_password

        else:
            return password == existing_password
Beispiel #4
0
    def create_log_identifier(audit_name, script_name):
        if os_utils.is_win():
            audit_name = audit_name.replace(":", "-")

        date_string = datetime.today().strftime("%y%m%d_%H%M%S")
        script_name = script_name.replace(" ", "_")
        log_identifier = script_name + "_" + audit_name + "_" + date_string
        return log_identifier
Beispiel #5
0
 def kill(self):
     if not self.is_finished():
         if not os_utils.is_win():
             group_id = os.getpgid(self.get_process_id())
             os.killpg(group_id, signal.SIGKILL)
             self._write_script_output('\n>> KILLED\n')
         else:
             subprocess.Popen("taskkill /F /T /PID " + self.get_process_id())
Beispiel #6
0
 def kill(self):
     if not self.is_finished():
         if not os_utils.is_win():
             group_id = os.getpgid(self.get_process_id())
             os.killpg(group_id, signal.SIGKILL)
             self._write_script_output('\n>> KILLED\n')
         else:
             subprocess.Popen("taskkill /F /T /PID " + self.get_process_id())
Beispiel #7
0
def normalize_hostname(hostname):
    if hostname == 'ip6-localhost':
        return 'localhost'
    if os_utils.is_win():
        import platform
        if hostname == platform.node():
            return 'localhost'

    return hostname
Beispiel #8
0
def find_matching_files(file_pattern, script_output):
    files = []
    separator = re.escape(os_utils.path_sep())
    output_patterns = [file_pattern]
    while len(output_patterns) > 0:
        output_pattern = output_patterns.pop(0)

        if '#' in output_pattern:
            regex_start = output_pattern.find('#')

            group_number_matches = re.findall('^#\d+#',
                                              output_pattern[regex_start:])
            if group_number_matches:
                first_match = group_number_matches[0]
                group_number = int(first_match[1:-1])
                pattern_start = regex_start + len(first_match) - 1
            else:
                group_number = 0
                pattern_start = regex_start

            regex_end = output_pattern.find('#', pattern_start + 1)
            while (regex_end >=
                   0) and output_pattern[regex_end:].startswith('#any_path'):
                regex_end = output_pattern.find('#', regex_end + 1)

            if regex_end >= 0:
                regex_pattern = output_pattern[pattern_start + 1:regex_end]

                if regex_pattern.startswith('#any_path') and (regex_start
                                                              == 0):
                    if os_utils.is_linux() or os_utils.is_mac():
                        regex_pattern = '~?' + regex_pattern
                    elif os_utils.is_win():
                        regex_pattern = '(([^\W\d_]:)|~)' + regex_pattern

                regex_pattern = regex_pattern.replace(
                    '#any_path', '(' + separator + '([\w.\-]|(\\\ ))+)+')
                found_matches = re.finditer(regex_pattern, script_output)

                for match in found_matches:
                    matched_group = match.group(group_number)
                    new_output_pattern = string_utils.replace(
                        output_pattern, matched_group, regex_start, regex_end)
                    output_patterns.append(new_output_pattern)

                continue

        if '*' not in output_pattern:
            files.append(output_pattern)

        else:
            recursive = '**' in output_pattern
            matching_files = file_utils.search_glob(output_pattern,
                                                    recursive=recursive)
            files.extend(matching_files)

    return files
Beispiel #9
0
def normalize_hostname(hostname):
    if hostname == 'ip6-localhost':
        return 'localhost'
    if os_utils.is_win():
        import platform
        if hostname == platform.node():
            return 'localhost'

    return hostname
Beispiel #10
0
    def test_authenticate_failure_when_crypt_with_plain_password(self):
        if self.verifier == 'htpasswd' and os_utils.is_win():
            return

        os_utils.set_linux()

        authenticator = self._create_authenticator(
            {'htpasswd_path': self.file_path})

        for username in crypt_users.keys():
            password = crypt_users[username]
            self._assert_rejected(username, password, authenticator)
Beispiel #11
0
    def test_authenticate_success_when_crypt(self):
        if self.verifier == 'htpasswd' and os_utils.is_win():
            return

        os_utils.set_linux()

        authenticator = self._create_authenticator(
            {'htpasswd_path': self.file_path})

        for username in crypt_users.keys():
            password = username_passwords[username]
            self._assert_authenticated(username, password, authenticator)
def find_matching_files(file_pattern, script_output):
    files = []
    separator = re.escape(os_utils.path_sep())
    output_patterns = [file_pattern]
    while len(output_patterns) > 0:
        output_pattern = output_patterns.pop(0)

        if '#' in output_pattern:
            regex_start = output_pattern.find('#')

            group_number_matches = re.findall('^#\d+#', output_pattern[regex_start:])
            if group_number_matches:
                first_match = group_number_matches[0]
                group_number = int(first_match[1:-1])
                pattern_start = regex_start + len(first_match) - 1
            else:
                group_number = 0
                pattern_start = regex_start

            regex_end = output_pattern.find('#', pattern_start + 1)
            while (regex_end >= 0) and output_pattern[regex_end:].startswith('#any_path'):
                regex_end = output_pattern.find('#', regex_end + 1)

            if regex_end >= 0:
                regex_pattern = output_pattern[pattern_start + 1:regex_end]

                if regex_pattern.startswith('#any_path') and (regex_start == 0):
                    if os_utils.is_linux() or os_utils.is_mac():
                        regex_pattern = '~?' + regex_pattern
                    elif os_utils.is_win():
                        regex_pattern = '(([^\W\d_]:)|~)' + regex_pattern

                regex_pattern = regex_pattern.replace('#any_path', '(' + separator + '([\w.\-]|(\\\ ))+)+')
                found_matches = re.finditer(regex_pattern, script_output)

                for match in found_matches:
                    matched_group = match.group(group_number)
                    new_output_pattern = string_utils.replace(output_pattern, matched_group, regex_start, regex_end)
                    output_patterns.append(new_output_pattern)

                continue

        if '*' not in output_pattern:
            files.append(output_pattern)

        else:
            recursive = '**' in output_pattern
            matching_files = file_utils.search_glob(output_pattern, recursive=recursive)
            files.extend(matching_files)

    return files
Beispiel #13
0
    def start_execution(self, command, working_directory):
        shell = False

        if os_utils.is_win():
            (command, shell) = prepare_cmd_for_win(command)

        self.process = subprocess.Popen(command,
                                        cwd=working_directory,
                                        stdin=subprocess.PIPE,
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.STDOUT,
                                        start_new_session=True,
                                        universal_newlines=True,
                                        shell=shell)
Beispiel #14
0
def relative_path(path, parent_path):
    path = normalize_path(path)
    parent_path = normalize_path(parent_path)

    if os_utils.is_win():
        path = path.capitalize()
        parent_path = parent_path.capitalize()

    if not path.startswith(parent_path):
        raise ValueError(path + ' is not subpath of ' + parent_path)

    relative_path = path[len(parent_path):]

    if relative_path.startswith(os.path.sep):
        return relative_path[1:]

    return relative_path
Beispiel #15
0
def split_command(script_command, working_directory=None):
    if ' ' in script_command:
        posix = not os_utils.is_win()
        args = shlex.split(script_command, posix=posix)

        if not posix:
            args = [string_utils.unwrap_quotes(arg) for arg in args]
    else:
        args = [script_command]

    script_path = file_utils.normalize_path(args[0], working_directory)
    script_args = args[1:]
    for i, body_arg in enumerate(script_args):
        expanded = os.path.expanduser(body_arg)
        if expanded != body_arg:
            script_args[i] = expanded

    return [script_path] + script_args
Beispiel #16
0
    def stop(self):
        if not self.is_finished():
            if not os_utils.is_win():
                group_id = os.getpgid(self.get_process_id())
                os.killpg(group_id, signal.SIGTERM)

                class KillChildren(object):
                    def finished(self):
                        try:
                            os.killpg(group_id, signal.SIGKILL)
                        except ProcessLookupError:
                            # probably there are no children left
                            pass

                self.add_finish_listener(KillChildren())

            else:
                self.process.terminate()

            self._write_script_output('\n>> STOPPED BY USER\n')
Beispiel #17
0
    def stop(self):
        if not self.is_finished():
            if not os_utils.is_win():
                group_id = os.getpgid(self._get_process_id())
                os.killpg(group_id, signal.SIGTERM)

                class KillChildren(object):
                    def finished(self):
                        try:
                            os.killpg(group_id, signal.SIGKILL)
                        except ProcessLookupError:
                            # probably there are no children left
                            pass

                self.add_finish_listener(KillChildren())

            else:
                self.process.terminate()

            self._write_script_output('\n>> STOPPED BY USER\n')
Beispiel #18
0
def split_command(script_command, working_directory=None):
    if ' ' in script_command:
        if _is_file_path(script_command, working_directory):
            args = [script_command]
        else:
            posix = not os_utils.is_win()
            args = shlex.split(script_command, posix=posix)

            if not posix:
                args = [string_utils.unwrap_quotes(arg) for arg in args]
    else:
        args = [script_command]

    script_path = file_utils.normalize_path(args[0], working_directory)
    if (not os.path.isabs(script_path)) or (not os.path.exists(script_path)):
        script_path = args[0]

    script_args = args[1:]
    for i, body_arg in enumerate(script_args):
        expanded = os.path.expanduser(body_arg)
        if expanded != body_arg:
            script_args[i] = expanded

    return [script_path] + script_args
Beispiel #19
0
def to_filename(txt):
    if os_utils.is_win():
        return txt.replace(':', '-')

    return txt
Beispiel #20
0
def init(server_config: ServerConfig,
         authenticator,
         authorizer,
         execution_service: ExecutionService,
         schedule_service: ScheduleService,
         execution_logging_service: ExecutionLoggingService,
         config_service: ConfigService,
         alerts_service: AlertsService,
         file_upload_feature: FileUploadFeature,
         file_download_feature: FileDownloadFeature,
         secret,
         server_version,
         conf_folder,
         *,
         start_server=True):
    ssl_context = None
    if server_config.is_ssl():
        ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
        ssl_context.load_cert_chain(server_config.get_ssl_cert_path(),
                                    server_config.get_ssl_key_path())

    auth = TornadoAuth(authenticator)
    if auth.is_enabled():
        identification = AuthBasedIdentification(auth)
    else:
        identification = IpBasedIdentification(server_config.ip_validator,
                                               server_config.user_header_name)

    downloads_folder = file_download_feature.get_result_files_folder()

    handlers = [
        (r'/conf', GetServerConf), (r'/scripts', GetScripts),
        (r'/scripts/([^/]*)', ScriptConfigSocket),
        (r'/scripts/([^/]*)/([^/]*)/list-files', ScriptParameterListFiles),
        (r'/executions/start', ScriptExecute),
        (r'/executions/stop/(.*)', ScriptStop),
        (r'/executions/kill/(.*)', ScriptKill),
        (r'/executions/io/(.*)', ScriptStreamSocket),
        (r'/executions/active', GetActiveExecutionIds),
        (r'/executions/config/(.*)', GetExecutingScriptConfig),
        (r'/executions/cleanup/(.*)', CleanupExecutingScript),
        (r'/executions/status/(.*)', GetExecutionStatus),
        (r'/history/execution_log/short', GetShortHistoryEntriesHandler),
        (r'/history/execution_log/long/(.*)', GetLongHistoryEntryHandler),
        (r'/schedule', AddSchedule), (r'/auth/info', AuthInfoHandler),
        (r'/result_files/(.*)', DownloadResultFile, {
            'path': downloads_folder
        }), (r'/admin/scripts', AdminUpdateScriptEndpoint),
        (r'/admin/scripts/(.*)', AdminGetScriptEndpoint),
        (r"/", ProxiedRedirectHandler, {
            "url": "/index.html"
        })
    ]

    if auth.is_enabled():
        handlers.append((r'/login', LoginHandler))
        handlers.append((r'/auth/config', AuthConfigHandler))
        handlers.append((r'/logout', LogoutHandler))

    handlers.append((r'/theme/(.*)', ThemeStaticFileHandler, {
        'path': os.path.join(conf_folder, 'theme')
    }))
    handlers.append((r"/(.*)", AuthorizedStaticFileHandler, {"path": "web"}))

    settings = {
        "cookie_secret": secret,
        "login_url": "/login.html",
        'websocket_ping_interval': 30,
        'websocket_ping_timeout': 300,
        'compress_response': True
    }

    application = tornado.web.Application(handlers, **settings)

    application.auth = auth

    application.server_config = server_config
    application.server_version = server_version
    application.authorizer = authorizer
    application.downloads_folder = downloads_folder
    application.file_download_feature = file_download_feature
    application.file_upload_feature = file_upload_feature
    application.execution_service = execution_service
    application.schedule_service = schedule_service
    application.execution_logging_service = execution_logging_service
    application.config_service = config_service
    application.alerts_service = alerts_service
    application.identification = identification
    application.max_request_size_mb = server_config.max_request_size_mb

    if os_utils.is_win() and env_utils.is_min_version('3.8'):
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
    io_loop = tornado.ioloop.IOLoop.current()

    global _http_server
    _http_server = httpserver.HTTPServer(application,
                                         ssl_options=ssl_context,
                                         max_buffer_size=10 * BYTES_IN_MB)
    _http_server.listen(server_config.port, address=server_config.address)

    intercept_stop_when_running_scripts(io_loop, execution_service)

    http_protocol = 'https' if server_config.ssl else 'http'
    print('Server is running on: %s://%s:%s' %
          (http_protocol, server_config.address, server_config.port))

    if start_server:
        io_loop.start()
def to_filename(txt):
    if os_utils.is_win():
        return txt.replace(':', '-')

    return txt
Beispiel #22
0
def to_filename(txt):
    if os_utils.is_win():
        return re.sub('[<>:"/\\\\|?*]', '_', txt)

    return txt.replace('/', '_')