async def get_agents_in_group(request, group_id, pretty=False, wait_for_complete=False, offset=0, limit=database_limit, select=None, sort=None, search=None, status=None, q=None): """Get the list of agents that belongs to the specified group. :param pretty: Show results in human-readable format :param wait_for_complete: Disable timeout response :param group_id: Group ID. :param offset: First element to return in the collection :param limit: Maximum number of elements to return :param select: Select which fields to return (separated by comma) :param sort: Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in ascending or descending order. :param search: Looks for elements with the specified string :param status: Filters by agent status. Use commas to enter multiple statuses. :param q: Query to filter results by. For example q="status=active" :return: AllItemsResponseAgents """ f_kwargs = { 'group_list': [group_id], 'offset': offset, 'limit': limit, 'sort': parse_api_param(sort, 'sort'), 'search': parse_api_param(search, 'search'), 'select': select, 'filters': { 'status': status, }, 'q': q } dapi = DistributedAPI( f=agent.get_agents_in_group, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies']) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
def test_DistributedAPI(install_type_mock, kwargs): """Test constructor from DistributedAPI class. Parameters ---------- kwargs : dict Dict with some kwargs to pass when instancing the class. """ dapi = DistributedAPI(f=agent.get_agents_summary_status, logger=logger, **kwargs) assert isinstance(dapi, DistributedAPI)
async def put_upgrade_agents(request, agents_list=None, pretty=False, wait_for_complete=False, wpk_repo=None, version=None, use_http=False, force=False): """Upgrade agents using a WPK file from online repository. Parameters ---------- pretty : bool Show results in human-readable format. wait_for_complete : bool Disable timeout response. agents_list : list List of agent IDs. All possible values from 000 onwards. wpk_repo : str WPK repository. version : str Wazuh version to upgrade to. use_http : bool Use protocol http. If it's false use https. By default the value is set to false. force : bool Force upgrade. Returns ------- ApiResponse Upgrade message after trying to upgrade the agents. """ f_kwargs = { 'agent_list': agents_list, 'wpk_repo': wpk_repo, 'version': version, 'use_http': use_http, 'force': force } dapi = DistributedAPI( f=agent.upgrade_agents, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='distributed_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies']) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def get_cluster_nodes(request, pretty=False, wait_for_complete=False, offset=0, limit=None, sort=None, search=None, select=None, nodes_list=None, q=None): """Get information about all nodes in the cluster or a list of them :param pretty: Show results in human-readable format :param wait_for_complete: Disable timeout response :param offset: First element to return in the collection :param limit: Maximum number of elements to return :param sort: Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in ascending or descending order. :param search: Looks for elements with the specified string :param select: Select which fields to return (separated by comma) :param nodes_list: List of node ids :param q: Query to filter results by. """ # Get type parameter from query type_ = request.query.get('type', 'all') f_kwargs = { 'filter_node': nodes_list, 'offset': offset, 'limit': limit, 'sort': parse_api_param(sort, 'sort'), 'search': parse_api_param(search, 'search'), 'select': select, 'filter_type': type_, 'q': q } nodes = raise_if_exc(await get_system_nodes()) dapi = DistributedAPI( f=cluster.get_nodes_info, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_master', is_async=True, wait_for_complete=wait_for_complete, logger=logger, local_client_arg='lc', rbac_permissions=request['token_info']['rbac_policies'], nodes=nodes) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def get_rules_requirement(request, requirement=None, pretty=False, wait_for_complete=False, offset=0, limit=None, sort=None, search=None): """Get all specified requirements :param requirement: Get the specified requirement in all rules in the system. :param pretty: Show results in human-readable format :param wait_for_complete: Disable timeout response :param offset: First element to return in the collection :param limit: Maximum number of elements to return :param sort: Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in ascending or descending order. :param search: Looks for elements with the specified string :return: Data object """ f_kwargs = { 'requirement': requirement.replace('-', '_'), 'offset': offset, 'limit': limit, 'sort_by': parse_api_param(sort, 'sort')['fields'] if sort is not None else [''], 'sort_ascending': True if sort is None or parse_api_param(sort, 'sort')['order'] == 'asc' else False, 'search_text': parse_api_param(search, 'search')['value'] if search is not None else None, 'complementary_search': parse_api_param(search, 'search')['negation'] if search is not None else None } dapi = DistributedAPI( f=rule_framework.get_requirement, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_any', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies']) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def get_ports_info(request, agent_id, pretty=False, wait_for_complete=False, offset=0, limit=None, select=None, sort=None, search=None, pid=None, protocol=None, tx_queue=None, state=None, process=None, q=None): """ Get ports info of an agent :param agent_id: Agent ID :param pretty: Show results in human-readable format :param wait_for_complete: Disable timeout response :param offset: First element to return in the collection :param limit: Maximum number of elements to return :param select: Select which fields to return (separated by comma) :param sort: Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in ascending or descending order. :param search: Looks for elements with the specified string :param pid: Filters by pid :param protocol: Filters by protocol :param tx_queue: Filters by tx_queue :param state: Filters by state :param process: Filters by process :param q: Query to filter results by. :return: Data """ filters = {'pid': pid, 'protocol': protocol, 'tx_queue': tx_queue, 'state': state, 'process': process} # Add nested fields to kwargs filters nested = ['local.ip', 'local.port', 'remote.ip'] for field in nested: filters[field] = request.query.get(field, None) f_kwargs = {'agent_list': [agent_id], 'offset': offset, 'limit': limit, 'select': select, 'sort': parse_api_param(sort, 'sort'), 'search': parse_api_param(search, 'search'), 'filters': filters, 'element_type': 'ports', 'q': q} dapi = DistributedAPI(f=syscollector.get_item_agent, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='distributed_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies'] ) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
def test_DistributedAPI_local_request(mock_local_request): """Test `local_request` method from class DistributedAPI and check the behaviour when an error raise.""" dapi_kwargs = {'f': manager.status, 'logger': logger} raise_if_exc_routine(dapi_kwargs=dapi_kwargs) dapi_kwargs = {'f': cluster.get_nodes_info, 'logger': logger, 'local_client_arg': 'lc'} raise_if_exc_routine(dapi_kwargs=dapi_kwargs) dapi_kwargs['is_async'] = True raise_if_exc_routine(dapi_kwargs=dapi_kwargs) with patch('asyncio.wait_for', new=AsyncMock(side_effect=TimeoutError('Testing'))): dapi = DistributedAPI(f=manager.status, logger=logger) try: raise_if_exc(loop.run_until_complete(dapi.distribute_function())) except ProblemException as e: assert e.ext['dapi_errors'][list(e.ext['dapi_errors'].keys())[0]]['error'] == \ 'Timeout executing API request' with patch('asyncio.wait_for', new=AsyncMock(side_effect=WazuhError(1001))): dapi_kwargs = {'f': manager.status, 'logger': logger} raise_if_exc_routine(dapi_kwargs=dapi_kwargs, expected_error=1001) dapi_kwargs['debug'] = True raise_if_exc_routine(dapi_kwargs=dapi_kwargs, expected_error=1001) with patch('asyncio.wait_for', new=AsyncMock(side_effect=WazuhInternalError(1001))): dapi_kwargs = {'f': manager.status, 'logger': logger} raise_if_exc_routine(dapi_kwargs=dapi_kwargs, expected_error=1001) dapi = DistributedAPI(f=manager.status, logger=logger, debug=True) try: raise_if_exc(loop.run_until_complete(dapi.distribute_function())) except WazuhInternalError as e: assert e.code == 1001 with patch('asyncio.wait_for', new=AsyncMock(side_effect=KeyError('Testing'))): dapi_kwargs = {'f': manager.status, 'logger': logger} raise_if_exc_routine(dapi_kwargs=dapi_kwargs, expected_error=1000) dapi = DistributedAPI(f=manager.status, logger=logger, debug=True) try: raise_if_exc(loop.run_until_complete(dapi.distribute_function())) except Exception as e: assert type(e) == KeyError
def test_DistributedAPI_local_request_errors(): """Check the behaviour when the local_request function raised an error.""" with patch( 'wazuh.core.cluster.dapi.dapi.DistributedAPI.execute_local_request', new=AsyncMock(side_effect=WazuhInternalError(1001))): dapi_kwargs = {'f': agent.get_agents_summary_status, 'logger': logger} raise_if_exc_routine(dapi_kwargs=dapi_kwargs, expected_error=1001) dapi_kwargs['debug'] = True dapi = DistributedAPI(f=agent.get_agents_summary_status, logger=logger, debug=True) try: raise_if_exc(loop.run_until_complete(dapi.distribute_function())) except WazuhInternalError as e: assert e.code == 1001 with patch( 'wazuh.core.cluster.dapi.dapi.DistributedAPI.execute_local_request', new=AsyncMock(side_effect=KeyError('Testing'))): dapi_kwargs = {'f': agent.get_agents_summary_status, 'logger': logger} raise_if_exc_routine(dapi_kwargs=dapi_kwargs, expected_error=1000) # Specify KeyError dapi = DistributedAPI(f=agent.get_agents_summary_status, logger=logger, debug=True) try: raise_if_exc(loop.run_until_complete(dapi.distribute_function())) except KeyError as e: assert 'KeyError' in repr(e)
async def restart_agents_by_group(request, group_id, pretty=False, wait_for_complete=False): """Restart all agents from a group. :param pretty: Show results in human-readable format :param wait_for_complete: Disable timeout response :param group_id: Group ID. :return: AllItemsResponseAgents """ f_kwargs = {'group_list': [group_id], 'select': ['id']} dapi = DistributedAPI(f=agent.get_agents_in_group, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies'] ) agents = raise_if_exc(await dapi.distribute_function()) agent_list = [a['id'] for a in agents.affected_items] if not agent_list: data = AffectedItemsWazuhResult(none_msg='Restart command was not sent to any agent') return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps) f_kwargs = {'agent_list': agent_list} dapi = DistributedAPI(f=agent.restart_agents, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='distributed_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies'] ) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def get_hotfixes_info(request, pretty=False, wait_for_complete=False, list_agents='*', offset=0, limit=None, sort=None, search=None, select=None, hotfix=None): """ Get hotfixes info from all agents or a list of them. :param pretty: Show results in human-readable format :param wait_for_complete: Disable timeout response :param list_agents: List of agent's IDs. :param offset: First element to return in the collection :param limit: Maximum number of elements to return :param sort: Sorts the collection by a field or fields (separated by comma). Use +/. at the beginning to list in ascending or descending order. :param search: Looks for elements with the specified string :param select: Select which fields to return (separated by comma) :param hotfix: Filters by hotfix in Windows agents :return:AllItemsResponseSyscollectorHotfixes """ filters = {'hotfix': hotfix} f_kwargs = { 'agent_list': list_agents, 'offset': offset, 'limit': limit, 'select': select, 'sort': parse_api_param(sort, 'sort'), 'search': parse_api_param(search, 'search'), 'filters': filters, 'element_type': 'hotfixes' } dapi = DistributedAPI( f=syscollector.get_item_agent, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='distributed_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, broadcasting=list_agents == '*', rbac_permissions=request['token_info']['rbac_policies']) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def get_network_interface_info(request, pretty=False, wait_for_complete=False, agents_list='*', offset=0, limit=None, select=None, sort=None, search=None, adapter=None, state=None, mtu=None): """ Get all network interfaces from all agents or a list of them. :param pretty: Show results in human-readable format :param wait_for_complete: Disable timeout response :param agents_list: List of agent's IDs. :param offset: First element to return in the collection :param limit: Maximum number of elements to return :param select: Select which fields to return (separated by comma) :param sort: Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in ascending or descending order. :param search: Looks for elements with the specified string :param adapter: Filters by adapter :param state: Filters by state :param mtu: Filters by mtu :return: AllItemsResponseSyscollectorInterface """ filters = { 'adapter': adapter, 'type': request.query.get('type', None), 'state': state, 'mtu': mtu } # Add nested fields to kwargs filters nested = ['tx.packets', 'rx.packets', 'tx.bytes', 'rx.bytes', 'tx.errors', 'rx.errors', 'tx.dropped', 'rx.dropped'] for field in nested: filters[field] = request.query.get(field, None) f_kwargs = {'agent_list': agents_list, 'offset': offset, 'limit': limit, 'select': select, 'sort': parse_api_param(sort, 'sort'), 'search': parse_api_param(search, 'search'), 'filters': filters, 'element_type': 'netiface' } dapi = DistributedAPI(f=syscollector.get_item_agent, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='distributed_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, broadcasting=agents_list == '*', rbac_permissions=request['token_info']['rbac_policies'] ) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def put_file(request, body, filename=None, overwrite=False, pretty=False, wait_for_complete=False): """Upload a rule file. Parameters ---------- body : dict Body request with the file content to be uploaded. filename : str, optional Name of the file. Default `None` overwrite : bool, optional If set to false, an exception will be raised when updating contents of an already existing file. Default `False` pretty : bool, optional Show results in human-readable format. Default `False` wait_for_complete : bool, optional Disable timeout response. Default `False` Returns ------- web.json_response """ # Parse body to utf-8 Body.validate_content_type( request, expected_content_type='application/octet-stream') parsed_body = Body.decode_body(body, unicode_error=1911, attribute_error=1912) f_kwargs = { 'filename': filename, 'overwrite': overwrite, 'content': parsed_body } dapi = DistributedAPI( f=rule_framework.upload_rule_file, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies']) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
def decode_token(token): """Decode a jwt formatted token and add processed policies. Raise an Unauthorized exception in case validation fails. Parameters ---------- token : str JWT formatted token Returns ------- Dict payload ot the token """ try: # Decode JWT token with local secret payload = jwt.decode(token, generate_secret(), algorithms=[JWT_ALGORITHM], audience='Wazuh API REST') # Check token and add processed policies in the Master node dapi = DistributedAPI(f=check_token, f_kwargs={ 'username': payload['sub'], 'roles': payload['rbac_roles'], 'token_nbf_time': payload['nbf'], 'run_as': payload['run_as'] }, request_type='local_master', is_async=False, wait_for_complete=True, logger=logging.getLogger('wazuh')) data = raise_if_exc( pool.submit(asyncio.run, dapi.distribute_function()).result()).to_dict() if not data['result']['valid']: raise Unauthorized payload['rbac_policies'] = data['result']['policies'] payload['rbac_policies']['rbac_mode'] = payload.pop('rbac_mode') # Detect local changes dapi = DistributedAPI(f=get_security_conf, request_type='local_master', is_async=False, wait_for_complete=True, logger=logging.getLogger('wazuh')) result = raise_if_exc( pool.submit(asyncio.run, dapi.distribute_function()).result()) current_rbac_mode = result['rbac_mode'] current_expiration_time = result['auth_token_exp_timeout'] if payload['rbac_policies']['rbac_mode'] != current_rbac_mode \ or (payload['exp'] - payload['nbf']) != current_expiration_time: raise Unauthorized return payload except JWTError as e: raise Unauthorized from e
async def get_attack(request, pretty=False, wait_for_complete=False, offset=0, limit=database_limit, phase_name=None, platform_name=None, q=None, search=None, select=None, sort=None): """Get information from MITRE ATT&CK database :param pretty: Show results in human-readable format :param wait_for_complete: Disable timeout response :param phase_name: Filters by phase :param platform_name: Filters by platform :param search: Search if the string is contained in the db :param offset: First item to return :param limit: Maximum number of items to return :param sort: Sort the items. Format: {'fields': ['field1', 'field2'], 'order': 'asc|desc'} :param select: Select fields to return. Format: {"fields":["field1","field2"]}. :param q: Query to filter by :return: Data """ f_kwargs = { 'id_': request.query.get('id', None), 'phase_name': phase_name, 'platform_name': platform_name, 'select': select, 'search': parse_api_param(search, 'search'), 'offset': offset, 'limit': limit, 'sort': parse_api_param(sort, 'sort'), 'q': q } dapi = DistributedAPI( f=mitre.get_attack, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies']) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def get_agent_fields(request, pretty=False, wait_for_complete=False, fields=None, offset=0, limit=database_limit, select=None, sort=None, search=None, q=None): """Get distinct fields in agents. Returns all the different combinations that agents have for the selected fields. It also indicates the total number of agents that have each combination. :param pretty: Show results in human-readable format :param wait_for_complete: Disable timeout response :param fields: List of fields affecting the operation. :param offset: First element to return in the collection :param limit: Maximum number of elements to return :param select: Select which fields to return (separated by comma) :param sort: Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in ascending or descending order. :param search: Looks for elements with the specified string :param q: Query to filter results by. For example q="status=active" :return: ListMetadata """ f_kwargs = { 'offset': offset, 'limit': limit, 'select': select, 'sort': parse_api_param(sort, 'sort'), 'search': parse_api_param(search, 'search'), 'fields': fields, 'q': q } dapi = DistributedAPI( f=agent.get_distinct_agents, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies']) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def get_configuration(request, pretty=False, wait_for_complete=False, section=None, field=None, raw: bool = False): """Get manager's or local_node's configuration (ossec.conf) Parameters ---------- pretty : bool, optional Show results in human-readable format. It only works when `raw` is False (JSON format). Default `True` wait_for_complete : bool, optional Disable response timeout or not. Default `False` section : str Indicates the wazuh configuration section field : str Indicates a section child, e.g, fields for rule section are include, decoder_dir, etc. raw : bool, optional Whether to return the file content in raw or JSON format. Default `True` Returns ------- web.json_response or ConnexionResponse Depending on the `raw` parameter, it will return an object or other: raw=True -> ConnexionResponse (application/xml) raw=False (default) -> web.json_response (application/json) If any exception was raised, it will return a web.json_response with details. """ f_kwargs = {'section': section, 'field': field, 'raw': raw} dapi = DistributedAPI( f=manager.read_ossec_conf, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_any', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies']) data = raise_if_exc(await dapi.distribute_function()) if isinstance(data, AffectedItemsWazuhResult): response = web.json_response(data=data, status=200, dumps=prettify if pretty else dumps) else: response = ConnexionResponse(body=data["message"], mimetype='application/xml', content_type='application/xml') return response
def generate_token(user_id=None, data=None, run_as=False): """Generate an encoded jwt token. This method should be called once a user is properly logged on. Parameters ---------- user_id : str Unique username data : dict Roles permissions for the user run_as : bool Indicate if the user has logged in with run_as or not Returns ------- JWT encode token """ dapi = DistributedAPI(f=get_security_conf, request_type='local_master', is_async=False, wait_for_complete=False, logger=logging.getLogger('wazuh-api')) result = raise_if_exc( pool.submit(asyncio.run, dapi.distribute_function()).result()).dikt timestamp = int(time()) payload = { "iss": JWT_ISSUER, "aud": "Wazuh API REST", "nbf": int(timestamp), "exp": int(timestamp + result['auth_token_exp_timeout']), "sub": str(user_id), "run_as": run_as, "rbac_roles": data['roles'], "rbac_mode": result['rbac_mode'] } return jwt.encode(payload, generate_keypair()[0], algorithm=JWT_ALGORITHM)
async def get_network_address_info(request, pretty=False, wait_for_complete=False, agents_list='*', offset=0, limit=None, select=None, sort=None, search=None, iface_name=None, proto=None, address=None, broadcast=None, netmask=None): """ Get the IPv4 and IPv6 addresses associated to all network interfaces :param pretty: Show results in human-readable format :param wait_for_complete: Disable timeout response :param agents_list: List of agent's IDs. :param offset: First element to return in the collection :param limit: Maximum number of elements to return :param select: Select which fields to return (separated by comma) :param sort: Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in ascending or descending order. :param search: Looks for elements with the specified string :param iface_name: Filters by interface name :param proto: Filters by IP protocol :param address: IP address associated with the network interface :param broadcast: Filters by broadcast direction :param netmask: Filters by netmask :return: AllItemsResponseSyscollectorNetwork """ f_kwargs = {'agent_list': agents_list, 'offset': offset, 'limit': limit, 'select': select, 'sort': parse_api_param(sort, 'sort'), 'search': parse_api_param(search, 'search'), 'filters': { 'iface_name': iface_name, 'proto': proto, 'address': address, 'broadcast': broadcast, 'netmask': netmask }, 'element_type': 'netaddr' } dapi = DistributedAPI(f=syscollector.get_item_agent, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='distributed_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, broadcasting=agents_list == '*', rbac_permissions=request['token_info']['rbac_policies'] ) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def security_revoke_tokens(): """Revokes all tokens on all nodes after a change in security configuration.""" nodes = await get_system_nodes() if isinstance(nodes, Exception): nodes = None dapi = DistributedAPI(f=revoke_tokens, request_type='distributed_master' if nodes is not None else 'local_any', is_async=False, wait_for_complete=True, broadcasting=nodes is not None, logger=logger, nodes=nodes) raise_if_exc(await dapi.distribute_function())
def generate_token(user_id=None, rbac_policies=None): """Generate an encoded jwt token. This method should be called once a user is properly logged on. Parameters ---------- user_id : str Unique username rbac_policies : dict Permissions for the user Returns ------- JWT encode token """ dapi = DistributedAPI(f=get_security_conf, request_type='local_master', is_async=False, wait_for_complete=True, logger=logging.getLogger('wazuh')) result = raise_if_exc( pool.submit(asyncio.run, dapi.distribute_function()).result()).dikt timestamp = int(time()) roles = rbac_policies['roles'] rbac_policies = rbac_policies['policies'] rbac_policies['rbac_mode'] = result['rbac_mode'] payload = { "iss": JWT_ISSUER, "aud": "Wazuh API REST", "nbf": int(timestamp), "exp": int(timestamp + result['auth_token_exp_timeout']), "sub": str(user_id), "rbac_roles": roles, "rbac_policies": rbac_policies } return jwt.encode(payload, generate_secret(), algorithm=JWT_ALGORITHM)
async def get_packages_info(request, pretty=False, wait_for_complete=False, agents_list='*', offset=0, limit=None, select=None, sort=None, search=None, vendor=None, name=None, architecture=None, version=None): """ Get packages info from all agents or a list of them. :param pretty: Show results in human-readable format :param wait_for_complete: Disable timeout response :param agents_list: List of agent's IDs. :param offset: First element to return in the collection :param limit: Maximum number of elements to return :param select: Select which fields to return (separated by comma) :param sort: Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in ascending or descending order. :param search: Looks for elements with the specified string :param vendor: Filters by vendor :param name: Filters by name :param architecture: Filters by architecture :param version: Filters by format :return: AllItemsResponseSyscollectorPackages """ f_kwargs = {'agent_list': agents_list, 'offset': offset, 'limit': limit, 'select': select, 'sort': parse_api_param(sort, 'sort'), 'search': parse_api_param(search, 'search'), 'filters': { 'vendor': vendor, 'name': name, 'architecture': architecture, 'format': request.query.get('format', None), 'version': version }, 'element_type': 'packages' } dapi = DistributedAPI(f=syscollector.get_item_agent, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='distributed_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, broadcasting=agents_list == '*', rbac_permissions=request['token_info']['rbac_policies'] ) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def get_decoders(request, decoder_names: list = None, pretty: bool = False, wait_for_complete: bool = False, offset: int = 0, limit: int = None, select: list = None, sort: str = None, search: str = None, q: str = None, filename: str = None, relative_dirname: str = None, status: str = None): """Get all decoders Returns information about all decoders included in ossec.conf. This information include decoder's route, decoder's name, decoder's file among others :param decoder_names: Filters by decoder name. :param pretty: Show results in human-readable format :param wait_for_complete: Disable timeout response :param offset: First element to return in the collection :param limit: Maximum number of elements to return :param select: List of selected fields to return :param sort: Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in ascending or descending order. :param search: Looks for elements with the specified string :param q: Query to filter results by. For example q="status=active" :param filename: List of filenames to filter by. :param relative_dirname: Filters by relative dirname. :param status: Filters by list status. :return: Data object """ f_kwargs = {'names': decoder_names, 'offset': offset, 'limit': limit, 'select': select, 'sort_by': parse_api_param(sort, 'sort')['fields'] if sort is not None else ['filename', 'position'], 'sort_ascending': True if sort is None or parse_api_param(sort, 'sort')['order'] == 'asc' else False, 'search_text': parse_api_param(search, 'search')['value'] if search is not None else None, 'complementary_search': parse_api_param(search, 'search')['negation'] if search is not None else None, 'q': q, 'filename': filename, 'status': status, 'relative_dirname': relative_dirname} dapi = DistributedAPI(f=decoder_framework.get_decoders, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_any', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies'] ) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def get_file(request, pretty: bool = False, wait_for_complete: bool = False, filename: str = None, raw: bool = False): """Get rule file content. Parameters ---------- pretty : bool, optional Show results in human-readable format. It only works when `raw` is False (JSON format). Default `True` wait_for_complete : bool, optional Disable response timeout or not. Default `False` filename : str Filename to download. raw : bool, optional Whether to return the file content in raw or JSON format. Default `False` Returns ------- web.json_response or ConnexionResponse Depending on the `raw` parameter, it will return an object or other: raw=True -> ConnexionResponse (application/xml) raw=False (default) -> web.json_response (application/json) If any exception was raised, it will return a web.json_response with details. """ f_kwargs = {'filename': filename, 'raw': raw} dapi = DistributedAPI( f=rule_framework.get_rule_file, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies']) data = raise_if_exc(await dapi.distribute_function()) if isinstance(data, AffectedItemsWazuhResult): response = web.json_response(data=data, status=200, dumps=prettify if pretty else dumps) else: response = ConnexionResponse(body=data["message"], mimetype='application/xml', content_type='application/xml') return response
async def get_file(request, pretty: bool = False, wait_for_complete: bool = False, filename: str = None, raw: bool = False): """"Get content of one CDB list file, in raw or dict format. Parameters ---------- pretty : bool Show results in human-readable format. wait_for_complete : bool Disable timeout response. filename : str Name of filename to get data from. raw : bool, optional Respond in raw format. Returns ------- web.json_response, ConnexionResponse Depending on the `raw` parameter, it will return an object or other: raw=True -> ConnexionResponse (text/plain) raw=False (default) -> web.json_response (application/json) If any exception was raised, it will return a web.json_response with details. """ f_kwargs = {'filename': filename, 'raw': raw} dapi = DistributedAPI( f=cdb_list.get_list_file, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies']) data = raise_if_exc(await dapi.distribute_function()) if isinstance(data, AffectedItemsWazuhResult): response = web.json_response(data=data, status=200, dumps=prettify if pretty else dumps) else: response = ConnexionResponse(body=data["message"], mimetype='text/plain', content_type='text/plain') return response
async def get_policies(request, policy_ids: list = None, pretty: bool = False, wait_for_complete: bool = False, offset: int = 0, limit: int = None, search: str = None, select: str = None, sort: str = None): """Returns information from all system policies. Parameters ---------- request : connexion.request policy_ids : list, optional List of policies pretty : bool, optional Show results in human-readable format wait_for_complete : bool, optional Disable timeout response offset : int, optional First item to return limit : int, optional Maximum number of items to return search : str, optional Looks for elements with the specified string select : str Select which fields to return (separated by comma) sort : str, optional Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in ascending or descending order Returns ------- Policies information """ f_kwargs = {'policy_ids': policy_ids, 'offset': offset, 'limit': limit, 'select': select, 'sort_by': parse_api_param(sort, 'sort')['fields'] if sort is not None else ['id'], 'sort_ascending': True if sort is None or parse_api_param(sort, 'sort')['order'] == 'asc' else False, 'search_text': parse_api_param(search, 'search')['value'] if search is not None else None, 'complementary_search': parse_api_param(search, 'search')['negation'] if search is not None else None } dapi = DistributedAPI(f=security.get_policies, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies'] ) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def update_policy(request, policy_id: int, pretty: bool = False, wait_for_complete: bool = False): """Update the information of one specified policy. Parameters ---------- request : connexion.request policy_id : int Specific policy id in the system to be updated pretty : bool, optional Show results in human-readable format wait_for_complete : bool, optional Disable timeout response Returns ------- Policy information updated """ # get body parameters policy_added_model = dict() try: policy_added_model = await request.json() except JSONDecodeError as e: raise_if_exc(APIError(code=2005, details=e.msg)) f_kwargs = { 'policy_id': policy_id, 'name': policy_added_model.get('name', None), 'policy': policy_added_model.get('policy', None) } dapi = DistributedAPI( f=security.update_policy, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies']) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def get_list_group(request, pretty=False, wait_for_complete=False, groups_list=None, offset=0, limit=None, sort=None, search=None): """Get groups. Returns a list containing basic information about each agent group such as number of agents belonging to the group and the checksums of the configuration and shared files. :param pretty: Show results in human-readable format :param wait_for_complete: Disable timeout response :param groups_list: Array of group's IDs. :param offset: First element to return in the collection :param limit: Maximum number of elements to return :param sort: Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in ascending or descending order. :param search: Looks for elements with the specified string :return: AllItemsResponseGroups """ hash_ = request.query.get( 'hash', 'md5') # Select algorithm to generate the returned checksums. f_kwargs = { 'offset': offset, 'limit': limit, 'group_list': groups_list, 'sort': parse_api_param(sort, 'sort'), 'search': parse_api_param(search, 'search'), 'hash_algorithm': hash_ } dapi = DistributedAPI( f=agent.get_agent_groups, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies']) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def put_files_node(request, body, node_id, path, overwrite=False, pretty=False, wait_for_complete=False): """Upload file contents in a specified cluster node. :param body: Body request with the content of the file to be uploaded :param node_id: Cluster node name :param path: Filepath to upload the new file :param overwrite: If set to false, an exception will be raised when uploading an already existing filename. :param pretty: Show results in human-readable format :param wait_for_complete: Disable timeout response """ # parse body to utf-8 Body.validate_content_type( request, expected_content_type='application/octet-stream') parsed_body = Body.decode_body(body, unicode_error=1911, attribute_error=1912) f_kwargs = { 'node_id': node_id, 'path': path, 'overwrite': overwrite, 'content': parsed_body } nodes = raise_if_exc(await get_system_nodes()) dapi = DistributedAPI( f=manager.upload_file, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='distributed_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies'], nodes=nodes) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def set_role_policy(request, role_id, policy_ids, position=None, pretty=False, wait_for_complete=False): """Add a list of policies to one specified role. Parameters ---------- role_id : int Role ID policy_ids : list of int List of policy IDs position : int Position where the new role will be inserted pretty : bool Show results in human-readable format wait_for_complete : bool Disable timeout response Returns ------- dict Role information """ f_kwargs = { 'role_id': role_id, 'policy_ids': policy_ids, 'position': position } dapi = DistributedAPI( f=security.set_role_policy, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies']) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
async def set_user_role(request, username: str, role_ids: list, position: int = None, pretty: bool = False, wait_for_complete: bool = False): """Add a list of roles to one specified user. Parameters ---------- request : connexion.request username : str User's username role_ids : list of int List of role ids position : int, optional Position where the new role will be inserted pretty : bool, optional Show results in human-readable format wait_for_complete : bool, optional Disable timeout response Returns ------- Dict User-Role information """ f_kwargs = { 'user_id': username, 'role_ids': role_ids, 'position': position } dapi = DistributedAPI( f=security.set_user_role, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='local_master', is_async=False, wait_for_complete=wait_for_complete, logger=logger, rbac_permissions=request['token_info']['rbac_policies']) data = raise_if_exc(await dapi.distribute_function()) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)