blob: ed0879714a8cfaa824dece32c77988e7d133b6ec [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
Ed Tanous08bbe112023-04-06 13:10:02 -07003#pragma once
4
5#include "dbus_utility.hpp"
6#include "error_messages.hpp"
7#include "http_request.hpp"
8#include "http_response.hpp"
9#include "logging.hpp"
10#include "routing/baserule.hpp"
11#include "utils/dbus_utils.hpp"
12
13#include <boost/url/format.hpp>
14#include <sdbusplus/unpack_properties.hpp>
15
16#include <memory>
Paul Fertser478c5a52024-06-26 22:27:59 +000017#include <string>
18#include <utility>
Ed Tanous08bbe112023-04-06 13:10:02 -070019#include <vector>
20
21namespace crow
22{
Gunnar Mills59ba6382023-08-01 12:41:17 -050023// Populate session with user information.
24inline bool
Paul Fertser478c5a52024-06-26 22:27:59 +000025 populateUserInfo(persistent_data::UserSession& session,
Gunnar Mills59ba6382023-08-01 12:41:17 -050026 const dbus::utility::DBusPropertiesMap& userInfoMap)
27{
Jonathan Doman522377d2023-08-18 15:27:54 -070028 std::string userRole;
29 bool remoteUser = false;
30 std::optional<bool> passwordExpired;
31 std::optional<std::vector<std::string>> userGroups;
Gunnar Mills59ba6382023-08-01 12:41:17 -050032
Jonathan Doman522377d2023-08-18 15:27:54 -070033 const bool success = sdbusplus::unpackPropertiesNoThrow(
34 redfish::dbus_utils::UnpackErrorPrinter(), userInfoMap, "UserPrivilege",
35 userRole, "RemoteUser", remoteUser, "UserPasswordExpired",
36 passwordExpired, "UserGroups", userGroups);
37
38 if (!success)
Gunnar Mills59ba6382023-08-01 12:41:17 -050039 {
Jonathan Doman522377d2023-08-18 15:27:54 -070040 BMCWEB_LOG_ERROR("Failed to unpack user properties.");
Gunnar Mills59ba6382023-08-01 12:41:17 -050041 return false;
42 }
Jonathan Doman522377d2023-08-18 15:27:54 -070043
44 if (!remoteUser && (!passwordExpired || !userGroups))
Gunnar Mills59ba6382023-08-01 12:41:17 -050045 {
Jonathan Doman522377d2023-08-18 15:27:54 -070046 BMCWEB_LOG_ERROR(
47 "Missing UserPasswordExpired or UserGroups property for local user");
48 return false;
Gunnar Mills59ba6382023-08-01 12:41:17 -050049 }
Jonathan Doman522377d2023-08-18 15:27:54 -070050
Paul Fertser478c5a52024-06-26 22:27:59 +000051 session.userRole = userRole;
52 BMCWEB_LOG_DEBUG("userName = {} userRole = {}", session.username, userRole);
Gunnar Mills59ba6382023-08-01 12:41:17 -050053
54 // Set isConfigureSelfOnly based on D-Bus results. This
55 // ignores the results from both pamAuthenticateUser and the
56 // value from any previous use of this session.
Paul Fertser478c5a52024-06-26 22:27:59 +000057 session.isConfigureSelfOnly = passwordExpired.value_or(false);
Gunnar Mills59ba6382023-08-01 12:41:17 -050058
Paul Fertser478c5a52024-06-26 22:27:59 +000059 session.userGroups.clear();
Jonathan Doman522377d2023-08-18 15:27:54 -070060 if (userGroups)
Gunnar Mills59ba6382023-08-01 12:41:17 -050061 {
Paul Fertser478c5a52024-06-26 22:27:59 +000062 session.userGroups.swap(*userGroups);
Gunnar Mills59ba6382023-08-01 12:41:17 -050063 }
64
65 return true;
66}
Ed Tanous08bbe112023-04-06 13:10:02 -070067
Patrick Williamsbd79bce2024-08-16 15:22:20 -040068inline bool isUserPrivileged(
69 Request& req, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
70 BaseRule& rule)
Ed Tanous08bbe112023-04-06 13:10:02 -070071{
Ed Tanousd3dfb6e2023-07-27 09:33:49 -070072 if (req.session == nullptr)
73 {
74 return false;
75 }
Ed Tanous08bbe112023-04-06 13:10:02 -070076 // Get the user's privileges from the role
77 redfish::Privileges userPrivileges =
78 redfish::getUserPrivileges(*req.session);
79
80 // Modify privileges if isConfigureSelfOnly.
81 if (req.session->isConfigureSelfOnly)
82 {
83 // Remove all privileges except ConfigureSelf
84 userPrivileges =
85 userPrivileges.intersection(redfish::Privileges{"ConfigureSelf"});
Ed Tanous62598e32023-07-17 17:06:25 -070086 BMCWEB_LOG_DEBUG("Operation limited to ConfigureSelf");
Ed Tanous08bbe112023-04-06 13:10:02 -070087 }
88
89 if (!rule.checkPrivileges(userPrivileges))
90 {
91 asyncResp->res.result(boost::beast::http::status::forbidden);
92 if (req.session->isConfigureSelfOnly)
93 {
94 redfish::messages::passwordChangeRequired(
95 asyncResp->res,
96 boost::urls::format("/redfish/v1/AccountService/Accounts/{}",
97 req.session->username));
98 }
99 return false;
100 }
101
Gunnar Mills59ba6382023-08-01 12:41:17 -0500102 req.userRole = req.session->userRole;
Ed Tanous08bbe112023-04-06 13:10:02 -0700103 return true;
104}
105
Paul Fertser478c5a52024-06-26 22:27:59 +0000106inline bool afterGetUserInfoValidate(
107 Request& req, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
108 BaseRule& rule, const dbus::utility::DBusPropertiesMap& userInfoMap)
Gunnar Mills59ba6382023-08-01 12:41:17 -0500109{
Paul Fertser478c5a52024-06-26 22:27:59 +0000110 if (req.session == nullptr || !populateUserInfo(*req.session, userInfoMap))
Gunnar Mills59ba6382023-08-01 12:41:17 -0500111 {
112 BMCWEB_LOG_ERROR("Failed to populate user information");
113 asyncResp->res.result(
114 boost::beast::http::status::internal_server_error);
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700115 return false;
Gunnar Mills59ba6382023-08-01 12:41:17 -0500116 }
117
118 if (!isUserPrivileged(req, asyncResp, rule))
119 {
120 // User is not privileged
121 BMCWEB_LOG_ERROR("Insufficient Privilege");
122 asyncResp->res.result(boost::beast::http::status::forbidden);
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700123 return false;
Gunnar Mills59ba6382023-08-01 12:41:17 -0500124 }
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700125
126 return true;
Gunnar Mills59ba6382023-08-01 12:41:17 -0500127}
128
129template <typename CallbackFn>
Paul Fertser478c5a52024-06-26 22:27:59 +0000130void requestUserInfo(const std::string& username,
131 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
132 CallbackFn&& callback)
133{
134 crow::connections::systemBus->async_method_call(
135 [asyncResp, callback = std::forward<CallbackFn>(callback)](
136 const boost::system::error_code& ec,
137 const dbus::utility::DBusPropertiesMap& userInfoMap) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400138 if (ec)
139 {
140 BMCWEB_LOG_ERROR("GetUserInfo failed...");
141 asyncResp->res.result(
142 boost::beast::http::status::internal_server_error);
143 return;
144 }
145 callback(userInfoMap);
146 },
Paul Fertser478c5a52024-06-26 22:27:59 +0000147 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
148 "xyz.openbmc_project.User.Manager", "GetUserInfo", username);
149}
150
151template <typename CallbackFn>
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700152void validatePrivilege(const std::shared_ptr<Request>& req,
Ed Tanous08bbe112023-04-06 13:10:02 -0700153 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
154 BaseRule& rule, CallbackFn&& callback)
155{
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700156 if (req->session == nullptr)
Ed Tanous08bbe112023-04-06 13:10:02 -0700157 {
158 return;
159 }
Paul Fertser478c5a52024-06-26 22:27:59 +0000160
161 requestUserInfo(
162 req->session->username, asyncResp,
Jonathan Doman102a4cd2024-04-15 16:56:23 -0700163 [req, asyncResp, &rule, callback = std::forward<CallbackFn>(callback)](
Gunnar Mills59ba6382023-08-01 12:41:17 -0500164 const dbus::utility::DBusPropertiesMap& userInfoMap) mutable {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400165 if (afterGetUserInfoValidate(*req, asyncResp, rule, userInfoMap))
166 {
167 callback();
168 }
169 });
Paul Fertser478c5a52024-06-26 22:27:59 +0000170}
171
172template <typename CallbackFn>
173void getUserInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
174 const std::string& username,
175 std::shared_ptr<persistent_data::UserSession>& session,
176 CallbackFn&& callback)
177{
178 requestUserInfo(
179 username, asyncResp,
180 [asyncResp, session, callback = std::forward<CallbackFn>(callback)](
181 const dbus::utility::DBusPropertiesMap& userInfoMap) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400182 if (!populateUserInfo(*session, userInfoMap))
183 {
184 BMCWEB_LOG_ERROR("Failed to populate user information");
185 asyncResp->res.result(
186 boost::beast::http::status::internal_server_error);
187 return;
188 }
189 callback();
190 });
Ed Tanous08bbe112023-04-06 13:10:02 -0700191}
192
193} // namespace crow