Revert "Fix authorization for LDAP users"

This reverts commit 5e931ae994307babe6c3520cbaca6a7139acc81d.

Reason for revert: Causing build failures

/bmcweb/redfish-core/include/node.hpp: In member function ‘bool redfish::Node::isAllowedWithoutConfigureSelf(const crow::Request&)’:
/bmcweb/redfish-core/include/node.hpp:182:36: error: ‘crow::persistent_data::UserRoleMap’ has not been declared
             crow::persistent_data::UserRoleMap::getInstance().getUserRole(

When 900f949773795141266271107219ea019f2839cd was merged first
this patch was not successfully rebased.

Change-Id: I947d96362c7dadea5572888468a11fac5ee361d4
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/http/routing.h b/http/routing.h
index 0929286..7846924 100644
--- a/http/routing.h
+++ b/http/routing.h
@@ -1250,59 +1250,48 @@
                          << static_cast<uint32_t>(req.method()) << " / "
                          << rules[ruleIndex]->getMethods();
 
-        if (req.session == nullptr)
+        redfish::Privileges userPrivileges;
+        if (req.session != nullptr)
         {
-            rules[ruleIndex]->handle(req, res, found.second);
+            // Get the user role from the session.
+            const std::string& userRole =
+                persistent_data::UserRoleMap::getInstance().getUserRole(
+                    req.session->username);
+
+            BMCWEB_LOG_DEBUG << "USER ROLE=" << userRole;
+
+            // Get the user privileges from the role
+            userPrivileges = redfish::getUserPrivileges(userRole);
+        }
+
+        if (!rules[ruleIndex]->checkPrivileges(userPrivileges))
+        {
+            res.result(boost::beast::http::status::forbidden);
+            res.end();
             return;
         }
 
-        crow::connections::systemBus->async_method_call(
-            [&req, &res, &rules, ruleIndex, found](
-                const boost::system::error_code ec,
-                std::map<std::string, std::variant<bool, std::string,
-                                                   std::vector<std::string>>>
-                    userInfo) {
-                if (ec)
-                {
-                    BMCWEB_LOG_ERROR << "GetUserInfo failed...";
-                    res.result(
-                        boost::beast::http::status::internal_server_error);
-                    res.end();
-                    return;
-                }
-
-                const std::string* userRolePtr = nullptr;
-                auto userInfoIter = userInfo.find("UserPrivilege");
-                if (userInfoIter != userInfo.end())
-                {
-                    userRolePtr =
-                        std::get_if<std::string>(&userInfoIter->second);
-                }
-
-                std::string userRole{};
-                if (userRolePtr != nullptr)
-                {
-                    userRole = *userRolePtr;
-                    BMCWEB_LOG_DEBUG << "userName = " << req.session->username
-                                     << " userRole = " << *userRolePtr;
-                }
-
-                // Get the user privileges from the role
-                redfish::Privileges userPrivileges =
-                    redfish::getUserPrivileges(userRole);
-
-                if (!rules[ruleIndex]->checkPrivileges(userPrivileges))
-                {
-                    res.result(boost::beast::http::status::forbidden);
-                    res.end();
-                    return;
-                }
-
-                rules[ruleIndex]->handle(req, res, found.second);
-            },
-            "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
-            "xyz.openbmc_project.User.Manager", "GetUserInfo",
-            req.session->username);
+        // any uncaught exceptions become 500s
+        try
+        {
+            rules[ruleIndex]->handle(req, res, found.second);
+        }
+        catch (std::exception& e)
+        {
+            BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
+            res.result(boost::beast::http::status::internal_server_error);
+            res.end();
+            return;
+        }
+        catch (...)
+        {
+            BMCWEB_LOG_ERROR
+                << "An uncaught exception occurred. The type was unknown "
+                   "so no information was available.";
+            res.result(boost::beast::http::status::internal_server_error);
+            res.end();
+            return;
+        }
     }
 
     void debugPrint()
diff --git a/include/sessions.hpp b/include/sessions.hpp
index 7c2575d..6e74f25 100644
--- a/include/sessions.hpp
+++ b/include/sessions.hpp
@@ -30,6 +30,250 @@
     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";
+
+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;
diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp
index 901c180..a2da120 100644
--- a/src/webserver_main.cpp
+++ b/src/webserver_main.cpp
@@ -108,6 +108,10 @@
 
     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();