Example #1
0
def test_agentd_state_config(configure_environment, test_case: list):

    control_service('stop', 'wazuh-agentd')

    # Truncate ossec.log in order to watch it correctly
    truncate_file(LOG_FILE_PATH)

    # Remove state file to check if agent behavior is as expected
    os.remove(state_file_path) if os.path.exists(state_file_path) else None

    # Set state interval value according to test case specs
    set_state_interval(test_case['interval'], internal_options)

    control_service('start', 'wazuh-agentd')

    # Check if test require checking state file existance
    if 'state_file_exist' in test_case:
        if test_case['state_file_exist']:
            # Wait until state file was dumped
            time.sleep(test_case['interval'])
        assert test_case['state_file_exist'] == os.path.exists(state_file_path)

    # Follow ossec.log to find desired messages by a callback
    wazuh_log_monitor = FileMonitor(LOG_FILE_PATH)
    wazuh_log_monitor.start(timeout=global_parameters.default_timeout,
                            callback=callbacks.get(test_case['log_expect']),
                            error_message='Event not found')
    assert wazuh_log_monitor.result()

    # Check if test require checking agentd status
    if 'agentd_ends' in test_case:
        assert (test_case['agentd_ends']
                is not check_if_process_is_running('wazuh-agentd'))
def test_execd_firewall_drop(set_debug_mode, get_configuration, test_version,
                             configure_environment, remove_ip_from_iptables,
                             start_agent, set_ar_conf_mode):
    """Check if firewall-drop Active Response is executed correctly.

    Args:
        set_debug_mode (fixture): Set execd daemon in debug mode.
        test_version (fixture): Validate Wazuh version.
        set_ar_conf_mode (fixture): Configure Active Responses used in tests.
        start_agent (fixture): Create Remoted and Authd simulators, register agent and start it.
        remove_ip_from_iptables (fixture): Remove the test IP from iptables if it exist
    """
    metadata = get_configuration['metadata']
    expected = metadata['results']
    ossec_log_monitor = FileMonitor(LOG_FILE_PATH)
    ar_log_monitor = FileMonitor(execd.AR_LOG_FILE_PATH)

    # Checking AR in ossec logs
    ossec_log_monitor.start(timeout=60,
                            callback=execd.wait_received_message_line)

    # Checking AR in active-response logs
    ar_log_monitor.start(timeout=60, callback=execd.wait_start_message_line)

    if expected['success']:
        for command_id in range(2):
            ar_log_monitor.start(timeout=60, callback=wait_message_line)
            last_log = ar_log_monitor.result()
            validate_ar_message(last_log, command_id)

            ar_log_monitor.start(timeout=60,
                                 callback=execd.wait_ended_message_line)

            # Checking if the IP was added/removed in iptables
            iptables_file = os.popen('iptables -L')
            flag = False
            for iptables_line in iptables_file:
                if metadata['ip'] in iptables_line:
                    flag = True

            if not flag and command_id == 0:
                raise AssertionError("IP was not added to iptable")
            elif flag and command_id == 1:
                raise AssertionError("IP was not deleted from iptable")

            time.sleep(5)
    else:
        ar_log_monitor.start(timeout=60,
                             callback=wait_invalid_input_message_line)
