summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0001-Add-asyncResp-support-during-handleUpgrade.patch194
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0002-Move-privileges-to-separate-entity.patch109
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0003-Add-Support-for-privilege-check-in-handleUpgrade.patch220
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0004-Add-Privileges-to-Websockets.patch140
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0005-Add-Privileges-to-SseSockets.patch63
5 files changed, 726 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0001-Add-asyncResp-support-during-handleUpgrade.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0001-Add-asyncResp-support-during-handleUpgrade.patch
new file mode 100644
index 000000000..6a6882971
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0001-Add-asyncResp-support-during-handleUpgrade.patch
@@ -0,0 +1,194 @@
+From aa8aed7069c3654d288b8198d1cd21fadb6e2a36 Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Mon, 18 Oct 2021 22:45:37 +0530
+Subject: [PATCH] Add asyncResp support during handleUpgrade
+
+The current implementation uses the earlier method of using the response
+object and calling response.end() to initiate completion handler.
+This commit modifies the implementation to use asyncResp, where the
+completion handler gets called asynchronously as the response object
+goes out of scope.
+
+Tested :
+ - websocket_test.py Passed
+ - KVM was functional in WebUI.
+ - POST to /redfish/v1/EventService/Subscriptions/SSE returned an error
+ message as expected and the connection was kept alive.
+ - GET on /redfish/v1/EventService/Subscriptions/SSE (SSE subscription)
+ was successful. The existing connection was successfully closed and
+ upgraded to SSE connection.
+
+Change-Id: I2d76b34a49a6432c507d939b21b37c1ced761f8e
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/app.hpp | 6 ++++--
+ http/http_connection.hpp | 30 +++++++++++++++++++++++----
+ http/routing.hpp | 37 +++++++++++++++++++++----------------
+ 3 files changed, 51 insertions(+), 22 deletions(-)
+
+diff --git a/http/app.hpp b/http/app.hpp
+index c1472e5..7e946dc 100644
+--- a/http/app.hpp
++++ b/http/app.hpp
+@@ -51,9 +51,11 @@ class App
+ App& operator=(const App&&) = delete;
+
+ template <typename Adaptor>
+- void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
++ void handleUpgrade(const Request& req,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ Adaptor&& adaptor)
+ {
+- router.handleUpgrade(req, res, std::forward<Adaptor>(adaptor));
++ router.handleUpgrade(req, asyncResp, std::forward<Adaptor>(adaptor));
+ }
+
+ void handle(Request& req,
+diff --git a/http/http_connection.hpp b/http/http_connection.hpp
+index 8d76b25..9911ced 100644
+--- a/http/http_connection.hpp
++++ b/http/http_connection.hpp
+@@ -381,10 +381,32 @@ class Connection :
+ (req->url == "/redfish/v1/EventService/Subscriptions/SSE"))
+ {
+ BMCWEB_LOG_DEBUG << "Request: " << this << " is getting upgraded";
+- handler->handleUpgrade(thisReq, res, std::move(adaptor));
+- // delete lambda with self shared_ptr
+- // to enable connection destruction
+- asyncResp->res.setCompleteRequestHandler(nullptr);
++ asyncResp->res.setCompleteRequestHandler(
++ [self(shared_from_this())](crow::Response& thisRes) {
++ if (self->res.resultInt() != 200)
++ {
++ // When any error occurs during handle upgradation,
++ // the result in response will be set to respective
++ // error. By default the Result will be OK (200),
++ // which implies successful handle upgrade. Response
++ // needs to be sent over this connection only on
++ // failure.
++ boost::asio::post(self->adaptor.get_executor(),
++ [self, &thisRes] {
++ self->completeRequest(thisRes);
++ });
++ }
++ else
++ {
++ // Set Complete request handler to NULL to remove
++ // the shared pointer of connection to enable
++ // connection destruction. As the connection would
++ // get upgraded, we wouldn't need this connection
++ // any longer
++ self->res.setCompleteRequestHandler(nullptr);
++ }
++ });
++ handler->handleUpgrade(thisReq, asyncResp, std::move(adaptor));
+ return;
+ }
+ handler->handle(thisReq, asyncResp);
+diff --git a/http/routing.hpp b/http/routing.hpp
+index 552e1cf..4bb81f2 100644
+--- a/http/routing.hpp
++++ b/http/routing.hpp
+@@ -1215,12 +1215,13 @@ class Router
+ }
+
+ template <typename Adaptor>
+- void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
++ void handleUpgrade(const Request& req,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ Adaptor&& adaptor)
+ {
+ if (static_cast<size_t>(req.method()) >= perMethods.size())
+ {
+- res.result(boost::beast::http::status::not_found);
+- res.end();
++ asyncResp->res.result(boost::beast::http::status::not_found);
+ return;
+ }
+
+@@ -1233,8 +1234,7 @@ class Router
+ if (ruleIndex == 0U)
+ {
+ BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
+- res.result(boost::beast::http::status::not_found);
+- res.end();
++ asyncResp->res.result(boost::beast::http::status::not_found);
+ return;
+ }
+
+@@ -1247,23 +1247,24 @@ class Router
+ {
+ BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
+ << req.url;
+- res.result(boost::beast::http::status::moved_permanently);
++ asyncResp->res.result(
++ boost::beast::http::status::moved_permanently);
+
+ // TODO absolute url building
+ if (req.getHeaderValue("Host").empty())
+ {
+- res.addHeader("Location", std::string(req.url) + "/");
++ asyncResp->res.addHeader("Location",
++ std::string(req.url) + "/");
+ }
+ else
+ {
+- res.addHeader(
++ asyncResp->res.addHeader(
+ "Location",
+ req.isSecure
+ ? "https://"
+ : "http://" + std::string(req.getHeaderValue("Host")) +
+ std::string(req.url) + "/");
+ }
+- res.end();
+ return;
+ }
+
+@@ -1274,8 +1275,7 @@ class Router
+ << " with " << req.methodString() << "("
+ << static_cast<uint32_t>(req.method()) << ") / "
+ << rules[ruleIndex]->getMethods();
+- res.result(boost::beast::http::status::not_found);
+- res.end();
++ asyncResp->res.result(boost::beast::http::status::not_found);
+ return;
+ }
+
+@@ -1286,14 +1286,19 @@ class Router
+ // any uncaught exceptions become 500s
+ try
+ {
+- rules[ruleIndex]->handleUpgrade(req, res,
++ // Creating temporary response object to call handleUpgrade
++ // We cannot pass the asyncResp as it will be destroyed
++ // The response object is not initialized as handleUpgrade wouldn't
++ // be using this object
++ crow::Response resp;
++ rules[ruleIndex]->handleUpgrade(req, resp,
+ std::forward<Adaptor>(adaptor));
+ }
+ catch (const std::exception& e)
+ {
+ BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
+- res.result(boost::beast::http::status::internal_server_error);
+- res.end();
++ asyncResp->res.result(
++ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ catch (...)
+@@ -1301,8 +1306,8 @@ class Router
+ 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();
++ asyncResp->res.result(
++ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ }
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0002-Move-privileges-to-separate-entity.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0002-Move-privileges-to-separate-entity.patch
new file mode 100644
index 000000000..1217147b4
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0002-Move-privileges-to-separate-entity.patch
@@ -0,0 +1,109 @@
+From 6483f0af926391e8d1f256ba0f23f3640260cfd1 Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Mon, 18 Oct 2021 22:52:17 +0530
+Subject: [PATCH] Move privileges to separate entity
+
+The privilege property of a rule is currently part of RuleParameterTraits
+structure. Moving this property (member function) out into a separate
+entity PrivilegeParameterTraits.
+This move is required to enable inheriting this entity into Weksockets
+and SseSockets.
+
+Tested:
+ - bmcweb is functional and is responding to Redfish URI's
+ - User Privilege check for URI's is functional.
+
+Change-Id: I288ab12258c15ae5a626f4409fc3b4a9cc574ea3
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/routing.hpp | 53 +++++++++++++++++++++++++++---------------------
+ 1 file changed, 30 insertions(+), 23 deletions(-)
+
+diff --git a/http/routing.hpp b/http/routing.hpp
+index 858f146..acc99dc 100644
+--- a/http/routing.hpp
++++ b/http/routing.hpp
+@@ -102,6 +102,8 @@ class BaseRule
+ friend class Router;
+ template <typename T>
+ friend struct RuleParameterTraits;
++ template <typename T>
++ friend struct PrivilegeParameterTraits;
+ };
+
+ namespace detail
+@@ -316,6 +318,33 @@ struct Wrapped
+ } // namespace routing_handler_call_helper
+ } // namespace detail
+
++template <typename T>
++struct PrivilegeParameterTraits
++{
++ using self_t = T;
++ self_t& privileges(
++ const std::initializer_list<std::initializer_list<const char*>>& p)
++ {
++ self_t* self = static_cast<self_t*>(this);
++ for (const std::initializer_list<const char*>& privilege : p)
++ {
++ self->privilegesSet.emplace_back(privilege);
++ }
++ return *self;
++ }
++
++ template <size_t N, typename... MethodArgs>
++ self_t& privileges(const std::array<redfish::Privileges, N>& p)
++ {
++ self_t* self = static_cast<self_t*>(this);
++ for (const redfish::Privileges& privilege : p)
++ {
++ self->privilegesSet.emplace_back(privilege);
++ }
++ return *self;
++ }
++};
++
+ class WebSocketRule : public BaseRule
+ {
+ using self_t = WebSocketRule;
+@@ -462,7 +491,7 @@ class SseSocketRule : public BaseRule
+ };
+
+ template <typename T>
+-struct RuleParameterTraits
++struct RuleParameterTraits : public PrivilegeParameterTraits<T>
+ {
+ using self_t = T;
+ WebSocketRule& websocket()
+@@ -503,28 +532,6 @@ struct RuleParameterTraits
+ self->methodsBitfield |= 1U << static_cast<size_t>(method);
+ return *self;
+ }
+-
+- self_t& privileges(
+- const std::initializer_list<std::initializer_list<const char*>>& p)
+- {
+- self_t* self = static_cast<self_t*>(this);
+- for (const std::initializer_list<const char*>& privilege : p)
+- {
+- self->privilegesSet.emplace_back(privilege);
+- }
+- return *self;
+- }
+-
+- template <size_t N, typename... MethodArgs>
+- self_t& privileges(const std::array<redfish::Privileges, N>& p)
+- {
+- self_t* self = static_cast<self_t*>(this);
+- for (const redfish::Privileges& privilege : p)
+- {
+- self->privilegesSet.emplace_back(privilege);
+- }
+- return *self;
+- }
+ };
+
+ class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0003-Add-Support-for-privilege-check-in-handleUpgrade.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0003-Add-Support-for-privilege-check-in-handleUpgrade.patch
new file mode 100644
index 000000000..4fe19e919
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0003-Add-Support-for-privilege-check-in-handleUpgrade.patch
@@ -0,0 +1,220 @@
+From 93f66a039d4e840d7597288b296f68d467039006 Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Mon, 18 Oct 2021 22:55:38 +0530
+Subject: [PATCH] Add Support for privilege check in handleUpgrade
+
+This commit enables privilege check for user(s) in case of upgraded
+connections.
+Currently users with no privileges will also be able to access
+Websockets connections (Ex: KVM).
+
+Tested:
+ - websocket_test.py Passed
+ - Admin and Operator users were able to access KVM on WebUI
+ - Readonly User was unable to access KVM on WebUI
+
+Change-Id: Id9d33aeca24d8fafb2e9dcc28c46a48930740cd6
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/app.hpp | 2 +-
+ http/routing.hpp | 164 +++++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 137 insertions(+), 29 deletions(-)
+
+diff --git a/http/app.hpp b/http/app.hpp
+index 7e946dc..d63c6cb 100644
+--- a/http/app.hpp
++++ b/http/app.hpp
+@@ -51,7 +51,7 @@ class App
+ App& operator=(const App&&) = delete;
+
+ template <typename Adaptor>
+- void handleUpgrade(const Request& req,
++ void handleUpgrade(Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ Adaptor&& adaptor)
+ {
+diff --git a/http/routing.hpp b/http/routing.hpp
+index 9443657..048734d 100644
+--- a/http/routing.hpp
++++ b/http/routing.hpp
+@@ -1217,7 +1217,7 @@ class Router
+ }
+
+ template <typename Adaptor>
+- void handleUpgrade(const Request& req,
++ void handleUpgrade(Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ Adaptor&& adaptor)
+ {
+@@ -1285,33 +1285,141 @@ class Router
+ << "' " << static_cast<uint32_t>(req.method()) << " / "
+ << rules[ruleIndex]->getMethods();
+
+- // any uncaught exceptions become 500s
+- try
+- {
+- // Creating temporary response object to call handleUpgrade
+- // We cannot pass the asyncResp as it will be destroyed
+- // The response object is not initialized as handleUpgrade wouldn't
+- // be using this object
+- crow::Response resp;
+- rules[ruleIndex]->handleUpgrade(req, resp,
+- std::forward<Adaptor>(adaptor));
+- }
+- catch (const std::exception& e)
+- {
+- BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
+- asyncResp->res.result(
+- boost::beast::http::status::internal_server_error);
+- return;
+- }
+- catch (...)
+- {
+- BMCWEB_LOG_ERROR
+- << "An uncaught exception occurred. The type was unknown "
+- "so no information was available.";
+- asyncResp->res.result(
+- boost::beast::http::status::internal_server_error);
+- return;
+- }
++ crow::connections::systemBus->async_method_call(
++ [&req, asyncResp, &rules, ruleIndex, &adaptor](
++ 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...";
++ asyncResp->res.result(
++ boost::beast::http::status::internal_server_error);
++ 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;
++ }
++
++ bool* remoteUserPtr = nullptr;
++ auto remoteUserIter = userInfo.find("RemoteUser");
++ if (remoteUserIter != userInfo.end())
++ {
++ remoteUserPtr = std::get_if<bool>(&remoteUserIter->second);
++ }
++ if (remoteUserPtr == nullptr)
++ {
++ BMCWEB_LOG_ERROR
++ << "RemoteUser property missing or wrong type";
++ asyncResp->res.result(
++ boost::beast::http::status::internal_server_error);
++ return;
++ }
++ bool remoteUser = *remoteUserPtr;
++
++ bool passwordExpired = false; // default for remote user
++ if (!remoteUser)
++ {
++ bool* passwordExpiredPtr = nullptr;
++ auto passwordExpiredIter =
++ userInfo.find("UserPasswordExpired");
++ if (passwordExpiredIter != userInfo.end())
++ {
++ passwordExpiredPtr =
++ std::get_if<bool>(&passwordExpiredIter->second);
++ }
++ if (passwordExpiredPtr != nullptr)
++ {
++ passwordExpired = *passwordExpiredPtr;
++ }
++ else
++ {
++ 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;
++ }
++ }
++
++ // Get the userprivileges from the role
++ redfish::Privileges userPrivileges =
++ redfish::getUserPrivileges(userRole);
++
++ // 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 = passwordExpired;
++
++ // Modifyprivileges if isConfigureSelfOnly.
++ if (req.session->isConfigureSelfOnly)
++ {
++ // Remove allprivileges except ConfigureSelf
++ userPrivileges = userPrivileges.intersection(
++ redfish::Privileges{"ConfigureSelf"});
++ BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf";
++ }
++
++ if (!rules[ruleIndex]->checkPrivileges(userPrivileges))
++ {
++ asyncResp->res.result(
++ boost::beast::http::status::forbidden);
++ if (req.session->isConfigureSelfOnly)
++ {
++ redfish::messages::passwordChangeRequired(
++ asyncResp->res,
++ crow::utility::urlFromPieces(
++ "redfish", "v1", "AccountService", "Accounts",
++ req.session->username));
++ }
++ return;
++ }
++
++ req.userRole = userRole;
++
++ // any uncaught exceptions become 500s
++ try
++ {
++ crow::Response resp;
++ rules[ruleIndex]->handleUpgrade(req, resp,
++ std::move(adaptor));
++ }
++ catch (std::exception& e)
++ {
++ BMCWEB_LOG_ERROR << "An uncaught exception occurred: "
++ << e.what();
++ asyncResp->res.result(
++ boost::beast::http::status::internal_server_error);
++ return;
++ }
++ catch (...)
++ {
++ BMCWEB_LOG_ERROR
++ << "An uncaught exception occurred. The type was "
++ "unknown so no information was available.";
++ asyncResp->res.result(
++ boost::beast::http::status::internal_server_error);
++ return;
++ }
++ },
++ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
++ "xyz.openbmc_project.User.Manager", "GetUserInfo",
++ req.session->username);
+ }
+
+ void handle(Request& req,
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0004-Add-Privileges-to-Websockets.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0004-Add-Privileges-to-Websockets.patch
new file mode 100644
index 000000000..19c671754
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0004-Add-Privileges-to-Websockets.patch
@@ -0,0 +1,140 @@
+From 9b27d3e7c1670d53cfb1c0a88cc75155ebfba71a Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Mon, 18 Oct 2021 22:58:29 +0530
+Subject: [PATCH] Add Privileges to Websockets
+
+This commit adds Privileges to Websockets.
+In the current implementation, once a rule is upgraded (i.e. from
+BaseRule to WebSocket), there is no provosion to add priviliges.
+In this commit, WebSocket inherits PrivilegeParameterTraits to enable
+privileges.
+
+Also, in the earlier implementation, .privilege() was called after
+BMCWEB_ROUTE(). This results in adding those privileges to the Base rule
+that is created. By moving the privileges() below websocket(), the
+privileges are applied to the websocket.
+
+Tested:
+ - websocket_test.py Passed
+ - Admin and Operator users were able to access KVM on WebUI
+ - Readonly User was unable to access KVM on WebUI
+
+Change-Id: Iff2051dbb7d363c902fd463fa446f280adc6d648
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/routing.hpp | 4 +++-
+ include/dbus_monitor.hpp | 3 ++-
+ include/kvm_websocket.hpp | 4 +++-
+ include/obmc_console.hpp | 4 +++-
+ include/vm_websocket.hpp | 4 +++-
+ 5 files changed, 14 insertions(+), 5 deletions(-)
+
+diff --git a/http/routing.hpp b/http/routing.hpp
+index e2a8fbb..6ea3185 100644
+--- a/http/routing.hpp
++++ b/http/routing.hpp
+@@ -345,7 +345,9 @@ struct PrivilegeParameterTraits
+ }
+ };
+
+-class WebSocketRule : public BaseRule
++class WebSocketRule :
++ public BaseRule,
++ public PrivilegeParameterTraits<WebSocketRule>
+ {
+ using self_t = WebSocketRule;
+
+diff --git a/include/dbus_monitor.hpp b/include/dbus_monitor.hpp
+index a6c86c6..163f884 100644
+--- a/include/dbus_monitor.hpp
++++ b/include/dbus_monitor.hpp
+@@ -5,6 +5,7 @@
+ #include <boost/container/flat_set.hpp>
+ #include <dbus_singleton.hpp>
+ #include <openbmc_dbus_rest.hpp>
++#include <registries/privilege_registry.hpp>
+ #include <sdbusplus/bus/match.hpp>
+ #include <sdbusplus/message/types.hpp>
+ #include <websocket.hpp>
+@@ -105,8 +106,8 @@ inline int onPropertyUpdate(sd_bus_message* m, void* userdata,
+ inline void requestRoutes(App& app)
+ {
+ BMCWEB_ROUTE(app, "/subscribe")
+- .privileges({{"Login"}})
+ .websocket()
++ .privileges(redfish::privileges::privilegeSetLogin)
+ .onopen([&](crow::websocket::Connection& conn,
+ const std::shared_ptr<bmcweb::AsyncResp>&) {
+ BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
+diff --git a/include/kvm_websocket.hpp b/include/kvm_websocket.hpp
+index a9dc8ea..3f124a2 100644
+--- a/include/kvm_websocket.hpp
++++ b/include/kvm_websocket.hpp
+@@ -4,6 +4,7 @@
+ #include <app.hpp>
+ #include <async_resp.hpp>
+ #include <boost/container/flat_map.hpp>
++#include <registries/privilege_registry.hpp>
+ #include <websocket.hpp>
+
+ namespace crow
+@@ -159,8 +160,9 @@ inline void requestRoutes(App& app)
+ sessions.reserve(maxSessions);
+
+ BMCWEB_ROUTE(app, "/kvm/0")
+- .privileges({{"ConfigureComponents", "ConfigureManager"}})
+ .websocket()
++ .privileges(redfish::privileges::
++ privilegeSetConfigureManagerOrConfigureComponents)
+ .onopen([](crow::websocket::Connection& conn,
+ const std::shared_ptr<bmcweb::AsyncResp>&) {
+ BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
+diff --git a/include/obmc_console.hpp b/include/obmc_console.hpp
+index ff0a51f..22a49a8 100644
+--- a/include/obmc_console.hpp
++++ b/include/obmc_console.hpp
+@@ -6,6 +6,7 @@
+ #include <boost/asio/local/stream_protocol.hpp>
+ #include <boost/container/flat_map.hpp>
+ #include <boost/container/flat_set.hpp>
++#include <registries/privilege_registry.hpp>
+ #include <websocket.hpp>
+
+ namespace crow
+@@ -136,8 +137,9 @@ inline void connectHandler(const boost::system::error_code& ec)
+ inline void requestRoutes(App& app)
+ {
+ BMCWEB_ROUTE(app, "/console0")
+- .privileges({{"ConfigureComponents", "ConfigureManager"}})
+ .websocket()
++ .privileges(redfish::privileges::
++ privilegeSetConfigureManagerOrConfigureComponents)
+ .onopen([](crow::websocket::Connection& conn,
+ const std::shared_ptr<bmcweb::AsyncResp>&) {
+ BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
+diff --git a/include/vm_websocket.hpp b/include/vm_websocket.hpp
+index 02f958a..ebbe68f 100644
+--- a/include/vm_websocket.hpp
++++ b/include/vm_websocket.hpp
+@@ -3,6 +3,7 @@
+ #include <boost/process/async_pipe.hpp>
+ #include <boost/process/child.hpp>
+ #include <boost/process/io.hpp>
++#include <registries/privilege_registry.hpp>
+ #include <websocket.hpp>
+
+ #include <csignal>
+@@ -156,8 +157,9 @@ static std::shared_ptr<Handler> handler;
+ inline void requestRoutes(App& app)
+ {
+ BMCWEB_ROUTE(app, "/vm/0/0")
+- .privileges({{"ConfigureComponents", "ConfigureManager"}})
+ .websocket()
++ .privileges(redfish::privileges::
++ privilegeSetConfigureManagerOrConfigureComponents)
+ .onopen([](crow::websocket::Connection& conn,
+ const std::shared_ptr<bmcweb::AsyncResp>&) {
+ BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0005-Add-Privileges-to-SseSockets.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0005-Add-Privileges-to-SseSockets.patch
new file mode 100644
index 000000000..06ffb3a46
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0005-Add-Privileges-to-SseSockets.patch
@@ -0,0 +1,63 @@
+From 0ceb343809ff498cbfa389c54a158d255a2cca88 Mon Sep 17 00:00:00 2001
+From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+Date: Mon, 18 Oct 2021 23:02:00 +0530
+Subject: [PATCH] Add Privileges to SseSockets
+
+This commit adds Privileges to Ssesockets.
+In the current implementation, once a rule is upgraded (i.e. from
+BaseRule to SseSocket), there is no provision to add priviliges.
+In this commit, SseSocket inherits PrivilegeParameterTraits to
+enable privileges.
+
+Also, in the earlier implementation, .privilege() was called after
+BMCWEB_ROUTE(). This results in adding those privileges to the Base
+rule that is created. By moving the privileges() below websocket(),
+the privileges are applied to the Ssesocket.
+
+Tested:
+ - SSE Subscription was successful with Admin and Operator Users
+ - SSE Subscription was rejected while using Readonly User
+ - websocket_test.py Passed
+ - Admin and Operator users were able to access KVM on WebUI
+ - Readonly User was unable to access KVM on WebUI
+
+Change-Id: I41739401893b1c2bf718e11ec7676d69f954c98f
+Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
+---
+ http/routing.hpp | 4 +++-
+ include/eventservice_sse.hpp | 3 ++-
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/http/routing.hpp b/http/routing.hpp
+index 6ea3185..13174b2 100644
+--- a/http/routing.hpp
++++ b/http/routing.hpp
+@@ -430,7 +430,9 @@ class WebSocketRule :
+ std::function<void(crow::websocket::Connection&)> errorHandler;
+ };
+
+-class SseSocketRule : public BaseRule
++class SseSocketRule :
++ public BaseRule,
++ public PrivilegeParameterTraits<SseSocketRule>
+ {
+ using self_t = SseSocketRule;
+
+diff --git a/include/eventservice_sse.hpp b/include/eventservice_sse.hpp
+index 2f22f98..f880344 100644
+--- a/include/eventservice_sse.hpp
++++ b/include/eventservice_sse.hpp
+@@ -192,8 +192,9 @@ static void deleteSubscription(std::shared_ptr<crow::SseConnection>& conn)
+ inline void requestRoutes(App& app)
+ {
+ BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/SSE")
+- .privileges({{"ConfigureComponents", "ConfigureManager"}})
+ .serverSentEvent()
++ .privileges(redfish::privileges::
++ privilegeSetConfigureManagerOrConfigureComponents)
+ .onopen([](std::shared_ptr<crow::SseConnection>& conn,
+ const crow::Request& req, crow::Response& res) {
+ BMCWEB_LOG_DEBUG << "Connection " << conn << " opened.";
+--
+2.17.1
+