xref: /openbmc/bmcweb/features/redfish/lib/account_service.hpp (revision f12894f8bd7fc26ffa16e5a89072e6c19095f866)
188d16c9aSLewanczyk, Dawid /*
288d16c9aSLewanczyk, Dawid // Copyright (c) 2018 Intel Corporation
388d16c9aSLewanczyk, Dawid //
488d16c9aSLewanczyk, Dawid // Licensed under the Apache License, Version 2.0 (the "License");
588d16c9aSLewanczyk, Dawid // you may not use this file except in compliance with the License.
688d16c9aSLewanczyk, Dawid // You may obtain a copy of the License at
788d16c9aSLewanczyk, Dawid //
888d16c9aSLewanczyk, Dawid //      http://www.apache.org/licenses/LICENSE-2.0
988d16c9aSLewanczyk, Dawid //
1088d16c9aSLewanczyk, Dawid // Unless required by applicable law or agreed to in writing, software
1188d16c9aSLewanczyk, Dawid // distributed under the License is distributed on an "AS IS" BASIS,
1288d16c9aSLewanczyk, Dawid // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1388d16c9aSLewanczyk, Dawid // See the License for the specific language governing permissions and
1488d16c9aSLewanczyk, Dawid // limitations under the License.
1588d16c9aSLewanczyk, Dawid */
1688d16c9aSLewanczyk, Dawid #pragma once
1788d16c9aSLewanczyk, Dawid #include "node.hpp"
1888d16c9aSLewanczyk, Dawid 
1965b0dc32SEd Tanous #include <error_messages.hpp>
20b9b2e0b2SEd Tanous #include <openbmc_dbus_rest.hpp>
21a840879dSEd Tanous #include <utils/json_utils.hpp>
22b9b2e0b2SEd Tanous 
231abe55efSEd Tanous namespace redfish
241abe55efSEd Tanous {
2588d16c9aSLewanczyk, Dawid 
26b9b2e0b2SEd Tanous using ManagedObjectType = std::vector<std::pair<
27b9b2e0b2SEd Tanous     sdbusplus::message::object_path,
28b9b2e0b2SEd Tanous     boost::container::flat_map<
29b9b2e0b2SEd Tanous         std::string, boost::container::flat_map<
30b9b2e0b2SEd Tanous                          std::string, sdbusplus::message::variant<bool>>>>>;
31b9b2e0b2SEd Tanous 
321abe55efSEd Tanous class AccountService : public Node
331abe55efSEd Tanous {
3488d16c9aSLewanczyk, Dawid   public:
351abe55efSEd Tanous     AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/")
361abe55efSEd Tanous     {
37c1a46bd2SBorawski.Lukasz         Node::json["@odata.id"] = "/redfish/v1/AccountService";
38c1a46bd2SBorawski.Lukasz         Node::json["@odata.type"] = "#AccountService.v1_1_0.AccountService";
39c1a46bd2SBorawski.Lukasz         Node::json["@odata.context"] =
4088d16c9aSLewanczyk, Dawid             "/redfish/v1/$metadata#AccountService.AccountService";
41c1a46bd2SBorawski.Lukasz         Node::json["Id"] = "AccountService";
42c1a46bd2SBorawski.Lukasz         Node::json["Description"] = "BMC User Accounts";
43c1a46bd2SBorawski.Lukasz         Node::json["Name"] = "Account Service";
44c1a46bd2SBorawski.Lukasz         Node::json["ServiceEnabled"] = true;
45c1a46bd2SBorawski.Lukasz         Node::json["MinPasswordLength"] = 1;
46c1a46bd2SBorawski.Lukasz         Node::json["MaxPasswordLength"] = 20;
471abe55efSEd Tanous         Node::json["Accounts"]["@odata.id"] =
481abe55efSEd Tanous             "/redfish/v1/AccountService/Accounts";
49c1a46bd2SBorawski.Lukasz         Node::json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
503ebd75f7SEd Tanous 
513ebd75f7SEd Tanous         entityPrivileges = {
524b1b8683SBorawski.Lukasz             {boost::beast::http::verb::get,
534b1b8683SBorawski.Lukasz              {{"ConfigureUsers"}, {"ConfigureManager"}}},
54e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
55e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
56e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
57e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
58e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
5988d16c9aSLewanczyk, Dawid     }
6088d16c9aSLewanczyk, Dawid 
6188d16c9aSLewanczyk, Dawid   private:
6255c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
631abe55efSEd Tanous                const std::vector<std::string>& params) override
641abe55efSEd Tanous     {
6555c7b7a2SEd Tanous         res.jsonValue = Node::json;
6688d16c9aSLewanczyk, Dawid         res.end();
6788d16c9aSLewanczyk, Dawid     }
6888d16c9aSLewanczyk, Dawid };
69b9b2e0b2SEd Tanous class AccountsCollection : public Node
70b9b2e0b2SEd Tanous {
71b9b2e0b2SEd Tanous   public:
72b9b2e0b2SEd Tanous     AccountsCollection(CrowApp& app) :
73b9b2e0b2SEd Tanous         Node(app, "/redfish/v1/AccountService/Accounts/")
74b9b2e0b2SEd Tanous     {
75b9b2e0b2SEd Tanous 
76b9b2e0b2SEd Tanous         Node::json = {{"@odata.context", "/redfish/v1/"
77b9b2e0b2SEd Tanous                                          "$metadata#ManagerAccountCollection."
78b9b2e0b2SEd Tanous                                          "ManagerAccountCollection"},
79b9b2e0b2SEd Tanous                       {"@odata.id", "/redfish/v1/AccountService/Accounts"},
80b9b2e0b2SEd Tanous                       {"@odata.type", "#ManagerAccountCollection."
81b9b2e0b2SEd Tanous                                       "ManagerAccountCollection"},
82b9b2e0b2SEd Tanous                       {"Name", "Accounts Collection"},
83b9b2e0b2SEd Tanous                       {"Description", "BMC User Accounts"}};
84b9b2e0b2SEd Tanous 
85b9b2e0b2SEd Tanous         entityPrivileges = {
86b9b2e0b2SEd Tanous             {boost::beast::http::verb::get,
87b9b2e0b2SEd Tanous              {{"ConfigureUsers"}, {"ConfigureManager"}}},
88b9b2e0b2SEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
89b9b2e0b2SEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
90b9b2e0b2SEd Tanous             {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
91b9b2e0b2SEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
92b9b2e0b2SEd Tanous             {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
93b9b2e0b2SEd Tanous     }
94b9b2e0b2SEd Tanous 
95b9b2e0b2SEd Tanous   private:
96b9b2e0b2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
97b9b2e0b2SEd Tanous                const std::vector<std::string>& params) override
98b9b2e0b2SEd Tanous     {
99b9b2e0b2SEd Tanous         res.jsonValue = Node::json;
100b9b2e0b2SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
101b9b2e0b2SEd Tanous         crow::connections::systemBus->async_method_call(
102b9b2e0b2SEd Tanous             [asyncResp](const boost::system::error_code ec,
103b9b2e0b2SEd Tanous                         const ManagedObjectType& users) {
104b9b2e0b2SEd Tanous                 if (ec)
105b9b2e0b2SEd Tanous                 {
106*f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
107b9b2e0b2SEd Tanous                     return;
108b9b2e0b2SEd Tanous                 }
109b9b2e0b2SEd Tanous 
110b9b2e0b2SEd Tanous                 nlohmann::json& memberArray =
111b9b2e0b2SEd Tanous                     asyncResp->res.jsonValue["Members"];
112b9b2e0b2SEd Tanous                 memberArray = nlohmann::json::array();
113b9b2e0b2SEd Tanous 
114b9b2e0b2SEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] = users.size();
115b9b2e0b2SEd Tanous                 for (auto& user : users)
116b9b2e0b2SEd Tanous                 {
117b9b2e0b2SEd Tanous                     const std::string& path =
118b9b2e0b2SEd Tanous                         static_cast<const std::string&>(user.first);
119b9b2e0b2SEd Tanous                     std::size_t lastIndex = path.rfind("/");
120b9b2e0b2SEd Tanous                     if (lastIndex == std::string::npos)
121b9b2e0b2SEd Tanous                     {
122b9b2e0b2SEd Tanous                         lastIndex = 0;
123b9b2e0b2SEd Tanous                     }
124b9b2e0b2SEd Tanous                     else
125b9b2e0b2SEd Tanous                     {
126b9b2e0b2SEd Tanous                         lastIndex += 1;
127b9b2e0b2SEd Tanous                     }
128b9b2e0b2SEd Tanous                     memberArray.push_back(
129b9b2e0b2SEd Tanous                         {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
130b9b2e0b2SEd Tanous                                            path.substr(lastIndex)}});
131b9b2e0b2SEd Tanous                 }
132b9b2e0b2SEd Tanous             },
133b9b2e0b2SEd Tanous             "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
134b9b2e0b2SEd Tanous             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
135b9b2e0b2SEd Tanous     }
13604ae99ecSEd Tanous     void doPost(crow::Response& res, const crow::Request& req,
13704ae99ecSEd Tanous                 const std::vector<std::string>& params) override
13804ae99ecSEd Tanous     {
13904ae99ecSEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
14004ae99ecSEd Tanous 
1419712f8acSEd Tanous         std::string username;
1429712f8acSEd Tanous         std::string password;
1439712f8acSEd Tanous         boost::optional<std::string> roleId("User");
1449712f8acSEd Tanous         boost::optional<bool> enabled = true;
1459712f8acSEd Tanous         if (!json_util::readJson(req, res, "UserName", username, "Password",
1469712f8acSEd Tanous                                  password, "RoleId", roleId, "Enabled",
1479712f8acSEd Tanous                                  enabled))
14804ae99ecSEd Tanous         {
14904ae99ecSEd Tanous             return;
15004ae99ecSEd Tanous         }
15104ae99ecSEd Tanous 
1529712f8acSEd Tanous         const char* priv = getRoleIdFromPrivilege(*roleId);
15304ae99ecSEd Tanous         if (priv == nullptr)
15404ae99ecSEd Tanous         {
155*f12894f8SJason M. Bills             messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
15604ae99ecSEd Tanous             return;
15704ae99ecSEd Tanous         }
1589712f8acSEd Tanous         roleId = priv;
15904ae99ecSEd Tanous 
16004ae99ecSEd Tanous         crow::connections::systemBus->async_method_call(
1619712f8acSEd Tanous             [asyncResp, username, password{std::move(password)}](
16204ae99ecSEd Tanous                 const boost::system::error_code ec) {
16304ae99ecSEd Tanous                 if (ec)
16404ae99ecSEd Tanous                 {
16504ae99ecSEd Tanous                     messages::resourceAlreadyExists(
166*f12894f8SJason M. Bills                         asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
167*f12894f8SJason M. Bills                         "UserName", username);
16804ae99ecSEd Tanous                     return;
16904ae99ecSEd Tanous                 }
17004ae99ecSEd Tanous 
17104ae99ecSEd Tanous                 if (!pamUpdatePassword(username, password))
17204ae99ecSEd Tanous                 {
17304ae99ecSEd Tanous                     // At this point we have a user that's been created, but the
17404ae99ecSEd Tanous                     // password set failed.  Something is wrong, so delete the
17504ae99ecSEd Tanous                     // user that we've already created
17604ae99ecSEd Tanous                     crow::connections::systemBus->async_method_call(
17704ae99ecSEd Tanous                         [asyncResp](const boost::system::error_code ec) {
17804ae99ecSEd Tanous                             if (ec)
17904ae99ecSEd Tanous                             {
180*f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
18104ae99ecSEd Tanous                                 return;
18204ae99ecSEd Tanous                             }
18304ae99ecSEd Tanous 
184*f12894f8SJason M. Bills                             messages::invalidObject(asyncResp->res, "Password");
18504ae99ecSEd Tanous                         },
18604ae99ecSEd Tanous                         "xyz.openbmc_project.User.Manager",
18704ae99ecSEd Tanous                         "/xyz/openbmc_project/user/" + username,
18804ae99ecSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
18904ae99ecSEd Tanous 
19004ae99ecSEd Tanous                     BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
19104ae99ecSEd Tanous                     return;
19204ae99ecSEd Tanous                 }
19304ae99ecSEd Tanous 
194*f12894f8SJason M. Bills                 messages::created(asyncResp->res);
19504ae99ecSEd Tanous                 asyncResp->res.addHeader(
19604ae99ecSEd Tanous                     "Location",
19704ae99ecSEd Tanous                     "/redfish/v1/AccountService/Accounts/" + username);
19804ae99ecSEd Tanous             },
19904ae99ecSEd Tanous             "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
2009712f8acSEd Tanous             "xyz.openbmc_project.User.Manager", "CreateUser", username,
20104ae99ecSEd Tanous             std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"},
2029712f8acSEd Tanous             *roleId, *enabled);
20304ae99ecSEd Tanous     }
20404ae99ecSEd Tanous 
20504ae99ecSEd Tanous     static const char* getRoleIdFromPrivilege(boost::beast::string_view role)
20604ae99ecSEd Tanous     {
20704ae99ecSEd Tanous         if (role == "Administrator")
20804ae99ecSEd Tanous         {
20904ae99ecSEd Tanous             return "priv-admin";
21004ae99ecSEd Tanous         }
21104ae99ecSEd Tanous         else if (role == "Callback")
21204ae99ecSEd Tanous         {
21304ae99ecSEd Tanous             return "priv-callback";
21404ae99ecSEd Tanous         }
21504ae99ecSEd Tanous         else if (role == "User")
21604ae99ecSEd Tanous         {
21704ae99ecSEd Tanous             return "priv-user";
21804ae99ecSEd Tanous         }
21904ae99ecSEd Tanous         else if (role == "Operator")
22004ae99ecSEd Tanous         {
22104ae99ecSEd Tanous             return "priv-operator";
22204ae99ecSEd Tanous         }
22304ae99ecSEd Tanous         return nullptr;
22404ae99ecSEd Tanous     }
225b9b2e0b2SEd Tanous };
226b9b2e0b2SEd Tanous 
227a840879dSEd Tanous template <typename Callback>
228a840879dSEd Tanous inline void checkDbusPathExists(const std::string& path, Callback&& callback)
229a840879dSEd Tanous {
230a840879dSEd Tanous     using GetObjectType =
231a840879dSEd Tanous         std::vector<std::pair<std::string, std::vector<std::string>>>;
232a840879dSEd Tanous 
233a840879dSEd Tanous     crow::connections::systemBus->async_method_call(
234a840879dSEd Tanous         [callback{std::move(callback)}](const boost::system::error_code ec,
235a840879dSEd Tanous                                         const GetObjectType& object_names) {
236a840879dSEd Tanous             callback(ec || object_names.size() == 0);
237a840879dSEd Tanous         },
238a840879dSEd Tanous         "xyz.openbmc_project.ObjectMapper",
239a840879dSEd Tanous         "/xyz/openbmc_project/object_mapper",
240a840879dSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetObject", path,
241a840879dSEd Tanous         std::array<std::string, 0>());
242a840879dSEd Tanous }
243a840879dSEd Tanous 
244b9b2e0b2SEd Tanous class ManagerAccount : public Node
245b9b2e0b2SEd Tanous {
246b9b2e0b2SEd Tanous   public:
247b9b2e0b2SEd Tanous     ManagerAccount(CrowApp& app) :
248b9b2e0b2SEd Tanous         Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string())
249b9b2e0b2SEd Tanous     {
250b9b2e0b2SEd Tanous         Node::json = {{"@odata.context",
251b9b2e0b2SEd Tanous                        "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
252b9b2e0b2SEd Tanous                       {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
253b9b2e0b2SEd Tanous 
254b9b2e0b2SEd Tanous                       {"Name", "User Account"},
255b9b2e0b2SEd Tanous                       {"Description", "User Account"},
256b9b2e0b2SEd Tanous                       {"Password", nullptr},
257b9b2e0b2SEd Tanous                       {"RoleId", "Administrator"},
258b9b2e0b2SEd Tanous                       {"Links",
259b9b2e0b2SEd Tanous                        {{"Role",
260b9b2e0b2SEd Tanous                          {{"@odata.id", "/redfish/v1/AccountService/Roles/"
261b9b2e0b2SEd Tanous                                         "Administrator"}}}}}};
262b9b2e0b2SEd Tanous 
263b9b2e0b2SEd Tanous         entityPrivileges = {
264b9b2e0b2SEd Tanous             {boost::beast::http::verb::get,
265b9b2e0b2SEd Tanous              {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}},
266b9b2e0b2SEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
267b9b2e0b2SEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
268b9b2e0b2SEd Tanous             {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
269b9b2e0b2SEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
270b9b2e0b2SEd Tanous             {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
271b9b2e0b2SEd Tanous     }
272b9b2e0b2SEd Tanous 
273b9b2e0b2SEd Tanous   private:
274b9b2e0b2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
275b9b2e0b2SEd Tanous                const std::vector<std::string>& params) override
276b9b2e0b2SEd Tanous     {
277b9b2e0b2SEd Tanous         res.jsonValue = Node::json;
278b9b2e0b2SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
279b9b2e0b2SEd Tanous 
280b9b2e0b2SEd Tanous         if (params.size() != 1)
281b9b2e0b2SEd Tanous         {
282*f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
283b9b2e0b2SEd Tanous             return;
284b9b2e0b2SEd Tanous         }
285b9b2e0b2SEd Tanous 
286b9b2e0b2SEd Tanous         crow::connections::systemBus->async_method_call(
287b9b2e0b2SEd Tanous             [asyncResp, accountName{std::string(params[0])}](
288b9b2e0b2SEd Tanous                 const boost::system::error_code ec,
289b9b2e0b2SEd Tanous                 const ManagedObjectType& users) {
290b9b2e0b2SEd Tanous                 if (ec)
291b9b2e0b2SEd Tanous                 {
292*f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
293b9b2e0b2SEd Tanous                     return;
294b9b2e0b2SEd Tanous                 }
295b9b2e0b2SEd Tanous 
296b9b2e0b2SEd Tanous                 for (auto& user : users)
297b9b2e0b2SEd Tanous                 {
298b9b2e0b2SEd Tanous                     const std::string& path =
299b9b2e0b2SEd Tanous                         static_cast<const std::string&>(user.first);
300b9b2e0b2SEd Tanous                     std::size_t lastIndex = path.rfind("/");
301b9b2e0b2SEd Tanous                     if (lastIndex == std::string::npos)
302b9b2e0b2SEd Tanous                     {
303b9b2e0b2SEd Tanous                         lastIndex = 0;
304b9b2e0b2SEd Tanous                     }
305b9b2e0b2SEd Tanous                     else
306b9b2e0b2SEd Tanous                     {
307b9b2e0b2SEd Tanous                         lastIndex += 1;
308b9b2e0b2SEd Tanous                     }
309b9b2e0b2SEd Tanous                     if (path.substr(lastIndex) == accountName)
310b9b2e0b2SEd Tanous                     {
31165b0dc32SEd Tanous                         for (const auto& interface : user.second)
31265b0dc32SEd Tanous                         {
31365b0dc32SEd Tanous                             if (interface.first ==
31465b0dc32SEd Tanous                                 "xyz.openbmc_project.User.Attributes")
31565b0dc32SEd Tanous                             {
31665b0dc32SEd Tanous                                 for (const auto& property : interface.second)
31765b0dc32SEd Tanous                                 {
31865b0dc32SEd Tanous                                     if (property.first == "UserEnabled")
31965b0dc32SEd Tanous                                     {
32065b0dc32SEd Tanous                                         const bool* userEnabled =
32165b0dc32SEd Tanous                                             mapbox::getPtr<const bool>(
32265b0dc32SEd Tanous                                                 property.second);
32365b0dc32SEd Tanous                                         if (userEnabled == nullptr)
32465b0dc32SEd Tanous                                         {
32565b0dc32SEd Tanous                                             BMCWEB_LOG_ERROR
32665b0dc32SEd Tanous                                                 << "UserEnabled wasn't a bool";
32765b0dc32SEd Tanous                                             continue;
32865b0dc32SEd Tanous                                         }
32965b0dc32SEd Tanous                                         asyncResp->res.jsonValue["Enabled"] =
33065b0dc32SEd Tanous                                             *userEnabled;
33165b0dc32SEd Tanous                                     }
33265b0dc32SEd Tanous                                     else if (property.first ==
33365b0dc32SEd Tanous                                              "UserLockedForFailedAttempt")
33465b0dc32SEd Tanous                                     {
33565b0dc32SEd Tanous                                         const bool* userLocked =
33665b0dc32SEd Tanous                                             mapbox::getPtr<const bool>(
33765b0dc32SEd Tanous                                                 property.second);
33865b0dc32SEd Tanous                                         if (userLocked == nullptr)
33965b0dc32SEd Tanous                                         {
34065b0dc32SEd Tanous                                             BMCWEB_LOG_ERROR
34165b0dc32SEd Tanous                                                 << "UserEnabled wasn't a bool";
34265b0dc32SEd Tanous                                             continue;
34365b0dc32SEd Tanous                                         }
34465b0dc32SEd Tanous                                         asyncResp->res.jsonValue["Locked"] =
34565b0dc32SEd Tanous                                             *userLocked;
34665b0dc32SEd Tanous                                     }
34765b0dc32SEd Tanous                                 }
34865b0dc32SEd Tanous                             }
34965b0dc32SEd Tanous                         }
35065b0dc32SEd Tanous 
351b9b2e0b2SEd Tanous                         asyncResp->res.jsonValue["@odata.id"] =
352b9b2e0b2SEd Tanous                             "/redfish/v1/AccountService/Accounts/" +
353b9b2e0b2SEd Tanous                             accountName;
354b9b2e0b2SEd Tanous                         asyncResp->res.jsonValue["Id"] = accountName;
355b9b2e0b2SEd Tanous                         asyncResp->res.jsonValue["UserName"] = accountName;
356b9b2e0b2SEd Tanous 
357b9b2e0b2SEd Tanous                         return;
358b9b2e0b2SEd Tanous                     }
359b9b2e0b2SEd Tanous                 }
360b9b2e0b2SEd Tanous 
361*f12894f8SJason M. Bills                 messages::resourceNotFound(asyncResp->res, "ManagerAccount",
362*f12894f8SJason M. Bills                                            accountName);
363b9b2e0b2SEd Tanous             },
364b9b2e0b2SEd Tanous             "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
365b9b2e0b2SEd Tanous             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
366b9b2e0b2SEd Tanous     }
367a840879dSEd Tanous 
368a840879dSEd Tanous     void doPatch(crow::Response& res, const crow::Request& req,
369a840879dSEd Tanous                  const std::vector<std::string>& params) override
370a840879dSEd Tanous     {
371a840879dSEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
372a840879dSEd Tanous         if (params.size() != 1)
373a840879dSEd Tanous         {
374*f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
375a840879dSEd Tanous             return;
376a840879dSEd Tanous         }
377a840879dSEd Tanous 
3789712f8acSEd Tanous         boost::optional<std::string> password;
3799712f8acSEd Tanous         boost::optional<bool> enabled;
3809712f8acSEd Tanous         if (!json_util::readJson(req, res, "Password", password, "Enabled",
3819712f8acSEd Tanous                                  enabled))
382a840879dSEd Tanous         {
383a840879dSEd Tanous             return;
384a840879dSEd Tanous         }
385a840879dSEd Tanous 
386a840879dSEd Tanous         // Check the user exists before updating the fields
387a840879dSEd Tanous         checkDbusPathExists(
388a840879dSEd Tanous             "/xyz/openbmc_project/users/" + params[0],
3899712f8acSEd Tanous             [username{std::string(params[0])}, password(std::move(password)),
3909712f8acSEd Tanous              enabled(std::move(enabled)), asyncResp](bool userExists) {
391a840879dSEd Tanous                 if (!userExists)
392a840879dSEd Tanous                 {
393a840879dSEd Tanous                     messages::resourceNotFound(
394*f12894f8SJason M. Bills                         asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
395*f12894f8SJason M. Bills                         username);
396a840879dSEd Tanous                     return;
397a840879dSEd Tanous                 }
398a840879dSEd Tanous 
3999712f8acSEd Tanous                 if (password)
400a840879dSEd Tanous                 {
4019712f8acSEd Tanous                     if (!pamUpdatePassword(username, *password))
402a840879dSEd Tanous                     {
403a840879dSEd Tanous                         BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
404*f12894f8SJason M. Bills                         messages::internalError(asyncResp->res);
405a840879dSEd Tanous                         return;
406a840879dSEd Tanous                     }
407a840879dSEd Tanous                 }
408a840879dSEd Tanous 
4099712f8acSEd Tanous                 if (enabled)
410a840879dSEd Tanous                 {
411a840879dSEd Tanous                     crow::connections::systemBus->async_method_call(
412a840879dSEd Tanous                         [asyncResp](const boost::system::error_code ec) {
413a840879dSEd Tanous                             if (ec)
414a840879dSEd Tanous                             {
4159712f8acSEd Tanous                                 BMCWEB_LOG_ERROR << "D-Bus responses error: "
4169712f8acSEd Tanous                                                  << ec;
417*f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
418a840879dSEd Tanous                                 return;
419a840879dSEd Tanous                             }
420a840879dSEd Tanous                             // TODO Consider support polling mechanism to
421a840879dSEd Tanous                             // verify status of host and chassis after
422a840879dSEd Tanous                             // execute the requested action.
423*f12894f8SJason M. Bills                             messages::success(asyncResp->res);
424a840879dSEd Tanous                         },
425a840879dSEd Tanous                         "xyz.openbmc_project.User.Manager",
426a840879dSEd Tanous                         "/xyz/openbmc_project/users/" + username,
427a840879dSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
428a840879dSEd Tanous                         "xyz.openbmc_project.User.Attributes"
429a840879dSEd Tanous                         "UserEnabled",
4309712f8acSEd Tanous                         sdbusplus::message::variant<bool>{*enabled});
431a840879dSEd Tanous                 }
432a840879dSEd Tanous             });
433a840879dSEd Tanous     }
43406e086d9SEd Tanous 
43506e086d9SEd Tanous     void doDelete(crow::Response& res, const crow::Request& req,
43606e086d9SEd Tanous                   const std::vector<std::string>& params) override
43706e086d9SEd Tanous     {
43806e086d9SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
43906e086d9SEd Tanous 
44006e086d9SEd Tanous         if (params.size() != 1)
44106e086d9SEd Tanous         {
442*f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
44306e086d9SEd Tanous             return;
44406e086d9SEd Tanous         }
44506e086d9SEd Tanous 
44606e086d9SEd Tanous         const std::string userPath = "/xyz/openbmc_project/user/" + params[0];
44706e086d9SEd Tanous 
44806e086d9SEd Tanous         crow::connections::systemBus->async_method_call(
44906e086d9SEd Tanous             [asyncResp, username{std::move(params[0])}](
45006e086d9SEd Tanous                 const boost::system::error_code ec) {
45106e086d9SEd Tanous                 if (ec)
45206e086d9SEd Tanous                 {
45306e086d9SEd Tanous                     messages::resourceNotFound(
454*f12894f8SJason M. Bills                         asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
455*f12894f8SJason M. Bills                         username);
45606e086d9SEd Tanous                     return;
45706e086d9SEd Tanous                 }
45806e086d9SEd Tanous 
459*f12894f8SJason M. Bills                 messages::accountRemoved(asyncResp->res);
46006e086d9SEd Tanous             },
46106e086d9SEd Tanous             "xyz.openbmc_project.User.Manager", userPath,
46206e086d9SEd Tanous             "xyz.openbmc_project.Object.Delete", "Delete");
46306e086d9SEd Tanous     }
4649712f8acSEd Tanous }; // namespace redfish
46588d16c9aSLewanczyk, Dawid 
46688d16c9aSLewanczyk, Dawid } // namespace redfish
467