summaryrefslogtreecommitdiff
path: root/http/routing.hpp
diff options
context:
space:
mode:
authorP Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>2021-09-17 22:49:04 +0300
committerEd Tanous <ed@tanous.net>2023-03-15 00:23:02 +0300
commit7e9093e625961f533250a6c193c1a474e98007c4 (patch)
treedef70a389a02ff981fd81958652f45204e1e5be1 /http/routing.hpp
parent4f10f7e3f7c8b3d67803f691d3a0b394b9bccfc1 (diff)
downloadbmcweb-7e9093e625961f533250a6c193c1a474e98007c4.tar.xz
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). The privilege check was already in place for normal connections (i.e. router->handle()). This commit lifts off the privilege check code and moves it into a common function (validatePrivilege()), which can be used both by handle() and handleUpgrade() and register required callback to be called. Also, the const qualifier for Request in the handleUpgrade() function's signature is removed to enable setting "isConfigureSelf" field of request. The signature of handleUpgrade() is made identical to handle() Tested: - websocket_test.py Passed - Admin and Operator users are able to access KVM on WebUI - Readonly User was unable to access KVM on WebUI Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com> Change-Id: I6f743c27e7e6077f1c6c56e6958922027e4404e8
Diffstat (limited to 'http/routing.hpp')
-rw-r--r--http/routing.hpp123
1 files changed, 78 insertions, 45 deletions
diff --git a/http/routing.hpp b/http/routing.hpp
index 40218fbf68..e86c77417f 100644
--- a/http/routing.hpp
+++ b/http/routing.hpp
@@ -57,6 +57,7 @@ class BaseRule
virtual void handle(const Request& /*req*/,
const std::shared_ptr<bmcweb::AsyncResp>&,
const RoutingParams&) = 0;
+#ifndef BMCWEB_ENABLE_SSL
virtual void
handleUpgrade(const Request& /*req*/,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
@@ -64,7 +65,7 @@ class BaseRule
{
asyncResp->res.result(boost::beast::http::status::not_found);
}
-#ifdef BMCWEB_ENABLE_SSL
+#else
virtual void handleUpgrade(
const Request& /*req*/,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
@@ -348,6 +349,7 @@ class WebSocketRule : public BaseRule
asyncResp->res.result(boost::beast::http::status::not_found);
}
+#ifndef BMCWEB_ENABLE_SSL
void handleUpgrade(const Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
boost::asio::ip::tcp::socket&& adaptor) override
@@ -361,7 +363,7 @@ class WebSocketRule : public BaseRule
closeHandler, errorHandler);
myConnection->start();
}
-#ifdef BMCWEB_ENABLE_SSL
+#else
void handleUpgrade(const Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
@@ -1243,20 +1245,10 @@ class Router
return findRoute;
}
- static void
- isUserPrivileged(const boost::system::error_code& ec, Request& req,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
- BaseRule& rule, const RoutingParams& params,
- const dbus::utility::DBusPropertiesMap& userInfoMap)
+ static bool isUserPrivileged(
+ Request& req, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ BaseRule& rule, const dbus::utility::DBusPropertiesMap& userInfoMap)
{
- if (ec)
- {
- BMCWEB_LOG_ERROR << "GetUserInfo failed...";
- asyncResp->res.result(
- boost::beast::http::status::internal_server_error);
- return;
- }
-
std::string userRole{};
const std::string* userRolePtr = nullptr;
const bool* remoteUser = nullptr;
@@ -1271,7 +1263,7 @@ class Router
{
asyncResp->res.result(
boost::beast::http::status::internal_server_error);
- return;
+ return false;
}
if (userRolePtr != nullptr)
@@ -1286,7 +1278,7 @@ class Router
BMCWEB_LOG_ERROR << "RemoteUser property missing or wrong type";
asyncResp->res.result(
boost::beast::http::status::internal_server_error);
- return;
+ return false;
}
bool expired = false;
if (passwordExpired == nullptr)
@@ -1298,7 +1290,7 @@ class Router
" local user but is missing or wrong type";
asyncResp->res.result(
boost::beast::http::status::internal_server_error);
- return;
+ return false;
}
}
else
@@ -1334,15 +1326,60 @@ class Router
"redfish", "v1", "AccountService",
"Accounts", req.session->username));
}
- return;
+ return false;
}
req.userRole = userRole;
- rule.handle(req, asyncResp, params);
+
+ return true;
+ }
+
+ template <typename CallbackFn>
+ void afterGetUserInfo(Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ BaseRule& rule, CallbackFn&& callback,
+ const boost::system::error_code& ec,
+ const dbus::utility::DBusPropertiesMap& userInfoMap)
+ {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "GetUserInfo failed...";
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+
+ if (!Router::isUserPrivileged(req, asyncResp, rule, userInfoMap))
+ {
+ // User is not privileged
+ BMCWEB_LOG_ERROR << "Insufficient Privilege";
+ asyncResp->res.result(boost::beast::http::status::forbidden);
+ return;
+ }
+ callback();
+ }
+
+ template <typename CallbackFn>
+ void validatePrivilege(Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ BaseRule& rule, CallbackFn&& callback)
+ {
+ crow::connections::systemBus->async_method_call(
+ [this, &req, asyncResp, &rule,
+ callback(std::forward<CallbackFn>(callback))](
+ const boost::system::error_code& ec,
+ const dbus::utility::DBusPropertiesMap& userInfoMap) mutable {
+ afterGetUserInfo(req, asyncResp, rule,
+ std::forward<CallbackFn>(callback), ec,
+ userInfoMap);
+ },
+ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+ "xyz.openbmc_project.User.Manager", "GetUserInfo",
+ req.session->username);
}
template <typename Adaptor>
- void handleUpgrade(const Request& req,
+ void handleUpgrade(Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Adaptor&& adaptor)
{
@@ -1372,24 +1409,28 @@ class Router
throw std::runtime_error("Trie internal structure corrupted!");
}
- if ((rules[ruleIndex]->getMethods() &
- (1U << static_cast<size_t>(*verb))) == 0)
+ BaseRule& rule = *rules[ruleIndex];
+ size_t methods = rule.getMethods();
+ if ((methods & (1U << static_cast<size_t>(*verb))) == 0)
{
- BMCWEB_LOG_DEBUG << "Rule found but method mismatch: "
- << req.url().encoded_path() << " with "
- << req.methodString() << "("
- << static_cast<uint32_t>(*verb) << ") / "
- << rules[ruleIndex]->getMethods();
+ BMCWEB_LOG_DEBUG
+ << "Rule found but method mismatch: "
+ << req.url().encoded_path() << " with " << req.methodString()
+ << "(" << static_cast<uint32_t>(*verb) << ") / " << methods;
asyncResp->res.result(boost::beast::http::status::not_found);
return;
}
- BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rules[ruleIndex]->rule
- << "' " << static_cast<uint32_t>(*verb) << " / "
- << rules[ruleIndex]->getMethods();
+ BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rule.rule << "' "
+ << static_cast<uint32_t>(*verb) << " / " << methods;
- rules[ruleIndex]->handleUpgrade(req, asyncResp,
- std::forward<Adaptor>(adaptor));
+ // TODO(ed) This should be able to use std::bind_front, but it doesn't
+ // appear to work with the std::move on adaptor.
+ validatePrivilege(req, asyncResp, rule,
+ [&rule, &req, asyncResp,
+ adaptor(std::forward<Adaptor>(adaptor))]() mutable {
+ rule.handleUpgrade(req, asyncResp, std::move(adaptor));
+ });
}
void handle(Request& req,
@@ -1457,19 +1498,11 @@ class Router
rule.handle(req, asyncResp, params);
return;
}
- std::string username = req.session->username;
-
- crow::connections::systemBus->async_method_call(
- [req{std::move(req)}, asyncResp, &rule, params](
-
- const boost::system::error_code& ec,
- const dbus::utility::DBusPropertiesMap& userInfoMap
- ) mutable {
- isUserPrivileged(ec, req, asyncResp, rule, params, userInfoMap);
- },
- "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
- "xyz.openbmc_project.User.Manager", "GetUserInfo", username);
+ validatePrivilege(req, asyncResp, rule,
+ std::bind_front(&BaseRule::handle, std::ref(rule),
+ std::ref(req), asyncResp,
+ std::ref(params)));
}
void debugPrint()