async def prevent_bruteforce_attack(request, block_time=300, attempts=5): """This function checks that the IPs that are requesting an API token do not do so repeatedly""" global ip_stats, ip_block if request.path == '/security/user/authenticate' and request.method == 'GET': try: if time() - block_time >= ip_stats[request.remote]['timestamp']: ip_stats.pop(request.remote) ip_block.remove(request.remote) except (KeyError, ValueError): pass if request.remote in ip_block: logger.warning( f'IP blocked due to exceeded number of logins attempts: {request.remote}' ) raise_if_exc(WazuhPermissionError(6000)) if request.remote not in ip_stats.keys(): ip_stats[request.remote] = dict() ip_stats[request.remote]['attempts'] = 1 ip_stats[request.remote]['timestamp'] = time() else: ip_stats[request.remote]['attempts'] += 1 if ip_stats[request.remote]['attempts'] >= attempts: ip_block.add(request.remote)
def list_handler(result: AffectedItemsWazuhResult, original: dict = None, allowed: dict = None, target: dict = None, add_denied: bool = False, **post_proc_kwargs): """ Post processor for framework list responses with affected items and optional denied items :param result: Dict with affected_items, failed_items and str_priority :param original: Original input call parameter values :param allowed: Allowed input call parameter values :param target: Name of the input parameters used to calculate resource access :param add_denied: Flag to add denied permissions to answer :return: AffectedItemsWazuhResult """ if add_denied: for res_id, target_param in target.items(): denied = _get_denied(original, allowed, target_param, res_id) if res_id in integer_resources: denied = {int(i) if i.isdigit() else i for i in denied} for denied_item in denied: result.add_failed_item( id_=denied_item, error=WazuhPermissionError( 4000, extra_message=f'Resource type: {res_id}', ids=denied)) else: if 'default_result_kwargs' in post_proc_kwargs and result is None: return AffectedItemsWazuhResult( **post_proc_kwargs['default_result_kwargs']) if 'exclude_codes' in post_proc_kwargs: result.remove_failed_items(post_proc_kwargs['exclude_codes']) return result
async def revoke_all_tokens(request, pretty: bool = False): """Revoke all tokens Parameters ---------- pretty : bool, optional Show results in human-readable format Returns ------- dict Status message """ f_kwargs = {} nodes = await get_system_nodes() if isinstance(nodes, Exception): nodes = None dapi = DistributedAPI(f=security.wrapper_revoke_tokens, f_kwargs=remove_nones_to_dict(f_kwargs), request_type='distributed_master' if nodes is not None else 'local_any', is_async=False, broadcasting=nodes is not None, wait_for_complete=True, logger=logger, rbac_permissions=request['token_info']['rbac_policies'], nodes=nodes ) data = raise_if_exc(await dapi.distribute_function()) if type(data) == AffectedItemsWazuhResult and len(data.affected_items) == 0: raise_if_exc(WazuhPermissionError(4000, data.message)) return web.json_response(data=data, status=200, dumps=prettify if pretty else dumps)
def wrapper(*args, **kwargs): original_kwargs = dict(kwargs) target_params, req_permissions, add_denied = \ _get_required_permissions(actions=actions, resources=resources, **kwargs) allow = _match_permissions(req_permissions=req_permissions, rbac_mode=rbac.get()['rbac_mode']) skip_execution = False for res_id, target_param in target_params.items(): try: if target_param in original_kwargs and not isinstance( original_kwargs[target_param], list): if original_kwargs[target_param] is not None: original_kwargs[target_param] = [ original_kwargs[target_param] ] # We don't have any permissions over the required resources if len(allow[res_id]) == 0 and \ original_kwargs.get(target_param, None) is not None and \ len(original_kwargs[target_param]) != 0: raise Exception if target_param != '*': # No resourceless and not static if target_param in original_kwargs and original_kwargs[ target_param] is not None: kwargs[target_param] = list( filter(lambda x: x in allow[res_id], original_kwargs[target_param])) else: kwargs[target_param] = list(allow[res_id]) elif len(allow[res_id]) == 0: raise Exception except Exception: if add_denied: denied = _get_denied(original_kwargs, allow, target_param, res_id, resources=resources) raise WazuhPermissionError( 4000, extra_message=f'Resource type: {res_id}', ids=denied, title="Permission Denied") else: if target_param != '*': kwargs[target_param] = list() else: skip_execution = True result = func(*args, **kwargs) if not skip_execution else None if post_proc_func is None: return result else: return post_proc_func(result, original=original_kwargs, allowed=allow, target=target_params, add_denied=add_denied, **post_proc_kwargs)
async def unlock_ip(request, block_time): """This function blocks/unblocks the IPs that are requesting an API token""" global ip_block, ip_stats try: if time() - block_time >= ip_stats[request.remote]['timestamp']: ip_stats.pop(request.remote) ip_block.remove(request.remote) except (KeyError, ValueError): pass if request.remote in ip_block: logger.warning(f'IP blocked due to exceeded number of logins attempts: {request.remote}') raise_if_exc(WazuhPermissionError(6000))
def list_handler(result: AffectedItemsWazuhResult, original: dict = None, allowed: dict = None, target: dict = None, add_denied: bool = False, **post_proc_kwargs): """Post processor for framework list responses with affected items and optional denied items. Parameters ---------- result : AffectedItemsWazuhResult Dict with affected_items, failed_items and str_priority. original : dict Original input call parameter values. allowed : dict Allowed input call parameter values. target : dict Name of the input parameters used to calculate resource access. add_denied : bool Flag to add denied permissions to answer. post_proc_kwargs : dict Additional kwargs used in post-processing. Returns ------- AffectedItemsWazuhResult """ if add_denied: for res_id, target_param in target.items(): denied = _get_denied(original, allowed, target_param, res_id) if res_id in integer_resources: denied = {int(i) if i.isdigit() else i for i in denied} for denied_item in denied: result.add_failed_item( id_=denied_item, error=WazuhPermissionError( 4000, extra_message=f'Resource type: {res_id}', ids=denied)) if not add_denied or post_proc_kwargs.get('force'): # Apply post processing exclusion/default values if the main resource was not explicit or # `force` parameter exists in `post_proc_kwargs` and is True if 'default_result_kwargs' in post_proc_kwargs and result is None: return AffectedItemsWazuhResult( **post_proc_kwargs['default_result_kwargs']) if 'exclude_codes' in post_proc_kwargs: result.remove_failed_items(post_proc_kwargs['exclude_codes']) return result
def get_permissions(user_id=None, auth_context=None): with AuthenticationManager() as auth: if not auth.user_allow_run_as(user_id) and auth_context: raise WazuhPermissionError(code=6004) elif auth.user_allow_run_as(user_id): permissions, roles = optimize_resources(auth_context=auth_context, user_id=user_id) else: permissions, roles = optimize_resources(user_id=user_id) result = { 'policies': permissions, 'roles': roles } return WazuhResult(result)
def get_permissions(user_id=None, auth_context=None): """Obtain the permissions of a user using auth_context or user_id :param auth_context: Authorization context of the current user :param user_id: Username of the current user """ with AuthenticationManager() as auth: if not auth.user_allow_run_as(user_id) and auth_context: raise WazuhPermissionError(6004) elif auth.user_allow_run_as(user_id): roles = get_roles(auth_context=auth_context, user_id=user_id) else: roles = get_roles(user_id=user_id) result = {'roles': roles} return WazuhResult(result)
def get_agent_by_name(name=None, select=None): """Gets an agent by its name. :param name: Agent_name. :param select: Select fields to return. Format: {"fields":["field1","field2"]}. :return: AffectedItemsWazuhResult. """ db_query = WazuhDBQueryAgents(filters={'name': name}) data = db_query.run() try: agent = data['items'][0]['id'] return get_agents(agent_list=[agent], select=select) except IndexError: raise WazuhResourceNotFound(1754) except Exception as e: if e.code == 4000: raise WazuhPermissionError(4000) raise e
(WazuhPermissionError, 4000, ['remediation', 'code'], 403, ProblemException), (WazuhResourceNotFound, 1710, ['remediation', 'code'], 404, ProblemException), (WazuhInternalError, 1000, ['remediation', 'code'], 500, ProblemException) ]) def test_create_problem(exception_type, code, extra_fields, returned_code, returned_exception): """Check that _create_problem returns exception with expected data""" with pytest.raises(returned_exception) as exc_info: util._create_problem(exception_type(code)) if returned_exception == ProblemException: assert exc_info.value.status == returned_code if extra_fields: assert all(x in exc_info.value.ext.keys() for x in extra_fields) assert None not in exc_info.value.ext.values() @pytest.mark.parametrize('obj, code', [ ((WazuhError(6001), ['value0', 'value1']), 429), ((WazuhInternalError(1000), ['value0', 'value1']), None), ((WazuhPermissionError(4000), ['value0', 'value1']), None), ((WazuhResourceNotFound(1710), ['value0', 'value1']), None) ]) @patch('api.util._create_problem') def test_raise_if_exc(mock_create_problem, obj, code): """Check that raise_if_exc calls _create_problem when an exception is given""" result = util.raise_if_exc(obj) if isinstance(obj, Exception): mock_create_problem.assert_called_once_with(obj, code) else: assert result == obj
async def test_middlewares_unlock_ip_ko(time_mock): """Test if `unlock_ip` raises an exception if the IP is still blocked.""" with patch("api.middlewares.raise_if_exc") as raise_mock: await unlock_ip(DummyRequest({'remote': "ip"}), 5) raise_mock.assert_called_once_with(WazuhPermissionError(6000))