blob: 4cafe52ec617df983a74ea1f3429fe03d5762cee [file] [log] [blame]
Ed Tanous08bbe112023-04-06 13:10:02 -07001#pragma once
2
3#include "dbus_utility.hpp"
4#include "error_messages.hpp"
5#include "http_request.hpp"
6#include "http_response.hpp"
7#include "logging.hpp"
8#include "routing/baserule.hpp"
9#include "utils/dbus_utils.hpp"
10
11#include <boost/url/format.hpp>
12#include <sdbusplus/unpack_properties.hpp>
13
14#include <memory>
15#include <vector>
16
17namespace crow
18{
Gunnar Mills59ba6382023-08-01 12:41:17 -050019// Populate session with user information.
20inline bool
21 populateUserInfo(Request& req,
Gunnar Mills59ba6382023-08-01 12:41:17 -050022 const dbus::utility::DBusPropertiesMap& userInfoMap)
23{
Gunnar Mills59ba6382023-08-01 12:41:17 -050024 if (req.session == nullptr)
25 {
26 return false;
27 }
28
Jonathan Doman522377d2023-08-18 15:27:54 -070029 std::string userRole;
30 bool remoteUser = false;
31 std::optional<bool> passwordExpired;
32 std::optional<std::vector<std::string>> userGroups;
Gunnar Mills59ba6382023-08-01 12:41:17 -050033
Jonathan Doman522377d2023-08-18 15:27:54 -070034 const bool success = sdbusplus::unpackPropertiesNoThrow(
35 redfish::dbus_utils::UnpackErrorPrinter(), userInfoMap, "UserPrivilege",
36 userRole, "RemoteUser", remoteUser, "UserPasswordExpired",
37 passwordExpired, "UserGroups", userGroups);
38
39 if (!success)
Gunnar Mills59ba6382023-08-01 12:41:17 -050040 {
Jonathan Doman522377d2023-08-18 15:27:54 -070041 BMCWEB_LOG_ERROR("Failed to unpack user properties.");
Gunnar Mills59ba6382023-08-01 12:41:17 -050042 return false;
43 }
Jonathan Doman522377d2023-08-18 15:27:54 -070044
45 if (!remoteUser && (!passwordExpired || !userGroups))
Gunnar Mills59ba6382023-08-01 12:41:17 -050046 {
Jonathan Doman522377d2023-08-18 15:27:54 -070047 BMCWEB_LOG_ERROR(
48 "Missing UserPasswordExpired or UserGroups property for local user");
49 return false;
Gunnar Mills59ba6382023-08-01 12:41:17 -050050 }
Jonathan Doman522377d2023-08-18 15:27:54 -070051
52 req.session->userRole = userRole;
53 BMCWEB_LOG_DEBUG("userName = {} userRole = {}", req.session->username,
54 userRole);
Gunnar Mills59ba6382023-08-01 12:41:17 -050055
56 // Set isConfigureSelfOnly based on D-Bus results. This
57 // ignores the results from both pamAuthenticateUser and the
58 // value from any previous use of this session.
Jonathan Doman522377d2023-08-18 15:27:54 -070059 req.session->isConfigureSelfOnly = passwordExpired.value_or(false);
Gunnar Mills59ba6382023-08-01 12:41:17 -050060
Jonathan Doman522377d2023-08-18 15:27:54 -070061 req.session->userGroups.clear();
62 if (userGroups)
Gunnar Mills59ba6382023-08-01 12:41:17 -050063 {
Jonathan Doman522377d2023-08-18 15:27:54 -070064 req.session->userGroups.swap(*userGroups);
Gunnar Mills59ba6382023-08-01 12:41:17 -050065 }
66
67 return true;
68}
Ed Tanous08bbe112023-04-06 13:10:02 -070069
70inline bool
71 isUserPrivileged(Request& req,
72 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
73 BaseRule& rule)
74{
Ed Tanousd3dfb6e2023-07-27 09:33:49 -070075 if (req.session == nullptr)
76 {
77 return false;
78 }
Ed Tanous08bbe112023-04-06 13:10:02 -070079 // Get the user's privileges from the role
80 redfish::Privileges userPrivileges =
81 redfish::getUserPrivileges(*req.session);
82
83 // Modify privileges if isConfigureSelfOnly.
84 if (req.session->isConfigureSelfOnly)
85 {
86 // Remove all privileges except ConfigureSelf
87 userPrivileges =
88 userPrivileges.intersection(redfish::Privileges{"ConfigureSelf"});
Ed Tanous62598e32023-07-17 17:06:25 -070089 BMCWEB_LOG_DEBUG("Operation limited to ConfigureSelf");
Ed Tanous08bbe112023-04-06 13:10:02 -070090 }
91
92 if (!rule.checkPrivileges(userPrivileges))
93 {
94 asyncResp->res.result(boost::beast::http::status::forbidden);
95 if (req.session->isConfigureSelfOnly)
96 {
97 redfish::messages::passwordChangeRequired(
98 asyncResp->res,
99 boost::urls::format("/redfish/v1/AccountService/Accounts/{}",
100 req.session->username));
101 }
102 return false;
103 }
104
Gunnar Mills59ba6382023-08-01 12:41:17 -0500105 req.userRole = req.session->userRole;
Ed Tanous08bbe112023-04-06 13:10:02 -0700106 return true;
107}
108
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700109inline bool
110 afterGetUserInfo(Request& req,
111 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
112 BaseRule& rule, const boost::system::error_code& ec,
113 const dbus::utility::DBusPropertiesMap& userInfoMap)
Gunnar Mills59ba6382023-08-01 12:41:17 -0500114{
115 if (ec)
116 {
117 BMCWEB_LOG_ERROR("GetUserInfo failed...");
118 asyncResp->res.result(
119 boost::beast::http::status::internal_server_error);
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700120 return false;
Gunnar Mills59ba6382023-08-01 12:41:17 -0500121 }
122
Jonathan Doman522377d2023-08-18 15:27:54 -0700123 if (!populateUserInfo(req, userInfoMap))
Gunnar Mills59ba6382023-08-01 12:41:17 -0500124 {
125 BMCWEB_LOG_ERROR("Failed to populate user information");
126 asyncResp->res.result(
127 boost::beast::http::status::internal_server_error);
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700128 return false;
Gunnar Mills59ba6382023-08-01 12:41:17 -0500129 }
130
131 if (!isUserPrivileged(req, asyncResp, rule))
132 {
133 // User is not privileged
134 BMCWEB_LOG_ERROR("Insufficient Privilege");
135 asyncResp->res.result(boost::beast::http::status::forbidden);
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700136 return false;
Gunnar Mills59ba6382023-08-01 12:41:17 -0500137 }
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700138
139 return true;
Gunnar Mills59ba6382023-08-01 12:41:17 -0500140}
141
142template <typename CallbackFn>
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700143void validatePrivilege(const std::shared_ptr<Request>& req,
Ed Tanous08bbe112023-04-06 13:10:02 -0700144 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
145 BaseRule& rule, CallbackFn&& callback)
146{
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700147 if (req->session == nullptr)
Ed Tanous08bbe112023-04-06 13:10:02 -0700148 {
149 return;
150 }
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700151 std::string username = req->session->username;
Gunnar Mills59ba6382023-08-01 12:41:17 -0500152 crow::connections::systemBus->async_method_call(
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700153 [req, asyncResp, &rule, callback = std::forward<CallbackFn>(callback)](
Gunnar Mills59ba6382023-08-01 12:41:17 -0500154 const boost::system::error_code& ec,
155 const dbus::utility::DBusPropertiesMap& userInfoMap) mutable {
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700156 if (afterGetUserInfo(*req, asyncResp, rule, ec, userInfoMap))
157 {
158 callback();
159 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500160 },
Gunnar Mills59ba6382023-08-01 12:41:17 -0500161 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
162 "xyz.openbmc_project.User.Manager", "GetUserInfo", username);
Ed Tanous08bbe112023-04-06 13:10:02 -0700163}
164
165} // namespace crow