Skip to content

Commit

Permalink
Merge pull request #1109 from wazuh/1102-manager-ack
Browse files Browse the repository at this point in the history
Remoted integration tests T1: Add test manager ACK
  • Loading branch information
BraulioV committed Mar 5, 2021
2 parents 3f4abe2 + adfd9de commit 72ccd0e
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 6 deletions.
6 changes: 6 additions & 0 deletions deps/wazuh_testing/wazuh_testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ def is_tcp(protocol):
return protocol.upper() == TCP


def is_tcp_udp(protocol):
_protocol = protocol.replace(' ','').upper().split(',')
_protocol.sort()
return ','.join(_protocol) == TCP_UDP


class Parameters:
"""Class to allocate all global parameters for testing"""

Expand Down
19 changes: 19 additions & 0 deletions deps/wazuh_testing/wazuh_testing/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,3 +544,22 @@ def intercept_socket_data(data):
finally:
mitm.shutdown()
control_service('start', daemon='wazuh-analysisd')


def check_agent_received_message(message_queue, search_pattern, timeout=5, update_position=True):
"""Allow to monitor the agent received messages to search a pattern regex.
Args:
message_queue (monitoring.Queue): Queue containing the messages received in the agent.
search_pattern (str): Regex to search in agent received messages.
timeout (int): Maximum time in seconds to search the event.
update_position (boolean): True to search in the entire queue, False to search in the current position of the
queue.
Raises:
TimeoutError: if the search pattern isn't found in the queue in the expected time.
"""
queue_monitor = monitoring.QueueMonitor(message_queue)

queue_monitor.start(timeout=timeout, callback=monitoring.make_callback(search_pattern, '.*'),
update_position=update_position)
11 changes: 6 additions & 5 deletions deps/wazuh_testing/wazuh_testing/tools/agent_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import ssl
import threading
import zlib
from collections import deque

from random import randint, sample, choice
from stat import S_IFLNK, S_IFREG, S_IRWXU, S_IRWXG, S_IRWXO
from string import ascii_letters, digits
Expand All @@ -29,9 +29,10 @@
import wazuh_testing.wazuh_db as wdb
from wazuh_testing import TCP
from wazuh_testing import is_udp, is_tcp
from wazuh_testing.tools.monitoring import wazuh_unpack
from wazuh_testing.tools.monitoring import wazuh_unpack, Queue
from wazuh_testing.tools.remoted_sim import Cipher


_data_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'data')

