forked from p15670423/monkey
Merge pull request #2331 from guardicore/2256-publish-agent-registration-data
2256 publish agent registration data
This commit is contained in:
commit
823829c001
|
@ -5,7 +5,7 @@ from . import IslandEventSubscriber
|
||||||
|
|
||||||
|
|
||||||
class IslandEventTopic(Enum):
|
class IslandEventTopic(Enum):
|
||||||
AGENT_CONNECTED = auto()
|
AGENT_REGISTERED = auto()
|
||||||
CLEAR_SIMULATION_DATA = auto()
|
CLEAR_SIMULATION_DATA = auto()
|
||||||
RESET_AGENT_CONFIGURATION = auto()
|
RESET_AGENT_CONFIGURATION = auto()
|
||||||
SET_ISLAND_MODE = auto()
|
SET_ISLAND_MODE = auto()
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from .handle_agent_registration import handle_agent_registration
|
||||||
from .reset_agent_configuration import reset_agent_configuration
|
from .reset_agent_configuration import reset_agent_configuration
|
||||||
from .reset_machine_repository import reset_machine_repository
|
from .reset_machine_repository import reset_machine_repository
|
||||||
from .set_agent_configuration_per_island_mode import set_agent_configuration_per_island_mode
|
from .set_agent_configuration_per_island_mode import set_agent_configuration_per_island_mode
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
from contextlib import suppress
|
||||||
|
from ipaddress import IPv4Address, IPv4Interface
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from common import AgentRegistrationData
|
||||||
|
from common.network.network_utils import address_to_ip_port
|
||||||
|
from monkey_island.cc.models import Agent, CommunicationType, Machine
|
||||||
|
from monkey_island.cc.repository import (
|
||||||
|
IAgentRepository,
|
||||||
|
IMachineRepository,
|
||||||
|
INodeRepository,
|
||||||
|
UnknownRecordError,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class handle_agent_registration:
|
||||||
|
"""
|
||||||
|
Update repositories when a new agent registers
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
machine_repository: IMachineRepository,
|
||||||
|
agent_repository: IAgentRepository,
|
||||||
|
node_repository: INodeRepository,
|
||||||
|
):
|
||||||
|
self._machine_repository = machine_repository
|
||||||
|
self._agent_repository = agent_repository
|
||||||
|
self._node_repository = node_repository
|
||||||
|
|
||||||
|
def __call__(self, agent_registration_data: AgentRegistrationData):
|
||||||
|
machine = self._update_machine_repository(agent_registration_data)
|
||||||
|
self._add_agent(agent_registration_data, machine)
|
||||||
|
self._add_node_communication(agent_registration_data, machine)
|
||||||
|
|
||||||
|
def _update_machine_repository(self, agent_registration_data: AgentRegistrationData) -> Machine:
|
||||||
|
machine = self._find_existing_machine_to_update(agent_registration_data)
|
||||||
|
|
||||||
|
if machine is None:
|
||||||
|
machine = Machine(id=self._machine_repository.get_new_id())
|
||||||
|
|
||||||
|
self._upsert_machine(machine, agent_registration_data)
|
||||||
|
|
||||||
|
return machine
|
||||||
|
|
||||||
|
def _find_existing_machine_to_update(
|
||||||
|
self, agent_registration_data: AgentRegistrationData
|
||||||
|
) -> Optional[Machine]:
|
||||||
|
with suppress(UnknownRecordError):
|
||||||
|
return self._machine_repository.get_machine_by_hardware_id(
|
||||||
|
agent_registration_data.machine_hardware_id
|
||||||
|
)
|
||||||
|
|
||||||
|
for network_interface in agent_registration_data.network_interfaces:
|
||||||
|
with suppress(UnknownRecordError):
|
||||||
|
# NOTE: For now, assume IPs are unique. In reality, two machines could share the
|
||||||
|
# same IP if there's a router between them.
|
||||||
|
return self._machine_repository.get_machines_by_ip(network_interface.ip)[0]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _upsert_machine(self, machine: Machine, agent_registration_data: AgentRegistrationData):
|
||||||
|
self._update_hardware_id(machine, agent_registration_data)
|
||||||
|
self._update_network_interfaces(machine, agent_registration_data)
|
||||||
|
|
||||||
|
self._machine_repository.upsert_machine(machine)
|
||||||
|
|
||||||
|
def _update_hardware_id(self, machine: Machine, agent_registration_data: AgentRegistrationData):
|
||||||
|
if (
|
||||||
|
machine.hardware_id is not None
|
||||||
|
and machine.hardware_id != agent_registration_data.machine_hardware_id
|
||||||
|
):
|
||||||
|
raise Exception(
|
||||||
|
f"Hardware ID mismatch:\n\tMachine: {machine}\n\t"
|
||||||
|
f"AgentRegistrationData: {agent_registration_data}"
|
||||||
|
)
|
||||||
|
|
||||||
|
machine.hardware_id = agent_registration_data.machine_hardware_id
|
||||||
|
|
||||||
|
def _update_network_interfaces(
|
||||||
|
self, machine: Machine, agent_registration_data: AgentRegistrationData
|
||||||
|
):
|
||||||
|
updated_network_interfaces: List[IPv4Interface] = []
|
||||||
|
agent_registration_data_ips = set(
|
||||||
|
map(lambda iface: iface.ip, agent_registration_data.network_interfaces)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Prefer interfaces provided by the AgentRegistrationData to those in the Machine record.
|
||||||
|
# The AgentRegistrationData was collected while running on the machine, whereas the Machine
|
||||||
|
# data may have only been collected from a scan. For example, the Machine and
|
||||||
|
# AgentRedistrationData may have the same IP with a different subnet mask.
|
||||||
|
for interface in machine.network_interfaces:
|
||||||
|
if interface.ip not in agent_registration_data_ips:
|
||||||
|
updated_network_interfaces.append(interface)
|
||||||
|
|
||||||
|
updated_network_interfaces.extend(agent_registration_data.network_interfaces)
|
||||||
|
|
||||||
|
machine.network_interfaces = sorted(updated_network_interfaces)
|
||||||
|
|
||||||
|
def _add_agent(self, agent_registration_data: AgentRegistrationData, machine: Machine):
|
||||||
|
new_agent = Agent(
|
||||||
|
id=agent_registration_data.id,
|
||||||
|
machine_id=machine.id,
|
||||||
|
start_time=agent_registration_data.start_time,
|
||||||
|
parent_id=agent_registration_data.parent_id,
|
||||||
|
cc_server=agent_registration_data.cc_server,
|
||||||
|
)
|
||||||
|
self._agent_repository.upsert_agent(new_agent)
|
||||||
|
|
||||||
|
def _add_node_communication(
|
||||||
|
self, agent_registration_data: AgentRegistrationData, src_machine: Machine
|
||||||
|
):
|
||||||
|
dst_machine = self._get_or_create_cc_machine(agent_registration_data.cc_server)
|
||||||
|
|
||||||
|
self._node_repository.upsert_communication(
|
||||||
|
src_machine.id, dst_machine.id, CommunicationType.CC
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_or_create_cc_machine(self, cc_server: str) -> Machine:
|
||||||
|
dst_ip = IPv4Address(address_to_ip_port(cc_server)[0])
|
||||||
|
|
||||||
|
try:
|
||||||
|
return self._machine_repository.get_machines_by_ip(dst_ip)[0]
|
||||||
|
except UnknownRecordError:
|
||||||
|
new_machine = Machine(
|
||||||
|
id=self._machine_repository.get_new_id(), network_interfaces=[IPv4Interface(dst_ip)]
|
||||||
|
)
|
||||||
|
self._machine_repository.upsert_machine(new_machine)
|
||||||
|
|
||||||
|
return new_machine
|
|
@ -5,6 +5,7 @@ from http import HTTPStatus
|
||||||
from flask import make_response, request
|
from flask import make_response, request
|
||||||
|
|
||||||
from common import AgentRegistrationData
|
from common import AgentRegistrationData
|
||||||
|
from monkey_island.cc.event_queue import IIslandEventQueue, IslandEventTopic
|
||||||
from monkey_island.cc.resources.AbstractResource import AbstractResource
|
from monkey_island.cc.resources.AbstractResource import AbstractResource
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -13,12 +14,18 @@ logger = logging.getLogger(__name__)
|
||||||
class Agents(AbstractResource):
|
class Agents(AbstractResource):
|
||||||
urls = ["/api/agents"]
|
urls = ["/api/agents"]
|
||||||
|
|
||||||
|
def __init__(self, island_event_queue: IIslandEventQueue):
|
||||||
|
self._island_event_queue = island_event_queue
|
||||||
|
|
||||||
def post(self):
|
def post(self):
|
||||||
try:
|
try:
|
||||||
# Just parse for now
|
# Just parse for now
|
||||||
agent_registration_data = AgentRegistrationData(**request.json)
|
agent_registration_data = AgentRegistrationData(**request.json)
|
||||||
|
|
||||||
logger.debug(f"Agent registered: {agent_registration_data}")
|
logger.debug(f"Agent registered: {agent_registration_data}")
|
||||||
|
self._island_event_queue.publish(
|
||||||
|
IslandEventTopic.AGENT_REGISTERED, agent_registration_data=agent_registration_data
|
||||||
|
)
|
||||||
|
|
||||||
return make_response({}, HTTPStatus.NO_CONTENT)
|
return make_response({}, HTTPStatus.NO_CONTENT)
|
||||||
except (TypeError, ValueError, json.JSONDecodeError) as err:
|
except (TypeError, ValueError, json.JSONDecodeError) as err:
|
||||||
|
|
|
@ -3,6 +3,7 @@ from functools import partial
|
||||||
from common import DIContainer
|
from common import DIContainer
|
||||||
from monkey_island.cc.event_queue import IIslandEventQueue, IslandEventTopic
|
from monkey_island.cc.event_queue import IIslandEventQueue, IslandEventTopic
|
||||||
from monkey_island.cc.island_event_handlers import (
|
from monkey_island.cc.island_event_handlers import (
|
||||||
|
handle_agent_registration,
|
||||||
reset_agent_configuration,
|
reset_agent_configuration,
|
||||||
reset_machine_repository,
|
reset_machine_repository,
|
||||||
set_agent_configuration_per_island_mode,
|
set_agent_configuration_per_island_mode,
|
||||||
|
@ -20,11 +21,20 @@ from monkey_island.cc.services.database import Database
|
||||||
def setup_island_event_handlers(container: DIContainer):
|
def setup_island_event_handlers(container: DIContainer):
|
||||||
island_event_queue = container.resolve(IIslandEventQueue)
|
island_event_queue = container.resolve(IIslandEventQueue)
|
||||||
|
|
||||||
|
_subscribe_agent_registration_events(island_event_queue, container)
|
||||||
_subscribe_reset_agent_configuration_events(island_event_queue, container)
|
_subscribe_reset_agent_configuration_events(island_event_queue, container)
|
||||||
_subscribe_clear_simulation_data_events(island_event_queue, container)
|
_subscribe_clear_simulation_data_events(island_event_queue, container)
|
||||||
_subscribe_set_island_mode_events(island_event_queue, container)
|
_subscribe_set_island_mode_events(island_event_queue, container)
|
||||||
|
|
||||||
|
|
||||||
|
def _subscribe_agent_registration_events(
|
||||||
|
island_event_queue: IIslandEventQueue, container: DIContainer
|
||||||
|
):
|
||||||
|
topic = IslandEventTopic.AGENT_REGISTERED
|
||||||
|
|
||||||
|
island_event_queue.subscribe(topic, container.resolve(handle_agent_registration))
|
||||||
|
|
||||||
|
|
||||||
def _subscribe_reset_agent_configuration_events(
|
def _subscribe_reset_agent_configuration_events(
|
||||||
island_event_queue: IIslandEventQueue, container: DIContainer
|
island_event_queue: IIslandEventQueue, container: DIContainer
|
||||||
):
|
):
|
||||||
|
|
|
@ -40,7 +40,7 @@ def test_subscribe_publish__no_event_body(
|
||||||
topic=IslandEventTopic.CLEAR_SIMULATION_DATA, subscriber=event_queue_subscriber
|
topic=IslandEventTopic.CLEAR_SIMULATION_DATA, subscriber=event_queue_subscriber
|
||||||
)
|
)
|
||||||
|
|
||||||
event_queue.publish(topic=IslandEventTopic.AGENT_CONNECTED)
|
event_queue.publish(topic=IslandEventTopic.AGENT_REGISTERED)
|
||||||
event_queue.publish(topic=IslandEventTopic.CLEAR_SIMULATION_DATA)
|
event_queue.publish(topic=IslandEventTopic.CLEAR_SIMULATION_DATA)
|
||||||
event_queue.publish(topic=IslandEventTopic.RESET_AGENT_CONFIGURATION)
|
event_queue.publish(topic=IslandEventTopic.RESET_AGENT_CONFIGURATION)
|
||||||
|
|
||||||
|
@ -64,9 +64,9 @@ def test_subscribe_publish__with_event_body(
|
||||||
|
|
||||||
event = "my event!"
|
event = "my event!"
|
||||||
my_callable = MyCallable()
|
my_callable = MyCallable()
|
||||||
event_queue.subscribe(topic=IslandEventTopic.AGENT_CONNECTED, subscriber=my_callable)
|
event_queue.subscribe(topic=IslandEventTopic.AGENT_REGISTERED, subscriber=my_callable)
|
||||||
|
|
||||||
event_queue.publish(topic=IslandEventTopic.AGENT_CONNECTED, event=event)
|
event_queue.publish(topic=IslandEventTopic.AGENT_REGISTERED, event=event)
|
||||||
event_queue.publish(topic=IslandEventTopic.CLEAR_SIMULATION_DATA)
|
event_queue.publish(topic=IslandEventTopic.CLEAR_SIMULATION_DATA)
|
||||||
event_queue.publish(topic=IslandEventTopic.RESET_AGENT_CONFIGURATION)
|
event_queue.publish(topic=IslandEventTopic.RESET_AGENT_CONFIGURATION)
|
||||||
|
|
||||||
|
@ -84,10 +84,10 @@ def test_keep_subscriber_in_scope(event_queue: IIslandEventQueue):
|
||||||
def subscribe():
|
def subscribe():
|
||||||
# fn will go out of scope after subscribe() returns.
|
# fn will go out of scope after subscribe() returns.
|
||||||
fn = MyCallable()
|
fn = MyCallable()
|
||||||
event_queue.subscribe(topic=IslandEventTopic.AGENT_CONNECTED, subscriber=fn)
|
event_queue.subscribe(topic=IslandEventTopic.AGENT_REGISTERED, subscriber=fn)
|
||||||
|
|
||||||
subscribe()
|
subscribe()
|
||||||
|
|
||||||
event_queue.publish(topic=IslandEventTopic.AGENT_CONNECTED)
|
event_queue.publish(topic=IslandEventTopic.AGENT_REGISTERED)
|
||||||
|
|
||||||
assert MyCallable.called
|
assert MyCallable.called
|
||||||
|
|
|
@ -0,0 +1,233 @@
|
||||||
|
from ipaddress import IPv4Address, IPv4Interface
|
||||||
|
from itertools import count
|
||||||
|
from typing import Sequence
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from common import AgentRegistrationData
|
||||||
|
from monkey_island.cc.island_event_handlers import handle_agent_registration
|
||||||
|
from monkey_island.cc.models import Agent, CommunicationType, Machine
|
||||||
|
from monkey_island.cc.repository import (
|
||||||
|
IAgentRepository,
|
||||||
|
IMachineRepository,
|
||||||
|
INodeRepository,
|
||||||
|
UnknownRecordError,
|
||||||
|
)
|
||||||
|
|
||||||
|
AGENT_ID = UUID("860aff5b-d2af-43ea-afb5-62bac3d30b7e")
|
||||||
|
|
||||||
|
SEED_ID = 10
|
||||||
|
|
||||||
|
MACHINE = Machine(
|
||||||
|
id=2,
|
||||||
|
hardware_id=5,
|
||||||
|
network_interfaces=[IPv4Interface("192.168.2.2/24")],
|
||||||
|
)
|
||||||
|
|
||||||
|
AGENT_REGISTRATION_DATA = AgentRegistrationData(
|
||||||
|
id=AGENT_ID,
|
||||||
|
machine_hardware_id=MACHINE.hardware_id,
|
||||||
|
start_time=0,
|
||||||
|
parent_id=None,
|
||||||
|
cc_server="192.168.1.1:5000",
|
||||||
|
network_interfaces=[IPv4Interface("192.168.1.2/24")],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def machine_repository() -> IMachineRepository:
|
||||||
|
machine_repository = MagicMock(spec=IMachineRepository)
|
||||||
|
machine_repository.get_new_id = MagicMock(side_effect=count(SEED_ID))
|
||||||
|
machine_repository.upsert_machine = MagicMock()
|
||||||
|
machine_repository.get_machine_by_hardware_id = MagicMock(side_effect=UnknownRecordError)
|
||||||
|
machine_repository.get_machines_by_ip = MagicMock(side_effect=UnknownRecordError)
|
||||||
|
return machine_repository
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def agent_repository() -> IAgentRepository:
|
||||||
|
agent_repository = MagicMock(spec=IAgentRepository)
|
||||||
|
agent_repository.upsert_agent = MagicMock()
|
||||||
|
return agent_repository
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def node_repository() -> INodeRepository:
|
||||||
|
node_repository = MagicMock(spec=INodeRepository)
|
||||||
|
node_repository.upsert_communication = MagicMock()
|
||||||
|
return node_repository
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def handler(machine_repository, agent_repository, node_repository) -> handle_agent_registration:
|
||||||
|
return handle_agent_registration(machine_repository, agent_repository, node_repository)
|
||||||
|
|
||||||
|
|
||||||
|
def build_get_machines_by_ip(ip_to_match: IPv4Address, machine_to_return: Machine):
|
||||||
|
def get_machines_by_ip(ip: IPv4Address) -> Sequence[Machine]:
|
||||||
|
if ip == ip_to_match:
|
||||||
|
return [machine_to_return]
|
||||||
|
|
||||||
|
raise UnknownRecordError
|
||||||
|
|
||||||
|
return get_machines_by_ip
|
||||||
|
|
||||||
|
|
||||||
|
def test_new_machine_added(handler, machine_repository):
|
||||||
|
expected_machine = Machine(
|
||||||
|
id=SEED_ID,
|
||||||
|
hardware_id=AGENT_REGISTRATION_DATA.machine_hardware_id,
|
||||||
|
network_interfaces=AGENT_REGISTRATION_DATA.network_interfaces,
|
||||||
|
)
|
||||||
|
machine_repository.get_machine_by_hardware_id = MagicMock(side_effect=UnknownRecordError)
|
||||||
|
machine_repository.get_machines_by_ip = MagicMock(side_effect=UnknownRecordError)
|
||||||
|
|
||||||
|
handler(AGENT_REGISTRATION_DATA)
|
||||||
|
|
||||||
|
machine_repository.upsert_machine.assert_any_call(expected_machine)
|
||||||
|
|
||||||
|
|
||||||
|
def test_existing_machine_updated__hardware_id(handler, machine_repository):
|
||||||
|
expected_updated_machine = Machine(
|
||||||
|
id=MACHINE.id,
|
||||||
|
hardware_id=MACHINE.hardware_id,
|
||||||
|
network_interfaces=[
|
||||||
|
AGENT_REGISTRATION_DATA.network_interfaces[0],
|
||||||
|
MACHINE.network_interfaces[0],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
machine_repository.get_machine_by_hardware_id = MagicMock(return_value=MACHINE)
|
||||||
|
|
||||||
|
handler(AGENT_REGISTRATION_DATA)
|
||||||
|
|
||||||
|
machine_repository.upsert_machine.assert_any_call(expected_updated_machine)
|
||||||
|
|
||||||
|
|
||||||
|
def test_existing_machine_updated__find_by_ip(handler, machine_repository):
|
||||||
|
agent_registration_data = AgentRegistrationData(
|
||||||
|
id=AGENT_ID,
|
||||||
|
machine_hardware_id=5,
|
||||||
|
start_time=0,
|
||||||
|
parent_id=None,
|
||||||
|
cc_server="192.168.1.1:5000",
|
||||||
|
network_interfaces=[
|
||||||
|
IPv4Interface("192.168.1.2/24"),
|
||||||
|
IPv4Interface("192.168.1.4/24"),
|
||||||
|
IPv4Interface("192.168.1.5/24"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
existing_machine = Machine(
|
||||||
|
id=1,
|
||||||
|
network_interfaces=[agent_registration_data.network_interfaces[-1]],
|
||||||
|
)
|
||||||
|
|
||||||
|
get_machines_by_ip = build_get_machines_by_ip(
|
||||||
|
existing_machine.network_interfaces[0].ip, existing_machine
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_updated_machine = existing_machine.copy()
|
||||||
|
expected_updated_machine.hardware_id = agent_registration_data.machine_hardware_id
|
||||||
|
expected_updated_machine.network_interfaces = agent_registration_data.network_interfaces
|
||||||
|
|
||||||
|
machine_repository.get_machine_by_hardware_id = MagicMock(side_effect=UnknownRecordError)
|
||||||
|
machine_repository.get_machines_by_ip = MagicMock(side_effect=get_machines_by_ip)
|
||||||
|
|
||||||
|
handler(agent_registration_data)
|
||||||
|
|
||||||
|
machine_repository.upsert_machine.assert_any_call(expected_updated_machine)
|
||||||
|
|
||||||
|
|
||||||
|
def test_hardware_id_mismatch(handler, machine_repository):
|
||||||
|
existing_machine = Machine(
|
||||||
|
id=1,
|
||||||
|
hardware_id=AGENT_REGISTRATION_DATA.machine_hardware_id + 99,
|
||||||
|
network_interfaces=AGENT_REGISTRATION_DATA.network_interfaces,
|
||||||
|
)
|
||||||
|
|
||||||
|
machine_repository.get_machine_by_hardware_id = MagicMock(side_effect=UnknownRecordError)
|
||||||
|
machine_repository.get_machines_by_ip = MagicMock(return_value=[existing_machine])
|
||||||
|
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
handler(AGENT_REGISTRATION_DATA)
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_agent(handler, agent_repository):
|
||||||
|
expected_agent = Agent(
|
||||||
|
id=AGENT_REGISTRATION_DATA.id,
|
||||||
|
machine_id=SEED_ID,
|
||||||
|
start_time=AGENT_REGISTRATION_DATA.start_time,
|
||||||
|
parent_id=AGENT_REGISTRATION_DATA.parent_id,
|
||||||
|
cc_server=AGENT_REGISTRATION_DATA.cc_server,
|
||||||
|
)
|
||||||
|
handler(AGENT_REGISTRATION_DATA)
|
||||||
|
|
||||||
|
agent_repository.upsert_agent.assert_called_with(expected_agent)
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_node_connection(handler, machine_repository, node_repository):
|
||||||
|
island_machine = Machine(
|
||||||
|
id=1,
|
||||||
|
hardware_id=99,
|
||||||
|
island=True,
|
||||||
|
network_interfaces=[IPv4Interface("192.168.1.1/24")],
|
||||||
|
)
|
||||||
|
get_machines_by_ip = build_get_machines_by_ip(
|
||||||
|
island_machine.network_interfaces[0].ip, island_machine
|
||||||
|
)
|
||||||
|
machine_repository.get_machines_by_ip = MagicMock(side_effect=get_machines_by_ip)
|
||||||
|
machine_repository.get_machine_by_hardware_id = MagicMock(return_value=MACHINE)
|
||||||
|
|
||||||
|
handler(AGENT_REGISTRATION_DATA)
|
||||||
|
|
||||||
|
node_repository.upsert_communication.assert_called_once()
|
||||||
|
node_repository.upsert_communication.assert_called_with(
|
||||||
|
MACHINE.id, island_machine.id, CommunicationType.CC
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_node_connection__unknown_server(handler, machine_repository, node_repository):
|
||||||
|
expected_new_server_machine = Machine(
|
||||||
|
id=SEED_ID,
|
||||||
|
network_interfaces=[IPv4Interface("192.168.1.1/32")],
|
||||||
|
)
|
||||||
|
|
||||||
|
machine_repository.get_machine_by_hardware_id = MagicMock(return_value=MACHINE)
|
||||||
|
handler(AGENT_REGISTRATION_DATA)
|
||||||
|
|
||||||
|
machine_repository.upsert_machine.assert_called_with(expected_new_server_machine)
|
||||||
|
node_repository.upsert_communication.assert_called_with(
|
||||||
|
MACHINE.id, SEED_ID, CommunicationType.CC
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_machine_interfaces_updated(handler, machine_repository):
|
||||||
|
existing_machine = Machine(
|
||||||
|
id=SEED_ID,
|
||||||
|
hardware_id=AGENT_REGISTRATION_DATA.machine_hardware_id,
|
||||||
|
network_interfaces=[IPv4Interface("192.168.1.2/32"), IPv4Interface("192.168.1.5/32")],
|
||||||
|
)
|
||||||
|
machine_repository.get_machine_by_hardware_id = MagicMock(return_value=existing_machine)
|
||||||
|
agent_registration_data = AgentRegistrationData(
|
||||||
|
id=AGENT_ID,
|
||||||
|
machine_hardware_id=MACHINE.hardware_id,
|
||||||
|
start_time=0,
|
||||||
|
parent_id=None,
|
||||||
|
cc_server="192.168.1.1:5000",
|
||||||
|
network_interfaces=[
|
||||||
|
IPv4Interface("192.168.1.2/24"),
|
||||||
|
IPv4Interface("192.168.1.3/16"),
|
||||||
|
IPv4Interface("192.168.1.4/24"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
expected_network_interfaces = sorted(
|
||||||
|
(*agent_registration_data.network_interfaces, existing_machine.network_interfaces[-1])
|
||||||
|
)
|
||||||
|
|
||||||
|
handler(agent_registration_data)
|
||||||
|
updated_machine = machine_repository.upsert_machine.call_args_list[0][0][0]
|
||||||
|
actual_network_interfaces = sorted(updated_machine.network_interfaces)
|
||||||
|
|
||||||
|
assert actual_network_interfaces == expected_network_interfaces
|
|
@ -1,8 +1,12 @@
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
from unittest.mock import MagicMock
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from tests.common import StubDIContainer
|
||||||
from tests.unit_tests.monkey_island.conftest import get_url_for_resource
|
from tests.unit_tests.monkey_island.conftest import get_url_for_resource
|
||||||
|
|
||||||
|
from monkey_island.cc.event_queue import IIslandEventQueue
|
||||||
from monkey_island.cc.resources import Agents
|
from monkey_island.cc.resources import Agents
|
||||||
|
|
||||||
AGENTS_URL = get_url_for_resource(Agents)
|
AGENTS_URL = get_url_for_resource(Agents)
|
||||||
|
@ -17,8 +21,16 @@ AGENT_REGISTRATION_DICT = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def flask_client(build_flask_client):
|
||||||
|
container = StubDIContainer()
|
||||||
|
container.register_instance(IIslandEventQueue, MagicMock(spec=IIslandEventQueue))
|
||||||
|
|
||||||
|
with build_flask_client(container) as flask_client:
|
||||||
|
yield flask_client
|
||||||
|
|
||||||
|
|
||||||
def test_agent_registration(flask_client):
|
def test_agent_registration(flask_client):
|
||||||
print(AGENTS_URL)
|
|
||||||
resp = flask_client.post(
|
resp = flask_client.post(
|
||||||
AGENTS_URL,
|
AGENTS_URL,
|
||||||
json=AGENT_REGISTRATION_DICT,
|
json=AGENT_REGISTRATION_DICT,
|
||||||
|
|
|
@ -318,7 +318,3 @@ SCANNED
|
||||||
EXPLOITED
|
EXPLOITED
|
||||||
CC
|
CC
|
||||||
CC_TUNNEL
|
CC_TUNNEL
|
||||||
|
|
||||||
IslandEventTopic.AGENT_CONNECTED
|
|
||||||
IslandEventTopic.CLEAR_SIMULATION_DATA
|
|
||||||
IslandEventTopic.RESET_AGENT_CONFIGURATION
|
|
||||||
|
|
Loading…
Reference in New Issue