Remove thread-local AuthenticatedApiUser & pass it as param instead

This commit is contained in:
Yonas Habteab 2025-09-15 11:17:45 +02:00
parent 5ca244c72f
commit 047f44a3b3
6 changed files with 86 additions and 63 deletions

View File

@ -53,8 +53,11 @@ Dictionary::Ptr ApiActions::CreateResult(int code, const String& status,
return result;
}
Dictionary::Ptr ApiActions::ProcessCheckResult(const ConfigObject::Ptr& object,
const Dictionary::Ptr& params)
Dictionary::Ptr ApiActions::ProcessCheckResult(
const ConfigObject::Ptr& object,
const ApiUser::Ptr&,
const Dictionary::Ptr& params
)
{
using Result = Checkable::ProcessingResult;
@ -140,8 +143,11 @@ Dictionary::Ptr ApiActions::ProcessCheckResult(const ConfigObject::Ptr& object,
return ApiActions::CreateResult(500, "Unexpected result (" + std::to_string(static_cast<int>(result)) + ") for object '" + checkable->GetName() + "'. Please submit a bug report at https://github.com/Icinga/icinga2");
}
Dictionary::Ptr ApiActions::RescheduleCheck(const ConfigObject::Ptr& object,
const Dictionary::Ptr& params)
Dictionary::Ptr ApiActions::RescheduleCheck(
const ConfigObject::Ptr& object,
const ApiUser::Ptr&,
const Dictionary::Ptr& params
)
{
Checkable::Ptr checkable = static_pointer_cast<Checkable>(object);
@ -165,8 +171,11 @@ Dictionary::Ptr ApiActions::RescheduleCheck(const ConfigObject::Ptr& object,
return ApiActions::CreateResult(200, "Successfully rescheduled check for object '" + checkable->GetName() + "'.");
}
Dictionary::Ptr ApiActions::SendCustomNotification(const ConfigObject::Ptr& object,
const Dictionary::Ptr& params)
Dictionary::Ptr ApiActions::SendCustomNotification(
const ConfigObject::Ptr& object,
const ApiUser::Ptr&,
const Dictionary::Ptr& params
)
{
Checkable::Ptr checkable = static_pointer_cast<Checkable>(object);
@ -188,8 +197,11 @@ Dictionary::Ptr ApiActions::SendCustomNotification(const ConfigObject::Ptr& obje
return ApiActions::CreateResult(200, "Successfully sent custom notification for object '" + checkable->GetName() + "'.");
}
Dictionary::Ptr ApiActions::DelayNotification(const ConfigObject::Ptr& object,
const Dictionary::Ptr& params)
Dictionary::Ptr ApiActions::DelayNotification(
const ConfigObject::Ptr& object,
const ApiUser::Ptr&,
const Dictionary::Ptr& params
)
{
Checkable::Ptr checkable = static_pointer_cast<Checkable>(object);
@ -206,8 +218,11 @@ Dictionary::Ptr ApiActions::DelayNotification(const ConfigObject::Ptr& object,
return ApiActions::CreateResult(200, "Successfully delayed notifications for object '" + checkable->GetName() + "'.");
}
Dictionary::Ptr ApiActions::AcknowledgeProblem(const ConfigObject::Ptr& object,
const Dictionary::Ptr& params)
Dictionary::Ptr ApiActions::AcknowledgeProblem(
const ConfigObject::Ptr& object,
const ApiUser::Ptr&,
const Dictionary::Ptr& params
)
{
Checkable::Ptr checkable = static_pointer_cast<Checkable>(object);
@ -268,8 +283,11 @@ Dictionary::Ptr ApiActions::AcknowledgeProblem(const ConfigObject::Ptr& object,
return ApiActions::CreateResult(200, "Successfully acknowledged problem for object '" + checkable->GetName() + "'.");
}
Dictionary::Ptr ApiActions::RemoveAcknowledgement(const ConfigObject::Ptr& object,
const Dictionary::Ptr& params)
Dictionary::Ptr ApiActions::RemoveAcknowledgement(
const ConfigObject::Ptr& object,
const ApiUser::Ptr&,
const Dictionary::Ptr& params
)
{
Checkable::Ptr checkable = static_pointer_cast<Checkable>(object);
@ -292,8 +310,11 @@ Dictionary::Ptr ApiActions::RemoveAcknowledgement(const ConfigObject::Ptr& objec
return ApiActions::CreateResult(200, "Successfully removed acknowledgement for object '" + checkable->GetName() + "'.");
}
Dictionary::Ptr ApiActions::AddComment(const ConfigObject::Ptr& object,
const Dictionary::Ptr& params)
Dictionary::Ptr ApiActions::AddComment(
const ConfigObject::Ptr& object,
const ApiUser::Ptr&,
const Dictionary::Ptr& params
)
{
Checkable::Ptr checkable = static_pointer_cast<Checkable>(object);
@ -331,8 +352,11 @@ Dictionary::Ptr ApiActions::AddComment(const ConfigObject::Ptr& object,
+ "'.", additional);
}
Dictionary::Ptr ApiActions::RemoveComment(const ConfigObject::Ptr& object,
const Dictionary::Ptr& params)
Dictionary::Ptr ApiActions::RemoveComment(
const ConfigObject::Ptr& object,
const ApiUser::Ptr&,
const Dictionary::Ptr& params
)
{
ConfigObjectsSharedLock lock (std::try_to_lock);
@ -365,8 +389,11 @@ Dictionary::Ptr ApiActions::RemoveComment(const ConfigObject::Ptr& object,
return ApiActions::CreateResult(200, "Successfully removed comment '" + commentName + "'.");
}
Dictionary::Ptr ApiActions::ScheduleDowntime(const ConfigObject::Ptr& object,
const Dictionary::Ptr& params)
Dictionary::Ptr ApiActions::ScheduleDowntime(
const ConfigObject::Ptr& object,
const ApiUser::Ptr&,
const Dictionary::Ptr& params
)
{
Checkable::Ptr checkable = static_pointer_cast<Checkable>(object);
@ -535,8 +562,11 @@ Dictionary::Ptr ApiActions::ScheduleDowntime(const ConfigObject::Ptr& object,
downtimeName + "' for object '" + checkable->GetName() + "'.", additional);
}
Dictionary::Ptr ApiActions::RemoveDowntime(const ConfigObject::Ptr& object,
const Dictionary::Ptr& params)
Dictionary::Ptr ApiActions::RemoveDowntime(
const ConfigObject::Ptr& object,
const ApiUser::Ptr&,
const Dictionary::Ptr& params
)
{
ConfigObjectsSharedLock lock (std::try_to_lock);
@ -588,24 +618,21 @@ Dictionary::Ptr ApiActions::RemoveDowntime(const ConfigObject::Ptr& object,
}
}
Dictionary::Ptr ApiActions::ShutdownProcess(const ConfigObject::Ptr& object,
const Dictionary::Ptr& params)
Dictionary::Ptr ApiActions::ShutdownProcess(const ConfigObject::Ptr&, const ApiUser::Ptr&, const Dictionary::Ptr&)
{
Application::RequestShutdown();
return ApiActions::CreateResult(200, "Shutting down Icinga 2.");
}
Dictionary::Ptr ApiActions::RestartProcess(const ConfigObject::Ptr& object,
const Dictionary::Ptr& params)
Dictionary::Ptr ApiActions::RestartProcess(const ConfigObject::Ptr&, const ApiUser::Ptr&, const Dictionary::Ptr&)
{
Application::RequestRestart();
return ApiActions::CreateResult(200, "Restarting Icinga 2.");
}
Dictionary::Ptr ApiActions::GenerateTicket(const ConfigObject::Ptr&,
const Dictionary::Ptr& params)
Dictionary::Ptr ApiActions::GenerateTicket(const ConfigObject::Ptr&, const ApiUser::Ptr&, const Dictionary::Ptr& params)
{
if (!params->Contains("cn"))
return ApiActions::CreateResult(400, "Option 'cn' is required");
@ -653,7 +680,11 @@ Value ApiActions::GetSingleObjectByNameUsingPermissions(const String& type, cons
return objs.at(0);
};
Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, const Dictionary::Ptr& params)
Dictionary::Ptr ApiActions::ExecuteCommand(
const ConfigObject::Ptr& object,
const ApiUser::Ptr& apiUser,
const Dictionary::Ptr& params
)
{
ApiListener::Ptr listener = ApiListener::GetInstance();
@ -717,11 +748,11 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, cons
nullptr, MacroProcessor::EscapeCallback(), nullptr, false
);
if (!ActionsHandler::AuthenticatedApiUser)
if (!apiUser)
BOOST_THROW_EXCEPTION(std::invalid_argument("Can't find API user."));
/* Get endpoint */
Endpoint::Ptr endpointPtr = GetSingleObjectByNameUsingPermissions(Endpoint::GetTypeName(), resolved_endpoint, ActionsHandler::AuthenticatedApiUser);
Endpoint::Ptr endpointPtr = GetSingleObjectByNameUsingPermissions(Endpoint::GetTypeName(), resolved_endpoint, apiUser);
if (!endpointPtr)
return ApiActions::CreateResult(404, "Can't find a valid endpoint for '" + resolved_endpoint + "'.");
@ -779,7 +810,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, cons
Dictionary::Ptr execParams = new Dictionary();
if (command_type == "CheckCommand") {
CheckCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(CheckCommand::GetTypeName(), resolved_command, ActionsHandler::AuthenticatedApiUser);
CheckCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(CheckCommand::GetTypeName(), resolved_command, apiUser);
if (!cmd)
return ApiActions::CreateResult(404, "Can't find a valid " + command_type + " for '" + resolved_command + "'.");
@ -791,7 +822,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, cons
cmd->Execute(checkable, cr, listener->GetWaitGroup(), execMacros, false);
}
} else if (command_type == "EventCommand") {
EventCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(EventCommand::GetTypeName(), resolved_command, ActionsHandler::AuthenticatedApiUser);
EventCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(EventCommand::GetTypeName(), resolved_command, apiUser);
if (!cmd)
return ApiActions::CreateResult(404, "Can't find a valid " + command_type + " for '" + resolved_command + "'.");
@ -803,7 +834,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, cons
cmd->Execute(checkable, execMacros, false);
}
} else if (command_type == "NotificationCommand") {
NotificationCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(NotificationCommand::GetTypeName(), resolved_command, ActionsHandler::AuthenticatedApiUser);
NotificationCommand::Ptr cmd = GetSingleObjectByNameUsingPermissions(NotificationCommand::GetTypeName(), resolved_command, apiUser);
if (!cmd)
return ApiActions::CreateResult(404, "Can't find a valid " + command_type + " for '" + resolved_command + "'.");
@ -820,7 +851,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, cons
MacroProcessor::EscapeCallback(), nullptr, false
);
User::Ptr user = GetSingleObjectByNameUsingPermissions(User::GetTypeName(), resolved_user, ActionsHandler::AuthenticatedApiUser);
User::Ptr user = GetSingleObjectByNameUsingPermissions(User::GetTypeName(), resolved_user, apiUser);
if (!user)
return ApiActions::CreateResult(404, "Can't find a valid user for '" + resolved_user + "'.");
@ -839,7 +870,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, cons
MacroProcessor::EscapeCallback(), nullptr, false
);
Notification::Ptr notification = GetSingleObjectByNameUsingPermissions(Notification::GetTypeName(), resolved_notification, ActionsHandler::AuthenticatedApiUser);
Notification::Ptr notification = GetSingleObjectByNameUsingPermissions(Notification::GetTypeName(), resolved_notification, apiUser);
if (!notification)
return ApiActions::CreateResult(404, "Can't find a valid notification for '" + resolved_notification + "'.");
@ -852,7 +883,7 @@ Dictionary::Ptr ApiActions::ExecuteCommand(const ConfigObject::Ptr& object, cons
});
cmd->Execute(notification, user, cr, NotificationType::NotificationCustom,
ActionsHandler::AuthenticatedApiUser->GetName(), "", execMacros, false);
apiUser->GetName(), "", execMacros, false);
}
}

