diff --git a/monkey/monkey_island/cc/repository/__init__.py b/monkey/monkey_island/cc/repository/__init__.py index d90f6aac6..344644f3c 100644 --- a/monkey/monkey_island/cc/repository/__init__.py +++ b/monkey/monkey_island/cc/repository/__init__.py @@ -10,3 +10,4 @@ from .i_agent_configuration_repository import IAgentConfigurationRepository from .file_agent_configuration_repository import FileAgentConfigurationRepository from .i_simulation_repository import ISimulationRepository from .file_simulation_repository import FileSimulationRepository +from .i_credentials_repository import ICredentialsRepository diff --git a/monkey/monkey_island/cc/resources/propagation_credentials.py b/monkey/monkey_island/cc/resources/propagation_credentials.py index d2d03730c..8b14e9b1f 100644 --- a/monkey/monkey_island/cc/resources/propagation_credentials.py +++ b/monkey/monkey_island/cc/resources/propagation_credentials.py @@ -1,15 +1,16 @@ +from flask import jsonify + +from monkey_island.cc.repository import ICredentialsRepository from monkey_island.cc.resources.AbstractResource import AbstractResource -from monkey_island.cc.services.config import ConfigService class PropagationCredentials(AbstractResource): urls = ["/api/propagation-credentials"] + def __init__(self, credentials_repository: ICredentialsRepository): + self._credentials_repository = credentials_repository + def get(self): - config = ConfigService.get_flat_config(should_decrypt=True) + propagation_credentials = self._credentials_repository.get_all_credentials() - propagation_credentials = ConfigService.get_config_propagation_credentials_from_flat_config( - config - ) - - return {"propagation_credentials": propagation_credentials} + return jsonify(propagation_credentials) diff --git a/monkey/monkey_island/cc/services/config.py b/monkey/monkey_island/cc/services/config.py index ac7844ca2..ea40c52a1 100644 --- a/monkey/monkey_island/cc/services/config.py +++ b/monkey/monkey_island/cc/services/config.py @@ -1,7 +1,6 @@ import collections import functools import logging -from typing import Dict, List from common.config_value_paths import ( LM_HASH_LIST_PATH, @@ -98,25 +97,6 @@ class ConfigService: mongo_key = ".".join(config_key_as_arr) mongo.db.config.update({}, {"$set": {mongo_key: value}}) - @staticmethod - def get_flat_config(should_decrypt=True): - config_json = ConfigService.get_config(should_decrypt) - flat_config_json = {} - for i in config_json: - if i == "ransomware": - # Don't flatten the ransomware because ransomware payload expects a dictionary #1260 - flat_config_json[i] = config_json[i] - continue - for j in config_json[i]: - for k in config_json[i][j]: - if isinstance(config_json[i][j][k], dict): - for key, value in config_json[i][j][k].items(): - flat_config_json[key] = value - else: - flat_config_json[k] = config_json[i][j][k] - - return flat_config_json - # Not added to interface because it's doable by get_config_field + set_config_field @staticmethod def add_item_to_config_set_if_dont_exist(item_path_array, item_value, should_encrypt): @@ -251,13 +231,3 @@ class ConfigService: if is_decrypt else get_datastore_encryptor().encrypt(config_arr) ) - - @staticmethod - def get_config_propagation_credentials_from_flat_config(config) -> Dict[str, List[str]]: - return { - "exploit_user_list": config.get("exploit_user_list", []), - "exploit_password_list": config.get("exploit_password_list", []), - "exploit_lm_hash_list": config.get("exploit_lm_hash_list", []), - "exploit_ntlm_hash_list": config.get("exploit_ntlm_hash_list", []), - "exploit_ssh_keys": config.get("exploit_ssh_keys", []), - } diff --git a/monkey/tests/monkey_island/__init__.py b/monkey/tests/monkey_island/__init__.py index 935752c37..ee3098390 100644 --- a/monkey/tests/monkey_island/__init__.py +++ b/monkey/tests/monkey_island/__init__.py @@ -3,3 +3,8 @@ from .mock_file_repository import MockFileRepository, FILE_CONTENTS, FILE_NAME from .open_error_file_repository import OpenErrorFileRepository from .in_memory_agent_configuration_repository import InMemoryAgentConfigurationRepository from .in_memory_simulation_configuration import InMemorySimulationRepository +from .stub_propagation_credentials_repository import StubPropagationCredentialsRepository +from .stub_propagation_credentials_repository import ( + PROPAGATION_CREDENTIALS_1, + PROPAGATION_CREDENTIALS_2, +) diff --git a/monkey/tests/monkey_island/stub_propagation_credentials_repository.py b/monkey/tests/monkey_island/stub_propagation_credentials_repository.py new file mode 100644 index 000000000..7bf6f85a7 --- /dev/null +++ b/monkey/tests/monkey_island/stub_propagation_credentials_repository.py @@ -0,0 +1,63 @@ +from typing import Sequence + +from monkey_island.cc.repository import ICredentialsRepository +from monkey_island.cc.services.telemetry.processing.credentials import Credentials + +fake_username = "m0nk3y_user" +fake_special_username = "m0nk3y.user" +fake_nt_hash = "c1c58f96cdf212b50837bc11a00be47c" +fake_lm_hash = "299BD128C1101FD6" +fake_password_1 = "trytostealthis" +fake_password_2 = "password" +fake_password_3 = "12345678" +PROPAGATION_CREDENTIALS_1 = { + "identities": [{"username": fake_username, "credential_type": "USERNAME"}], + "secrets": [ + {"nt_hash": fake_nt_hash, "credential_type": "NT_HASH"}, + {"lm_hash": fake_lm_hash, "credential_type": "LM_HASH"}, + {"password": fake_password_1, "credential_type": "PASSWORD"}, + ], +} + +PROPAGATION_CREDENTIALS_2 = { + "identities": [ + {"username": fake_username, "credential_type": "USERNAME"}, + {"username": fake_special_username, "credential_type": "USERNAME"}, + ], + "secrets": [ + {"password": fake_password_1, "credential_type": "PASSWORD"}, + {"password": fake_password_2, "credential_type": "PASSWORD"}, + {"password": fake_password_3, "credential_type": "PASSWORD"}, + ], +} + + +# TODO: Use Credentials from common.credentials when serialization is implemented +class StubPropagationCredentialsRepository(ICredentialsRepository): + def get_configured_credentials(self) -> Sequence[Credentials]: + pass + + def get_stolen_credentials(self) -> Sequence[Credentials]: + pass + + def get_all_credentials(self) -> Sequence[Credentials]: + + return [ + Credentials.from_mapping(PROPAGATION_CREDENTIALS_1, monkey_guid="some_guid"), + Credentials.from_mapping(PROPAGATION_CREDENTIALS_2, monkey_guid="second_guid"), + ] + + def save_configured_credentials(self, credentials: Credentials): + pass + + def save_stolen_credentials(self, credentials: Credentials): + pass + + def remove_configured_credentials(self): + pass + + def remove_stolen_credentials(self): + pass + + def remove_all_credentials(self): + pass diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py new file mode 100644 index 000000000..08b8e942f --- /dev/null +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_propagation_credentials.py @@ -0,0 +1,39 @@ +import json + +import pytest +from tests.common import StubDIContainer +from tests.monkey_island import ( + PROPAGATION_CREDENTIALS_1, + PROPAGATION_CREDENTIALS_2, + StubPropagationCredentialsRepository, +) +from tests.unit_tests.monkey_island.conftest import get_url_for_resource + +from monkey_island.cc.repository import ICredentialsRepository +from monkey_island.cc.resources.propagation_credentials import PropagationCredentials + + +@pytest.fixture +def flask_client(build_flask_client): + container = StubDIContainer() + + container.register(ICredentialsRepository, StubPropagationCredentialsRepository) + + with build_flask_client(container) as flask_client: + yield flask_client + + +def test_propagation_credentials_endpoint_get(flask_client): + propagation_credentials_url = get_url_for_resource(PropagationCredentials) + + resp = flask_client.get(propagation_credentials_url) + + assert resp.status_code == 200 + actual_propagation_credentials = json.loads(resp.data) + assert len(actual_propagation_credentials) == 2 + + # TODO: delete the removal of monkey_guid key when the serialization of credentials + del actual_propagation_credentials[0]["monkey_guid"] + assert actual_propagation_credentials[0] == PROPAGATION_CREDENTIALS_1 + del actual_propagation_credentials[1]["monkey_guid"] + assert actual_propagation_credentials[1] == PROPAGATION_CREDENTIALS_2 diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/test_config.py b/monkey/tests/unit_tests/monkey_island/cc/services/test_config.py deleted file mode 100644 index 37249c2bc..000000000 --- a/monkey/tests/unit_tests/monkey_island/cc/services/test_config.py +++ /dev/null @@ -1,17 +0,0 @@ -from monkey_island.cc.services.config import ConfigService - -# If tests fail because config path is changed, sync with -# monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js - - -def test_get_config_propagation_credentials_from_flat_config(flat_monkey_config): - expected_creds = { - "exploit_lm_hash_list": ["lm_hash_1", "lm_hash_2"], - "exploit_ntlm_hash_list": ["nt_hash_1", "nt_hash_2", "nt_hash_3"], - "exploit_password_list": ["test", "iloveyou", "12345"], - "exploit_ssh_keys": [{"private_key": "my_private_key", "public_key": "my_public_key"}], - "exploit_user_list": ["Administrator", "root", "user", "ubuntu"], - } - - creds = ConfigService.get_config_propagation_credentials_from_flat_config(flat_monkey_config) - assert creds == expected_creds