From 57d2920c2a822a7d5adcf8467302cbe43962a343 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 4 Apr 2023 15:53:24 +0530 Subject: [PATCH 1/5] Island: Pass OTP generator to AgentOTP resource's constructor --- .../authentication_service/flask_resources/agent_otp.py | 3 +++ .../flask_resources/register_resources.py | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/authentication_service/flask_resources/agent_otp.py b/monkey/monkey_island/cc/services/authentication_service/flask_resources/agent_otp.py index eaf5956ecf8..e8fff7e8669 100644 --- a/monkey/monkey_island/cc/services/authentication_service/flask_resources/agent_otp.py +++ b/monkey/monkey_island/cc/services/authentication_service/flask_resources/agent_otp.py @@ -13,6 +13,9 @@ class AgentOTP(AbstractResource): urls = ["/api/agent-otp"] + def __init__(self, otp_generator: IOTPGenerator): + self._otp_generator = otp_generator + def get(self): """ Requests an Agent's one-time password diff --git a/monkey/monkey_island/cc/services/authentication_service/flask_resources/register_resources.py b/monkey/monkey_island/cc/services/authentication_service/flask_resources/register_resources.py index b7aeb350f35..2f0d94d3ed7 100644 --- a/monkey/monkey_island/cc/services/authentication_service/flask_resources/register_resources.py +++ b/monkey/monkey_island/cc/services/authentication_service/flask_resources/register_resources.py @@ -17,7 +17,9 @@ def register_resources(api: flask_restful.Api, authentication_facade: Authentica ) api.add_resource(Login, *Login.urls, resource_class_args=(authentication_facade,)) api.add_resource(Logout, *Logout.urls, resource_class_args=(authentication_facade,)) - api.add_resource(AgentOTP, *AgentOTP.urls) + # TODO: Get OTPGenerator after #3187 and #3190 + otp_generator = None + api.add_resource(AgentOTP, *AgentOTP.urls, resource_class_args=(otp_generator,)) api.add_resource( AgentOTPLogin, *AgentOTPLogin.urls, From f3c9b02cb0db6b3ee1f55828b304dac73b931759 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 4 Apr 2023 15:55:42 +0530 Subject: [PATCH 2/5] Island: Generate OTP and send in response in AgentOTP GET --- .../authentication_service/flask_resources/agent_otp.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/services/authentication_service/flask_resources/agent_otp.py b/monkey/monkey_island/cc/services/authentication_service/flask_resources/agent_otp.py index e8fff7e8669..fe5390641cd 100644 --- a/monkey/monkey_island/cc/services/authentication_service/flask_resources/agent_otp.py +++ b/monkey/monkey_island/cc/services/authentication_service/flask_resources/agent_otp.py @@ -2,6 +2,8 @@ from monkey_island.cc.flask_utils import AbstractResource +from ..i_otp_generator import IOTPGenerator + class AgentOTP(AbstractResource): """ @@ -23,4 +25,4 @@ def get(self): :return: One-time password in the response body """ - return make_response({"otp": "supersecretpassword"}) + return make_response({"otp": self._otp_generator.generate_otp()}) From 9a8c31070baa119236431ed48a31841cd77b0070 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 4 Apr 2023 12:49:40 -0400 Subject: [PATCH 3/5] Island: Pass IOTPGenerator to /api/agent-otp endpoint --- .../flask_resources/register_resources.py | 10 +++++++--- .../services/authentication_service/setup.py | 5 ++++- .../authentication_service/conftest.py | 20 ++++++++++++++----- .../flask_resources/test_agent_otp.py | 10 ++++++++-- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/monkey/monkey_island/cc/services/authentication_service/flask_resources/register_resources.py b/monkey/monkey_island/cc/services/authentication_service/flask_resources/register_resources.py index 2f0d94d3ed7..cd4438ea437 100644 --- a/monkey/monkey_island/cc/services/authentication_service/flask_resources/register_resources.py +++ b/monkey/monkey_island/cc/services/authentication_service/flask_resources/register_resources.py @@ -1,6 +1,7 @@ import flask_restful from ..authentication_facade import AuthenticationFacade +from ..i_otp_generator import IOTPGenerator from .agent_otp import AgentOTP from .agent_otp_login import AgentOTPLogin from .login import Login @@ -10,15 +11,18 @@ from .registration_status import RegistrationStatus -def register_resources(api: flask_restful.Api, authentication_facade: AuthenticationFacade): +def register_resources( + api: flask_restful.Api, + authentication_facade: AuthenticationFacade, + otp_generator: IOTPGenerator, +): api.add_resource(Register, *Register.urls, resource_class_args=(authentication_facade,)) api.add_resource( RegistrationStatus, *RegistrationStatus.urls, resource_class_args=(authentication_facade,) ) api.add_resource(Login, *Login.urls, resource_class_args=(authentication_facade,)) api.add_resource(Logout, *Logout.urls, resource_class_args=(authentication_facade,)) - # TODO: Get OTPGenerator after #3187 and #3190 - otp_generator = None + api.add_resource(AgentOTP, *AgentOTP.urls, resource_class_args=(otp_generator,)) api.add_resource( AgentOTPLogin, diff --git a/monkey/monkey_island/cc/services/authentication_service/setup.py b/monkey/monkey_island/cc/services/authentication_service/setup.py index 39e34bdbcc0..57cfffd895d 100644 --- a/monkey/monkey_island/cc/services/authentication_service/setup.py +++ b/monkey/monkey_island/cc/services/authentication_service/setup.py @@ -8,6 +8,7 @@ from monkey_island.cc.server_utils.encryption import ILockableEncryptor from .authentication_facade import AuthenticationFacade +from .authentication_service_otp_generator import AuthenticationServiceOTPGenerator from .configure_flask_security import configure_flask_security from .flask_resources import register_resources from .mongo_otp_repository import MongoOTPRepository @@ -17,8 +18,10 @@ def setup_authentication(api, app: Flask, container: DIContainer, data_dir: Path): security = configure_flask_security(app, data_dir) + authentication_facade = _build_authentication_facade(container, security) - register_resources(api, authentication_facade) + otp_generator = AuthenticationServiceOTPGenerator(authentication_facade) + register_resources(api, authentication_facade, otp_generator) # revoke all old tokens so that the user has to log in again on startup authentication_facade.revoke_all_tokens_for_all_users() diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/authentication_service/conftest.py b/monkey/tests/unit_tests/monkey_island/cc/services/authentication_service/conftest.py index 0917c30ef63..ffb8ba47887 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/authentication_service/conftest.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/authentication_service/conftest.py @@ -11,7 +11,7 @@ init_mock_security_app, ) -from monkey_island.cc.services.authentication_service import register_resources +from monkey_island.cc.services.authentication_service import IOTPGenerator, register_resources from monkey_island.cc.services.authentication_service.authentication_facade import ( AuthenticationFacade, ) @@ -29,16 +29,26 @@ def mock_authentication_facade(): @pytest.fixture -def build_flask_client(mock_authentication_facade): +def mock_otp_generator() -> IOTPGenerator: + mog = MagicMock(spec=IOTPGenerator) + + return mog + + +@pytest.fixture +def build_flask_client( + mock_authentication_facade: AuthenticationFacade, + mock_otp_generator: IOTPGenerator, +): def inner(): - return get_mock_auth_app(mock_authentication_facade).test_client() + return get_mock_auth_app(mock_authentication_facade, mock_otp_generator).test_client() return inner -def get_mock_auth_app(authentication_facade: AuthenticationFacade): +def get_mock_auth_app(authentication_facade: AuthenticationFacade, otp_generator: IOTPGenerator): app, api = init_mock_security_app() - register_resources(api, authentication_facade) + register_resources(api, authentication_facade, otp_generator) return app diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/authentication_service/flask_resources/test_agent_otp.py b/monkey/tests/unit_tests/monkey_island/cc/services/authentication_service/flask_resources/test_agent_otp.py index 0fc5dcd8260..c0cd6519f1a 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/authentication_service/flask_resources/test_agent_otp.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/authentication_service/flask_resources/test_agent_otp.py @@ -1,7 +1,12 @@ +from typing import Callable + import pytest +from monkey_island.cc.services.authentication_service import IOTPGenerator from monkey_island.cc.services.authentication_service.flask_resources.agent_otp import AgentOTP +OTP = "supersecretpassword" + @pytest.fixture def make_otp_request(flask_client): @@ -13,8 +18,9 @@ def _make_otp_request(): return _make_otp_request -def test_agent_otp__successful(make_otp_request): +def test_agent_otp__successful(make_otp_request: Callable, mock_otp_generator: IOTPGenerator): + mock_otp_generator.generate_otp.return_value = OTP response = make_otp_request() assert response.status_code == 200 - assert response.json["otp"] == "supersecretpassword" + assert response.json["otp"] == OTP From 63cd919069d3d74c45466551d69eede8490870ae Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 4 Apr 2023 13:02:19 -0400 Subject: [PATCH 4/5] Island: Register an IOTPGenerator in the DI container --- .../monkey_island/cc/services/authentication_service/setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/monkey/monkey_island/cc/services/authentication_service/setup.py b/monkey/monkey_island/cc/services/authentication_service/setup.py index 57cfffd895d..9555655d633 100644 --- a/monkey/monkey_island/cc/services/authentication_service/setup.py +++ b/monkey/monkey_island/cc/services/authentication_service/setup.py @@ -11,6 +11,7 @@ from .authentication_service_otp_generator import AuthenticationServiceOTPGenerator from .configure_flask_security import configure_flask_security from .flask_resources import register_resources +from .i_otp_generator import IOTPGenerator from .mongo_otp_repository import MongoOTPRepository from .token_generator import TokenGenerator from .token_parser import TokenParser @@ -21,6 +22,8 @@ def setup_authentication(api, app: Flask, container: DIContainer, data_dir: Path authentication_facade = _build_authentication_facade(container, security) otp_generator = AuthenticationServiceOTPGenerator(authentication_facade) + container.register_instance(IOTPGenerator, otp_generator) + register_resources(api, authentication_facade, otp_generator) # revoke all old tokens so that the user has to log in again on startup From d64b7cb82dd3035d0be5ae9b3d53b666d0b2e227 Mon Sep 17 00:00:00 2001 From: Kekoa Kaaikala Date: Tue, 4 Apr 2023 17:51:39 +0000 Subject: [PATCH 5/5] UT: Use HTTPStatus for status code --- .../authentication_service/flask_resources/test_agent_otp.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/authentication_service/flask_resources/test_agent_otp.py b/monkey/tests/unit_tests/monkey_island/cc/services/authentication_service/flask_resources/test_agent_otp.py index c0cd6519f1a..6ee9dfd1714 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/authentication_service/flask_resources/test_agent_otp.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/authentication_service/flask_resources/test_agent_otp.py @@ -1,3 +1,4 @@ +from http import HTTPStatus from typing import Callable import pytest @@ -22,5 +23,5 @@ def test_agent_otp__successful(make_otp_request: Callable, mock_otp_generator: I mock_otp_generator.generate_otp.return_value = OTP response = make_otp_request() - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response.json["otp"] == OTP