From 255da5b0911406f27fc69af0c74acc43522eca37 Mon Sep 17 00:00:00 2001 From: Martchus Date: Sun, 10 Jul 2022 20:08:31 +0200 Subject: [PATCH] Allow passing secrets to build action --- librepomgr/CMakeLists.txt | 2 +- librepomgr/authentication.h | 1 + librepomgr/buildactions/buildaction.cpp | 19 ++++++++++-- librepomgr/buildactions/buildaction.h | 7 ++++- librepomgr/serversetup.cpp | 5 +++- librepomgr/tests/buildactions.cpp | 5 +++- librepomgr/webapi/routes_buildaction.cpp | 14 ++++----- librepomgr/webapi/server.cpp | 6 ++-- librepomgr/webapi/session.cpp | 37 +++++++++++++++++++----- librepomgr/webapi/session.h | 26 ++++++++--------- 10 files changed, 85 insertions(+), 37 deletions(-) diff --git a/librepomgr/CMakeLists.txt b/librepomgr/CMakeLists.txt index c3aef37..5534311 100644 --- a/librepomgr/CMakeLists.txt +++ b/librepomgr/CMakeLists.txt @@ -85,7 +85,7 @@ use_cpp_utilities(VISIBILITY PUBLIC) # find passwordfile find_package(passwordfile${CONFIGURATION_PACKAGE_SUFFIX} 5.0.0 REQUIRED) -use_password_file(VISIBILITY PUBLIC) +use_password_file() # find boost libraries option(BOOST_STATIC_LINKAGE "${STATIC_LINKAGE}" "link statically against Boost (instead of dynamically)") diff --git a/librepomgr/authentication.h b/librepomgr/authentication.h index 18f6e3e..5beec57 100644 --- a/librepomgr/authentication.h +++ b/librepomgr/authentication.h @@ -13,6 +13,7 @@ enum class UserPermissions : std::uint64_t { ModifyBuildActions = ReadBuildActionsDetails | DownloadArtefacts | (1 << 2), PerformAdminActions = (1 << 3), TryAgain = (1 << 4), + AccessSecrets = (1 << 5), DefaultPermissions = ReadBuildActionsDetails, }; diff --git a/librepomgr/buildactions/buildaction.cpp b/librepomgr/buildactions/buildaction.cpp index 1613a9f..a696455 100644 --- a/librepomgr/buildactions/buildaction.cpp +++ b/librepomgr/buildactions/buildaction.cpp @@ -3,6 +3,8 @@ #include "../webapi/session.h" +#include + #include #include @@ -259,7 +261,7 @@ bool BuildAction::haveSucceeded(const std::vector> * the build action is setup-globally visible. * \returns Returns immediately. The real work is done in a build action thread. */ -LibPkg::StorageID BuildAction::start(ServiceSetup &setup) +LibPkg::StorageID BuildAction::start(ServiceSetup &setup, std::unique_ptr &&secrets) { if (!isScheduled()) { return 0; @@ -269,6 +271,13 @@ LibPkg::StorageID BuildAction::start(ServiceSetup &setup) status = BuildActionStatus::Running; m_setup = &setup; + // grab secrets from session + // note: That's done regardless of the type because we might need to pass the secrets to the next + // action in the chain (regardless of the current build action's type). + if (secrets) { + m_secrets = std::move(secrets); + } + switch (type) { case BuildActionType::Invalid: resultData = "type is invalid"; @@ -366,7 +375,13 @@ LibPkg::StorageID BuildAction::conclude(BuildActionResult result) const auto followUps = m_setup->building.followUpBuildActions(id); for (auto &followUpAction : followUps) { if (followUpAction->isScheduled() && BuildAction::haveSucceeded(m_setup->building.getBuildActions(followUpAction->startAfter))) { - followUpAction->start(*m_setup); + auto secrets = std::unique_ptr(); + if (m_secrets) { + secrets = std::make_unique(); + secrets->setPath(m_secrets->path()); + secrets->setPassword(m_secrets->password()); + } + followUpAction->start(*m_setup, std::move(secrets)); } } // note: Not cleaning up the follow-up actions here because at some point I might implement recursive restarting. diff --git a/librepomgr/buildactions/buildaction.h b/librepomgr/buildactions/buildaction.h index 44ffb45..07b179e 100644 --- a/librepomgr/buildactions/buildaction.h +++ b/librepomgr/buildactions/buildaction.h @@ -36,6 +36,10 @@ class BuildActionsTests; +namespace Io { +class PasswordFile; +} + namespace LibRepoMgr { struct ServiceSetup; @@ -208,7 +212,7 @@ public: static bool haveSucceeded(const std::vector> &buildActions); bool isAborted() const; const std::atomic_bool &aborted() const; - LibPkg::StorageID start(ServiceSetup &setup); + LibPkg::StorageID start(ServiceSetup &setup, std::unique_ptr &&secrets); void assignStartAfter(const std::vector> &startsAfterBuildActions); void abort(); void appendOutput(std::string_view output); @@ -256,6 +260,7 @@ private: std::mutex m_outputSessionMutex; std::shared_ptr m_outputSession; std::unique_ptr m_internalBuildAction; + std::unique_ptr m_secrets; }; inline bool BuildActionBase::isScheduled() const diff --git a/librepomgr/serversetup.cpp b/librepomgr/serversetup.cpp index 199e7b2..09418b8 100644 --- a/librepomgr/serversetup.cpp +++ b/librepomgr/serversetup.cpp @@ -15,6 +15,8 @@ #include #include +#include + #include #include #include @@ -307,7 +309,8 @@ StorageID ServiceSetup::BuildSetup::storeBuildAction(const std::shared_ptrsetup()) { - return buildAction->start(*buildAction->setup()); + // FIXME: Do we actually ever get here? + return buildAction->start(*buildAction->setup(), std::unique_ptr()); } } else { for (const auto id : buildAction->startAfter) { diff --git a/librepomgr/tests/buildactions.cpp b/librepomgr/tests/buildactions.cpp index 903bf56..2f2a18e 100644 --- a/librepomgr/tests/buildactions.cpp +++ b/librepomgr/tests/buildactions.cpp @@ -8,6 +8,8 @@ #include "../buildactions/buildactionprivate.h" #include "../buildactions/subprocess.h" +#include + #include #include #include @@ -72,6 +74,7 @@ private: std::string m_configDbFile, m_buildingDbFile; ServiceSetup m_setup; + std::unique_ptr m_secrets; std::shared_ptr m_buildAction; std::filesystem::path m_workingDir; double m_timeoutFactor = 0.0; @@ -190,7 +193,7 @@ void BuildActionsTests::resetBuildAction() void BuildActionsTests::runBuildAction(const char *message, CppUtilities::TimeSpan timeout) { resetBuildAction(); - m_buildAction->start(m_setup); + m_buildAction->start(m_setup, std::move(m_secrets)); auto &ioc = m_setup.building.ioContext; ioc.restart(); boost::asio::executor_work_guard workGuard = boost::asio::make_work_guard(ioc); diff --git a/librepomgr/webapi/routes_buildaction.cpp b/librepomgr/webapi/routes_buildaction.cpp index 4139361..0155a3a 100644 --- a/librepomgr/webapi/routes_buildaction.cpp +++ b/librepomgr/webapi/routes_buildaction.cpp @@ -279,7 +279,7 @@ void postBuildAction(const Params ¶ms, ResponseHandler &&handler) // start build action immediately or just add to setup-global list for now auto buildLock2 = params.setup.building.lockToWrite(); if (startImmediately) { - buildAction->start(params.setup); + buildAction->start(params.setup, params.session.secrets()); } else { params.setup.building.storeBuildAction(buildAction); } @@ -385,7 +385,7 @@ static std::vector> allocateBuildActionIDs(ServiceS return previousActions; } -static bool startFirstBuildActions(ServiceSetup &setup, SequencedBuildActions &newActionSequence) +static bool startFirstBuildActions(const Params ¶ms, SequencedBuildActions &newActionSequence) { auto handledFirstAction = false; for (auto &sequencedAction : newActionSequence.actions) { @@ -393,13 +393,13 @@ static bool startFirstBuildActions(ServiceSetup &setup, SequencedBuildActions &n auto &action = *maybeAction; handledFirstAction = true; if (action->isScheduled()) { - action->start(setup); + action->start(params.setup, params.session.secrets()); } if (!newActionSequence.concurrent) { return true; } } else if (auto *const subSequence = std::get_if(&sequencedAction)) { - if (startFirstBuildActions(setup, *subSequence) && !newActionSequence.concurrent) { + if (startFirstBuildActions(params, *subSequence) && !newActionSequence.concurrent) { return true; } } @@ -475,7 +475,7 @@ void postBuildActionsFromTask(const Params ¶ms, ResponseHandler &&handler, c // start first build action immediately (read-lock sufficient because build action not part of setup-global list yet) if (startNow) { - startFirstBuildActions(params.setup, newActionSequence); + startFirstBuildActions(params, newActionSequence); } // add build actions to setup-global list @@ -547,7 +547,7 @@ void postCloneBuildActions(const Params ¶ms, ResponseHandler &&handler) clone->type = orig->type; clone->startAfter = orig->startAfter; if (startImmediately) { - clone->start(params.setup); + clone->start(params.setup, params.session.secrets()); } params.setup.building.storeBuildAction(std::move(clone)); cloneIds.emplace_back(id); @@ -572,7 +572,7 @@ void postStartBuildActions(const Params ¶ms, ResponseHandler &&handler) return; } for (auto &action : buildActionsSearchResult.actions) { - action->start(params.setup); + action->start(params.setup, params.session.secrets()); } buildActionsSearchResult.lock = std::monostate{}; handler(makeText(params.request(), "ok")); diff --git a/librepomgr/webapi/server.cpp b/librepomgr/webapi/server.cpp index 782fd23..6b9a103 100644 --- a/librepomgr/webapi/server.cpp +++ b/librepomgr/webapi/server.cpp @@ -35,9 +35,9 @@ const Router Server::s_router = { { { http::verb::get, "/api/v0/build-action/details" }, Route{&Routes::getBuildActionDetails, UserPermissions::ReadBuildActionsDetails} }, { { http::verb::get, "/api/v0/build-action/logfile" }, Route{&Routes::getBuildActionLogFile, UserPermissions::ReadBuildActionsDetails} }, { { http::verb::get, "/api/v0/build-action/artefact" }, Route{&Routes::getBuildActionArtefact, UserPermissions::DownloadArtefacts} }, - { { http::verb::post, "/api/v0/build-action" }, Route{&Routes::postBuildAction, UserPermissions::ModifyBuildActions} }, - { { http::verb::post, "/api/v0/build-action/clone" }, Route{&Routes::postCloneBuildActions, UserPermissions::ModifyBuildActions} }, - { { http::verb::post, "/api/v0/build-action/start" }, Route{&Routes::postStartBuildActions, UserPermissions::ModifyBuildActions} }, + { { http::verb::post, "/api/v0/build-action" }, Route{&Routes::postBuildAction, UserPermissions::ModifyBuildActions | UserPermissions::AccessSecrets} }, + { { http::verb::post, "/api/v0/build-action/clone" }, Route{&Routes::postCloneBuildActions, UserPermissions::ModifyBuildActions | UserPermissions::AccessSecrets} }, + { { http::verb::post, "/api/v0/build-action/start" }, Route{&Routes::postStartBuildActions, UserPermissions::ModifyBuildActions | UserPermissions::AccessSecrets} }, { { http::verb::post, "/api/v0/build-action/stop" }, Route{&Routes::postStopBuildActions, UserPermissions::ModifyBuildActions} }, { { http::verb::post, "/api/v0/quit" }, Route{&Routes::postQuit, UserPermissions::PerformAdminActions} }, }; diff --git a/librepomgr/webapi/session.cpp b/librepomgr/webapi/session.cpp index 9fd1751..e9880e2 100644 --- a/librepomgr/webapi/session.cpp +++ b/librepomgr/webapi/session.cpp @@ -7,6 +7,8 @@ #include "../serversetup.h" +#include + #include #include #include @@ -22,6 +24,17 @@ using namespace CppUtilities::EscapeCodes; namespace LibRepoMgr { namespace WebAPI { +Session::Session(boost::asio::ip::tcp::socket &&socket, ServiceSetup &setup) + : m_socket(std::move(socket)) + , m_strand(m_socket.get_executor()) + , m_setup(setup) +{ +} + +Session::~Session() +{ +} + void Session::receive() { m_parser = make_unique(); @@ -89,13 +102,19 @@ void Session::received(boost::system::error_code ec, size_t bytesTransferred) return; } // prepare file with secrets for user - if(!userAuth.name.empty() && !userAuth.password.empty()) { + if (!userAuth.name.empty() && !userAuth.password.empty() + && (static_cast(requiredPermissions) & static_cast(UserPermissions::AccessSecrets))) { try { - m_secrets.clear(); - m_secrets.setPath(argsToString("secrets/"sv, userAuth.name)); - m_secrets.setPassword(userAuth.password.data(), userAuth.password.size()); + if (m_secrets) { + m_secrets->clear(); + } else { + m_secrets = std::make_unique(); + } + m_secrets->setPath(argsToString("secrets/"sv, userAuth.name)); + m_secrets->setPassword(userAuth.password.data(), userAuth.password.size()); } catch (const std::ios_base::failure &e) { - cerr << Phrases::WarningMessage << "Failed to close password file \"" << m_secrets.path() << "\" (before preparing new one): " << e.what() << Phrases::End; + cerr << Phrases::WarningMessage << "Failed to close password file \"" << m_secrets->path() + << "\" (before preparing new one): " << e.what() << Phrases::End; } } } @@ -112,10 +131,12 @@ void Session::received(boost::system::error_code ec, size_t bytesTransferred) // discard password; secrets are expected to be read on the immediate call of the route try { - m_secrets.clearPassword(); - m_secrets.close(); + if (m_secrets) { + m_secrets->clearPassword(); + m_secrets->close(); + } } catch (const std::ios_base::failure &e) { - cerr << Phrases::WarningMessage << "Failed to close password file \"" << m_secrets.path() << "\": " << e.what() << Phrases::End; + cerr << Phrases::WarningMessage << "Failed to close password file \"" << m_secrets->path() << "\": " << e.what() << Phrases::End; } return; } diff --git a/librepomgr/webapi/session.h b/librepomgr/webapi/session.h index 47d0d5c..b0d88d7 100644 --- a/librepomgr/webapi/session.h +++ b/librepomgr/webapi/session.h @@ -3,7 +3,7 @@ #include "./typedefs.h" -#include +#include "../global.h" #include #include @@ -12,15 +12,22 @@ #include #include +#include + +namespace Io { +class PasswordFile; +} + namespace LibRepoMgr { struct ServiceSetup; namespace WebAPI { -class Session : public std::enable_shared_from_this { +class LIBREPOMGR_EXPORT Session : public std::enable_shared_from_this { public: Session(boost::asio::ip::tcp::socket &&socket, ServiceSetup &config); + ~Session(); void receive(); void respond(std::shared_ptr &&response); @@ -33,7 +40,7 @@ public: void received(boost::system::error_code ec, std::size_t bytesTransferred); void responded(boost::system::error_code ec, std::size_t bytesTransferred, bool shouldClose); static boost::beast::string_view determineMimeType(std::string_view path, boost::beast::string_view fallback = "text/plain"); - Io::PasswordFile &secrets(); + std::unique_ptr &&secrets(); private: boost::asio::ip::tcp::socket m_socket; @@ -42,16 +49,9 @@ private: std::unique_ptr m_parser; ServiceSetup &m_setup; std::shared_ptr m_res; - Io::PasswordFile m_secrets; + std::unique_ptr m_secrets; }; -inline Session::Session(boost::asio::ip::tcp::socket &&socket, ServiceSetup &setup) - : m_socket(std::move(socket)) - , m_strand(m_socket.get_executor()) - , m_setup(setup) -{ -} - inline const Request &Session::request() const { return m_parser->get(); @@ -67,9 +67,9 @@ inline boost::asio::ip::tcp::socket &Session::socket() return m_socket; } -inline Io::PasswordFile &Session::secrets() +inline std::unique_ptr &&Session::secrets() { - return m_secrets; + return std::move(m_secrets); } } // namespace WebAPI