os_list = ["debian7", "debian8", "debian9", "debian10", "ubuntu12.04",
Expand Down Expand Up @@ -92,7 +93,7 @@ class Agent:
stop_receive (int): Flag to determine when to activate and deactivate the agent event listener.
stage_disconnect (str): WPK process state variable.
rcv_msg_limit (int): max elements for the received message queue.
rcv_msg_queue (deque): Doubly Ended Queue to store received messages in the agent.
rcv_msg_queue (monitoring.Queue): Queue to store received messages in the agent.
disable_all_modules (boolean): Disable all simulated modules for this agent
"""
def __init__(self, manager_address, cypher="aes", os=None, inventory_sample=None, rootcheck_sample=None,
Expand Down Expand Up @@ -138,7 +139,7 @@ def __init__(self, manager_address, cypher="aes", os=None, inventory_sample=None
self.stop_receive = 0
self.stage_disconnect = None
self.setup(disable_all_modules=disable_all_modules)
self.rcv_msg_queue = deque([], maxlen=rcv_msg_limit)
self.rcv_msg_queue = Queue(rcv_msg_limit)

def setup(self, disable_all_modules):
"""Set up agent: os, registration, encryption key, start up msg and activate modules."""
Expand Down Expand Up @@ -403,7 +404,7 @@ def process_message(self, sender, message):
message (str): Decoder message in ISO-8859-1 format.
"""
msg_decoded_list = message.split(' ')
self.rcv_msg_queue.append(message)
self.rcv_msg_queue.put(message)
if '#!-req' in msg_decoded_list[0]:
self.process_command(sender, msg_decoded_list)
elif '#!-up' in msg_decoded_list[0]:
Expand Down
2 changes: 1 addition & 1 deletion deps/wazuh_testing/wazuh_testing/tools/monitoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ class Queue(queue.Queue):
def peek(self, *args, position=0, **kwargs):
"""Peek any given position without modifying the queue status.
The difference between `peek` and `get` is `peek` pops the item and `get` does not.
The difference between `peek` and `get` is `get` pops the item and `peek` does not.
Args:
position (int, optional) : Element of the queue to return. Default `0`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Test manager ACK

## Overview

These tests will check if the manager sends the ACK message after receiving the `start-up` message from agent.

## Objective

The objective is to check that the manager sends the ACK message using the different protocols.

## General info

|Tier | Number of tests | Time spent |
|:--:|:--:|:--:|
| 0 | 4 | 1m 15s |

## Expected behavior

Success if the agent receives the ACK message from the manager after sending the `start-up` message. Failure otherwise.

## Testing

The testing is based on configuring the manager to receive messages via `TCP`, `UDP`, `TCP-UDP` and `UDP-TCP`.

First, the simulated agent will send the `start-up` message to the manager, and then, the agent will save all the
incoming messages from the agent in a buffer.

The `start-up` message sent by the agent is as follows:

```
#!-agent startup
```

Next, the test will search the ACK message in the agent buffer (it contains the string `#!-agent ack`).

An example of the `ACK` message is as follows:

```
4112dbb63510267c613d5b6da095b4ea274310000000010:2203:#!-agent ack
```

### Checks

- Manager sends the ACK message using `TCP` protocol.
- Manager sends the ACK message using `UDP` protocol.
- Manager sends the ACK message using `TCP,UDP` configuration.
- Manager sends the ACK message using `UDP,TCP` configuration.

## Comments

An important aspect to take into account is the time needed by wazuh-remoted to reload the `client.keys`.
By default it is **10 seconds**, but this option is configurable in the `internal_options.conf`, using the
following directive:

```
remoted.keyupdate_interval=2
```

The test itself waits until the info is loaded, so reducing this time will also reduce the test time.
It is recommended to set this time between 2 and 5 seconds.

## Code documentation
::: tests.integration.test_remoted.test_manager_messages.test_manager_ack
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,8 @@ nav:
- Test configuration allowed and denied ips valids: tests/integration/test_remoted/test_configuration/test_basic_configuration_syslog_allowed_denied_ips_valid.md
- Test configuration denied ips: tests/integration/test_remoted/test_configuration/test_basic_configuration_syslog_denied_ips.md
- Test configuration syslog no allowed ips provided: tests/integration/test_remoted/test_configuration/test_basic_configuration_syslog_no_allowed_ips.md
- Test manager messages:
- tests/integration/test_remoted/test_manager_messages/test_manager_ack.md
- Test communications through the sockets:
- tests/integration/test_remoted/test_socket_communication/test_ping_pong_message.md
- tests/integration/test_remoted/test_socket_communication/test_syslog_message.md
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
- tags:
- test_manager_ack
apply_to_modules:
- test_manager_ack
sections:
- section: remote
elements:
- connection:
value: secure
- port:
value: 1514
- protocol:
value: PROTOCOL
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import pytest
import os
import wazuh_testing.tools.agent_simulator as ag

from time import sleep
from wazuh_testing import remote as rd
from wazuh_testing import is_tcp_udp
from wazuh_testing.tools import LOG_FILE_PATH
from wazuh_testing.tools.configuration import load_wazuh_configurations
from wazuh_testing.tools.monitoring import FileMonitor


# Marks
pytestmark = pytest.mark.tier(level=1)

# Variables
current_test_path = os.path.dirname(os.path.realpath(__file__))
test_data_path = os.path.join(current_test_path, 'data')
configurations_path = os.path.join(test_data_path, 'wazuh_manager_ack.yaml')

wazuh_log_monitor = FileMonitor(LOG_FILE_PATH)

# Set configuration
parameters = [
{'PROTOCOL': 'tcp'},
{'PROTOCOL': 'udp'},
{'PROTOCOL': 'tcp,udp'},
{'PROTOCOL': 'udp,tcp'},
]

metadata = [
{'protocol': 'tcp'},
{'protocol': 'udp'},
{'protocol': 'tcp,udp'},
{'protocol': 'udp,tcp'},
]

agent_info = {
'manager_address': '127.0.0.1',
'os': 'debian7',
'version': '4.2.0',
'disable_all_modules': True
}

configuration_ids = [item['PROTOCOL'].upper() for item in parameters]

# Configuration data
configurations = load_wazuh_configurations(configurations_path, __name__, params=parameters, metadata=metadata)


def check_manager_ack(protocol):
"""Allow to check if the manager sends the ACK message after receiving the start-up message from agent.
Args:
protocol (str): It can be UDP or TCP.
Raises:
TimeoutError: If agent does not receive the manager ACK message in the expected time.
"""

# Create agent and sender object with default parameters
agent = ag.Agent(**agent_info)

# Sleep to avoid ConnectionRefusedError
sleep(1)

sender = ag.Sender(agent_info['manager_address'], protocol=protocol)

# Activate receives_messages modules in simulated agent.
agent.set_module_status('receive_messages', 'enabled')

# Run injector with only receive messages module enabled
injector = ag.Injector(sender, agent)
try:
injector.run()

# Wait until remoted has loaded the new agent key
rd.wait_to_remoted_key_update(wazuh_log_monitor)

# Send the start-up message
sender.send_event(agent.startup_msg)

# Check ACK manager message
rd.check_agent_received_message(agent.rcv_msg_queue, '#!-agent ack')
finally:
injector.stop_receive()


@pytest.fixture(scope='module', params=configurations, ids=configuration_ids)
def get_configuration(request):
"""Get configurations from the module."""
return request.param


def test_manager_ack(get_configuration, configure_environment, restart_remoted):
"""Check if the manager sends the ACK message after receiving the start-up message from the agent."""
protocol = get_configuration['metadata']['protocol']

if is_tcp_udp(protocol):
check_manager_ack(rd.TCP)
check_manager_ack(rd.UDP)
else:
check_manager_ack(protocol)

0 comments on commit 72ccd0e

Please sign in to comment.