View File

@ -17,20 +17,20 @@ namespace icinga
class ApiActions
{
public:
static Dictionary::Ptr ProcessCheckResult(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr RescheduleCheck(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr SendCustomNotification(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr DelayNotification(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr AcknowledgeProblem(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr RemoveAcknowledgement(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr AddComment(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr RemoveComment(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr ScheduleDowntime(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr RemoveDowntime(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr ShutdownProcess(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr RestartProcess(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr GenerateTicket(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr ExecuteCommand(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr ProcessCheckResult(const ConfigObject::Ptr& object, const ApiUser::Ptr&, const Dictionary::Ptr& params);
static Dictionary::Ptr RescheduleCheck(const ConfigObject::Ptr& object, const ApiUser::Ptr&, const Dictionary::Ptr& params);
static Dictionary::Ptr SendCustomNotification(const ConfigObject::Ptr& object, const ApiUser::Ptr&, const Dictionary::Ptr& params);
static Dictionary::Ptr DelayNotification(const ConfigObject::Ptr& object, const ApiUser::Ptr&, const Dictionary::Ptr& params);
static Dictionary::Ptr AcknowledgeProblem(const ConfigObject::Ptr& object, const ApiUser::Ptr&, const Dictionary::Ptr& params);
static Dictionary::Ptr RemoveAcknowledgement(const ConfigObject::Ptr& object, const ApiUser::Ptr&, const Dictionary::Ptr& params);
static Dictionary::Ptr AddComment(const ConfigObject::Ptr& object, const ApiUser::Ptr&, const Dictionary::Ptr& params);
static Dictionary::Ptr RemoveComment(const ConfigObject::Ptr& object, const ApiUser::Ptr&, const Dictionary::Ptr& params);
static Dictionary::Ptr ScheduleDowntime(const ConfigObject::Ptr& object, const ApiUser::Ptr&, const Dictionary::Ptr& params);
static Dictionary::Ptr RemoveDowntime(const ConfigObject::Ptr& object, const ApiUser::Ptr&, const Dictionary::Ptr& params);
static Dictionary::Ptr ShutdownProcess(const ConfigObject::Ptr&, const ApiUser::Ptr&, const Dictionary::Ptr&);
static Dictionary::Ptr RestartProcess(const ConfigObject::Ptr&, const ApiUser::Ptr&, const Dictionary::Ptr&);
static Dictionary::Ptr GenerateTicket(const ConfigObject::Ptr& object, const ApiUser::Ptr&, const Dictionary::Ptr& params);
static Dictionary::Ptr ExecuteCommand(const ConfigObject::Ptr& object, const ApiUser::Ptr& apiUser, const Dictionary::Ptr& params);
private:
static Dictionary::Ptr CreateResult(int code, const String& status, const Dictionary::Ptr& additional = nullptr);

View File

@ -11,8 +11,6 @@
using namespace icinga;
thread_local ApiUser::Ptr ActionsHandler::AuthenticatedApiUser;
REGISTER_URLHANDLER("/v1/actions", ActionsHandler);
bool ActionsHandler::HandleRequest(
@ -79,11 +77,6 @@ bool ActionsHandler::HandleRequest(
bool verbose = false;
ActionsHandler::AuthenticatedApiUser = user;
Defer a ([]() {
ActionsHandler::AuthenticatedApiUser = nullptr;
});
if (params)
verbose = HttpUtility::GetLastParameter(params, "verbose");
@ -110,7 +103,7 @@ bool ActionsHandler::HandleRequest(
}
try {
results.emplace_back(action->Invoke(obj, params));
results.emplace_back(action->Invoke(obj, user, params));
} catch (const std::exception& ex) {
Dictionary::Ptr fail = new Dictionary({
{ "code", 500 },

View File

@ -13,8 +13,6 @@ class ActionsHandler final : public HttpHandler
public:
DECLARE_PTR_TYPEDEFS(ActionsHandler);
static thread_local ApiUser::Ptr AuthenticatedApiUser;
bool HandleRequest(
const WaitGroup::Ptr& waitGroup,
const HttpRequest& request,

View File

@ -9,9 +9,9 @@ ApiAction::ApiAction(std::vector<String> types, Callback action)
: m_Types(std::move(types)), m_Callback(std::move(action))
{ }
Value ApiAction::Invoke(const ConfigObject::Ptr& target, const Dictionary::Ptr& params)
Value ApiAction::Invoke(const ConfigObject::Ptr& target, const ApiUser::Ptr& user, const Dictionary::Ptr& params)
{
return m_Callback(target, params);
return m_Callback(target, user, params);
}
const std::vector<String>& ApiAction::GetTypes() const

View File

@ -8,6 +8,7 @@
#include "base/value.hpp"
#include "base/dictionary.hpp"
#include "base/configobject.hpp"
#include "remote/apiuser.hpp"
#include <vector>
#include <boost/algorithm/string/replace.hpp>
@ -24,11 +25,11 @@ class ApiAction final : public Object
public:
DECLARE_PTR_TYPEDEFS(ApiAction);
typedef std::function<Value(const ConfigObject::Ptr& target, const Dictionary::Ptr& params)> Callback;
typedef std::function<Value(const ConfigObject::Ptr& target, const ApiUser::Ptr&, const Dictionary::Ptr& params)> Callback;
ApiAction(std::vector<String> registerTypes, Callback function);
Value Invoke(const ConfigObject::Ptr& target, const Dictionary::Ptr& params);
Value Invoke(const ConfigObject::Ptr& target, const ApiUser::Ptr& user, const Dictionary::Ptr& params);
const std::vector<String>& GetTypes() const;