Skip to content

Commit 23779fe

Browse files
committed
Merge branch '3078-move-auth-facade-construction' into develop
Issue #3078 PR #3190
2 parents 6f9a2ea + 3a13ba9 commit 23779fe

File tree

3 files changed

+72
-44
lines changed

3 files changed

+72
-44
lines changed

monkey/monkey_island/cc/app.py

+2-37
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33

44
import flask_restful
55
from flask import Flask, Response, send_from_directory
6-
from flask_security import Security
76
from werkzeug.exceptions import NotFound
87

98
from common import DIContainer
10-
from monkey_island.cc.event_queue import IIslandEventQueue
119
from monkey_island.cc.flask_utils import FlaskDIWrapper
1210
from monkey_island.cc.resources import (
1311
AgentBinaries,
@@ -36,17 +34,7 @@
3634
from monkey_island.cc.resources.security_report import SecurityReport
3735
from monkey_island.cc.resources.version import Version
3836
from monkey_island.cc.server_utils.consts import MONKEY_ISLAND_ABS_PATH
39-
from monkey_island.cc.server_utils.encryption import ILockableEncryptor
4037
from monkey_island.cc.services import register_agent_configuration_resources, setup_authentication
41-
from monkey_island.cc.services.authentication_service.authentication_facade import (
42-
AuthenticationFacade,
43-
)
44-
from monkey_island.cc.services.authentication_service.configure_flask_security import (
45-
configure_flask_security,
46-
)
47-
from monkey_island.cc.services.authentication_service.mongo_otp_repository import MongoOTPRepository
48-
from monkey_island.cc.services.authentication_service.token_generator import TokenGenerator
49-
from monkey_island.cc.services.authentication_service.token_parser import TokenParser
5038
from monkey_island.cc.services.representations import output_json
5139

5240
HOME_FILE = "index.html"
@@ -139,7 +127,7 @@ def init_app(
139127
data_dir: Path,
140128
):
141129
"""
142-
Simple docstirng for init_app
130+
Simple docstring for init_app
143131
144132
:param mongo_url: A url
145133
:param container: Dependency injection container
@@ -152,31 +140,8 @@ def init_app(
152140
init_app_config(app)
153141
init_app_url_rules(app)
154142

143+
setup_authentication(api, app, container, data_dir)
155144
flask_resource_manager = FlaskDIWrapper(api, container)
156-
datastore = configure_flask_security(app, data_dir)
157-
authentication_facade = _build_authentication_facade(container, datastore)
158-
setup_authentication(api, authentication_facade)
159145
init_api_resources(flask_resource_manager)
160146

161147
return app
162-
163-
164-
def _build_authentication_facade(container: DIContainer, security: Security):
165-
repository_encryptor = container.resolve(ILockableEncryptor)
166-
island_event_queue = container.resolve(IIslandEventQueue)
167-
168-
token_generator = TokenGenerator(security)
169-
refresh_token_expiration = (
170-
security.app.config["SECURITY_TOKEN_MAX_AGE"]
171-
+ security.app.config["SECURITY_REFRESH_TOKEN_TIMEDELTA"]
172-
)
173-
token_parser = TokenParser(security, refresh_token_expiration)
174-
175-
return AuthenticationFacade(
176-
repository_encryptor,
177-
island_event_queue,
178-
security.datastore,
179-
token_generator,
180-
token_parser,
181-
container.resolve(MongoOTPRepository),
182-
)
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,45 @@
1-
from . import register_resources
1+
from pathlib import Path
2+
3+
from flask import Flask
4+
from flask_security import Security
5+
6+
from common import DIContainer
7+
from monkey_island.cc.event_queue import IIslandEventQueue
8+
from monkey_island.cc.server_utils.encryption import ILockableEncryptor
9+
210
from .authentication_facade import AuthenticationFacade
11+
from .configure_flask_security import configure_flask_security
12+
from .flask_resources import register_resources
13+
from .mongo_otp_repository import MongoOTPRepository
14+
from .token_generator import TokenGenerator
15+
from .token_parser import TokenParser
316

417

5-
def setup_authentication(api, authentication_facade: AuthenticationFacade):
18+
def setup_authentication(api, app: Flask, container: DIContainer, data_dir: Path):
19+
security = configure_flask_security(app, data_dir)
20+
authentication_facade = _build_authentication_facade(container, security)
621
register_resources(api, authentication_facade)
22+
723
# revoke all old tokens so that the user has to log in again on startup
824
authentication_facade.revoke_all_tokens_for_all_users()
25+
26+
27+
def _build_authentication_facade(container: DIContainer, security: Security):
28+
repository_encryptor = container.resolve(ILockableEncryptor)
29+
island_event_queue = container.resolve(IIslandEventQueue)
30+
31+
token_generator = TokenGenerator(security)
32+
refresh_token_expiration = (
33+
security.app.config["SECURITY_TOKEN_MAX_AGE"]
34+
+ security.app.config["SECURITY_REFRESH_TOKEN_TIMEDELTA"]
35+
)
36+
token_parser = TokenParser(security, refresh_token_expiration)
37+
38+
return AuthenticationFacade(
39+
repository_encryptor,
40+
island_event_queue,
41+
security.datastore,
42+
token_generator,
43+
token_parser,
44+
container.resolve(MongoOTPRepository),
45+
)

monkey/tests/unit_tests/monkey_island/cc/services/authentication_service/test_authentication_service.py

+31-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import time
2+
from pathlib import Path
23
from unittest.mock import MagicMock, call
34

5+
import mongomock
6+
import pymongo
47
import pytest
58
from flask_security import UserDatastore
69
from tests.common import StubDIContainer
@@ -181,11 +184,13 @@ def test_revoke_all_tokens_for_all_users(
181184
mock_user_datastore: UserDatastore,
182185
authentication_facade: AuthenticationFacade,
183186
):
184-
[user.save() for user in USERS]
187+
for user in USERS:
188+
user.save(force_insert=True)
185189
authentication_facade.revoke_all_tokens_for_all_users()
186190

187191
assert mock_user_datastore.set_uniquifier.call_count == len(USERS)
188-
[mock_user_datastore.set_uniquifier.assert_any_call(user) for user in USERS]
192+
for user in USERS:
193+
mock_user_datastore.set_uniquifier.assert_any_call(user)
189194

190195

191196
def test_generate_otp__saves_otp(
@@ -206,14 +211,35 @@ def test_generate_otp__uses_expected_expiration_time(
206211
assert expiration_time == expected_expiration_time
207212

208213

214+
# mongomock.MongoClient is not a pymongo.MongoClient. This class allows us to register a
215+
# mongomock.MongoClient as a pymongo.MongoClient with the StubDIContainer.
216+
class MockMongoClient(mongomock.MongoClient, pymongo.MongoClient):
217+
pass
218+
219+
209220
def test_setup_authentication__revokes_tokens(
221+
monkeypatch,
222+
mock_flask_app,
223+
mock_user_datastore: UserDatastore,
210224
mock_island_event_queue: IIslandEventQueue,
211225
mock_repository_encryptor: ILockableEncryptor,
212-
mock_authentication_facade: AuthenticationFacade,
213226
):
227+
for user in USERS:
228+
user.save(force_insert=True)
229+
230+
mock_security = MagicMock()
231+
mock_security.datastore = mock_user_datastore
232+
monkeypatch.setattr(
233+
"monkey_island.cc.services.authentication_service.setup.configure_flask_security",
234+
lambda *args: mock_security,
235+
)
236+
214237
container = StubDIContainer()
215238
container.register_instance(ILockableEncryptor, mock_repository_encryptor)
216239
container.register_instance(IIslandEventQueue, mock_island_event_queue)
217-
setup_authentication(MagicMock(), mock_authentication_facade)
240+
container.register_instance(pymongo.MongoClient, MockMongoClient())
241+
setup_authentication(MagicMock(), MagicMock(), container, Path("data_dir"))
218242

219-
assert mock_authentication_facade.revoke_all_tokens_for_all_users.called
243+
assert mock_user_datastore.set_uniquifier.call_count == len(USERS)
244+
for user in USERS:
245+
mock_user_datastore.set_uniquifier.assert_any_call(user)

0 commit comments

Comments
 (0)