def check_time_to_connect(timeout):
    """Wait until client try connect.

    Args:
        timeout (int, optional): Maximum timeout. Default `-1`

    Returns:
        int: Integer with elapsed time in seconds.
    """
    def wait_connect(line):
        if 'Trying to connect to server' in line:
            return line
        return None

    log_monitor = FileMonitor(LOG_FILE_PATH)
    try:
        log_monitor.start(timeout=timeout + 2, callback=wait_connect)
    except TimeoutError:
        return -1

    final_line = log_monitor.result()
    initial_line = None
    elapsed_time = None

    with open(LOG_FILE_PATH, 'r') as log_file:
        lines = log_file.readlines()
        # find enrollment end
        for line in lines:
            if "INFO: Valid key received" in line:
                initial_line = line
                break

    if initial_line is not None and final_line is not None:
        form = '%H:%M:%S'
        initial_time = datetime.datetime.strptime(initial_line.split()[1],
                                                  form).time()
        final_time = datetime.datetime.strptime(final_line.split()[1],
                                                form).time()
        initial_delta = datetime.timedelta(hours=initial_time.hour,
                                           minutes=initial_time.minute,
                                           seconds=initial_time.second)
        final_delta = datetime.timedelta(hours=final_time.hour,
                                         minutes=final_time.minute,
                                         seconds=final_time.second)
        elapsed_time = (final_delta - initial_delta).total_seconds()

    return elapsed_time
def test_agentd_parametrized_reconnections(configure_authd_server, start_authd,
                                           stop_agent, set_keys,
                                           configure_environment,
                                           get_configuration):
    """Check how the agent behaves when there are delays between connection attempts to the server.

    For this purpose, different values for max_retries and retry_interval parameters are tested.

    Args:
        configure_authd_server (fixture): Initialize a simulated authd connection.
        start_authd (fixture): Enable authd to accept connections and perform enrollments.
        stop_agent (fixture): Stop Wazuh's agent.
        set_keys (fixture): Write to client.keys file the agent's enrollment details.
        configure_environment (fixture): Configure a custom environment for testing.
        get_configuration (fixture): Get configurations from the module.
    """
    DELTA = 1
    RECV_TIMEOUT = 5
    ENROLLMENT_SLEEP = 20
    LOG_TIMEOUT = 30

    global remoted_server

    PROTOCOL = protocol = get_configuration['metadata']['PROTOCOL']
    RETRIES = get_configuration['metadata']['MAX_RETRIES']
    INTERVAL = get_configuration['metadata']['RETRY_INTERVAL']
    ENROLL = get_configuration['metadata']['ENROLL']

    control_service('stop')
    clean_logs()
    log_monitor = FileMonitor(LOG_FILE_PATH)
    remoted_server = RemotedSimulator(protocol=PROTOCOL,
                                      client_keys=CLIENT_KEYS_PATH)
    control_service('start')

    # 2 Check for unsuccessful connection retries in Agentd initialization
    interval = INTERVAL
    if PROTOCOL == 'udp':
        interval += RECV_TIMEOUT

    if ENROLL == 'yes':
        total_retries = RETRIES + 1
    else:
        total_retries = RETRIES

    for retry in range(total_retries):
        # 3 If auto enrollment is enabled, retry check enrollment and retries after that
        if ENROLL == 'yes' and retry == total_retries - 1:
            # Wait successfully enrollment
            try:
                log_monitor.start(timeout=20, callback=wait_enrollment)
            except TimeoutError as err:
                raise AssertionError("No successful enrollment after retries!")
            last_log = parse_time_from_log_line(log_monitor.result())

            # Next retry will be after enrollment sleep
            interval = ENROLLMENT_SLEEP

        try:
            log_monitor.start(timeout=interval + LOG_TIMEOUT,
                              callback=wait_connect)
        except TimeoutError as err:
            raise AssertionError("Connection attempts took too much!")
        actual_retry = parse_time_from_log_line(log_monitor.result())
        if retry > 0:
            delta_retry = actual_retry - last_log
            # Check if delay was applied
            assert delta_retry >= timedelta(seconds=interval -
                                            DELTA), "Retries to quick"
            assert delta_retry <= timedelta(seconds=interval +
                                            DELTA), "Retries to slow"
        last_log = actual_retry

    # 4 Wait for server rollback
    try:
        log_monitor.start(timeout=30, callback=wait_server_rollback)
    except TimeoutError as err:
        raise AssertionError("Server rollback took too much!")

    # 5 Check amount of retries and enrollment
    (connect, enroll) = count_retry_mesages()
    assert connect == total_retries
    if ENROLL == 'yes':
        assert enroll == 1
    else:
        assert enroll == 0

    return
