diff --git a/monkey/monkey_island/cc/app.py b/monkey/monkey_island/cc/app.py index 5d3d475e5..7d053fa25 100644 --- a/monkey/monkey_island/cc/app.py +++ b/monkey/monkey_island/cc/app.py @@ -31,9 +31,7 @@ from monkey_island.cc.resources.blackbox.telemetry_blackbox_endpoint import ( from monkey_island.cc.resources.credentials.configured_propagation_credentials import ( ConfiguredPropagationCredentials, ) -from monkey_island.cc.resources.credentials.stolen_propagation_credentials import ( - StolenPropagationCredentials, -) +from monkey_island.cc.resources.credentials.propagation_credentials import PropagationCredentials from monkey_island.cc.resources.edge import Edge from monkey_island.cc.resources.exploitations.manual_exploitation import ManualExploitation from monkey_island.cc.resources.exploitations.monkey_exploitation import MonkeyExploitation @@ -48,7 +46,6 @@ from monkey_island.cc.resources.node import Node from monkey_island.cc.resources.node_states import NodeStates from monkey_island.cc.resources.pba_file_download import PBAFileDownload from monkey_island.cc.resources.pba_file_upload import FileUpload -from monkey_island.cc.resources.credentials.propagation_credentials import PropagationCredentials from monkey_island.cc.resources.ransomware_report import RansomwareReport from monkey_island.cc.resources.root import Root from monkey_island.cc.resources.security_report import SecurityReport @@ -192,7 +189,6 @@ def init_restful_endpoints(api: FlaskDIWrapper): api.add_resource(PropagationCredentials) api.add_resource(ConfiguredPropagationCredentials) - api.add_resource(StolenPropagationCredentials) api.add_resource(RemoteRun) api.add_resource(VersionUpdate) diff --git a/monkey/monkey_island/cc/resources/credentials/propagation_credentials.py b/monkey/monkey_island/cc/resources/credentials/propagation_credentials.py index 8d72fe427..0c8b65988 100644 --- a/monkey/monkey_island/cc/resources/credentials/propagation_credentials.py +++ b/monkey/monkey_island/cc/resources/credentials/propagation_credentials.py @@ -1,4 +1,6 @@ -from flask import make_response +from http import HTTPStatus + +from flask import make_response, request from common.credentials import Credentials from monkey_island.cc.repository import ICredentialsRepository @@ -6,12 +8,35 @@ from monkey_island.cc.resources.AbstractResource import AbstractResource class PropagationCredentials(AbstractResource): - urls = ["/api/propagation-credentials"] + urls = ["/api/propagation-credentials", "/api/propagation-credentials/stolen-credentials"] def __init__(self, credentials_repository: ICredentialsRepository): self._credentials_repository = credentials_repository def get(self): - propagation_credentials = self._credentials_repository.get_all_credentials() + propagation_credentials = [] - return make_response(Credentials.to_json_array(propagation_credentials), 200) + if request.url.endswith("/stolen-credentials"): + propagation_credentials = self._credentials_repository.get_stolen_credentials() + else: + propagation_credentials = self._credentials_repository.get_all_credentials() + + return make_response(Credentials.to_json_array(propagation_credentials), HTTPStatus.OK) + + def post(self): + credentials = [Credentials.from_json(c) for c in request.json] + + if request.url.endswith("/stolen-credentials"): + self._credentials_repository.save_stolen_credentials(credentials) + else: + return {}, HTTPStatus.METHOD_NOT_ALLOWED + + return {}, HTTPStatus.NO_CONTENT + + def delete(self): + if request.url.endswith("/stolen-credentials"): + self._credentials_repository.remove_stolen_credentials() + else: + return {}, HTTPStatus.METHOD_NOT_ALLOWED + + return {}, HTTPStatus.NO_CONTENT diff --git a/monkey/monkey_island/cc/resources/credentials/stolen_propagation_credentials.py b/monkey/monkey_island/cc/resources/credentials/stolen_propagation_credentials.py deleted file mode 100644 index e733b2297..000000000 --- a/monkey/monkey_island/cc/resources/credentials/stolen_propagation_credentials.py +++ /dev/null @@ -1,28 +0,0 @@ -import logging - -from flask import jsonify, request - -from common.credentials import Credentials -from monkey_island.cc.repository import ICredentialsRepository -from monkey_island.cc.resources.AbstractResource import AbstractResource - -logger = logging.getLogger(__name__) - - -class StolenPropagationCredentials(AbstractResource): - urls = ["/api/propagation-credentials/stolen"] - - def __init__(self, credentials_repository: ICredentialsRepository): - self._credentials_repository = credentials_repository - - def get(self): - return jsonify(self._credentials_repository.get_stolen_credentials()) - - def post(self): - credentials = Credentials.from_mapping(request.json) - self._credentials_repository.save_stolen_credentials(credentials) - return {}, 204 - - def delete(self): - self._credentials_repository.remove_stolen_credentials() - return {}, 204 diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/credentials/test_propagation_credentials.py b/monkey/tests/unit_tests/monkey_island/cc/resources/credentials/test_propagation_credentials.py index 01748c215..a6750b80d 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/credentials/test_propagation_credentials.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/credentials/test_propagation_credentials.py @@ -1,34 +1,110 @@ +import json +from http import HTTPStatus + import pytest from tests.common import StubDIContainer -from tests.monkey_island import ( +from tests.data_for_tests.propagation_credentials import ( PROPAGATION_CREDENTIALS_1, PROPAGATION_CREDENTIALS_2, - StubPropagationCredentialsRepository, + PROPAGATION_CREDENTIALS_3, + PROPAGATION_CREDENTIALS_4, ) -from tests.unit_tests.monkey_island.conftest import get_url_for_resource +from tests.monkey_island import InMemoryCredentialsRepository from common.credentials import Credentials from monkey_island.cc.repository import ICredentialsRepository from monkey_island.cc.resources.credentials.propagation_credentials import PropagationCredentials +ALL_CREDENTIALS_URL = PropagationCredentials.urls[0] +STOLEN_CREDENTIALS_URL = PropagationCredentials.urls[1] + @pytest.fixture -def flask_client(build_flask_client): +def credentials_repository(): + return InMemoryCredentialsRepository() + + +@pytest.fixture +def flask_client(build_flask_client, credentials_repository): container = StubDIContainer() - container.register(ICredentialsRepository, StubPropagationCredentialsRepository) + container.register_instance(ICredentialsRepository, credentials_repository) 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) +def test_propagation_credentials_endpoint_get(flask_client, credentials_repository): + credentials_repository.save_configured_credentials( + [PROPAGATION_CREDENTIALS_1, PROPAGATION_CREDENTIALS_3] + ) + credentials_repository.save_stolen_credentials( + [PROPAGATION_CREDENTIALS_2, PROPAGATION_CREDENTIALS_4] + ) - resp = flask_client.get(propagation_credentials_url) + resp = flask_client.get(ALL_CREDENTIALS_URL) actual_propagation_credentials = Credentials.from_json_array(resp.text) - assert resp.status_code == 200 + assert resp.status_code == HTTPStatus.OK + assert len(actual_propagation_credentials) == 4 + assert PROPAGATION_CREDENTIALS_1 in actual_propagation_credentials + assert PROPAGATION_CREDENTIALS_2 in actual_propagation_credentials + assert PROPAGATION_CREDENTIALS_3 in actual_propagation_credentials + assert PROPAGATION_CREDENTIALS_4 in actual_propagation_credentials + + +def test_propagation_credentials_endpoint__get_stolen(flask_client, credentials_repository): + credentials_repository.save_stolen_credentials( + [PROPAGATION_CREDENTIALS_1, PROPAGATION_CREDENTIALS_2] + ) + + resp = flask_client.get(STOLEN_CREDENTIALS_URL) + actual_propagation_credentials = Credentials.from_json_array(resp.text) + + assert resp.status_code == HTTPStatus.OK assert len(actual_propagation_credentials) == 2 assert actual_propagation_credentials[0] == PROPAGATION_CREDENTIALS_1 assert actual_propagation_credentials[1] == PROPAGATION_CREDENTIALS_2 + + +def test_propagation_credentials_endpoint__post_stolen(flask_client, credentials_repository): + credentials_repository.save_stolen_credentials([PROPAGATION_CREDENTIALS_1]) + + resp = flask_client.post( + STOLEN_CREDENTIALS_URL, + json=[ + Credentials.to_json(PROPAGATION_CREDENTIALS_2), + Credentials.to_json(PROPAGATION_CREDENTIALS_3), + ], + ) + assert resp.status_code == HTTPStatus.NO_CONTENT + + resp = flask_client.get(STOLEN_CREDENTIALS_URL) + retrieved_propagation_credentials = Credentials.from_json_array(resp.text) + + assert resp.status_code == HTTPStatus.OK + assert len(retrieved_propagation_credentials) == 3 + assert PROPAGATION_CREDENTIALS_1 in retrieved_propagation_credentials + assert PROPAGATION_CREDENTIALS_2 in retrieved_propagation_credentials + assert PROPAGATION_CREDENTIALS_3 in retrieved_propagation_credentials + + +def test_stolen_propagation_credentials_endpoint_delete(flask_client, credentials_repository): + credentials_repository.save_stolen_credentials( + [PROPAGATION_CREDENTIALS_1, PROPAGATION_CREDENTIALS_2] + ) + resp = flask_client.delete(STOLEN_CREDENTIALS_URL) + assert resp.status_code == HTTPStatus.NO_CONTENT + + resp = flask_client.get(STOLEN_CREDENTIALS_URL) + assert len(json.loads(resp.text)) == 0 + + +def test_propagation_credentials_endpoint__propagation_credentials_post_not_allowed(flask_client): + resp = flask_client.post(ALL_CREDENTIALS_URL, json=[]) + assert resp.status_code == HTTPStatus.METHOD_NOT_ALLOWED + + +def test_propagation_credentials_endpoint__propagation_credentials_delete_not_allowed(flask_client): + resp = flask_client.delete(ALL_CREDENTIALS_URL) + assert resp.status_code == HTTPStatus.METHOD_NOT_ALLOWED diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/credentials/test_stolen_propagation_credentials.py b/monkey/tests/unit_tests/monkey_island/cc/resources/credentials/test_stolen_propagation_credentials.py deleted file mode 100644 index 138849085..000000000 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/credentials/test_stolen_propagation_credentials.py +++ /dev/null @@ -1,43 +0,0 @@ -import json - -from tests.data_for_tests.propagation_credentials import ( - PROPAGATION_CREDENTIALS_1, - PROPAGATION_CREDENTIALS_2, -) -from tests.unit_tests.monkey_island.conftest import get_url_for_resource - -from monkey_island.cc.resources.credentials.stolen_propagation_credentials import ( - StolenPropagationCredentials, -) - - -def test_stolen_propagation_credentials_endpoint_get(flask_client): - stolen_propagation_credentials_url = get_url_for_resource(StolenPropagationCredentials) - - resp = flask_client.get(stolen_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 - - -def test_stolen_propagation_credentials_endpoint_post(flask_client): - stolen_propagation_credentials_url = get_url_for_resource(StolenPropagationCredentials) - - resp = flask_client.post(stolen_propagation_credentials_url, json=PROPAGATION_CREDENTIALS_1) - - assert resp.status_code == 204 - - -def test_stolen_propagation_credentials_endpoint_delete(flask_client): - stolen_propagation_credentials_url = get_url_for_resource(StolenPropagationCredentials) - - resp = flask_client.delete(stolen_propagation_credentials_url) - - assert resp.status_code == 204