def __init__(self, session, config_path=None): reset_config(filepath=config_path) try: control_config() except ValueError as e: logger.error(e) raise e self.config_path = config_path self.host = config.get(Sections.SERVER, "host") self.api_port = config.get(Sections.SERVER, "api_port") self.websocket_port = config.get(Sections.SERVER, "websocket_port") self.workspace = config.get(Sections.SERVER, "workspace") self.agent_token = config[Sections.TOKENS].get("agent", None) self.agent_name = config.get(Sections.AGENT, "agent_name") self.session = session self.websocket = None self.websocket_token = None executors_list_str = config[Sections.AGENT].get("executors", []).split(",") if "" in executors_list_str: executors_list_str.remove("") self.executors = { executor_name: Executor(executor_name, config) for executor_name in executors_list_str } ssl_cert_path = config[Sections.SERVER].get("ssl_cert", None) self.ws_ssl_enabled = self.api_ssl_enabled = config[Sections.SERVER].get("ssl", "False").lower() in ["t", "true"] self.api_kwargs = {"ssl": ssl.create_default_context(cafile=ssl_cert_path)} if self.api_ssl_enabled and ssl_cert_path else {} self.ws_kwargs = {"ssl": ssl.create_default_context(cafile=ssl_cert_path)} if self.ws_ssl_enabled and ssl_cert_path else {} self.execution_id = None
def test_with_agent_token(delete_token): runner = CliRunner() content_path = old_version_path() / '1.0_with_agent_token.ini' with open(content_path, 'r') as content_file: content = content_file.read() with runner.isolated_filesystem() as file_system: path = Path(file_system) / "dispatcher.ini" with path.open(mode="w") as content_file: content_file.write(content) env = os.environ env["DEBUG_INPUT_MODE"] = "True" input_str = f"A\n{DispatcherInput(delete_agent_token=delete_token).input_str()}Q\n" escape_string = "\0\n" * 1000 result = runner.invoke(config_wizard, args=["-c", path], input=f'{input_str}{escape_string}', env=env) assert result.exit_code == 0, result.exception config_mod.reset_config(path) if delete_token: assert "agent" not in config_mod.instance.options( config_mod.Sections.TOKENS) else: assert "agent" in config_mod.instance.options( config_mod.Sections.TOKENS)
def test_basic_built(tmp_custom_config, config_changes_dict): # noqa F811 reset_config(tmp_custom_config.config_file_path) config_path = tmp_custom_config.config_file_path.with_suffix(".yaml") for section in config_changes_dict["replace"]: for option in config_changes_dict["replace"][section]: if section == "executor": if "ex1" not in configuration[Sections.AGENT][Sections.EXECUTORS]: configuration[Sections.AGENT][Sections.EXECUTORS]["ex1"] = {} configuration[Sections.AGENT][Sections.EXECUTORS]["ex1"][option] = config_changes_dict["replace"][ section ][option] continue elif section not in configuration: configuration[section] = {} configuration[section][option] = config_changes_dict["replace"][section][option] for section in config_changes_dict["remove"]: if "section" in config_changes_dict["remove"][section]: if section in configuration: configuration.pop(section) else: for option in config_changes_dict["remove"][section]: if ( section == "executor" and "ex1" in configuration[Sections.AGENT][Sections.EXECUTORS] and option in configuration[Sections.AGENT][Sections.EXECUTORS]["ex1"] ): configuration[Sections.AGENT][Sections.EXECUTORS]["ex1"].pop(option) elif section in configuration and option in configuration[section]: configuration[section].pop(option) save_config(config_path) if "expected_exception" in config_changes_dict: with pytest.raises(config_changes_dict["expected_exception"]): Dispatcher(None, config_path) else: Dispatcher(None, config_path)
def tmp_custom_config(): config = TmpConfig() ini_path = pathlib.Path( __file__).parent.parent / "data" / "test_config.ini" shutil.copyfile(ini_path, config.config_file_path) reset_config(config.config_file_path) yield config os.remove(config.config_file_path)
def tmp_custom_config(config=None): config = TmpConfig() ini_path = (pathlib.Path(__file__).parent.parent / 'data' / 'test_config.ini') shutil.copyfile(ini_path, config.config_file_path) reset_config(config.config_file_path) yield config os.remove(config.config_file_path)
def process_config_file(config_filepath: Path, logger): if config_filepath is None and not os.path.exists(config.CONFIG_FILENAME): logger.info("Config file doesn't exist. Run the command " "`faraday-dispatcher config-wizard` to create one") exit(1) config_filepath = config_filepath or Path(config.CONFIG_FILENAME) config_filepath = Path(config_filepath) config.reset_config(config_filepath) return config_filepath
def test_new_config(testing_inputs: Dict[(str, object)], ini_config): runner = CliRunner() content = None content_path = ini_config["dir"] if content_path != "": with open(content_path, "r") as content_file: content = content_file.read() with runner.isolated_filesystem() as file_system: if content: path = Path(file_system) / "dispatcher.ini" with path.open(mode="w") as content_file: content_file.write(content) else: path = Path(file_system) """ The in_data variable will be consumed for the cli command, but in order to avoid unexpected inputs with no data (and a infinite wait), a \0\n block of input is added at the end of the input. Furthermore the \0 is added as a possible choice of the ones and should exit with error. """ in_data = "Q\nN\n" if ini_config["id_str"] == "no_ini" else "" in_data += parse_inputs(testing_inputs) + "\0\n" * 1000 env = os.environ env["DEBUG_INPUT_MODE"] = "True" result = runner.invoke(config_wizard, args=["-c", path], input=in_data, env=env) assert result.exit_code == testing_inputs["exit_code"], result.exception if "exception" in testing_inputs: assert str(result.exception) == str(testing_inputs["exception"]) assert testing_inputs["exception"].__class__ == result.exception.__class__ else: # Control '\0' is not passed in the output, as the input is echoed assert "\0\n" not in result.output if "expected_outputs" in testing_inputs: for expected_output in testing_inputs["expected_outputs"]: assert expected_output in result.output expected_executors_set = set.union(ini_config["old_executors"], testing_inputs["after_executors"]) expected_workspaces_set = set.union(ini_config["old_workspaces"], testing_inputs["after_workspaces"]) if path.suffix == ".ini": path = path.with_suffix(".yaml") config_mod.reset_config(path) executor_config_set = set(config_mod.instance[Sections.AGENT].get("executors")) assert executor_config_set == expected_executors_set workspace_config_set = set(config_mod.instance[Sections.SERVER].get("workspaces")) assert workspace_config_set == expected_workspaces_set assert f"Section: {Sections.TOKENS}" not in result.output
def __init__(self, session, config_path=None): reset_config(filepath=config_path) try: verify() control_config() except ValueError as e: logger.error(e) raise e self.config_path = config_path self.host = config.get(Sections.SERVER, "host") self.api_port = config.get(Sections.SERVER, "api_port") self.websocket_port = config.get(Sections.SERVER, "websocket_port") self.agent_token = config[Sections.TOKENS].get( "agent", None) if Sections.TOKENS in config else None self.agent_name = config.get(Sections.AGENT, "agent_name") self.session = session self.websocket = None self.websocket_token = None self.workspaces = _parse_list(config.get(Sections.SERVER, "workspaces")) self.executors = { executor_name: Executor(executor_name, config) for executor_name in _parse_list(config[Sections.AGENT].get( "executors", "")) } self.ws_ssl_enabled = self.api_ssl_enabled = config[ Sections.SERVER].get("ssl", "False").lower() in [ "t", "true", ] ssl_cert_path = config[Sections.SERVER].get("ssl_cert", None) if not Path(ssl_cert_path).exists(): raise ValueError( f"SSL cert does not exist in path {ssl_cert_path}") self.api_kwargs: Dict[str, object] = ({ "ssl": ssl.create_default_context(cafile=ssl_cert_path) if "HTTPS_PROXY" not in os.environ else False } if self.api_ssl_enabled and ssl_cert_path else {}) if "HTTPS_PROXY" in os.environ: logger.info("HTTPS_PROXY is set; will not do SSL verify") ws_ssl_context = ssl.create_default_context() ws_ssl_context.check_hostname = False ws_ssl_context.verify_mode = ssl.CERT_NONE else: ws_ssl_context = ssl.create_default_context(cafile=ssl_cert_path) self.ws_kwargs = {"ssl": ws_ssl_context} if self.ws_ssl_enabled else {} self.execution_id = None self.executor_tasks: Dict[str, List[Task]] = { Dispatcher.TaskLabels.EXECUTOR: [], Dispatcher.TaskLabels.CONNECTION_CHECK: [], } self.sigterm_received = False
def __init__(self, session, config_path=None): reset_config(filepath=config_path) try: control_config() except ValueError as e: logger.error(e) raise e self.config_path = config_path self.host = config.instance[Sections.SERVER]["host"] self.api_port = config.instance[Sections.SERVER]["api_port"] self.websocket_port = config.instance[Sections.SERVER]["websocket_port"] self.agent_token = ( config.instance[Sections.TOKENS].get("agent") if Sections.TOKENS in config.instance else None ) self.agent_name = config.instance[Sections.AGENT]["agent_name"] self.session = session self.websocket = None self.websocket_token = None self.workspaces = config.instance[Sections.SERVER]["workspaces"] self.executors = { executor_name: Executor(executor_name, executor_data) for executor_name, executor_data in config.instance[Sections.AGENT].get("executors", {}).items() } self.ws_ssl_enabled = self.api_ssl_enabled = config.instance[Sections.SERVER].get("ssl", False) ssl_cert_path = config.instance[Sections.SERVER].get("ssl_cert", None) ssl_ignore = config.instance[Sections.SERVER].get("ssl_ignore", False) if not Path(ssl_cert_path).exists(): raise ValueError(f"SSL cert does not exist in path {ssl_cert_path}") if self.api_ssl_enabled: if ssl_cert_path: ssl_cert_context = ssl.create_default_context(cafile=ssl_cert_path) self.api_kwargs = {"ssl": ssl_cert_context} self.ws_kwargs = {"ssl": ssl_cert_context} else: if ssl_ignore or "HTTPS_PROXY" in os.environ: ignore_ssl_context = ssl.create_default_context() ignore_ssl_context.check_hostname = False ignore_ssl_context.verify_mode = ssl.CERT_NONE self.api_kwargs = {"ssl": ignore_ssl_context} self.ws_kwargs = {"ssl": ignore_ssl_context} else: self.api_kwargs: Dict[str, object] = {} self.ws_kwargs: Dict[str, object] = {} else: self.api_kwargs: Dict[str, object] = {} self.ws_kwargs: Dict[str, object] = {} self.execution_id = None self.executor_tasks: Dict[str, List[Task]] = { Dispatcher.TaskLabels.EXECUTOR: [], Dispatcher.TaskLabels.CONNECTION_CHECK: [], } self.sigterm_received = False
def test_new_config(testing_inputs: Dict[(str, object)], ini_config): runner = CliRunner() content = None content_path = ini_config["dir"] if content_path != "": with open(content_path, 'r') as content_file: content = content_file.read() with runner.isolated_filesystem() as file_system: if content: path = Path(file_system) / "dispatcher.ini" with path.open(mode="w") as content_file: content_file.write(content) else: path = Path(file_system) ''' The in_data variable will be consumed for the cli command, but in order to avoid unexpected inputs with no data (and a infinite wait), a \0\n block of input is added at the end of the input. Furthermore the \0 is added as a possible choice of the ones and should exit with error. ''' in_data = parse_inputs(testing_inputs) + "\0\n" * 1000 env = os.environ env["DEBUG_INPUT_MODE"] = "True" result = runner.invoke(config_wizard, args=["-c", path], input=in_data, env=env) assert result.exit_code == testing_inputs[ "exit_code"], result.exception if "exception" in testing_inputs: assert str(result.exception) == str(testing_inputs["exception"]) assert result.exception.__class__ == testing_inputs[ "exception"].__class__ else: assert '\0\n' not in result.output # Control '\0' is not passed in the output, as the input is echoed if "expected_outputs" in testing_inputs: for expected_output in testing_inputs["expected_outputs"]: assert expected_output in result.output expected_executors_set = set.union(ini_config["old_executors"], testing_inputs["after_executors"]) config_mod.reset_config(path) executor_config_set = set( config_mod.instance.get(config_mod.Sections.AGENT, "executors").split(",")) if '' in executor_config_set: executor_config_set.remove('') assert executor_config_set == expected_executors_set
def __init__(self, config_filepath: Path): self.config_filepath = config_filepath try: config.reset_config(config_filepath) except ValueError as e: if e.args[1] or config_filepath.is_file(): # the filepath is either a file, or a folder containing a file, # which can't be processed raise e config.control_config() self.executors_dict = {} self.load_executors()
def __init__(self, config_filepath: Path): self.config_filepath = config_filepath try: config.reset_config(config_filepath) except ValueError as e: if e.args[1] or config_filepath.is_file(): raise e # the filepath is either a file, or a folder containing a file, which can't be processed try: config.verify() except ValueError as e: print(f"{Bcolors.FAIL}{e}{Bcolors.ENDC}") sys.exit(1) self.executors_list = [] self.load_executors()
def __init__(self, session, config_path=None): reset_config(filepath=config_path) self.control_config() self.config_path = config_path self.host = config.get(Sections.SERVER, "host") self.api_port = config.get(Sections.SERVER, "api_port") self.websocket_port = config.get(Sections.SERVER, "websocket_port") self.workspace = config.get(Sections.SERVER, "workspace") self.agent_token = config[Sections.TOKENS].get("agent", None) self.agent_name = config.get(Sections.AGENT, "agent_name") self.session = session self.websocket = None self.websocket_token = None self.executors = { executor_name: Executor(executor_name, config) for executor_name in config[Sections.AGENT].get("executors", []).split(",") }
def test_with_agent_token(delete_token): runner = CliRunner() content_path = old_version_path() / "1.2_with_agent_token.ini" with open(content_path, "r") as content_file: content = content_file.read() with runner.isolated_filesystem() as file_system: path = Path(file_system) / "dispatcher.ini" with path.open(mode="w") as content_file: content_file.write(content) env = os.environ env["DEBUG_INPUT_MODE"] = "True" input_str = DispatcherInput( ssl="false", delete_agent_token=delete_token, workspaces=[ WorkspaceInput(name="aworkspace", adm_type=ADMType.ADD) ], ).input_str() input_str = f"A\n{input_str}Q\n" escape_string = "\0\n" * 1000 result = runner.invoke( config_wizard, args=["-c", path], input=f"{input_str}{escape_string}", env=env, ) assert result.exit_code == 0, result.exception assert f"Section: {config_mod.Sections.TOKENS}" in result.output config_mod.reset_config(path) if delete_token: assert "agent" not in config_mod.instance.options( config_mod.Sections.TOKENS) else: assert "agent" in config_mod.instance.options( config_mod.Sections.TOKENS)
async def main(config_file): if config_file is None and not os.path.exists(config.CONFIG_FILENAME): logger.info("Config file doesn't exist. Creating a new one") os.makedirs(config.CONFIG_PATH, exist_ok=True) shutil.copyfile(config.EXAMPLE_CONFIG_FILENAME, config.CONFIG_FILENAME) logger.info(f"Config file at {config.CONFIG_FILENAME} created") config_file = config_file or config.CONFIG_FILENAME config.reset_config(config_file) async with ClientSession(raise_for_status=True) as session: try: dispatcher = Dispatcher(session, config_file) except ValueError as ex: print(f'{Bcolors.FAIL}Error configuring dispatcher: ' f'{Bcolors.BOLD}{str(ex)}{Bcolors.ENDC}') print(f'Try checking your config file located at {Bcolors.BOLD}' f'{config.CONFIG_FILENAME}{Bcolors.ENDC}') return 1 await dispatcher.register() await dispatcher.connect() return 0
from faraday_agent_dispatcher.config import instance as config, reset_config, Sections,\ save_config, EXAMPLE_CONFIG_FILENAME from faraday_agent_dispatcher.utils.url_utils import api_url from tests.data.basic_executor import host_data, vuln_data from tests.utils.text_utils import fuzzy_string import os from pathlib import Path from requests import Session import subprocess import time reset_config(EXAMPLE_CONFIG_FILENAME) HOST = config.get(Sections.SERVER, "host") API_PORT = config.get(Sections.SERVER, "api_port") WS_PORT = config.get(Sections.SERVER, "websocket_port") WORKSPACE = fuzzy_string( 6).lower() # TODO FIX WHEN FARADAY ACCEPTS CAPITAL FIRST LETTER AGENT_NAME = fuzzy_string(6) EXECUTOR_NAME = fuzzy_string(6) USER = os.getenv("FARADAY_USER") EMAIL = os.getenv("FARADAY_EMAIL") PASS = os.getenv("FARADAY_PASSWORD") CONFIG_DIR = "./config_file.ini" LOGGER_DIR = "./logs" agent_ok_status_keys_set = {
def tmp_default_config(): config = TmpConfig() shutil.copyfile(EXAMPLE_CONFIG_FILENAME, config.config_file_path) reset_config(config.config_file_path) yield config os.remove(config.config_file_path)
def test_override_ssl_cert_with_default(ini_config): runner = CliRunner() content = None content_path = ini_config["dir"] if content_path != "": with open(content_path, "r") as content_file: content = content_file.read() with runner.isolated_filesystem() as file_system: if content: path = Path(file_system) / "dispatcher.ini" with path.open(mode="w") as content_file: content_file.write(content) else: path = Path(file_system) """ The in_data variable will be consumed for the cli command, but in order to avoid unexpected inputs with no data (and a infinite wait), a \0\n block of input is added at the end of the input. Furthermore the \0 is added as a possible choice of the ones and should exit with error. """ testing_inputs = [ { "dispatcher_input": DispatcherInput( host="https://127.0.0.1", workspaces=[WorkspaceInput(name="aworkspace", adm_type=ADMType.ADD)], ssl_cert=Path(__file__).parent.parent / "data" / "mock.pub", ), }, { "dispatcher_input": DispatcherInput( host="https://127.0.0.1", ssl_cert="", workspaces=[WorkspaceInput(name="aworkspace", adm_type=ADMType.ADD)], ), }, ] in_data0 = parse_inputs(testing_inputs[0]) + "\0\n" * 1000 env = os.environ env["DEBUG_INPUT_MODE"] = "True" result = runner.invoke(config_wizard, args=["-c", path], input=in_data0, env=env) assert result.exit_code == 0, result.exception # Control '\0' is not passed in the output, as the input is echoed assert "\0\n" not in result.output path = path.with_suffix(".yaml") in_data1 = parse_inputs(testing_inputs[1]) + "\0\n" * 1000 env = os.environ env["DEBUG_INPUT_MODE"] = "True" result = runner.invoke(config_wizard, args=["-c", path], input=in_data1, env=env) assert result.exit_code == 0, result.exception # Control '\0' is not passed in the output, as the input is echoed assert "\0\n" not in result.output config_mod.reset_config(path) assert "" == config_mod.instance[Sections.SERVER]["ssl_cert"] assert f"Section: {Sections.TOKENS}" not in result.output