diff options
author | Ed Tanous <edtanous@google.com> | 2023-04-06 23:10:02 +0300 |
---|---|---|
committer | Ed Tanous <ed@tanous.net> | 2023-06-09 22:13:40 +0300 |
commit | 08bbe1199f02d09f908cd3adcf4329e4bd67fd52 (patch) | |
tree | 9824a615569928f65523f13a876a0def301562dd /include | |
parent | b90d14f220cba6de26dcf8749b2f8df062487d72 (diff) | |
download | bmcweb-08bbe1199f02d09f908cd3adcf4329e4bd67fd52.tar.xz |
Break up router into separate files
The router is a giant behemoth. Start breaking it down into pieces.
Tested: Redfish service validator passes.
Signed-off-by: Ed Tanous <edtanous@google.com>
Change-Id: I9d04f53a58ffce3ecbd88dded1aa6e9648d2a762
Diffstat (limited to 'include')
-rw-r--r-- | include/dbus_privileges.hpp | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/include/dbus_privileges.hpp b/include/dbus_privileges.hpp new file mode 100644 index 0000000000..377a41cbee --- /dev/null +++ b/include/dbus_privileges.hpp @@ -0,0 +1,180 @@ +#pragma once + +#include "dbus_utility.hpp" +#include "error_messages.hpp" +#include "http_request.hpp" +#include "http_response.hpp" +#include "logging.hpp" +#include "routing/baserule.hpp" +#include "utils/dbus_utils.hpp" + +#include <boost/url/format.hpp> +#include <sdbusplus/unpack_properties.hpp> + +#include <memory> +#include <vector> + +namespace crow +{ +// Populate session with user information. +inline bool + populateUserInfo(Request& req, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + const dbus::utility::DBusPropertiesMap& userInfoMap) +{ + const std::string* userRolePtr = nullptr; + const bool* remoteUser = nullptr; + const bool* passwordExpired = nullptr; + const std::vector<std::string>* userGroups = nullptr; + + const bool success = sdbusplus::unpackPropertiesNoThrow( + redfish::dbus_utils::UnpackErrorPrinter(), userInfoMap, "UserPrivilege", + userRolePtr, "RemoteUser", remoteUser, "UserPasswordExpired", + passwordExpired, "UserGroups", userGroups); + + if (!success) + { + BMCWEB_LOG_ERROR << "Failed to unpack user properties."; + asyncResp->res.result( + boost::beast::http::status::internal_server_error); + return false; + } + + if (userRolePtr != nullptr) + { + req.session->userRole = *userRolePtr; + BMCWEB_LOG_DEBUG << "userName = " << req.session->username + << " userRole = " << *userRolePtr; + } + + if (remoteUser == nullptr) + { + BMCWEB_LOG_ERROR << "RemoteUser property missing or wrong type"; + asyncResp->res.result( + boost::beast::http::status::internal_server_error); + return false; + } + bool expired = false; + if (passwordExpired == nullptr) + { + if (!*remoteUser) + { + BMCWEB_LOG_ERROR << "UserPasswordExpired property is expected for" + " local user but is missing or wrong type"; + asyncResp->res.result( + boost::beast::http::status::internal_server_error); + return false; + } + } + else + { + expired = *passwordExpired; + } + + // Set isConfigureSelfOnly based on D-Bus results. This + // ignores the results from both pamAuthenticateUser and the + // value from any previous use of this session. + req.session->isConfigureSelfOnly = expired; + + if (userGroups != nullptr) + { + // Populate session with user groups. + for (const auto& userGroup : *userGroups) + { + req.session->userGroups.emplace_back(userGroup); + } + } + + return true; +} + +inline bool + isUserPrivileged(Request& req, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + BaseRule& rule) +{ + // Get the user's privileges from the role + redfish::Privileges userPrivileges = + redfish::getUserPrivileges(*req.session); + + // Modify privileges if isConfigureSelfOnly. + if (req.session->isConfigureSelfOnly) + { + // Remove all privileges except ConfigureSelf + userPrivileges = + userPrivileges.intersection(redfish::Privileges{"ConfigureSelf"}); + BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf"; + } + + if (!rule.checkPrivileges(userPrivileges)) + { + asyncResp->res.result(boost::beast::http::status::forbidden); + if (req.session->isConfigureSelfOnly) + { + redfish::messages::passwordChangeRequired( + asyncResp->res, + boost::urls::format("/redfish/v1/AccountService/Accounts/{}", + req.session->username)); + } + return false; + } + + req.userRole = req.session->userRole; + return true; +} + +template <typename CallbackFn> +void afterGetUserInfo(Request& req, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + BaseRule& rule, CallbackFn&& callback, + const boost::system::error_code& ec, + const dbus::utility::DBusPropertiesMap& userInfoMap) +{ + if (ec) + { + BMCWEB_LOG_ERROR << "GetUserInfo failed..."; + asyncResp->res.result( + boost::beast::http::status::internal_server_error); + return; + } + + if (!populateUserInfo(req, asyncResp, userInfoMap)) + { + BMCWEB_LOG_ERROR << "Failed to populate user information"; + asyncResp->res.result( + boost::beast::http::status::internal_server_error); + return; + } + + if (!isUserPrivileged(req, asyncResp, rule)) + { + // User is not privileged + BMCWEB_LOG_ERROR << "Insufficient Privilege"; + asyncResp->res.result(boost::beast::http::status::forbidden); + return; + } + callback(req); +} + +template <typename CallbackFn> +void validatePrivilege(Request& req, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + BaseRule& rule, CallbackFn&& callback) +{ + if (req.session == nullptr) + { + return; + } + std::string username = req.session->username; + crow::connections::systemBus->async_method_call( + [&req, asyncResp, &rule, callback(std::forward<CallbackFn>(callback))]( + const boost::system::error_code& ec, + const dbus::utility::DBusPropertiesMap& userInfoMap) mutable { + afterGetUserInfo(req, asyncResp, rule, + std::forward<CallbackFn>(callback), ec, userInfoMap); + }, + "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", + "xyz.openbmc_project.User.Manager", "GetUserInfo", username); +} + +} // namespace crow |