Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement AgentOTP GET #3191

Merged
merged 5 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from monkey_island.cc.flask_utils import AbstractResource

from ..i_otp_generator import IOTPGenerator


class AgentOTP(AbstractResource):
"""
Expand All @@ -13,11 +15,14 @@ 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

:return: One-time password in the response body
"""

return make_response({"otp": "supersecretpassword"})
return make_response({"otp": self._otp_generator.generate_otp()})
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -10,14 +11,19 @@
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,))
api.add_resource(AgentOTP, *AgentOTP.urls)

api.add_resource(AgentOTP, *AgentOTP.urls, resource_class_args=(otp_generator,))
api.add_resource(
AgentOTPLogin,
*AgentOTPLogin.urls,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@
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 .i_otp_generator import IOTPGenerator
from .mongo_otp_repository import MongoOTPRepository
from .token_generator import TokenGenerator
from .token_parser import TokenParser


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)
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
authentication_facade.revoke_all_tokens_for_all_users()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
Expand All @@ -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


Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
from http import HTTPStatus
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):
Expand All @@ -13,8 +19,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.status_code == HTTPStatus.OK
assert response.json["otp"] == OTP