xref: /openbmc/bmcweb/features/redfish/lib/account_service.hpp (revision 9712f8ac42746e65f32c2bc3de0835846652568e)
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                 {
106b9b2e0b2SEd Tanous                     asyncResp->res.result(
107b9b2e0b2SEd Tanous                         boost::beast::http::status::internal_server_error);
108b9b2e0b2SEd Tanous                     return;
109b9b2e0b2SEd Tanous                 }
110b9b2e0b2SEd Tanous 
111b9b2e0b2SEd Tanous                 nlohmann::json& memberArray =
112b9b2e0b2SEd Tanous                     asyncResp->res.jsonValue["Members"];
113b9b2e0b2SEd Tanous                 memberArray = nlohmann::json::array();
114b9b2e0b2SEd Tanous 
115b9b2e0b2SEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] = users.size();
116b9b2e0b2SEd Tanous                 for (auto& user : users)
117b9b2e0b2SEd Tanous                 {
118b9b2e0b2SEd Tanous                     const std::string& path =
119b9b2e0b2SEd Tanous                         static_cast<const std::string&>(user.first);
120b9b2e0b2SEd Tanous                     std::size_t lastIndex = path.rfind("/");
121b9b2e0b2SEd Tanous                     if (lastIndex == std::string::npos)
122b9b2e0b2SEd Tanous                     {
123b9b2e0b2SEd Tanous                         lastIndex = 0;
124b9b2e0b2SEd Tanous                     }
125b9b2e0b2SEd Tanous                     else
126b9b2e0b2SEd Tanous                     {
127b9b2e0b2SEd Tanous                         lastIndex += 1;
128b9b2e0b2SEd Tanous                     }
129b9b2e0b2SEd Tanous                     memberArray.push_back(
130b9b2e0b2SEd Tanous                         {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
131b9b2e0b2SEd Tanous                                            path.substr(lastIndex)}});
132b9b2e0b2SEd Tanous                 }
133b9b2e0b2SEd Tanous             },
134b9b2e0b2SEd Tanous             "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
135b9b2e0b2SEd Tanous             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
136b9b2e0b2SEd Tanous     }
13704ae99ecSEd Tanous     void doPost(crow::Response& res, const crow::Request& req,
13804ae99ecSEd Tanous                 const std::vector<std::string>& params) override
13904ae99ecSEd Tanous     {
14004ae99ecSEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
14104ae99ecSEd Tanous 
142*9712f8acSEd Tanous         std::string username;
143*9712f8acSEd Tanous         std::string password;
144*9712f8acSEd Tanous         boost::optional<std::string> roleId("User");
145*9712f8acSEd Tanous         boost::optional<bool> enabled = true;
146*9712f8acSEd Tanous         if (!json_util::readJson(req, res, "UserName", username, "Password",
147*9712f8acSEd Tanous                                  password, "RoleId", roleId, "Enabled",
148*9712f8acSEd Tanous                                  enabled))
14904ae99ecSEd Tanous         {
15004ae99ecSEd Tanous             return;
15104ae99ecSEd Tanous         }
15204ae99ecSEd Tanous 
153*9712f8acSEd Tanous         const char* priv = getRoleIdFromPrivilege(*roleId);
15404ae99ecSEd Tanous         if (priv == nullptr)
15504ae99ecSEd Tanous         {
15604ae99ecSEd Tanous             messages::addMessageToErrorJson(
157*9712f8acSEd Tanous                 res.jsonValue,
158*9712f8acSEd Tanous                 messages::propertyValueNotInList(*roleId, "RoleId"));
159*9712f8acSEd Tanous             res.result(boost::beast::http::status::bad_request);
16004ae99ecSEd Tanous             return;
16104ae99ecSEd Tanous         }
162*9712f8acSEd Tanous         roleId = priv;
16304ae99ecSEd Tanous 
16404ae99ecSEd Tanous         crow::connections::systemBus->async_method_call(
165*9712f8acSEd Tanous             [asyncResp, username, password{std::move(password)}](
16604ae99ecSEd Tanous                 const boost::system::error_code ec) {
16704ae99ecSEd Tanous                 if (ec)
16804ae99ecSEd Tanous                 {
16904ae99ecSEd Tanous                     messages::addMessageToErrorJson(
17004ae99ecSEd Tanous                         asyncResp->res.jsonValue,
17104ae99ecSEd Tanous                         messages::resourceAlreadyExists(
17204ae99ecSEd Tanous                             "#ManagerAccount.v1_0_3.ManagerAccount", "UserName",
17304ae99ecSEd Tanous                             username));
17404ae99ecSEd Tanous                     asyncResp->res.result(
17504ae99ecSEd Tanous                         boost::beast::http::status::bad_request);
17604ae99ecSEd Tanous                     return;
17704ae99ecSEd Tanous                 }
17804ae99ecSEd Tanous 
17904ae99ecSEd Tanous                 if (!pamUpdatePassword(username, password))
18004ae99ecSEd Tanous                 {
18104ae99ecSEd Tanous                     // At this point we have a user that's been created, but the
18204ae99ecSEd Tanous                     // password set failed.  Something is wrong, so delete the
18304ae99ecSEd Tanous                     // user that we've already created
18404ae99ecSEd Tanous                     crow::connections::systemBus->async_method_call(
18504ae99ecSEd Tanous                         [asyncResp](const boost::system::error_code ec) {
18604ae99ecSEd Tanous                             if (ec)
18704ae99ecSEd Tanous                             {
18804ae99ecSEd Tanous                                 asyncResp->res.result(
18904ae99ecSEd Tanous                                     boost::beast::http::status::
19004ae99ecSEd Tanous                                         internal_server_error);
19104ae99ecSEd Tanous                                 return;
19204ae99ecSEd Tanous                             }
19304ae99ecSEd Tanous 
19404ae99ecSEd Tanous                             asyncResp->res.result(
19504ae99ecSEd Tanous                                 boost::beast::http::status::bad_request);
19604ae99ecSEd Tanous                         },
19704ae99ecSEd Tanous                         "xyz.openbmc_project.User.Manager",
19804ae99ecSEd Tanous                         "/xyz/openbmc_project/user/" + username,
19904ae99ecSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
20004ae99ecSEd Tanous 
20104ae99ecSEd Tanous                     BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
20204ae99ecSEd Tanous                     return;
20304ae99ecSEd Tanous                 }
20404ae99ecSEd Tanous 
20504ae99ecSEd Tanous                 messages::addMessageToJsonRoot(asyncResp->res.jsonValue,
20604ae99ecSEd Tanous                                                messages::created());
20704ae99ecSEd Tanous                 asyncResp->res.addHeader(
20804ae99ecSEd Tanous                     "Location",
20904ae99ecSEd Tanous                     "/redfish/v1/AccountService/Accounts/" + username);
21004ae99ecSEd Tanous             },
21104ae99ecSEd Tanous             "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
212*9712f8acSEd Tanous             "xyz.openbmc_project.User.Manager", "CreateUser", username,
21304ae99ecSEd Tanous             std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"},
214*9712f8acSEd Tanous             *roleId, *enabled);
21504ae99ecSEd Tanous     }
21604ae99ecSEd Tanous 
21704ae99ecSEd Tanous     static const char* getRoleIdFromPrivilege(boost::beast::string_view role)
21804ae99ecSEd Tanous     {
21904ae99ecSEd Tanous         if (role == "Administrator")
22004ae99ecSEd Tanous         {
22104ae99ecSEd Tanous             return "priv-admin";
22204ae99ecSEd Tanous         }
22304ae99ecSEd Tanous         else if (role == "Callback")
22404ae99ecSEd Tanous         {
22504ae99ecSEd Tanous             return "priv-callback";
22604ae99ecSEd Tanous         }
22704ae99ecSEd Tanous         else if (role == "User")
22804ae99ecSEd Tanous         {
22904ae99ecSEd Tanous             return "priv-user";
23004ae99ecSEd Tanous         }
23104ae99ecSEd Tanous         else if (role == "Operator")
23204ae99ecSEd Tanous         {
23304ae99ecSEd Tanous             return "priv-operator";
23404ae99ecSEd Tanous         }
23504ae99ecSEd Tanous         return nullptr;
23604ae99ecSEd Tanous     }
237b9b2e0b2SEd Tanous };
238b9b2e0b2SEd Tanous 
239a840879dSEd Tanous template <typename Callback>
240a840879dSEd Tanous inline void checkDbusPathExists(const std::string& path, Callback&& callback)
241a840879dSEd Tanous {
242a840879dSEd Tanous     using GetObjectType =
243a840879dSEd Tanous         std::vector<std::pair<std::string, std::vector<std::string>>>;
244a840879dSEd Tanous 
245a840879dSEd Tanous     crow::connections::systemBus->async_method_call(
246a840879dSEd Tanous         [callback{std::move(callback)}](const boost::system::error_code ec,
247a840879dSEd Tanous                                         const GetObjectType& object_names) {
248a840879dSEd Tanous             callback(ec || object_names.size() == 0);
249a840879dSEd Tanous         },
250a840879dSEd Tanous         "xyz.openbmc_project.ObjectMapper",
251a840879dSEd Tanous         "/xyz/openbmc_project/object_mapper",
252a840879dSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetObject", path,
253a840879dSEd Tanous         std::array<std::string, 0>());
254a840879dSEd Tanous }
255a840879dSEd Tanous 
256b9b2e0b2SEd Tanous class ManagerAccount : public Node
257b9b2e0b2SEd Tanous {
258b9b2e0b2SEd Tanous   public:
259b9b2e0b2SEd Tanous     ManagerAccount(CrowApp& app) :
260b9b2e0b2SEd Tanous         Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string())
261b9b2e0b2SEd Tanous     {
262b9b2e0b2SEd Tanous         Node::json = {{"@odata.context",
263b9b2e0b2SEd Tanous                        "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
264b9b2e0b2SEd Tanous                       {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
265b9b2e0b2SEd Tanous 
266b9b2e0b2SEd Tanous                       {"Name", "User Account"},
267b9b2e0b2SEd Tanous                       {"Description", "User Account"},
268b9b2e0b2SEd Tanous                       {"Password", nullptr},
269b9b2e0b2SEd Tanous                       {"RoleId", "Administrator"},
270b9b2e0b2SEd Tanous                       {"Links",
271b9b2e0b2SEd Tanous                        {{"Role",
272b9b2e0b2SEd Tanous                          {{"@odata.id", "/redfish/v1/AccountService/Roles/"
273b9b2e0b2SEd Tanous                                         "Administrator"}}}}}};
274b9b2e0b2SEd Tanous 
275b9b2e0b2SEd Tanous         entityPrivileges = {
276b9b2e0b2SEd Tanous             {boost::beast::http::verb::get,
277b9b2e0b2SEd Tanous              {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}},
278b9b2e0b2SEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
279b9b2e0b2SEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
280b9b2e0b2SEd Tanous             {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
281b9b2e0b2SEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
282b9b2e0b2SEd Tanous             {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
283b9b2e0b2SEd Tanous     }
284b9b2e0b2SEd Tanous 
285b9b2e0b2SEd Tanous   private:
286b9b2e0b2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
287b9b2e0b2SEd Tanous                const std::vector<std::string>& params) override
288b9b2e0b2SEd Tanous     {
289b9b2e0b2SEd Tanous         res.jsonValue = Node::json;
290b9b2e0b2SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
291b9b2e0b2SEd Tanous 
292b9b2e0b2SEd Tanous         if (params.size() != 1)
293b9b2e0b2SEd Tanous         {
294b9b2e0b2SEd Tanous             res.result(boost::beast::http::status::internal_server_error);
295b9b2e0b2SEd Tanous             return;
296b9b2e0b2SEd Tanous         }
297b9b2e0b2SEd Tanous 
298b9b2e0b2SEd Tanous         crow::connections::systemBus->async_method_call(
299b9b2e0b2SEd Tanous             [asyncResp, accountName{std::string(params[0])}](
300b9b2e0b2SEd Tanous                 const boost::system::error_code ec,
301b9b2e0b2SEd Tanous                 const ManagedObjectType& users) {
302b9b2e0b2SEd Tanous                 if (ec)
303b9b2e0b2SEd Tanous                 {
304b9b2e0b2SEd Tanous                     asyncResp->res.result(
305b9b2e0b2SEd Tanous                         boost::beast::http::status::internal_server_error);
306b9b2e0b2SEd Tanous                     return;
307b9b2e0b2SEd Tanous                 }
308b9b2e0b2SEd Tanous 
309b9b2e0b2SEd Tanous                 for (auto& user : users)
310b9b2e0b2SEd Tanous                 {
311b9b2e0b2SEd Tanous                     const std::string& path =
312b9b2e0b2SEd Tanous                         static_cast<const std::string&>(user.first);
313b9b2e0b2SEd Tanous                     std::size_t lastIndex = path.rfind("/");
314b9b2e0b2SEd Tanous                     if (lastIndex == std::string::npos)
315b9b2e0b2SEd Tanous                     {
316b9b2e0b2SEd Tanous                         lastIndex = 0;
317b9b2e0b2SEd Tanous                     }
318b9b2e0b2SEd Tanous                     else
319b9b2e0b2SEd Tanous                     {
320b9b2e0b2SEd Tanous                         lastIndex += 1;
321b9b2e0b2SEd Tanous                     }
322b9b2e0b2SEd Tanous                     if (path.substr(lastIndex) == accountName)
323b9b2e0b2SEd Tanous                     {
32465b0dc32SEd Tanous                         for (const auto& interface : user.second)
32565b0dc32SEd Tanous                         {
32665b0dc32SEd Tanous                             if (interface.first ==
32765b0dc32SEd Tanous                                 "xyz.openbmc_project.User.Attributes")
32865b0dc32SEd Tanous                             {
32965b0dc32SEd Tanous                                 for (const auto& property : interface.second)
33065b0dc32SEd Tanous                                 {
33165b0dc32SEd Tanous                                     if (property.first == "UserEnabled")
33265b0dc32SEd Tanous                                     {
33365b0dc32SEd Tanous                                         const bool* userEnabled =
33465b0dc32SEd Tanous                                             mapbox::getPtr<const bool>(
33565b0dc32SEd Tanous                                                 property.second);
33665b0dc32SEd Tanous                                         if (userEnabled == nullptr)
33765b0dc32SEd Tanous                                         {
33865b0dc32SEd Tanous                                             BMCWEB_LOG_ERROR
33965b0dc32SEd Tanous                                                 << "UserEnabled wasn't a bool";
34065b0dc32SEd Tanous                                             continue;
34165b0dc32SEd Tanous                                         }
34265b0dc32SEd Tanous                                         asyncResp->res.jsonValue["Enabled"] =
34365b0dc32SEd Tanous                                             *userEnabled;
34465b0dc32SEd Tanous                                     }
34565b0dc32SEd Tanous                                     else if (property.first ==
34665b0dc32SEd Tanous                                              "UserLockedForFailedAttempt")
34765b0dc32SEd Tanous                                     {
34865b0dc32SEd Tanous                                         const bool* userLocked =
34965b0dc32SEd Tanous                                             mapbox::getPtr<const bool>(
35065b0dc32SEd Tanous                                                 property.second);
35165b0dc32SEd Tanous                                         if (userLocked == nullptr)
35265b0dc32SEd Tanous                                         {
35365b0dc32SEd Tanous                                             BMCWEB_LOG_ERROR
35465b0dc32SEd Tanous                                                 << "UserEnabled wasn't a bool";
35565b0dc32SEd Tanous                                             continue;
35665b0dc32SEd Tanous                                         }
35765b0dc32SEd Tanous                                         asyncResp->res.jsonValue["Locked"] =
35865b0dc32SEd Tanous                                             *userLocked;
35965b0dc32SEd Tanous                                     }
36065b0dc32SEd Tanous                                 }
36165b0dc32SEd Tanous                             }
36265b0dc32SEd Tanous                         }
36365b0dc32SEd Tanous 
364b9b2e0b2SEd Tanous                         asyncResp->res.jsonValue["@odata.id"] =
365b9b2e0b2SEd Tanous                             "/redfish/v1/AccountService/Accounts/" +
366b9b2e0b2SEd Tanous                             accountName;
367b9b2e0b2SEd Tanous                         asyncResp->res.jsonValue["Id"] = accountName;
368b9b2e0b2SEd Tanous                         asyncResp->res.jsonValue["UserName"] = accountName;
369b9b2e0b2SEd Tanous 
370b9b2e0b2SEd Tanous                         return;
371b9b2e0b2SEd Tanous                     }
372b9b2e0b2SEd Tanous                 }
373b9b2e0b2SEd Tanous 
374b9b2e0b2SEd Tanous                 asyncResp->res.result(boost::beast::http::status::not_found);
375b9b2e0b2SEd Tanous             },
376b9b2e0b2SEd Tanous             "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
377b9b2e0b2SEd Tanous             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
378b9b2e0b2SEd Tanous     }
379a840879dSEd Tanous 
380a840879dSEd Tanous     void doPatch(crow::Response& res, const crow::Request& req,
381a840879dSEd Tanous                  const std::vector<std::string>& params) override
382a840879dSEd Tanous     {
383a840879dSEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
384a840879dSEd Tanous         if (params.size() != 1)
385a840879dSEd Tanous         {
386a840879dSEd Tanous             res.result(boost::beast::http::status::internal_server_error);
387a840879dSEd Tanous             return;
388a840879dSEd Tanous         }
389a840879dSEd Tanous 
390*9712f8acSEd Tanous         boost::optional<std::string> password;
391*9712f8acSEd Tanous         boost::optional<bool> enabled;
392*9712f8acSEd Tanous         if (!json_util::readJson(req, res, "Password", password, "Enabled",
393*9712f8acSEd Tanous                                  enabled))
394a840879dSEd Tanous         {
395a840879dSEd Tanous             return;
396a840879dSEd Tanous         }
397a840879dSEd Tanous 
398a840879dSEd Tanous         // Check the user exists before updating the fields
399a840879dSEd Tanous         checkDbusPathExists(
400a840879dSEd Tanous             "/xyz/openbmc_project/users/" + params[0],
401*9712f8acSEd Tanous             [username{std::string(params[0])}, password(std::move(password)),
402*9712f8acSEd Tanous              enabled(std::move(enabled)), asyncResp](bool userExists) {
403a840879dSEd Tanous                 if (!userExists)
404a840879dSEd Tanous                 {
405a840879dSEd Tanous                     messages::addMessageToErrorJson(
406a840879dSEd Tanous                         asyncResp->res.jsonValue,
407a840879dSEd Tanous                         messages::resourceNotFound(
408a840879dSEd Tanous                             "#ManagerAccount.v1_0_3.ManagerAccount", username));
409a840879dSEd Tanous 
410a840879dSEd Tanous                     asyncResp->res.result(
411a840879dSEd Tanous                         boost::beast::http::status::not_found);
412a840879dSEd Tanous                     return;
413a840879dSEd Tanous                 }
414a840879dSEd Tanous 
415*9712f8acSEd Tanous                 if (password)
416a840879dSEd Tanous                 {
417*9712f8acSEd Tanous                     if (!pamUpdatePassword(username, *password))
418a840879dSEd Tanous                     {
419a840879dSEd Tanous                         BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
420*9712f8acSEd Tanous                         asyncResp->res.result(
421*9712f8acSEd Tanous                             boost::beast::http::status::internal_server_error);
422a840879dSEd Tanous                         return;
423a840879dSEd Tanous                     }
424a840879dSEd Tanous                 }
425a840879dSEd Tanous 
426*9712f8acSEd Tanous                 if (enabled)
427a840879dSEd Tanous                 {
428a840879dSEd Tanous                     crow::connections::systemBus->async_method_call(
429a840879dSEd Tanous                         [asyncResp](const boost::system::error_code ec) {
430a840879dSEd Tanous                             if (ec)
431a840879dSEd Tanous                             {
432*9712f8acSEd Tanous                                 BMCWEB_LOG_ERROR << "D-Bus responses error: "
433*9712f8acSEd Tanous                                                  << ec;
434a840879dSEd Tanous                                 asyncResp->res.result(
435a840879dSEd Tanous                                     boost::beast::http::status::
436a840879dSEd Tanous                                         internal_server_error);
437a840879dSEd Tanous                                 return;
438a840879dSEd Tanous                             }
439a840879dSEd Tanous                             // TODO Consider support polling mechanism to
440a840879dSEd Tanous                             // verify status of host and chassis after
441a840879dSEd Tanous                             // execute the requested action.
442a840879dSEd Tanous                             BMCWEB_LOG_DEBUG << "Response with no content";
443a840879dSEd Tanous                             asyncResp->res.result(
444a840879dSEd Tanous                                 boost::beast::http::status::no_content);
445a840879dSEd Tanous                         },
446a840879dSEd Tanous                         "xyz.openbmc_project.User.Manager",
447a840879dSEd Tanous                         "/xyz/openbmc_project/users/" + username,
448a840879dSEd Tanous                         "org.freedesktop.DBus.Properties", "Set",
449a840879dSEd Tanous                         "xyz.openbmc_project.User.Attributes"
450a840879dSEd Tanous                         "UserEnabled",
451*9712f8acSEd Tanous                         sdbusplus::message::variant<bool>{*enabled});
452a840879dSEd Tanous                 }
453a840879dSEd Tanous             });
454a840879dSEd Tanous     }
45506e086d9SEd Tanous 
45606e086d9SEd Tanous     void doDelete(crow::Response& res, const crow::Request& req,
45706e086d9SEd Tanous                   const std::vector<std::string>& params) override
45806e086d9SEd Tanous     {
45906e086d9SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
46006e086d9SEd Tanous 
46106e086d9SEd Tanous         if (params.size() != 1)
46206e086d9SEd Tanous         {
46306e086d9SEd Tanous             res.result(boost::beast::http::status::internal_server_error);
46406e086d9SEd Tanous             return;
46506e086d9SEd Tanous         }
46606e086d9SEd Tanous 
46706e086d9SEd Tanous         const std::string userPath = "/xyz/openbmc_project/user/" + params[0];
46806e086d9SEd Tanous 
46906e086d9SEd Tanous         crow::connections::systemBus->async_method_call(
47006e086d9SEd Tanous             [asyncResp, username{std::move(params[0])}](
47106e086d9SEd Tanous                 const boost::system::error_code ec) {
47206e086d9SEd Tanous                 if (ec)
47306e086d9SEd Tanous                 {
47406e086d9SEd Tanous                     messages::addMessageToErrorJson(
47506e086d9SEd Tanous                         asyncResp->res.jsonValue,
47606e086d9SEd Tanous                         messages::resourceNotFound(
47706e086d9SEd Tanous                             "#ManagerAccount.v1_0_3.ManagerAccount", username));
47806e086d9SEd Tanous                     asyncResp->res.result(
47906e086d9SEd Tanous                         boost::beast::http::status::not_found);
48006e086d9SEd Tanous                     return;
48106e086d9SEd Tanous                 }
48206e086d9SEd Tanous 
48306e086d9SEd Tanous                 messages::addMessageToJsonRoot(asyncResp->res.jsonValue,
48406e086d9SEd Tanous                                                messages::accountRemoved());
48506e086d9SEd Tanous             },
48606e086d9SEd Tanous             "xyz.openbmc_project.User.Manager", userPath,
48706e086d9SEd Tanous             "xyz.openbmc_project.Object.Delete", "Delete");
48806e086d9SEd Tanous     }
489*9712f8acSEd Tanous }; // namespace redfish
49088d16c9aSLewanczyk, Dawid 
49188d16c9aSLewanczyk, Dawid } // namespace redfish
492