diff options
author | Ratan Gupta <ratagupt@linux.vnet.ibm.com> | 2019-04-03 07:38:11 +0300 |
---|---|---|
committer | Ed Tanous <ed.tanous@intel.com> | 2019-07-09 19:36:10 +0300 |
commit | 12c04ef5d04d62fd7b19506faf4eb2b08662e979 (patch) | |
tree | 80598052c6a8187619d159dba63ffd2b636ceccf | |
parent | e90c50528a87fd15a7ae3f6b49e0ab83b1873d0c (diff) | |
download | bmcweb-12c04ef5d04d62fd7b19506faf4eb2b08662e979.tar.xz |
Redfish(Authorization): Add the privilege in the user session object.
This commit fetches the user privilege during creation of the
session by making D-bus call and add the privilege in the
user session object.
Change-Id: I0e9da8a52df00fc753b13101066ce6d0be9e2ce3
Signed-off-by: Ratan Gupta <ratagupt@linux.vnet.ibm.com>
-rw-r--r-- | include/sessions.hpp | 264 | ||||
-rw-r--r-- | src/webserver_main.cpp | 4 |
2 files changed, 262 insertions, 6 deletions
diff --git a/include/sessions.hpp b/include/sessions.hpp index 6bc1c99f04..f8f3e8efdd 100644 --- a/include/sessions.hpp +++ b/include/sessions.hpp @@ -1,17 +1,15 @@ #pragma once -#include <crow/app.h> -#include <crow/http_request.h> -#include <crow/http_response.h> - #include <boost/container/flat_map.hpp> #include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid_generators.hpp> #include <boost/uuid/uuid_io.hpp> +#include <dbus_singleton.hpp> #include <nlohmann/json.hpp> #include <pam_authenticate.hpp> #include <random> -#include <webassets.hpp> + +#include "crow/logging.h" namespace crow { @@ -25,11 +23,258 @@ enum class PersistenceType SINGLE_REQUEST // User times out once this request is completed. }; +constexpr char const* userService = "xyz.openbmc_project.User.Manager"; +constexpr char const* userObjPath = "/xyz/openbmc_project/user"; +constexpr char const* userAttrIface = "xyz.openbmc_project.User.Attributes"; +constexpr char const* dbusPropertiesIface = "org.freedesktop.DBus.Properties"; + +class SessionStore; + +struct UserRoleMap +{ + using GetManagedPropertyType = + boost::container::flat_map<std::string, + std::variant<std::string, bool>>; + + using InterfacesPropertiesType = + boost::container::flat_map<std::string, GetManagedPropertyType>; + + using GetManagedObjectsType = std::vector< + std::pair<sdbusplus::message::object_path, InterfacesPropertiesType>>; + + static UserRoleMap& getInstance() + { + static UserRoleMap userRoleMap; + return userRoleMap; + } + + UserRoleMap(const UserRoleMap&) = delete; + UserRoleMap& operator=(const UserRoleMap&) = delete; + + std::string getUserRole(std::string_view name) + { + auto it = roleMap.find(std::string(name)); + if (it == roleMap.end()) + { + BMCWEB_LOG_ERROR << "User name " << name + << " is not found in the UserRoleMap."; + return ""; + } + return it->second; + } + + std::string + extractUserRole(const InterfacesPropertiesType& interfacesProperties) + { + auto iface = interfacesProperties.find(userAttrIface); + if (iface == interfacesProperties.end()) + { + return {}; + } + + auto& properties = iface->second; + auto property = properties.find("UserPrivilege"); + if (property == properties.end()) + { + return {}; + } + + const std::string* role = std::get_if<std::string>(&property->second); + if (role == nullptr) + { + BMCWEB_LOG_ERROR << "UserPrivilege property value is null"; + return {}; + } + + return *role; + } + + private: + void userAdded(sdbusplus::message::message& m) + { + sdbusplus::message::object_path objPath; + InterfacesPropertiesType interfacesProperties; + + try + { + m.read(objPath, interfacesProperties); + } + catch (const sdbusplus::exception::SdBusError& e) + { + BMCWEB_LOG_ERROR << "Failed to parse user add signal." + << "ERROR=" << e.what() + << "REPLY_SIG=" << m.get_signature(); + return; + } + BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; + + std::size_t lastPos = objPath.str.rfind("/"); + if (lastPos == std::string::npos) + { + return; + }; + + std::string name = objPath.str.substr(lastPos + 1); + std::string role = this->extractUserRole(interfacesProperties); + + // Insert the newly added user name and the role + auto res = roleMap.emplace(name, role); + if (res.second == false) + { + BMCWEB_LOG_ERROR << "Insertion of the user=\"" << name + << "\" in the roleMap failed."; + return; + } + } + + void userRemoved(sdbusplus::message::message& m) + { + sdbusplus::message::object_path objPath; + + try + { + m.read(objPath); + } + catch (const sdbusplus::exception::SdBusError& e) + { + BMCWEB_LOG_ERROR << "Failed to parse user delete signal."; + BMCWEB_LOG_ERROR << "ERROR=" << e.what() + << "REPLY_SIG=" << m.get_signature(); + return; + } + + BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; + + std::size_t lastPos = objPath.str.rfind("/"); + if (lastPos == std::string::npos) + { + return; + }; + + // User name must be atleast 1 char in length. + if ((lastPos + 1) >= objPath.str.length()) + { + return; + } + + std::string name = objPath.str.substr(lastPos + 1); + + roleMap.erase(name); + } + + void userPropertiesChanged(sdbusplus::message::message& m) + { + std::string interface; + GetManagedPropertyType changedProperties; + m.read(interface, changedProperties); + const std::string path = m.get_path(); + + BMCWEB_LOG_DEBUG << "Object Path = \"" << path << "\""; + + std::size_t lastPos = path.rfind("/"); + if (lastPos == std::string::npos) + { + return; + }; + + // User name must be at least 1 char in length. + if ((lastPos + 1) == path.length()) + { + return; + } + + std::string user = path.substr(lastPos + 1); + + BMCWEB_LOG_DEBUG << "User Name = \"" << user << "\""; + + auto index = changedProperties.find("UserPrivilege"); + if (index == changedProperties.end()) + { + return; + } + + const std::string* role = std::get_if<std::string>(&index->second); + if (role == nullptr) + { + return; + } + BMCWEB_LOG_DEBUG << "Role = \"" << *role << "\""; + + auto it = roleMap.find(user); + if (it == roleMap.end()) + { + BMCWEB_LOG_ERROR << "User Name = \"" << user + << "\" is not found. But, received " + "propertiesChanged signal"; + return; + } + it->second = *role; + } + + UserRoleMap() : + userAddedSignal( + *crow::connections::systemBus, + sdbusplus::bus::match::rules::interfacesAdded(userObjPath), + [this](sdbusplus::message::message& m) { + BMCWEB_LOG_DEBUG << "User Added"; + this->userAdded(m); + }), + userRemovedSignal( + *crow::connections::systemBus, + sdbusplus::bus::match::rules::interfacesRemoved(userObjPath), + [this](sdbusplus::message::message& m) { + BMCWEB_LOG_DEBUG << "User Removed"; + this->userRemoved(m); + }), + userPropertiesChangedSignal( + *crow::connections::systemBus, + sdbusplus::bus::match::rules::path_namespace(userObjPath) + + sdbusplus::bus::match::rules::type::signal() + + sdbusplus::bus::match::rules::member("PropertiesChanged") + + sdbusplus::bus::match::rules::interface(dbusPropertiesIface) + + sdbusplus::bus::match::rules::argN(0, userAttrIface), + [this](sdbusplus::message::message& m) { + BMCWEB_LOG_DEBUG << "Properties Changed"; + this->userPropertiesChanged(m); + }) + { + crow::connections::systemBus->async_method_call( + [this](boost::system::error_code ec, + GetManagedObjectsType& managedObjects) { + if (ec) + { + BMCWEB_LOG_DEBUG << "User manager call failed, ignoring"; + return; + } + + for (auto& managedObj : managedObjects) + { + std::size_t lastPos = managedObj.first.str.rfind("/"); + if (lastPos == std::string::npos) + { + continue; + }; + std::string name = managedObj.first.str.substr(lastPos + 1); + std::string role = extractUserRole(managedObj.second); + roleMap.emplace(name, role); + } + }, + userService, userObjPath, "org.freedesktop.DBus.ObjectManager", + "GetManagedObjects"); + } + + boost::container::flat_map<std::string, std::string> roleMap; + sdbusplus::bus::match_t userAddedSignal; + sdbusplus::bus::match_t userRemovedSignal; + sdbusplus::bus::match_t userPropertiesChangedSignal; +}; + struct UserSession { std::string uniqueId; std::string sessionToken; std::string username; + std::string userRole; std::string csrfToken; std::chrono::time_point<std::chrono::steady_clock> lastUpdated; PersistenceType persistence; @@ -138,8 +383,14 @@ class SessionStore { uniqueId[i] = alphanum[dist(rd)]; } + + // Get the User Privilege + const std::string& role = + UserRoleMap::getInstance().getUserRole(username); + + BMCWEB_LOG_DEBUG << "user name=\"" << username << "\" role = " << role; auto session = std::make_shared<UserSession>(UserSession{ - uniqueId, sessionToken, std::string(username), csrfToken, + uniqueId, sessionToken, std::string(username), role, csrfToken, std::chrono::steady_clock::now(), persistence}); auto it = authTokens.emplace(std::make_pair(sessionToken, session)); // Only need to write to disk if session isn't about to be destroyed. @@ -250,6 +501,7 @@ class SessionStore } } } + std::chrono::time_point<std::chrono::steady_clock> lastTimeoutUpdate; boost::container::flat_map<std::string, std::shared_ptr<UserSession>> authTokens; diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp index 1c9c1f18d3..602c216709 100644 --- a/src/webserver_main.cpp +++ b/src/webserver_main.cpp @@ -99,6 +99,10 @@ int main(int argc, char** argv) std::make_shared<sdbusplus::asio::connection>(*io); redfish::RedfishService redfish(app); + // Keep the user role map hot in memory and + // track the changes using match object + crow::persistent_data::UserRoleMap::getInstance(); + app.run(); io->run(); |