Example #5
0
def test_wpk_manager(set_debug_mode, get_configuration, configure_environment,
                     restart_service, configure_agents):
    metadata = get_configuration.get('metadata')
    protocol = metadata['protocol']
    expected_status = metadata['status']
    sender = Sender(SERVER_ADDRESS, protocol=protocol)
    log_monitor = FileMonitor(LOG_FILE_PATH)
    expected_error_msg = metadata.get('error_msg')
    sha_list = metadata.get('sha_list')
    injectors = []
    file_name = ''
    installer = ''

    if 'VALIDSHA1' in sha_list:
        sha_list = get_sha_list(metadata)

    command = 'upgrade'
    if metadata.get('command') == 'upgrade_custom':
        command = 'upgrade_custom'
        if not expected_error_msg or ('The WPK file does not exist' not in expected_error_msg):
            file_name = metadata.get('message_params').get('file_path')
            file = os.path.join(UPGRADE_PATH, file_name)
            create_wpk_custom_file(file)
            metadata['message_params']['file_path'] = file
            sha_list = [hashlib.sha1(open(file, 'rb').read()).hexdigest()]
        if metadata.get('message_params').get('installer'):
            installer = metadata.get('message_params').get('installer')
        else:
            installer = 'upgrade.sh'

    for index, agent in enumerate(agents):
        agent.set_wpk_variables(sha_list[index],
                                metadata['upgrade_exec_result'][index],
                                metadata['upgrade_notification'][index],
                                metadata['upgrade_script_result'][index],
                                stage_disconnect=metadata['stage_disconnect'][index])
        injector = Injector(sender, agent)
        injectors.append(injector)
        injector.run()
        if protocol == "tcp":
            sender = Sender(manager_address=SERVER_ADDRESS, protocol=protocol)

    agents_id = [int(x.id) for x in agents]

    data = {
        'command': command,
        'parameters': {'agents': agents_id}
    }

    # If have params for test case add to the data to send
    if metadata.get('message_params'):
        data['parameters'].update(metadata.get('message_params'))

    # remove wpk if need check http or version
    if metadata.get('checks') and ('use_http' in metadata.get('checks') or 'version' in metadata.get('checks')):
        remove_wpk_package()

    # Give time for registration key to be available and send a few heartbeats
    time.sleep(40)

    # Send upgrade request
    response = send_message(data, UPGRADE_SOCKET)

    if metadata.get('checks') and (('use_http' in metadata.get('checks')) or ('version' in metadata.get('checks'))):
        # Checking version or http in logs
        try:
            log_monitor.start(timeout=60, callback=wait_download)
        except TimeoutError as err:
            raise AssertionError("Download wpk log took too much!")

        last_log = log_monitor.result()
        if 'use_http' in metadata.get('checks'):
            if metadata.get('message_params') and \
                metadata.get('message_params').get('use_http') and \
                    metadata.get('message_params').get('use_http'):
                assert "'http://" in last_log, "Use http protocol did not match expected! Expected 'http://'"
            else:
                assert "'https://" in last_log, "Use http protocol did not match expected! Expected 'https://'"

        if 'version' in metadata.get('checks'):
            if metadata.get('message_params') and \
                    metadata.get('message_params').get('version'):
                assert metadata.get('message_params').get('version') in \
                    last_log, f'Versions did not match expected! \
                                Expected {metadata.get("message_params").get("version")}'
            else:
                assert MANAGER_VERSION in last_log, \
                    f'Versions did not match expected! Expected {MANAGER_VERSION}'
        # let time to download wpk
        try:
            log_monitor.start(timeout=600, callback=wait_downloaded)
        except TimeoutError as err:
            raise AssertionError("Finish download wpk log took too much!")
        # time.sleep(60)

    if metadata.get('checks') and ('chunk_size' in metadata.get('checks')):
        # Checking version in logs
        try:
            log_monitor.start(timeout=60, callback=wait_chunk_size)
        except TimeoutError as err:
            raise AssertionError("Chunk size log tooks too much!")
        chunk = metadata.get('chunk_size')
        last_log = log_monitor.result()
        assert f'com write {chunk}' in last_log, \
            f'Chunk size did not match expected! Expected {chunk} obtained {last_log}'

    if metadata.get('checks') and ('wpk_name' in metadata.get('checks')):
        # Checking version in logs
        try:
            log_monitor.start(timeout=180, callback=wait_wpk_custom)
        except TimeoutError as err:
            raise AssertionError("Custom wpk log tooks too much!")

        last_log = log_monitor.result()
        assert f'com upgrade {file_name} {installer}' in last_log, \
            f'Wpk custom package did not match expected! ' \
            f'Expected {metadata.get("message_params").get("file_path")} obtained {last_log}'

    if metadata.get('first_attempt'):
        # Chech that result of first attempt is Success
        assert 'Success' == response['data'][0]['message'], \
            f'First upgrade response did not match expected! ' \
            f'Expected {metadata.get("expected_response")} obtained {response["data"][0]["message"]}'

        repeat_message = data
        # Continue with the validations of first attempt
        task_ids = [item.get('agent') for item in response['data']]
        for index, agent_id in enumerate(task_ids):
            data = {
                "origin": {
                    "module": "api"
                },
                "command": 'upgrade_result',
                "parameters": {
                    "agents": [agent_id]
                }
            }
            time.sleep(30)
            response = send_message(data, TASK_SOCKET)
            retries = 0
            while (response['data'][0]['status'] != metadata.get('first_attempt')) \
                    and (retries < 10):
                time.sleep(30)
                response = send_message(data, TASK_SOCKET)
                retries += 1
            assert metadata.get('first_attempt') == response['data'][0]['status'], \
                f'First upgrade status did not match expected! ' \
                f'Expected {metadata.get("first_attempt")} obtained {response["data"][0]["status"]}'

        # send upgrade request again
        response = send_message(repeat_message, UPGRADE_SOCKET)

    if metadata.get('expected_response') == 'Success':
        # Chech that result is expected
        assert metadata.get('expected_response') == response['data'][0]['message'], \
            f'Upgrade response did not match expected! ' \
            f'Expected {metadata.get("expected_response")} obtained {response["data"][0]["message"]}'

        # Continue with the test validations
        task_ids = [item.get('agent') for item in response['data']]
        for index, agent_id in enumerate(task_ids):
            data = {
                "origin": {
                    "module": "api"
                },
                "command": 'upgrade_result',
                "parameters": {
                    "agents": [agent_id]
                }
            }
            time.sleep(30)
            response = send_message(data, TASK_SOCKET)
            retries = 0
            while response['data'][0]['status'] == 'Updating' and retries < 30 and \
                    response['data'][0]['status'] != expected_status[index]:
                time.sleep(30)
                response = send_message(data, TASK_SOCKET)
                retries += 1
            assert expected_status[index] == response['data'][0]['status'], \
                f'Upgrade status did not match expected! ' \
                f'Expected {expected_status[index]} obtained {response["data"][0]["status"]} at index {index}'
            if expected_status[index] == 'Error':
                assert expected_error_msg[index] == response['data'][0]['error_msg'], \
                    f'Error msg did not match expected! ' \
                    f'Expected {expected_error_msg[index]} obtained {response["data"][0]["error_msg"]} at index {index}'
    else:
        assert metadata.get('expected_response') == response['data'][0]['message'], \
            f'Upgrade response did not match expected! ' \
            f'Expected {metadata.get("expected_response")} obtained {response["data"][0]["message"]}'

    for injector in injectors:
        injector.stop_receive()

    time.sleep(3)  # Wait for agents threads to stop