blob: 65b404249235de8ea4390d837c9b38206c231a3e [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{
19// Populate session with user information.
20inline bool
21 populateUserInfo(Request& req,
22 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
23 const dbus::utility::DBusPropertiesMap& userInfoMap)
24{
25 const std::string* userRolePtr = nullptr;
26 const bool* remoteUser = nullptr;
27 const bool* passwordExpired = nullptr;
28 const std::vector<std::string>* userGroups = nullptr;
29
30 const bool success = sdbusplus::unpackPropertiesNoThrow(
31 redfish::dbus_utils::UnpackErrorPrinter(), userInfoMap, "UserPrivilege",
32 userRolePtr, "RemoteUser", remoteUser, "UserPasswordExpired",
33 passwordExpired, "UserGroups", userGroups);
34
35 if (!success)
36 {
Ed Tanous62598e32023-07-17 17:06:25 -070037 BMCWEB_LOG_ERROR("Failed to unpack user properties.");
Ed Tanous08bbe112023-04-06 13:10:02 -070038 asyncResp->res.result(
39 boost::beast::http::status::internal_server_error);
40 return false;
41 }
42
43 if (userRolePtr != nullptr)
44 {
45 req.session->userRole = *userRolePtr;
Ed Tanous62598e32023-07-17 17:06:25 -070046 BMCWEB_LOG_DEBUG("userName = {} userRole = {}", req.session->username,
47 *userRolePtr);
Ed Tanous08bbe112023-04-06 13:10:02 -070048 }
49
50 if (remoteUser == nullptr)
51 {
Ed Tanous62598e32023-07-17 17:06:25 -070052 BMCWEB_LOG_ERROR("RemoteUser property missing or wrong type");
Ed Tanous08bbe112023-04-06 13:10:02 -070053 asyncResp->res.result(
54 boost::beast::http::status::internal_server_error);
55 return false;
56 }
57 bool expired = false;
58 if (passwordExpired == nullptr)
59 {
60 if (!*remoteUser)
61 {
Ed Tanous62598e32023-07-17 17:06:25 -070062 BMCWEB_LOG_ERROR("UserPasswordExpired property is expected for"
63 " local user but is missing or wrong type");
Ed Tanous08bbe112023-04-06 13:10:02 -070064 asyncResp->res.result(
65 boost::beast::http::status::internal_server_error);
66 return false;
67 }
68 }
69 else
70 {
71 expired = *passwordExpired;
72 }
73
74 // Set isConfigureSelfOnly based on D-Bus results. This
75 // ignores the results from both pamAuthenticateUser and the
76 // value from any previous use of this session.
77 req.session->isConfigureSelfOnly = expired;
78
79 if (userGroups != nullptr)
80 {
81 // Populate session with user groups.
82 for (const auto& userGroup : *userGroups)
83 {
84 req.session->userGroups.emplace_back(userGroup);
85 }
86 }
87
88 return true;
89}
90
91inline bool
92 isUserPrivileged(Request& req,
93 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
94 BaseRule& rule)
95{
96 // Get the user's privileges from the role
97 redfish::Privileges userPrivileges =
98 redfish::getUserPrivileges(*req.session);
99
100 // Modify privileges if isConfigureSelfOnly.
101 if (req.session->isConfigureSelfOnly)
102 {
103 // Remove all privileges except ConfigureSelf
104 userPrivileges =
105 userPrivileges.intersection(redfish::Privileges{"ConfigureSelf"});
Ed Tanous62598e32023-07-17 17:06:25 -0700106 BMCWEB_LOG_DEBUG("Operation limited to ConfigureSelf");
Ed Tanous08bbe112023-04-06 13:10:02 -0700107 }
108
109 if (!rule.checkPrivileges(userPrivileges))
110 {
111 asyncResp->res.result(boost::beast::http::status::forbidden);
112 if (req.session->isConfigureSelfOnly)
113 {
114 redfish::messages::passwordChangeRequired(
115 asyncResp->res,
116 boost::urls::format("/redfish/v1/AccountService/Accounts/{}",
117 req.session->username));
118 }
119 return false;
120 }
121
122 req.userRole = req.session->userRole;
123 return true;
124}
125
126template <typename CallbackFn>
127void afterGetUserInfo(Request& req,
128 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
129 BaseRule& rule, CallbackFn&& callback,
130 const boost::system::error_code& ec,
131 const dbus::utility::DBusPropertiesMap& userInfoMap)
132{
133 if (ec)
134 {
Ed Tanous62598e32023-07-17 17:06:25 -0700135 BMCWEB_LOG_ERROR("GetUserInfo failed...");
Ed Tanous08bbe112023-04-06 13:10:02 -0700136 asyncResp->res.result(
137 boost::beast::http::status::internal_server_error);
138 return;
139 }
140
141 if (!populateUserInfo(req, asyncResp, userInfoMap))
142 {
Ed Tanous62598e32023-07-17 17:06:25 -0700143 BMCWEB_LOG_ERROR("Failed to populate user information");
Ed Tanous08bbe112023-04-06 13:10:02 -0700144 asyncResp->res.result(
145 boost::beast::http::status::internal_server_error);
146 return;
147 }
148
149 if (!isUserPrivileged(req, asyncResp, rule))
150 {
151 // User is not privileged
Ed Tanous62598e32023-07-17 17:06:25 -0700152 BMCWEB_LOG_ERROR("Insufficient Privilege");
Ed Tanous08bbe112023-04-06 13:10:02 -0700153 asyncResp->res.result(boost::beast::http::status::forbidden);
154 return;
155 }
156 callback(req);
157}
158
159template <typename CallbackFn>
160void validatePrivilege(Request& req,
161 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
162 BaseRule& rule, CallbackFn&& callback)
163{
164 if (req.session == nullptr)
165 {
166 return;
167 }
168 std::string username = req.session->username;
169 crow::connections::systemBus->async_method_call(
170 [&req, asyncResp, &rule, callback(std::forward<CallbackFn>(callback))](
171 const boost::system::error_code& ec,
172 const dbus::utility::DBusPropertiesMap& userInfoMap) mutable {
173 afterGetUserInfo(req, asyncResp, rule,
174 std::forward<CallbackFn>(callback), ec, userInfoMap);
175 },
176 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
177 "xyz.openbmc_project.User.Manager", "GetUserInfo", username);
178}
179
180} // namespace crow