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
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