From 05524517a8fcca5e11f4a689d92bffa366117d74 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 28 Aug 2023 18:19:22 +0530 Subject: [PATCH 01/18] BB: Install Agent plugins to Island --- .../island_client/monkey_island_client.py | 31 +++++++++++++++++++ envs/monkey_zoo/blackbox/test_blackbox.py | 2 ++ 2 files changed, 33 insertions(+) diff --git a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py index 6df9878e091..9d2989e534d 100644 --- a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py +++ b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py @@ -35,6 +35,37 @@ def __init__(self, requests: IMonkeyIslandRequests): def get_api_status(self): return self.requests.get("api") + def install_agent_plugins(self): + available_plugins_index_url = "api/agent-plugins/available/index" + install_plugin_url = "api/install-agent-plugin" + + plugin_repository_index = self.requests.get(available_plugins_index_url) + available_plugins = plugin_repository_index.plugins + + for plugin_type in available_plugins: + for plugin_name in available_plugins[plugin_type]: + for plugin_versions in available_plugins[plugin_type][plugin_name]: + latest_version_plugin_metadata = plugin_versions[-1] + latest_version = latest_version_plugin_metadata.version + + install_plugin_request = { + "plugin_type": plugin_type, + "name": plugin_name, + "version": latest_version, + } + + if self.requests.put_json( + url=install_plugin_url, json=install_plugin_request + ).ok: + logger.info( + f"Installed {plugin_name} {plugin_type} v{latest_version} to Island" + ) + else: + logger.error( + f"Could not install {plugin_name} {plugin_type} " + f"v{latest_version} to Island" + ) + @avoid_race_condition def set_masque(self, masque): masque = b"" if masque is None else masque diff --git a/envs/monkey_zoo/blackbox/test_blackbox.py b/envs/monkey_zoo/blackbox/test_blackbox.py index 4ef035c22be..aa77c278443 100644 --- a/envs/monkey_zoo/blackbox/test_blackbox.py +++ b/envs/monkey_zoo/blackbox/test_blackbox.py @@ -114,6 +114,8 @@ def island_client(monkey_island_requests): if not client_established: pytest.exit("BB tests couldn't establish communication to the island.") + island_client_object.install_agent_plugins() + yield island_client_object From 3ed6369796bf4d5e2df2b614fd1692c2b99ba31e Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 29 Aug 2023 13:49:01 +0530 Subject: [PATCH 02/18] BB: Don't attempt plugin installation if it is already installed to the Island --- .../island_client/monkey_island_client.py | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py index 9d2989e534d..29b2663ea56 100644 --- a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py +++ b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py @@ -37,16 +37,31 @@ def get_api_status(self): def install_agent_plugins(self): available_plugins_index_url = "api/agent-plugins/available/index" + installed_plugins_manifests_url = "api/agent-plugins/installed/manifests" install_plugin_url = "api/install-agent-plugin" plugin_repository_index = self.requests.get(available_plugins_index_url) - available_plugins = plugin_repository_index.plugins - - for plugin_type in available_plugins: - for plugin_name in available_plugins[plugin_type]: - for plugin_versions in available_plugins[plugin_type][plugin_name]: - latest_version_plugin_metadata = plugin_versions[-1] - latest_version = latest_version_plugin_metadata.version + available_plugins_index = plugin_repository_index.plugins + + installed_plugins_manifests = self.requests.get(installed_plugins_manifests_url) + + # all of the responses from the API endpoints are serialized + # so we don't need to worry about type conversion + for plugin_type in available_plugins_index: + for plugin_name in available_plugins_index[plugin_type]: + for plugin_versions in available_plugins_index[plugin_type][plugin_name]: + latest_version = plugin_versions[-1].version + + # if a plugin of the latest version is already installed, skip + installed_plugin = installed_plugins_manifests.get(plugin_type, {}).get( + plugin_name, {} + ) + if installed_plugin and installed_plugin.get("version", "") == latest_version: + logger.info( + f"{plugin_name} {plugin_type} v{latest_version} " + "already installed to Island" + ) + continue install_plugin_request = { "plugin_type": plugin_type, From 30cda69c8db7d98a12e14ad177cd1966c46c144b Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 29 Aug 2023 13:50:20 +0530 Subject: [PATCH 03/18] BB: Install plugins to Island before running exploitation tests --- envs/monkey_zoo/blackbox/test_blackbox.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_blackbox.py b/envs/monkey_zoo/blackbox/test_blackbox.py index aa77c278443..1e4a47d0439 100644 --- a/envs/monkey_zoo/blackbox/test_blackbox.py +++ b/envs/monkey_zoo/blackbox/test_blackbox.py @@ -114,8 +114,6 @@ def island_client(monkey_island_requests): if not client_established: pytest.exit("BB tests couldn't establish communication to the island.") - island_client_object.install_agent_plugins() - yield island_client_object @@ -567,6 +565,8 @@ def run_exploitation_test( timeout_in_seconds=DEFAULT_TIMEOUT_SECONDS, masque: Optional[bytes] = None, ): + island_client.install_agent_plugins() + analyzer = CommunicationAnalyzer( island_client, get_target_ips(test_configuration), @@ -601,6 +601,9 @@ def test_credentials_reuse_ssh_key(self, island_client): def test_depth_2_a(self, island_client): test_name = "Depth2A test suite" + + island_client.install_agent_plugins() + communication_analyzer = CommunicationAnalyzer( island_client, get_target_ips(depth_2_a_test_configuration), @@ -635,6 +638,8 @@ def test_depth_1_a(self, island_client): test_name = "Depth1A test suite" masque = b"m0nk3y" + island_client.install_agent_plugins() + communication_analyzer = CommunicationAnalyzer( island_client, get_target_ips(depth_1_a_test_configuration), @@ -661,6 +666,9 @@ def test_depth_1_a(self, island_client): def test_depth_3_a(self, island_client): test_name = "Depth3A test suite" + + island_client.install_agent_plugins() + communication_analyzer = CommunicationAnalyzer( island_client, get_target_ips(depth_3_a_test_configuration), @@ -700,6 +708,8 @@ def test_zerologon_exploiter(self, island_client): "2864b62ea4496934a5d6e86f50b834a5", ] + island_client.install_agent_plugins() + zero_logon_analyzer = ZerologonAnalyzer(island_client, expected_creds) communication_analyzer = CommunicationAnalyzer( island_client, From df480b7a6d43de2eb125b545a7ce436cbdaa9280 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 29 Aug 2023 14:25:56 +0530 Subject: [PATCH 04/18] BB: Fix logic in MonkeyIslandClient.install_agent_plugins() --- .../island_client/monkey_island_client.py | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py index 29b2663ea56..a9f4b46ff46 100644 --- a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py +++ b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py @@ -40,46 +40,46 @@ def install_agent_plugins(self): installed_plugins_manifests_url = "api/agent-plugins/installed/manifests" install_plugin_url = "api/install-agent-plugin" - plugin_repository_index = self.requests.get(available_plugins_index_url) - available_plugins_index = plugin_repository_index.plugins + response = self.requests.get(available_plugins_index_url) + plugin_repository_index = response.json() + available_plugins_index = plugin_repository_index["plugins"] - installed_plugins_manifests = self.requests.get(installed_plugins_manifests_url) + response = self.requests.get(installed_plugins_manifests_url) + installed_plugins_manifests = response.json() # all of the responses from the API endpoints are serialized # so we don't need to worry about type conversion for plugin_type in available_plugins_index: for plugin_name in available_plugins_index[plugin_type]: - for plugin_versions in available_plugins_index[plugin_type][plugin_name]: - latest_version = plugin_versions[-1].version + plugin_versions = available_plugins_index[plugin_type][plugin_name] + latest_version = plugin_versions[-1]["version"] + + # if a plugin of the latest version is already installed, skip + installed_plugin = installed_plugins_manifests.get(plugin_type, {}).get( + plugin_name, {} + ) + if installed_plugin and installed_plugin.get("version", "") == latest_version: + logger.info( + f"{plugin_name} {plugin_type} v{latest_version} " + "already installed to Island" + ) + continue + + install_plugin_request = { + "plugin_type": plugin_type, + "name": plugin_name, + "version": latest_version, + } - # if a plugin of the latest version is already installed, skip - installed_plugin = installed_plugins_manifests.get(plugin_type, {}).get( - plugin_name, {} + if self.requests.put_json(url=install_plugin_url, json=install_plugin_request).ok: + logger.info( + f"Installed {plugin_name} {plugin_type} v{latest_version} to Island" + ) + else: + logger.error( + f"Could not install {plugin_name} {plugin_type} " + f"v{latest_version} to Island" ) - if installed_plugin and installed_plugin.get("version", "") == latest_version: - logger.info( - f"{plugin_name} {plugin_type} v{latest_version} " - "already installed to Island" - ) - continue - - install_plugin_request = { - "plugin_type": plugin_type, - "name": plugin_name, - "version": latest_version, - } - - if self.requests.put_json( - url=install_plugin_url, json=install_plugin_request - ).ok: - logger.info( - f"Installed {plugin_name} {plugin_type} v{latest_version} to Island" - ) - else: - logger.error( - f"Could not install {plugin_name} {plugin_type} " - f"v{latest_version} to Island" - ) @avoid_race_condition def set_masque(self, masque): From 80befa30b3317207644198558972db60de9c0f27 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 29 Aug 2023 16:27:14 +0530 Subject: [PATCH 05/18] Island: Fix InstallAgentPlugin resource to handle string version argument --- .../flask_resources/install_agent_plugin.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/agent_plugin_service/flask_resources/install_agent_plugin.py b/monkey/monkey_island/cc/services/agent_plugin_service/flask_resources/install_agent_plugin.py index bbe75886aad..92466a81424 100644 --- a/monkey/monkey_island/cc/services/agent_plugin_service/flask_resources/install_agent_plugin.py +++ b/monkey/monkey_island/cc/services/agent_plugin_service/flask_resources/install_agent_plugin.py @@ -3,6 +3,7 @@ from http import HTTPStatus from typing import Tuple +import semver from flask import make_response, request from flask_security import auth_token_required, roles_accepted @@ -66,7 +67,11 @@ def _get_plugin_information_from_request( raise ValueError(message) try: - plugin_version = PluginVersion(**plugin_version_arg) + # TODO: (1) semver.parse is deprecated + # (2) knowledge of semver usage shouldn't be leaked here anyway, + # handling a string argument (like "1.0.2") should be done in + # PluginVersion itself + plugin_version = PluginVersion(**semver.parse(plugin_version_arg)) except ValueError as err: message = f"Invalid plugin version argument: {plugin_version_arg}: {err}." raise ValueError(message) From 5eb4b9ec2397e30f5a286b6fcd7ef1030d00c642 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 29 Aug 2023 18:09:03 +0530 Subject: [PATCH 06/18] UT: Fix test for InstallAgentPlugin and leave a TODO --- .../flask_resources/test_install_agent_plugin.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/agent_plugin_service/flask_resources/test_install_agent_plugin.py b/monkey/tests/unit_tests/monkey_island/cc/services/agent_plugin_service/flask_resources/test_install_agent_plugin.py index 4dbe884164b..cc24c667a71 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/agent_plugin_service/flask_resources/test_install_agent_plugin.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/agent_plugin_service/flask_resources/test_install_agent_plugin.py @@ -16,10 +16,9 @@ AGENT_PLUGIN = b"SomePlugin" PLUGIN_TYPE = "Exploiter" PLUGIN_NAME = "RDP" -VERSION_DICT = {"major": "1", "minor": "0", "patch": "1"} -VERSION = '{"major": "1", "minor": "0", "patch": "1"}' +VERSION = "1.0.1" REQUEST_JSON_DATA = ( - f'{{"plugin_type": "{PLUGIN_TYPE}", "name": "{PLUGIN_NAME}", "version": {VERSION}}}' + f'{{"plugin_type": "{PLUGIN_TYPE}", "name": "{PLUGIN_NAME}", "version": "{VERSION}"}}' ) @@ -64,7 +63,9 @@ def test_install_plugin__json(agent_plugin_service, flask_client): agent_plugin_service.install_plugin_from_repository.assert_called_with( plugin_type=AgentPluginType(PLUGIN_TYPE), plugin_name=PLUGIN_NAME, - plugin_version=PluginVersion(**VERSION_DICT), + # TODO: the following is a hack until the TODO in + # InstallAgentPlugin._get_plugin_information_from_request() is done + plugin_version=PluginVersion(*(VERSION.split("."))), ) From 0d8a1f421bced942a98d6a970aef790031019a6c Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 29 Aug 2023 18:10:11 +0530 Subject: [PATCH 07/18] Island: Remove code for installing plugins from data dir --- monkey/monkey_island/cc/server_setup.py | 2 - .../monkey_island/cc/server_utils/consts.py | 2 - .../monkey_island/cc/services/initialize.py | 9 +--- monkey/monkey_island/cc/setup/__init__.py | 1 - monkey/monkey_island/cc/setup/data_dir.py | 41 ------------------- .../cc/setup/plugin_installation.py | 31 -------------- 6 files changed, 1 insertion(+), 85 deletions(-) delete mode 100644 monkey/monkey_island/cc/setup/plugin_installation.py diff --git a/monkey/monkey_island/cc/server_setup.py b/monkey/monkey_island/cc/server_setup.py index 00fdfb3de39..45a21f481bf 100644 --- a/monkey/monkey_island/cc/server_setup.py +++ b/monkey/monkey_island/cc/server_setup.py @@ -37,7 +37,6 @@ from monkey_island.cc.services.initialize import initialize_services # noqa: E402 from monkey_island.cc.setup import ( # noqa: E402 PyWSGILoggingFilter, - install_plugins, island_config_options_validator, setup_agent_event_handlers, setup_island_event_handlers, @@ -68,7 +67,6 @@ def run_monkey_island(): container = _initialize_di_container(ip_addresses, version, config_options.data_dir) setup_island_event_handlers(container) setup_agent_event_handlers(container) - install_plugins(container, config_options.data_dir) _start_island_server(ip_addresses, island_args.setup_only, config_options, container) diff --git a/monkey/monkey_island/cc/server_utils/consts.py b/monkey/monkey_island/cc/server_utils/consts.py index 0030dc223f6..4d961ecf057 100644 --- a/monkey/monkey_island/cc/server_utils/consts.py +++ b/monkey/monkey_island/cc/server_utils/consts.py @@ -36,8 +36,6 @@ def _get_monkey_island_abs_path() -> str: DEFAULT_LOG_LEVEL = "INFO" -PLUGIN_DIR_NAME = "plugins" - DEFAULT_START_MONGO_DB = True DEFAULT_CRT_PATH = str(Path(MONKEY_ISLAND_ABS_PATH, "cc", "server.crt")) diff --git a/monkey/monkey_island/cc/services/initialize.py b/monkey/monkey_island/cc/services/initialize.py index db225efb514..d9b99881a3f 100644 --- a/monkey/monkey_island/cc/services/initialize.py +++ b/monkey/monkey_island/cc/services/initialize.py @@ -46,7 +46,7 @@ NetworkModelUpdateFacade, initialize_machine_repository, ) -from monkey_island.cc.server_utils.consts import MONKEY_ISLAND_ABS_PATH, PLUGIN_DIR_NAME +from monkey_island.cc.server_utils.consts import MONKEY_ISLAND_ABS_PATH from monkey_island.cc.server_utils.encryption import ILockableEncryptor, RepositoryEncryptor from monkey_island.cc.services import ( AgentSignalsService, @@ -133,13 +133,6 @@ def _register_repositories(container: DIContainer, data_dir: Path): IFileRepository, _decorate_file_repository(LocalStorageFileRepository(data_dir / "runtime_data")), ) - container.register_convention( - IFileRepository, - "plugin_file_repository", - FileRepositoryLockingDecorator( - FileRepositoryLoggingDecorator(LocalStorageFileRepository(data_dir / PLUGIN_DIR_NAME)) - ), - ) container.register_instance(ISimulationRepository, container.resolve(FileSimulationRepository)) container.register_instance( diff --git a/monkey/monkey_island/cc/setup/__init__.py b/monkey/monkey_island/cc/setup/__init__.py index 20b7b9b9e7d..97a7ccfc2ed 100644 --- a/monkey/monkey_island/cc/setup/__init__.py +++ b/monkey/monkey_island/cc/setup/__init__.py @@ -1,4 +1,3 @@ from .pywsgi_logging_filter import PyWSGILoggingFilter from .island_event_handlers import setup_island_event_handlers from .agent_event_handlers import setup_agent_event_handlers -from .plugin_installation import install_plugins diff --git a/monkey/monkey_island/cc/setup/data_dir.py b/monkey/monkey_island/cc/setup/data_dir.py index 66696a61a74..e4c33182c40 100644 --- a/monkey/monkey_island/cc/setup/data_dir.py +++ b/monkey/monkey_island/cc/setup/data_dir.py @@ -5,7 +5,6 @@ from common.utils.file_utils import create_secure_directory from common.version import get_version -from monkey_island.cc.server_utils.consts import MONKEY_ISLAND_ABS_PATH, PLUGIN_DIR_NAME from monkey_island.cc.setup.env_utils import is_running_on_docker from monkey_island.cc.setup.version_file_setup import get_version_from_dir, write_version @@ -23,7 +22,6 @@ def setup_data_dir(data_dir_path: Path): _handle_old_data_directory(data_dir_path) create_secure_directory(data_dir_path) write_version(data_dir_path) - _copy_plugins_into_data_dir(data_dir_path) logger.info(f"Data directory set up in {data_dir_path}.") @@ -92,42 +90,3 @@ def _data_dir_version_mismatch_exists(data_dir_path: Path) -> bool: island_version = get_version() return island_version != data_dir_version - - -def _copy_plugins_into_data_dir(data_dir_path: Path): - plugin_source_dir = Path(MONKEY_ISLAND_ABS_PATH) / PLUGIN_DIR_NAME - try: - plugins_dir = _create_plugins_dir(data_dir_path) - plugin_tar_files = list(plugin_source_dir.glob("*.tar")) - except Exception: - logger.exception( - f"An error occured while creating plugins data directory: {plugin_source_dir}" - ) - return - - for plugin_tar_file in plugin_tar_files: - plugin_dest_path = plugins_dir / plugin_tar_file.name - if plugin_dest_path.exists(): - logger.info( - "Skipping plugin tar file copy: " - f"destination file {plugin_dest_path} already exists." - ) - continue - - try: - logger.info(f"Copying plugin tar file: {plugin_tar_file} -> {plugin_dest_path}") - shutil.copy2(plugin_tar_file, plugin_dest_path) - except FileNotFoundError: - logger.exception( - f"An error occured while copying plugin {plugin_tar_file} " - f"to the data directory: {data_dir_path}" - ) - - -def _create_plugins_dir(plugins_dir_parent_dir: Path) -> Path: - plugins_dir = plugins_dir_parent_dir / PLUGIN_DIR_NAME - logger.info(f"Plugins directory: {plugins_dir}") - - if not plugins_dir.exists(): - create_secure_directory(plugins_dir) - return plugins_dir diff --git a/monkey/monkey_island/cc/setup/plugin_installation.py b/monkey/monkey_island/cc/setup/plugin_installation.py deleted file mode 100644 index 52360b8656f..00000000000 --- a/monkey/monkey_island/cc/setup/plugin_installation.py +++ /dev/null @@ -1,31 +0,0 @@ -import logging -from pathlib import Path - -from common import DIContainer -from monkey_island.cc.services.agent_plugin_service import IAgentPluginService -from monkey_island.cc.services.agent_plugin_service.errors import PluginInstallationError - -from .data_dir import PLUGIN_DIR_NAME - -logger = logging.getLogger(__name__) - - -def install_plugins(container: DIContainer, data_dir: Path): - agent_plugin_service = container.resolve(IAgentPluginService) - - plugins_dir = data_dir / PLUGIN_DIR_NAME - - for path in plugins_dir.iterdir(): - if path.is_symlink(): - logger.warning(f"Skipping symlink at {path}") - continue - if not path.is_file(): - logger.warning(f"Skipping non-file at {path}") - continue - - with open(path, "rb") as f: - plugin_archive = f.read() - try: - agent_plugin_service.install_plugin_archive(plugin_archive) - except PluginInstallationError: - logger.warning(f"Failed to install plugin at {path}") From f1425780013a14099bd573f25b06a591ef3b300f Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 29 Aug 2023 18:11:33 +0530 Subject: [PATCH 08/18] UT: Remove tests for plugin dir in data dir --- .../monkey_island/cc/setup/test_data_dir.py | 70 ------------------- 1 file changed, 70 deletions(-) diff --git a/monkey/tests/unit_tests/monkey_island/cc/setup/test_data_dir.py b/monkey/tests/unit_tests/monkey_island/cc/setup/test_data_dir.py index 3be7807c9f3..e476784b11d 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/setup/test_data_dir.py +++ b/monkey/tests/unit_tests/monkey_island/cc/setup/test_data_dir.py @@ -1,10 +1,7 @@ from pathlib import Path import pytest -from tests.monkey_island.utils import assert_linux_permissions, assert_windows_permissions -from common.utils.environment import is_windows_os -from monkey_island.cc.server_utils.consts import PLUGIN_DIR_NAME from monkey_island.cc.setup.data_dir import IncompatibleDataDirectory, setup_data_dir from monkey_island.cc.setup.env_utils import DOCKER_ENV_VAR from monkey_island.cc.setup.version_file_setup import _version_filename @@ -132,70 +129,3 @@ def test_old_data_dir_docker_no_version(monkeypatch, temp_data_dir_path): with pytest.raises(IncompatibleDataDirectory): setup_data_dir(temp_data_dir_path) - - -def test_plugin_dir_created(temp_data_dir_path): - setup_data_dir(temp_data_dir_path) - assert (temp_data_dir_path / PLUGIN_DIR_NAME).is_dir() - - -def test_plugin_dir_permissions(temp_data_dir_path): - setup_data_dir(temp_data_dir_path) - if is_windows_os(): - assert_windows_permissions(temp_data_dir_path / PLUGIN_DIR_NAME) - else: - assert_linux_permissions(temp_data_dir_path / PLUGIN_DIR_NAME) - - -def test_plugins_copied_to_plugin_dir(monkeypatch, tmp_path, temp_data_dir_path): - plugin_contents = "test plugin" - plugin_src_dir = tmp_path / PLUGIN_DIR_NAME - plugin_src_dir.mkdir() - test_plugin = plugin_src_dir / "test_plugin.tar" - test_plugin.write_text(plugin_contents) - monkeypatch.setattr("monkey_island.cc.setup.data_dir.MONKEY_ISLAND_ABS_PATH", tmp_path) - - setup_data_dir(temp_data_dir_path) - assert (temp_data_dir_path / PLUGIN_DIR_NAME / test_plugin.name).read_text() == plugin_contents - - -def test_plugins_in_plugin_dir_not_overwitten( - monkeypatch, tmp_path, temp_data_dir_path, temp_version_file_path -): - temp_data_dir_path.mkdir() - temp_version_file_path.write_text(current_version) - - test_plugin_name = "test_plugin.tar" - original_plugin_contents = "original plugin" - plugin_dir = temp_data_dir_path / PLUGIN_DIR_NAME - plugin_dir.mkdir() - plugin_dir_plugin = plugin_dir / test_plugin_name - plugin_dir_plugin.write_text(original_plugin_contents) - - plugin_src_dir = tmp_path / PLUGIN_DIR_NAME - plugin_src_dir.mkdir() - new_plugin = plugin_src_dir / test_plugin_name - new_plugin.write_text("new plugin") - monkeypatch.setattr("monkey_island.cc.setup.data_dir.MONKEY_ISLAND_ABS_PATH", tmp_path) - - setup_data_dir(temp_data_dir_path) - - assert plugin_dir_plugin.read_text() == original_plugin_contents - - -def test_setup_plugin_dir_existing_dir_permissions(temp_data_dir_path): - if is_windows_os(): - assert_permissions = assert_windows_permissions - else: - assert_permissions = assert_linux_permissions - - plugin_dir_path = temp_data_dir_path / PLUGIN_DIR_NAME - temp_data_dir_path.mkdir() - plugin_dir_path.mkdir() - - assert plugin_dir_path.is_dir() - with pytest.raises(AssertionError): - assert_permissions(plugin_dir_path) - - setup_data_dir(plugin_dir_path) - assert_permissions(plugin_dir_path) From 49652974570bd6132a958cfc28b6cc8b5b76f550 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 29 Aug 2023 08:55:13 -0400 Subject: [PATCH 09/18] Common: Add PluginVersion.from_str() classmethod --- monkey/common/agent_plugins/agent_plugin_manifest.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/monkey/common/agent_plugins/agent_plugin_manifest.py b/monkey/common/agent_plugins/agent_plugin_manifest.py index 8ce67cb65b8..3b2239aefa9 100644 --- a/monkey/common/agent_plugins/agent_plugin_manifest.py +++ b/monkey/common/agent_plugins/agent_plugin_manifest.py @@ -1,5 +1,5 @@ import re -from typing import Callable, Mapping, Optional, Tuple, Type +from typing import Callable, Mapping, Optional, Self, Tuple, Type from pydantic import ConstrainedStr, HttpUrl from semver import VersionInfo @@ -24,7 +24,7 @@ class PluginVersion(VersionInfo): @classmethod def __get_validators__(cls): """Return a list of validator methods for pydantic models.""" - yield cls.parse + yield cls.from_str @classmethod def __modify_schema__(cls, field_schema): @@ -37,6 +37,11 @@ def __modify_schema__(cls, field_schema): ] ) + @classmethod + def from_str(cls, version: str) -> Self: + """Convert a string to a PluginVersion.""" + return cls.parse(version) + class AgentPluginManifest(InfectionMonkeyBaseModel): """ From c167c4dd75d9f8daa3e3427d14a4359058cba74b Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 29 Aug 2023 08:55:39 -0400 Subject: [PATCH 10/18] Island: Handle proper version format in InstallAgentPlugin endpoint --- .../flask_resources/install_agent_plugin.py | 7 +------ .../flask_resources/test_install_agent_plugin.py | 5 ++--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/monkey/monkey_island/cc/services/agent_plugin_service/flask_resources/install_agent_plugin.py b/monkey/monkey_island/cc/services/agent_plugin_service/flask_resources/install_agent_plugin.py index 92466a81424..4de68ef8544 100644 --- a/monkey/monkey_island/cc/services/agent_plugin_service/flask_resources/install_agent_plugin.py +++ b/monkey/monkey_island/cc/services/agent_plugin_service/flask_resources/install_agent_plugin.py @@ -3,7 +3,6 @@ from http import HTTPStatus from typing import Tuple -import semver from flask import make_response, request from flask_security import auth_token_required, roles_accepted @@ -67,11 +66,7 @@ def _get_plugin_information_from_request( raise ValueError(message) try: - # TODO: (1) semver.parse is deprecated - # (2) knowledge of semver usage shouldn't be leaked here anyway, - # handling a string argument (like "1.0.2") should be done in - # PluginVersion itself - plugin_version = PluginVersion(**semver.parse(plugin_version_arg)) + plugin_version = PluginVersion.from_str(plugin_version_arg) except ValueError as err: message = f"Invalid plugin version argument: {plugin_version_arg}: {err}." raise ValueError(message) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/agent_plugin_service/flask_resources/test_install_agent_plugin.py b/monkey/tests/unit_tests/monkey_island/cc/services/agent_plugin_service/flask_resources/test_install_agent_plugin.py index cc24c667a71..e2bd5c68aa3 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/agent_plugin_service/flask_resources/test_install_agent_plugin.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/agent_plugin_service/flask_resources/test_install_agent_plugin.py @@ -16,6 +16,7 @@ AGENT_PLUGIN = b"SomePlugin" PLUGIN_TYPE = "Exploiter" PLUGIN_NAME = "RDP" +VERSION_DICT = {"major": "1", "minor": "0", "patch": "1"} VERSION = "1.0.1" REQUEST_JSON_DATA = ( f'{{"plugin_type": "{PLUGIN_TYPE}", "name": "{PLUGIN_NAME}", "version": "{VERSION}"}}' @@ -63,9 +64,7 @@ def test_install_plugin__json(agent_plugin_service, flask_client): agent_plugin_service.install_plugin_from_repository.assert_called_with( plugin_type=AgentPluginType(PLUGIN_TYPE), plugin_name=PLUGIN_NAME, - # TODO: the following is a hack until the TODO in - # InstallAgentPlugin._get_plugin_information_from_request() is done - plugin_version=PluginVersion(*(VERSION.split("."))), + plugin_version=PluginVersion.from_str(VERSION), ) From 96337cb366fac456f5c4836c5301bba88140444d Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 30 Aug 2023 08:20:21 -0400 Subject: [PATCH 11/18] Build: Remove legacy "environment" section from appimage server_config --- build_scripts/appimage/server_config.json.standard | 3 --- 1 file changed, 3 deletions(-) diff --git a/build_scripts/appimage/server_config.json.standard b/build_scripts/appimage/server_config.json.standard index 889654ea2b2..0fee130ccb5 100644 --- a/build_scripts/appimage/server_config.json.standard +++ b/build_scripts/appimage/server_config.json.standard @@ -1,9 +1,6 @@ { "data_dir": "~/.monkey_island", "log_level": "DEBUG", - "environment": { - "server_config": "password" - }, "mongodb": { "start_mongodb": true } From 4e87a7425c27e6969823bf89db4fac7b43d83513 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 30 Aug 2023 09:14:28 -0400 Subject: [PATCH 12/18] Island: Log version and deployment on setup --- monkey/monkey_island/cc/server_setup.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/monkey/monkey_island/cc/server_setup.py b/monkey/monkey_island/cc/server_setup.py index 45a21f481bf..84f657d6934 100644 --- a/monkey/monkey_island/cc/server_setup.py +++ b/monkey/monkey_island/cc/server_setup.py @@ -102,7 +102,11 @@ def _configure_logging(config_options): def _collect_system_info() -> Tuple[Sequence[IPv4Address], Deployment, Version]: deployment = _get_deployment() + logger.info(f"Monkey Island deployment: {deployment}") + version = Version(get_version(), deployment) + logger.info(f"Monkey Island version: {version.version_number}") + return (get_my_ip_addresses(), deployment, version) From f2436847efd67d76f04f554a425637ecb9478bb3 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 30 Aug 2023 09:51:04 -0400 Subject: [PATCH 13/18] BB: Install agent plugins immediately after registration --- envs/monkey_zoo/blackbox/test_blackbox.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_blackbox.py b/envs/monkey_zoo/blackbox/test_blackbox.py index 1e4a47d0439..3efad11ced9 100644 --- a/envs/monkey_zoo/blackbox/test_blackbox.py +++ b/envs/monkey_zoo/blackbox/test_blackbox.py @@ -118,10 +118,13 @@ def island_client(monkey_island_requests): @pytest.fixture(autouse=True, scope="session") -def register(island_client): +def setup_island(island_client): logging.info("Registering a new user") island_client.register() + logging.info("Installing all available plugins") + island_client.install_agent_plugins() + @pytest.mark.parametrize( "authenticated_endpoint", @@ -565,8 +568,6 @@ def run_exploitation_test( timeout_in_seconds=DEFAULT_TIMEOUT_SECONDS, masque: Optional[bytes] = None, ): - island_client.install_agent_plugins() - analyzer = CommunicationAnalyzer( island_client, get_target_ips(test_configuration), @@ -602,8 +603,6 @@ def test_credentials_reuse_ssh_key(self, island_client): def test_depth_2_a(self, island_client): test_name = "Depth2A test suite" - island_client.install_agent_plugins() - communication_analyzer = CommunicationAnalyzer( island_client, get_target_ips(depth_2_a_test_configuration), @@ -638,8 +637,6 @@ def test_depth_1_a(self, island_client): test_name = "Depth1A test suite" masque = b"m0nk3y" - island_client.install_agent_plugins() - communication_analyzer = CommunicationAnalyzer( island_client, get_target_ips(depth_1_a_test_configuration), @@ -667,8 +664,6 @@ def test_depth_1_a(self, island_client): def test_depth_3_a(self, island_client): test_name = "Depth3A test suite" - island_client.install_agent_plugins() - communication_analyzer = CommunicationAnalyzer( island_client, get_target_ips(depth_3_a_test_configuration), @@ -708,8 +703,6 @@ def test_zerologon_exploiter(self, island_client): "2864b62ea4496934a5d6e86f50b834a5", ] - island_client.install_agent_plugins() - zero_logon_analyzer = ZerologonAnalyzer(island_client, expected_creds) communication_analyzer = CommunicationAnalyzer( island_client, From 0ac72d3dc68181c1774a7b96964431aff35fbfa0 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 30 Aug 2023 09:54:14 -0400 Subject: [PATCH 14/18] BB: Install agent plugins concurrently Reduces installation time by 61% --- .../island_client/monkey_island_client.py | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py index a9f4b46ff46..992d24495ab 100644 --- a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py +++ b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py @@ -2,7 +2,8 @@ import logging import time from http import HTTPStatus -from typing import List, Mapping, Optional, Sequence +from threading import Thread +from typing import Any, Dict, List, Mapping, Optional, Sequence from common import OperatingSystem from common.credentials import Credentials @@ -47,6 +48,8 @@ def install_agent_plugins(self): response = self.requests.get(installed_plugins_manifests_url) installed_plugins_manifests = response.json() + install_threads: List[Thread] = [] + # all of the responses from the API endpoints are serialized # so we don't need to worry about type conversion for plugin_type in available_plugins_index: @@ -70,16 +73,37 @@ def install_agent_plugins(self): "name": plugin_name, "version": latest_version, } - - if self.requests.put_json(url=install_plugin_url, json=install_plugin_request).ok: - logger.info( - f"Installed {plugin_name} {plugin_type} v{latest_version} to Island" - ) - else: - logger.error( - f"Could not install {plugin_name} {plugin_type} " - f"v{latest_version} to Island" - ) + t = Thread( + target=self._install_single_agent_plugin, + args=( + plugin_name, + plugin_type, + latest_version, + install_plugin_url, + install_plugin_request, + ), + daemon=True, + ) + t.start() + install_threads.append(t) + + for t in install_threads: + t.join() + + def _install_single_agent_plugin( + self, + plugin_name: str, + plugin_type: str, + latest_version: str, + url: str, + request: Dict[str, Any], + ): + if self.requests.put_json(url=url, json=request).ok: + logger.info(f"Installed {plugin_name} {plugin_type} v{latest_version} to Island") + else: + logger.error( + f"Could not install {plugin_name} {plugin_type} " f"v{latest_version} to Island" + ) @avoid_race_condition def set_masque(self, masque): From 8ba0190c455709cc39979c835dc0e4d4456e4efb Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 30 Aug 2023 10:36:11 -0400 Subject: [PATCH 15/18] Common: Make AgentPluginType a StrEnum --- monkey/common/agent_plugins/agent_plugin_type.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/common/agent_plugins/agent_plugin_type.py b/monkey/common/agent_plugins/agent_plugin_type.py index da598676750..1e92c326f78 100644 --- a/monkey/common/agent_plugins/agent_plugin_type.py +++ b/monkey/common/agent_plugins/agent_plugin_type.py @@ -1,7 +1,7 @@ -from enum import Enum +from enum import StrEnum -class AgentPluginType(Enum): +class AgentPluginType(StrEnum): CREDENTIALS_COLLECTOR = "Credentials_Collector" EXPLOITER = "Exploiter" FINGERPRINTER = "Fingerprinter" From 0183d8064bd022dfcfe45e257ab29ed07f95c5b1 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 30 Aug 2023 10:44:46 -0400 Subject: [PATCH 16/18] Common: Deserialize AgentPluginType as enum instead of string --- .../agent_plugin_repository_index.py | 4 +++ .../test_agent_plugin_repository_index.py | 25 +++++++++++-------- vulture_allowlist.py | 1 + 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/monkey/common/agent_plugins/agent_plugin_repository_index.py b/monkey/common/agent_plugins/agent_plugin_repository_index.py index c55cbadec63..03ee3c1ffa1 100644 --- a/monkey/common/agent_plugins/agent_plugin_repository_index.py +++ b/monkey/common/agent_plugins/agent_plugin_repository_index.py @@ -63,3 +63,7 @@ def _infection_monkey_version_parser( return VersionInfo.parse(value) raise TypeError(f'Expected "{DEVELOPMENT}" or a valid semantic version, got {type(value)}') + + @validator("plugins") + def _convert_str_type_to_enum(cls, plugins): + return {AgentPluginType(t): plugins for t, plugins in plugins.items()} diff --git a/monkey/tests/unit_tests/common/agent_plugins/test_agent_plugin_repository_index.py b/monkey/tests/unit_tests/common/agent_plugins/test_agent_plugin_repository_index.py index 5016141c401..d013159a6e0 100644 --- a/monkey/tests/unit_tests/common/agent_plugins/test_agent_plugin_repository_index.py +++ b/monkey/tests/unit_tests/common/agent_plugins/test_agent_plugin_repository_index.py @@ -1,4 +1,5 @@ import random +from enum import Enum from pathlib import PurePosixPath import pytest @@ -32,7 +33,7 @@ def get_plugin_metadata_with_given_version(version: str) -> AgentPluginMetadata: PLUGIN_VERSION_3_0_1 = get_plugin_metadata_with_given_version("3.0.1") PLUGIN_VERSION_3_0_1_SERIALIZED = { "name": PAYLOAD_PLUGIN_NAME, - "type_": AgentPluginType.PAYLOAD.value, + "type_": str(AgentPluginType.PAYLOAD), "resource_path": "/tmp", "sha256": "7ac0f5c62a9bcb81af3e9d67a764d7bbd3cce9af7cd26c211f136400ebe703c4", "description": "an awesome payload plugin", @@ -51,7 +52,7 @@ def get_plugin_metadata_with_given_version(version: str) -> AgentPluginMetadata: REPOSITORY_INDEX_PLUGINS = {AgentPluginType.PAYLOAD: {PAYLOAD_PLUGIN_NAME: [PLUGIN_VERSION_3_0_1]}} REPOSITORY_INDEX_PLUGINS_SERIALIZED = { - AgentPluginType.PAYLOAD.value: {PAYLOAD_PLUGIN_NAME: [PLUGIN_VERSION_3_0_1_SERIALIZED]} + str(AgentPluginType.PAYLOAD): {PAYLOAD_PLUGIN_NAME: [PLUGIN_VERSION_3_0_1_SERIALIZED]} } @@ -99,7 +100,11 @@ def test_agent_plugin_repository_index_serialization(object_, expected_serializa ], ) def test_agent_plugin_repository_index_deserialization(expected_object, serialized): - assert AgentPluginRepositoryIndex(**serialized) == expected_object + repository_index = AgentPluginRepositoryIndex(**serialized) + + assert repository_index == expected_object + for agent_plugin_type in repository_index.plugins.keys(): + assert isinstance(agent_plugin_type, Enum) def test_plugins_sorted_by_version(): @@ -111,16 +116,14 @@ def test_plugins_sorted_by_version(): repository_index = AgentPluginRepositoryIndex( compatible_infection_monkey_version="development", plugins={ - AgentPluginType.PAYLOAD.value: {PAYLOAD_PLUGIN_NAME: UNSORTED_PLUGIN_VERSIONS}, - AgentPluginType.EXPLOITER.value: {}, - AgentPluginType.CREDENTIALS_COLLECTOR.value: { - PAYLOAD_PLUGIN_NAME: [PLUGIN_VERSION_1_0_0] - }, + AgentPluginType.PAYLOAD: {PAYLOAD_PLUGIN_NAME: UNSORTED_PLUGIN_VERSIONS}, + AgentPluginType.EXPLOITER: {}, + AgentPluginType.CREDENTIALS_COLLECTOR: {PAYLOAD_PLUGIN_NAME: [PLUGIN_VERSION_1_0_0]}, }, ) assert repository_index.plugins == { - AgentPluginType.PAYLOAD.value: {PAYLOAD_PLUGIN_NAME: SORTED_PLUGIN_VERSIONS}, - AgentPluginType.EXPLOITER.value: {}, - AgentPluginType.CREDENTIALS_COLLECTOR.value: {PAYLOAD_PLUGIN_NAME: [PLUGIN_VERSION_1_0_0]}, + AgentPluginType.PAYLOAD: {PAYLOAD_PLUGIN_NAME: SORTED_PLUGIN_VERSIONS}, + AgentPluginType.EXPLOITER: {}, + AgentPluginType.CREDENTIALS_COLLECTOR: {PAYLOAD_PLUGIN_NAME: [PLUGIN_VERSION_1_0_0]}, } diff --git a/vulture_allowlist.py b/vulture_allowlist.py index 49e501e8950..af213b6d5ef 100644 --- a/vulture_allowlist.py +++ b/vulture_allowlist.py @@ -199,6 +199,7 @@ AgentPluginRepositoryIndex._infection_monkey_version_parser AgentPluginRepositoryIndex._sort_plugins_by_version AgentPluginRepositoryIndex.use_enum_values +AgentPluginRepositoryIndex._convert_str_type_to_enum CPUConsumptionEvent.cpu_number CPUConsumptionEvent.utilization From 212de4c157637f2d4a6b083eeb16b7173f56eafb Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 30 Aug 2023 11:19:30 -0400 Subject: [PATCH 17/18] BB: Refactor install_agent_plugins() --- .../island_client/monkey_island_client.py | 95 +++++++++++-------- 1 file changed, 54 insertions(+), 41 deletions(-) diff --git a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py index 992d24495ab..7d5124c51d4 100644 --- a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py +++ b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py @@ -6,6 +6,7 @@ from typing import Any, Dict, List, Mapping, Optional, Sequence from common import OperatingSystem +from common.agent_plugins import AgentPluginRepositoryIndex, AgentPluginType from common.credentials import Credentials from common.types import AgentID, MachineID from envs.monkey_zoo.blackbox.island_client.i_monkey_island_requests import IMonkeyIslandRequests @@ -20,6 +21,7 @@ GET_AGENT_EVENTS_ENDPOINT = "api/agent-events" LOGOUT_ENDPOINT = "api/logout" GET_AGENT_OTP_ENDPOINT = "/api/agent-otp" +INSTALL_PLUGIN_URL = "api/install-agent-plugin" logger = logging.getLogger(__name__) @@ -39,66 +41,77 @@ def get_api_status(self): def install_agent_plugins(self): available_plugins_index_url = "api/agent-plugins/available/index" installed_plugins_manifests_url = "api/agent-plugins/installed/manifests" - install_plugin_url = "api/install-agent-plugin" response = self.requests.get(available_plugins_index_url) - plugin_repository_index = response.json() - available_plugins_index = plugin_repository_index["plugins"] + plugin_repository_index = AgentPluginRepositoryIndex(**response.json()) response = self.requests.get(installed_plugins_manifests_url) - installed_plugins_manifests = response.json() + installed_plugins = response.json() install_threads: List[Thread] = [] # all of the responses from the API endpoints are serialized # so we don't need to worry about type conversion - for plugin_type in available_plugins_index: - for plugin_name in available_plugins_index[plugin_type]: - plugin_versions = available_plugins_index[plugin_type][plugin_name] - latest_version = plugin_versions[-1]["version"] - - # if a plugin of the latest version is already installed, skip - installed_plugin = installed_plugins_manifests.get(plugin_type, {}).get( - plugin_name, {} + for plugin_type in plugin_repository_index.plugins: + install_threads.extend( + self._install_all_agent_plugins_of_type( + plugin_type, plugin_repository_index, installed_plugins ) - if installed_plugin and installed_plugin.get("version", "") == latest_version: - logger.info( - f"{plugin_name} {plugin_type} v{latest_version} " - "already installed to Island" - ) - continue - - install_plugin_request = { - "plugin_type": plugin_type, - "name": plugin_name, - "version": latest_version, - } - t = Thread( - target=self._install_single_agent_plugin, - args=( - plugin_name, - plugin_type, - latest_version, - install_plugin_url, - install_plugin_request, - ), - daemon=True, - ) - t.start() - install_threads.append(t) + ) for t in install_threads: t.join() + def _install_all_agent_plugins_of_type( + self, + plugin_type: AgentPluginType, + plugin_repository_index: AgentPluginRepositoryIndex, + installed_plugins: Dict[str, Any], + ) -> Sequence[Thread]: + logger.info(f"Installing {plugin_type} plugins") + install_threads: List[Thread] = [] + for plugin_name in plugin_repository_index.plugins[plugin_type]: + plugin_versions = plugin_repository_index.plugins[plugin_type][plugin_name] + latest_version = str(plugin_versions[-1].version) + + if self._latest_version_already_installed( + installed_plugins, plugin_type, plugin_name, latest_version + ): + logger.info(f"{plugin_type}-{plugin_name}-v{latest_version} is already installed") + continue + + t = Thread( + target=self._install_single_agent_plugin, + args=(plugin_name, plugin_type, latest_version), + daemon=True, + ) + t.start() + install_threads.append(t) + + return install_threads + + def _latest_version_already_installed( + self, + installed_plugins: Dict[str, Any], + plugin_type: AgentPluginType, + plugin_name: str, + latest_version: str, + ) -> bool: + installed_plugin = installed_plugins.get(plugin_type, {}).get(plugin_name, {}) + return installed_plugin and installed_plugin.get("version", "") == latest_version + def _install_single_agent_plugin( self, plugin_name: str, - plugin_type: str, + plugin_type: AgentPluginType, latest_version: str, - url: str, - request: Dict[str, Any], ): - if self.requests.put_json(url=url, json=request).ok: + install_plugin_request = { + "plugin_type": plugin_type, + "name": plugin_name, + "version": latest_version, + } + if self.requests.put_json(url=INSTALL_PLUGIN_URL, json=install_plugin_request).ok: logger.info(f"Installed {plugin_name} {plugin_type} v{latest_version} to Island") else: logger.error( From f722dad7e7e15c0932e290651ae1f594ac967dcc Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 30 Aug 2023 11:44:21 -0400 Subject: [PATCH 18/18] Island: Remove unnecessary calls to get_all_plugin_manifests() --- .../agent_configuration_schema_compiler.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/monkey/monkey_island/cc/services/agent_configuration_service/agent_configuration_schema_compiler.py b/monkey/monkey_island/cc/services/agent_configuration_service/agent_configuration_schema_compiler.py index c50dee9c572..a2f57ba5020 100644 --- a/monkey/monkey_island/cc/services/agent_configuration_service/agent_configuration_schema_compiler.py +++ b/monkey/monkey_island/cc/services/agent_configuration_service/agent_configuration_schema_compiler.py @@ -41,13 +41,12 @@ def _add_plugins(self, schema: Dict[str, Any]) -> Dict[str, Any]: schema = self._add_hard_coded_plugins(schema) config_schemas = deepcopy(self._agent_plugin_service.get_all_plugin_configuration_schemas()) + all_plugin_manifests = self._agent_plugin_service.get_all_plugin_manifests() for plugin_type in config_schemas.keys(): for plugin_name in config_schemas[plugin_type].keys(): config_schema = config_schemas[plugin_type][plugin_name] - plugin_manifest = self._agent_plugin_service.get_all_plugin_manifests()[ - plugin_type - ][plugin_name] + plugin_manifest = all_plugin_manifests[plugin_type][plugin_name] config_schema.update(plugin_manifest.dict(simplify=True)) schema = self._add_plugin_to_schema(schema, plugin_type, plugin_name, config_schema) return schema