Redfish(Authorization): Map the user role with the Redfish privileges

This commit gets the role of the user from the session object and
map it with the redfish privileges and then allow/reject the asked
operation depending on the userprivileges and the entity privileges.

Change-Id: I40be06c28e80b47fe76891cacf863f8495bace88
Signed-off-by: Ratan Gupta <ratagupt@linux.vnet.ibm.com>
diff --git a/crow/include/crow/http_request.h b/crow/include/crow/http_request.h
index 0ba0266..ef0bb28 100644
--- a/crow/include/crow/http_request.h
+++ b/crow/include/crow/http_request.h
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "sessions.hpp"
+
 #include <boost/asio/io_context.hpp>
 #include <boost/beast/http.hpp>
 #include <boost/beast/websocket.hpp>
@@ -22,6 +24,8 @@
     void* middlewareContext{};
     boost::asio::io_context* ioService{};
 
+    std::shared_ptr<crow::persistent_data::UserSession> session;
+
     Request(boost::beast::http::request<boost::beast::http::string_body>& req) :
         req(req), body(req.body())
     {
diff --git a/crow/include/crow/routing.h b/crow/include/crow/routing.h
index d1c33b5..c97c874 100644
--- a/crow/include/crow/routing.h
+++ b/crow/include/crow/routing.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "privileges.hpp"
+#include "sessions.hpp"
 
 #include <boost/container/flat_map.hpp>
 #include <boost/container/small_vector.hpp>
@@ -1229,11 +1230,17 @@
                          << (uint32_t)req.method() << " / "
                          << rules[ruleIndex]->getMethods();
 
-        // TODO: load user privileges from configuration as soon as its
-        // available now we are granting all privileges to everyone.
-        redfish::Privileges userPrivileges{"Login", "ConfigureManager",
-                                           "ConfigureSelf", "ConfigureUsers",
-                                           "ConfigureComponents"};
+        redfish::Privileges userPrivileges;
+        if (req.session != nullptr)
+        {
+            // Get the user role from the session.
+            const std::string& userRole = req.session->userRole;
+
+            BMCWEB_LOG_DEBUG << "USER ROLE=" << userRole;
+
+            // Get the user privileges from the role
+            userPrivileges = redfish::getUserPrivileges(userRole);
+        }
 
         if (!rules[ruleIndex]->checkPrivileges(userPrivileges))
         {
diff --git a/include/token_authorization_middleware.hpp b/include/token_authorization_middleware.hpp
index 697e400..ee34d00 100644
--- a/include/token_authorization_middleware.hpp
+++ b/include/token_authorization_middleware.hpp
@@ -22,7 +22,6 @@
   public:
     struct Context
     {
-        std::shared_ptr<crow::persistent_data::UserSession> session;
     };
 
     void beforeHandle(crow::Request& req, Response& res, Context& ctx)
@@ -32,12 +31,12 @@
             return;
         }
 
-        ctx.session = performXtokenAuth(req);
-        if (ctx.session == nullptr)
+        req.session = performXtokenAuth(req);
+        if (req.session == nullptr)
         {
-            ctx.session = performCookieAuth(req);
+            req.session = performCookieAuth(req);
         }
-        if (ctx.session == nullptr)
+        if (req.session == nullptr)
         {
             std::string_view authHeader = req.getHeaderValue("Authorization");
             if (!authHeader.empty())
@@ -45,16 +44,16 @@
                 // Reject any kind of auth other than basic or token
                 if (boost::starts_with(authHeader, "Token "))
                 {
-                    ctx.session = performTokenAuth(authHeader);
+                    req.session = performTokenAuth(authHeader);
                 }
                 else if (boost::starts_with(authHeader, "Basic "))
                 {
-                    ctx.session = performBasicAuth(authHeader);
+                    req.session = performBasicAuth(authHeader);
                 }
             }
         }
 
-        if (ctx.session == nullptr)
+        if (req.session == nullptr)
         {
             BMCWEB_LOG_WARNING << "[AuthMiddleware] authorization failed";
 
@@ -93,12 +92,12 @@
         // middleware, but because it is upstream, it doesn't have access to the
         // session information.  Should the data middleware persist the current
         // user session?
-        if (ctx.session != nullptr &&
-            ctx.session->persistence ==
+        if (req.session != nullptr &&
+            req.session->persistence ==
                 crow::persistent_data::PersistenceType::SINGLE_REQUEST)
         {
             persistent_data::SessionStore::getInstance().removeSession(
-                ctx.session);
+                req.session);
         }
     }
 
@@ -431,24 +430,22 @@
         });
 
     BMCWEB_ROUTE(app, "/logout")
-        .methods(
-            "POST"_method)([&](const crow::Request& req, crow::Response& res) {
-            auto& session =
-                app.template getContext<token_authorization::Middleware>(req)
-                    .session;
-            if (session != nullptr)
-            {
-                res.jsonValue = {
-                    {"data", "User '" + session->username + "' logged out"},
-                    {"message", "200 OK"},
-                    {"status", "ok"}};
+        .methods("POST"_method)(
+            [&](const crow::Request& req, crow::Response& res) {
+                auto& session = req.session;
+                if (session != nullptr)
+                {
+                    res.jsonValue = {
+                        {"data", "User '" + session->username + "' logged out"},
+                        {"message", "200 OK"},
+                        {"status", "ok"}};
 
-                persistent_data::SessionStore::getInstance().removeSession(
-                    session);
-            }
-            res.end();
-            return;
-        });
+                    persistent_data::SessionStore::getInstance().removeSession(
+                        session);
+                }
+                res.end();
+                return;
+            });
 }
 } // namespace token_authorization
 } // namespace crow
diff --git a/redfish-core/include/privileges.hpp b/redfish-core/include/privileges.hpp
index ca44551..ec6e6a5 100644
--- a/redfish-core/include/privileges.hpp
+++ b/redfish-core/include/privileges.hpp
@@ -177,6 +177,29 @@
     std::bitset<maxPrivilegeCount> privilegeBitset = 0;
 };
 
+inline const Privileges& getUserPrivileges(const std::string& userRole)
+{
+    // Redfish privilege : Administrator
+    if (userRole == "priv-admin")
+    {
+        static Privileges admin{"Login", "ConfigureManager", "ConfigureSelf",
+                                "ConfigureUsers", "ConfigureComponents"};
+        return admin;
+    }
+    else if (userRole == "priv-operator")
+    {
+        // Redfish privilege : Operator
+        static Privileges op{"Login", "ConfigureSelf", "ConfigureComponents"};
+        return op;
+    }
+    else
+    {
+        // Redfish privilege : Readonly
+        static Privileges readOnly{"Login", "ConfigureSelf"};
+        return readOnly;
+    }
+}
+
 using OperationMap = boost::container::flat_map<boost::beast::http::verb,
                                                 std::vector<Privileges>>;