diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing')
5 files changed, 732 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..b3aa11774 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/http_routing/0001-Add-asyncResp-support-during-handleUpgrade.patch @@ -0,0 +1,202 @@ +From f2c3271c8eb405a05a3ec383791e1adc3c4a7f86 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, 50 insertions(+), 23 deletions(-) + +diff --git a/http/app.hpp b/http/app.hpp +index 4735197..c46dcf7 100644 +--- a/http/app.hpp ++++ b/http/app.hpp +@@ -45,9 +45,11 @@ class App + } + + 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::move(adaptor)); ++ router.handleUpgrade(req, asyncResp, std::move(adaptor)); + } + + void handle(Request& req, +diff --git a/http/http_connection.hpp b/http/http_connection.hpp +index 9d53c17..cdd3707 100644 +--- a/http/http_connection.hpp ++++ b/http/http_connection.hpp +@@ -361,6 +361,7 @@ class Connection : + boost::asio::post(self->adaptor.get_executor(), + [self] { self->completeRequest(); }); + }); ++ auto asyncResp = std::make_shared<bmcweb::AsyncResp>(res); + + if ((thisReq.isUpgrade() && + boost::iequals( +@@ -369,13 +370,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 +- res.setCompleteRequestHandler(nullptr); ++ res.setCompleteRequestHandler([self(shared_from_this())] { ++ 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] { self->completeRequest(); }); ++ } ++ 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; + } +- auto asyncResp = std::make_shared<bmcweb::AsyncResp>(res); ++ + handler->handle(thisReq, asyncResp); + } + +diff --git a/http/routing.hpp b/http/routing.hpp +index 25e4ce8..858f146 100644 +--- a/http/routing.hpp ++++ b/http/routing.hpp +@@ -1202,12 +1202,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; + } + +@@ -1220,8 +1221,7 @@ class Router + if (!ruleIndex) + { + 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; + } + +@@ -1234,23 +1234,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; + } + +@@ -1261,8 +1262,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; + } + +@@ -1273,13 +1273,18 @@ class Router + // any uncaught exceptions become 500s + try + { +- rules[ruleIndex]->handleUpgrade(req, res, std::move(adaptor)); ++ // 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::move(adaptor)); + } + catch (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 (...) +@@ -1287,8 +1292,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..1ba584616 --- /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,218 @@ +From aabe4718b8e6c1f7b91af29cbaf85d5fa1fa0a99 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 | 162 +++++++++++++++++++++++++++++++++++++++-------- + 2 files changed, 136 insertions(+), 28 deletions(-) + +diff --git a/http/app.hpp b/http/app.hpp +index c46dcf7..dd51eee 100644 +--- a/http/app.hpp ++++ b/http/app.hpp +@@ -45,7 +45,7 @@ class App + } + + 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 acc99dc..e2a8fbb 100644 +--- a/http/routing.hpp ++++ b/http/routing.hpp +@@ -1209,7 +1209,7 @@ class Router + } + + template <typename Adaptor> +- void handleUpgrade(const Request& req, ++ void handleUpgrade(Request& req, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + Adaptor&& adaptor) + { +@@ -1277,32 +1277,140 @@ 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::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; +- } ++ 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, ++ "/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..64e235ce3 --- /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 <app.hpp> + #include <boost/beast/core/flat_static_buffer.hpp> + #include <boost/process.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 + |