xref: /openbmc/bmcweb/features/redfish/lib/account_service.hpp (revision 84e12cb7760160f7fae9e7e0e9f9b48629bc3029)
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<
29*84e12cb7SAppaRao Puli         std::string,
30*84e12cb7SAppaRao Puli         boost::container::flat_map<
31*84e12cb7SAppaRao Puli             std::string, sdbusplus::message::variant<bool, std::string>>>>>;
32*84e12cb7SAppaRao Puli 
33*84e12cb7SAppaRao Puli inline std::string getPrivilegeFromRoleId(boost::beast::string_view role)
34*84e12cb7SAppaRao Puli {
35*84e12cb7SAppaRao Puli     if (role == "priv-admin")
36*84e12cb7SAppaRao Puli     {
37*84e12cb7SAppaRao Puli         return "Administrator";
38*84e12cb7SAppaRao Puli     }
39*84e12cb7SAppaRao Puli     else if (role == "priv-callback")
40*84e12cb7SAppaRao Puli     {
41*84e12cb7SAppaRao Puli         return "Callback";
42*84e12cb7SAppaRao Puli     }
43*84e12cb7SAppaRao Puli     else if (role == "priv-user")
44*84e12cb7SAppaRao Puli     {
45*84e12cb7SAppaRao Puli         return "User";
46*84e12cb7SAppaRao Puli     }
47*84e12cb7SAppaRao Puli     else if (role == "priv-operator")
48*84e12cb7SAppaRao Puli     {
49*84e12cb7SAppaRao Puli         return "Operator";
50*84e12cb7SAppaRao Puli     }
51*84e12cb7SAppaRao Puli     return "";
52*84e12cb7SAppaRao Puli }
53*84e12cb7SAppaRao Puli inline std::string getRoleIdFromPrivilege(boost::beast::string_view role)
54*84e12cb7SAppaRao Puli {
55*84e12cb7SAppaRao Puli     if (role == "Administrator")
56*84e12cb7SAppaRao Puli     {
57*84e12cb7SAppaRao Puli         return "priv-admin";
58*84e12cb7SAppaRao Puli     }
59*84e12cb7SAppaRao Puli     else if (role == "Callback")
60*84e12cb7SAppaRao Puli     {
61*84e12cb7SAppaRao Puli         return "priv-callback";
62*84e12cb7SAppaRao Puli     }
63*84e12cb7SAppaRao Puli     else if (role == "User")
64*84e12cb7SAppaRao Puli     {
65*84e12cb7SAppaRao Puli         return "priv-user";
66*84e12cb7SAppaRao Puli     }
67*84e12cb7SAppaRao Puli     else if (role == "Operator")
68*84e12cb7SAppaRao Puli     {
69*84e12cb7SAppaRao Puli         return "priv-operator";
70*84e12cb7SAppaRao Puli     }
71*84e12cb7SAppaRao Puli     return "";
72*84e12cb7SAppaRao Puli }
73b9b2e0b2SEd Tanous 
741abe55efSEd Tanous class AccountService : public Node
751abe55efSEd Tanous {
7688d16c9aSLewanczyk, Dawid   public:
771abe55efSEd Tanous     AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/")
781abe55efSEd Tanous     {
793ebd75f7SEd Tanous         entityPrivileges = {
804b1b8683SBorawski.Lukasz             {boost::beast::http::verb::get,
814b1b8683SBorawski.Lukasz              {{"ConfigureUsers"}, {"ConfigureManager"}}},
82e0d918bcSEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
83e0d918bcSEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
84e0d918bcSEd Tanous             {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
85e0d918bcSEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
86e0d918bcSEd Tanous             {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
8788d16c9aSLewanczyk, Dawid     }
8888d16c9aSLewanczyk, Dawid 
8988d16c9aSLewanczyk, Dawid   private:
9055c7b7a2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
911abe55efSEd Tanous                const std::vector<std::string>& params) override
921abe55efSEd Tanous     {
930f74e643SEd Tanous         res.jsonValue["@odata.id"] = "/redfish/v1/AccountService";
940f74e643SEd Tanous         res.jsonValue["@odata.type"] = "#AccountService.v1_1_0.AccountService";
950f74e643SEd Tanous         res.jsonValue["@odata.context"] =
960f74e643SEd Tanous             "/redfish/v1/$metadata#AccountService.AccountService";
970f74e643SEd Tanous         res.jsonValue["Id"] = "AccountService";
980f74e643SEd Tanous         res.jsonValue["Description"] = "BMC User Accounts";
990f74e643SEd Tanous         res.jsonValue["Name"] = "Account Service";
1000f74e643SEd Tanous         res.jsonValue["ServiceEnabled"] = true;
1010f74e643SEd Tanous         res.jsonValue["MinPasswordLength"] = 1;
1020f74e643SEd Tanous         res.jsonValue["MaxPasswordLength"] = 20;
1030f74e643SEd Tanous         res.jsonValue["Accounts"]["@odata.id"] =
1040f74e643SEd Tanous             "/redfish/v1/AccountService/Accounts";
1050f74e643SEd Tanous         res.jsonValue["Roles"]["@odata.id"] =
1060f74e643SEd Tanous             "/redfish/v1/AccountService/Roles";
1070f74e643SEd Tanous 
10888d16c9aSLewanczyk, Dawid         res.end();
10988d16c9aSLewanczyk, Dawid     }
11088d16c9aSLewanczyk, Dawid };
111b9b2e0b2SEd Tanous class AccountsCollection : public Node
112b9b2e0b2SEd Tanous {
113b9b2e0b2SEd Tanous   public:
114b9b2e0b2SEd Tanous     AccountsCollection(CrowApp& app) :
115b9b2e0b2SEd Tanous         Node(app, "/redfish/v1/AccountService/Accounts/")
116b9b2e0b2SEd Tanous     {
117b9b2e0b2SEd Tanous         entityPrivileges = {
118b9b2e0b2SEd Tanous             {boost::beast::http::verb::get,
119b9b2e0b2SEd Tanous              {{"ConfigureUsers"}, {"ConfigureManager"}}},
120b9b2e0b2SEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
121b9b2e0b2SEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
122b9b2e0b2SEd Tanous             {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
123b9b2e0b2SEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
124b9b2e0b2SEd Tanous             {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
125b9b2e0b2SEd Tanous     }
126b9b2e0b2SEd Tanous 
127b9b2e0b2SEd Tanous   private:
128b9b2e0b2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
129b9b2e0b2SEd Tanous                const std::vector<std::string>& params) override
130b9b2e0b2SEd Tanous     {
131b9b2e0b2SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
1320f74e643SEd Tanous         res.jsonValue = {{"@odata.context",
1330f74e643SEd Tanous                           "/redfish/v1/"
1340f74e643SEd Tanous                           "$metadata#ManagerAccountCollection."
1350f74e643SEd Tanous                           "ManagerAccountCollection"},
1360f74e643SEd Tanous                          {"@odata.id", "/redfish/v1/AccountService/Accounts"},
1370f74e643SEd Tanous                          {"@odata.type", "#ManagerAccountCollection."
1380f74e643SEd Tanous                                          "ManagerAccountCollection"},
1390f74e643SEd Tanous                          {"Name", "Accounts Collection"},
1400f74e643SEd Tanous                          {"Description", "BMC User Accounts"}};
1410f74e643SEd Tanous 
142b9b2e0b2SEd Tanous         crow::connections::systemBus->async_method_call(
143b9b2e0b2SEd Tanous             [asyncResp](const boost::system::error_code ec,
144b9b2e0b2SEd Tanous                         const ManagedObjectType& users) {
145b9b2e0b2SEd Tanous                 if (ec)
146b9b2e0b2SEd Tanous                 {
147f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
148b9b2e0b2SEd Tanous                     return;
149b9b2e0b2SEd Tanous                 }
150b9b2e0b2SEd Tanous 
151b9b2e0b2SEd Tanous                 nlohmann::json& memberArray =
152b9b2e0b2SEd Tanous                     asyncResp->res.jsonValue["Members"];
153b9b2e0b2SEd Tanous                 memberArray = nlohmann::json::array();
154b9b2e0b2SEd Tanous 
155b9b2e0b2SEd Tanous                 asyncResp->res.jsonValue["Members@odata.count"] = users.size();
156b9b2e0b2SEd Tanous                 for (auto& user : users)
157b9b2e0b2SEd Tanous                 {
158b9b2e0b2SEd Tanous                     const std::string& path =
159b9b2e0b2SEd Tanous                         static_cast<const std::string&>(user.first);
160b9b2e0b2SEd Tanous                     std::size_t lastIndex = path.rfind("/");
161b9b2e0b2SEd Tanous                     if (lastIndex == std::string::npos)
162b9b2e0b2SEd Tanous                     {
163b9b2e0b2SEd Tanous                         lastIndex = 0;
164b9b2e0b2SEd Tanous                     }
165b9b2e0b2SEd Tanous                     else
166b9b2e0b2SEd Tanous                     {
167b9b2e0b2SEd Tanous                         lastIndex += 1;
168b9b2e0b2SEd Tanous                     }
169b9b2e0b2SEd Tanous                     memberArray.push_back(
170b9b2e0b2SEd Tanous                         {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
171b9b2e0b2SEd Tanous                                            path.substr(lastIndex)}});
172b9b2e0b2SEd Tanous                 }
173b9b2e0b2SEd Tanous             },
174b9b2e0b2SEd Tanous             "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
175b9b2e0b2SEd Tanous             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
176b9b2e0b2SEd Tanous     }
17704ae99ecSEd Tanous     void doPost(crow::Response& res, const crow::Request& req,
17804ae99ecSEd Tanous                 const std::vector<std::string>& params) override
17904ae99ecSEd Tanous     {
18004ae99ecSEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
18104ae99ecSEd Tanous 
1829712f8acSEd Tanous         std::string username;
1839712f8acSEd Tanous         std::string password;
1849712f8acSEd Tanous         boost::optional<std::string> roleId("User");
1859712f8acSEd Tanous         boost::optional<bool> enabled = true;
1869712f8acSEd Tanous         if (!json_util::readJson(req, res, "UserName", username, "Password",
1879712f8acSEd Tanous                                  password, "RoleId", roleId, "Enabled",
1889712f8acSEd Tanous                                  enabled))
18904ae99ecSEd Tanous         {
19004ae99ecSEd Tanous             return;
19104ae99ecSEd Tanous         }
19204ae99ecSEd Tanous 
193*84e12cb7SAppaRao Puli         std::string priv = getRoleIdFromPrivilege(*roleId);
194*84e12cb7SAppaRao Puli         if (priv.empty())
19504ae99ecSEd Tanous         {
196f12894f8SJason M. Bills             messages::propertyValueNotInList(asyncResp->res, *roleId, "RoleId");
19704ae99ecSEd Tanous             return;
19804ae99ecSEd Tanous         }
1999712f8acSEd Tanous         roleId = priv;
20004ae99ecSEd Tanous 
20104ae99ecSEd Tanous         crow::connections::systemBus->async_method_call(
2029712f8acSEd Tanous             [asyncResp, username, password{std::move(password)}](
20304ae99ecSEd Tanous                 const boost::system::error_code ec) {
20404ae99ecSEd Tanous                 if (ec)
20504ae99ecSEd Tanous                 {
20604ae99ecSEd Tanous                     messages::resourceAlreadyExists(
207f12894f8SJason M. Bills                         asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
208f12894f8SJason M. Bills                         "UserName", username);
20904ae99ecSEd Tanous                     return;
21004ae99ecSEd Tanous                 }
21104ae99ecSEd Tanous 
21204ae99ecSEd Tanous                 if (!pamUpdatePassword(username, password))
21304ae99ecSEd Tanous                 {
21404ae99ecSEd Tanous                     // At this point we have a user that's been created, but the
21504ae99ecSEd Tanous                     // password set failed.  Something is wrong, so delete the
21604ae99ecSEd Tanous                     // user that we've already created
21704ae99ecSEd Tanous                     crow::connections::systemBus->async_method_call(
21804ae99ecSEd Tanous                         [asyncResp](const boost::system::error_code ec) {
21904ae99ecSEd Tanous                             if (ec)
22004ae99ecSEd Tanous                             {
221f12894f8SJason M. Bills                                 messages::internalError(asyncResp->res);
22204ae99ecSEd Tanous                                 return;
22304ae99ecSEd Tanous                             }
22404ae99ecSEd Tanous 
225f12894f8SJason M. Bills                             messages::invalidObject(asyncResp->res, "Password");
22604ae99ecSEd Tanous                         },
22704ae99ecSEd Tanous                         "xyz.openbmc_project.User.Manager",
22804ae99ecSEd Tanous                         "/xyz/openbmc_project/user/" + username,
22904ae99ecSEd Tanous                         "xyz.openbmc_project.Object.Delete", "Delete");
23004ae99ecSEd Tanous 
23104ae99ecSEd Tanous                     BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
23204ae99ecSEd Tanous                     return;
23304ae99ecSEd Tanous                 }
23404ae99ecSEd Tanous 
235f12894f8SJason M. Bills                 messages::created(asyncResp->res);
23604ae99ecSEd Tanous                 asyncResp->res.addHeader(
23704ae99ecSEd Tanous                     "Location",
23804ae99ecSEd Tanous                     "/redfish/v1/AccountService/Accounts/" + username);
23904ae99ecSEd Tanous             },
24004ae99ecSEd Tanous             "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
2419712f8acSEd Tanous             "xyz.openbmc_project.User.Manager", "CreateUser", username,
24204ae99ecSEd Tanous             std::array<const char*, 4>{"ipmi", "redfish", "ssh", "web"},
2439712f8acSEd Tanous             *roleId, *enabled);
24404ae99ecSEd Tanous     }
245b9b2e0b2SEd Tanous };
246b9b2e0b2SEd Tanous 
247a840879dSEd Tanous template <typename Callback>
248a840879dSEd Tanous inline void checkDbusPathExists(const std::string& path, Callback&& callback)
249a840879dSEd Tanous {
250a840879dSEd Tanous     using GetObjectType =
251a840879dSEd Tanous         std::vector<std::pair<std::string, std::vector<std::string>>>;
252a840879dSEd Tanous 
253a840879dSEd Tanous     crow::connections::systemBus->async_method_call(
254a840879dSEd Tanous         [callback{std::move(callback)}](const boost::system::error_code ec,
255a840879dSEd Tanous                                         const GetObjectType& object_names) {
256*84e12cb7SAppaRao Puli             callback(!ec && object_names.size() != 0);
257a840879dSEd Tanous         },
258a840879dSEd Tanous         "xyz.openbmc_project.ObjectMapper",
259a840879dSEd Tanous         "/xyz/openbmc_project/object_mapper",
260a840879dSEd Tanous         "xyz.openbmc_project.ObjectMapper", "GetObject", path,
261a840879dSEd Tanous         std::array<std::string, 0>());
262a840879dSEd Tanous }
263a840879dSEd Tanous 
264b9b2e0b2SEd Tanous class ManagerAccount : public Node
265b9b2e0b2SEd Tanous {
266b9b2e0b2SEd Tanous   public:
267b9b2e0b2SEd Tanous     ManagerAccount(CrowApp& app) :
268b9b2e0b2SEd Tanous         Node(app, "/redfish/v1/AccountService/Accounts/<str>/", std::string())
269b9b2e0b2SEd Tanous     {
270b9b2e0b2SEd Tanous         entityPrivileges = {
271b9b2e0b2SEd Tanous             {boost::beast::http::verb::get,
272b9b2e0b2SEd Tanous              {{"ConfigureUsers"}, {"ConfigureManager"}, {"ConfigureSelf"}}},
273b9b2e0b2SEd Tanous             {boost::beast::http::verb::head, {{"Login"}}},
274b9b2e0b2SEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
275b9b2e0b2SEd Tanous             {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
276b9b2e0b2SEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
277b9b2e0b2SEd Tanous             {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
278b9b2e0b2SEd Tanous     }
279b9b2e0b2SEd Tanous 
280b9b2e0b2SEd Tanous   private:
281b9b2e0b2SEd Tanous     void doGet(crow::Response& res, const crow::Request& req,
282b9b2e0b2SEd Tanous                const std::vector<std::string>& params) override
283b9b2e0b2SEd Tanous     {
2840f74e643SEd Tanous         res.jsonValue = {
2850f74e643SEd Tanous             {"@odata.context",
2860f74e643SEd Tanous              "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
2870f74e643SEd Tanous             {"@odata.type", "#ManagerAccount.v1_0_3.ManagerAccount"},
2880f74e643SEd Tanous             {"Name", "User Account"},
2890f74e643SEd Tanous             {"Description", "User Account"},
2900f74e643SEd Tanous             {"Password", nullptr},
291*84e12cb7SAppaRao Puli             {"RoleId", "Administrator"}};
2920f74e643SEd Tanous 
293b9b2e0b2SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
294b9b2e0b2SEd Tanous 
295b9b2e0b2SEd Tanous         if (params.size() != 1)
296b9b2e0b2SEd Tanous         {
297f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
298b9b2e0b2SEd Tanous             return;
299b9b2e0b2SEd Tanous         }
300b9b2e0b2SEd Tanous 
301b9b2e0b2SEd Tanous         crow::connections::systemBus->async_method_call(
302b9b2e0b2SEd Tanous             [asyncResp, accountName{std::string(params[0])}](
303b9b2e0b2SEd Tanous                 const boost::system::error_code ec,
304b9b2e0b2SEd Tanous                 const ManagedObjectType& users) {
305b9b2e0b2SEd Tanous                 if (ec)
306b9b2e0b2SEd Tanous                 {
307f12894f8SJason M. Bills                     messages::internalError(asyncResp->res);
308b9b2e0b2SEd Tanous                     return;
309b9b2e0b2SEd Tanous                 }
310*84e12cb7SAppaRao Puli                 auto userIt = users.begin();
311b9b2e0b2SEd Tanous 
312*84e12cb7SAppaRao Puli                 for (; userIt != users.end(); userIt++)
313b9b2e0b2SEd Tanous                 {
314*84e12cb7SAppaRao Puli                     if (boost::ends_with(userIt->first.str, "/" + accountName))
315b9b2e0b2SEd Tanous                     {
316*84e12cb7SAppaRao Puli                         break;
317b9b2e0b2SEd Tanous                     }
318b9b2e0b2SEd Tanous                 }
319*84e12cb7SAppaRao Puli                 if (userIt == users.end())
320b9b2e0b2SEd Tanous                 {
321*84e12cb7SAppaRao Puli                     messages::resourceNotFound(asyncResp->res, "ManagerAccount",
322*84e12cb7SAppaRao Puli                                                accountName);
323*84e12cb7SAppaRao Puli                     return;
324*84e12cb7SAppaRao Puli                 }
325*84e12cb7SAppaRao Puli                 for (const auto& interface : userIt->second)
32665b0dc32SEd Tanous                 {
32765b0dc32SEd Tanous                     if (interface.first ==
32865b0dc32SEd Tanous                         "xyz.openbmc_project.User.Attributes")
32965b0dc32SEd Tanous                     {
33065b0dc32SEd Tanous                         for (const auto& property : interface.second)
33165b0dc32SEd Tanous                         {
33265b0dc32SEd Tanous                             if (property.first == "UserEnabled")
33365b0dc32SEd Tanous                             {
33465b0dc32SEd Tanous                                 const bool* userEnabled =
335*84e12cb7SAppaRao Puli                                     sdbusplus::message::variant_ns::get_if<
336*84e12cb7SAppaRao Puli                                         bool>(&property.second);
33765b0dc32SEd Tanous                                 if (userEnabled == nullptr)
33865b0dc32SEd Tanous                                 {
33965b0dc32SEd Tanous                                     BMCWEB_LOG_ERROR
34065b0dc32SEd Tanous                                         << "UserEnabled wasn't a bool";
341*84e12cb7SAppaRao Puli                                     messages::internalError(asyncResp->res);
342*84e12cb7SAppaRao Puli                                     return;
34365b0dc32SEd Tanous                                 }
34465b0dc32SEd Tanous                                 asyncResp->res.jsonValue["Enabled"] =
34565b0dc32SEd Tanous                                     *userEnabled;
34665b0dc32SEd Tanous                             }
34765b0dc32SEd Tanous                             else if (property.first ==
34865b0dc32SEd Tanous                                      "UserLockedForFailedAttempt")
34965b0dc32SEd Tanous                             {
35065b0dc32SEd Tanous                                 const bool* userLocked =
351*84e12cb7SAppaRao Puli                                     sdbusplus::message::variant_ns::get_if<
352*84e12cb7SAppaRao Puli                                         bool>(&property.second);
35365b0dc32SEd Tanous                                 if (userLocked == nullptr)
35465b0dc32SEd Tanous                                 {
355*84e12cb7SAppaRao Puli                                     BMCWEB_LOG_ERROR << "UserLockedForF"
356*84e12cb7SAppaRao Puli                                                         "ailedAttempt "
357*84e12cb7SAppaRao Puli                                                         "wasn't a bool";
358*84e12cb7SAppaRao Puli                                     messages::internalError(asyncResp->res);
359*84e12cb7SAppaRao Puli                                     return;
36065b0dc32SEd Tanous                                 }
36165b0dc32SEd Tanous                                 asyncResp->res.jsonValue["Locked"] =
36265b0dc32SEd Tanous                                     *userLocked;
36365b0dc32SEd Tanous                             }
364*84e12cb7SAppaRao Puli                             else if (property.first == "UserPrivilege")
365*84e12cb7SAppaRao Puli                             {
366*84e12cb7SAppaRao Puli                                 const std::string* userRolePtr =
367*84e12cb7SAppaRao Puli                                     sdbusplus::message::variant_ns::get_if<
368*84e12cb7SAppaRao Puli                                         std::string>(&property.second);
369*84e12cb7SAppaRao Puli                                 if (userRolePtr == nullptr)
370*84e12cb7SAppaRao Puli                                 {
371*84e12cb7SAppaRao Puli                                     BMCWEB_LOG_ERROR
372*84e12cb7SAppaRao Puli                                         << "UserPrivilege wasn't a "
373*84e12cb7SAppaRao Puli                                            "string";
374*84e12cb7SAppaRao Puli                                     messages::internalError(asyncResp->res);
375*84e12cb7SAppaRao Puli                                     return;
376*84e12cb7SAppaRao Puli                                 }
377*84e12cb7SAppaRao Puli                                 std::string priv =
378*84e12cb7SAppaRao Puli                                     getPrivilegeFromRoleId(*userRolePtr);
379*84e12cb7SAppaRao Puli                                 if (priv.empty())
380*84e12cb7SAppaRao Puli                                 {
381*84e12cb7SAppaRao Puli                                     BMCWEB_LOG_ERROR << "Invalid user role";
382*84e12cb7SAppaRao Puli                                     messages::internalError(asyncResp->res);
383*84e12cb7SAppaRao Puli                                     return;
384*84e12cb7SAppaRao Puli                                 }
385*84e12cb7SAppaRao Puli                                 asyncResp->res.jsonValue["RoleId"] = priv;
386*84e12cb7SAppaRao Puli 
387*84e12cb7SAppaRao Puli                                 asyncResp->res.jsonValue["Links"]["Role"] = {
388*84e12cb7SAppaRao Puli                                     {"@odata.id", "/redfish/v1/AccountService/"
389*84e12cb7SAppaRao Puli                                                   "Roles/" +
390*84e12cb7SAppaRao Puli                                                       priv}};
391*84e12cb7SAppaRao Puli                             }
39265b0dc32SEd Tanous                         }
39365b0dc32SEd Tanous                     }
39465b0dc32SEd Tanous                 }
39565b0dc32SEd Tanous 
396b9b2e0b2SEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
397*84e12cb7SAppaRao Puli                     "/redfish/v1/AccountService/Accounts/" + accountName;
398b9b2e0b2SEd Tanous                 asyncResp->res.jsonValue["Id"] = accountName;
399b9b2e0b2SEd Tanous                 asyncResp->res.jsonValue["UserName"] = accountName;
400b9b2e0b2SEd Tanous             },
401b9b2e0b2SEd Tanous             "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
402b9b2e0b2SEd Tanous             "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
403b9b2e0b2SEd Tanous     }
404a840879dSEd Tanous 
405a840879dSEd Tanous     void doPatch(crow::Response& res, const crow::Request& req,
406a840879dSEd Tanous                  const std::vector<std::string>& params) override
407a840879dSEd Tanous     {
408a840879dSEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
409a840879dSEd Tanous         if (params.size() != 1)
410a840879dSEd Tanous         {
411f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
412a840879dSEd Tanous             return;
413a840879dSEd Tanous         }
414a840879dSEd Tanous 
415*84e12cb7SAppaRao Puli         boost::optional<std::string> newUserName;
4169712f8acSEd Tanous         boost::optional<std::string> password;
4179712f8acSEd Tanous         boost::optional<bool> enabled;
418*84e12cb7SAppaRao Puli         boost::optional<std::string> roleId;
419*84e12cb7SAppaRao Puli         if (!json_util::readJson(req, res, "UserName", newUserName, "Password",
420*84e12cb7SAppaRao Puli                                  password, "RoleId", roleId, "Enabled",
4219712f8acSEd Tanous                                  enabled))
422a840879dSEd Tanous         {
423a840879dSEd Tanous             return;
424a840879dSEd Tanous         }
425a840879dSEd Tanous 
426*84e12cb7SAppaRao Puli         const std::string& username = params[0];
427*84e12cb7SAppaRao Puli 
428*84e12cb7SAppaRao Puli         if (!newUserName)
429a840879dSEd Tanous         {
430*84e12cb7SAppaRao Puli             // If the username isn't being updated, we can update the properties
431*84e12cb7SAppaRao Puli             // directly
432*84e12cb7SAppaRao Puli             updateUserProperties(asyncResp, username, password, enabled,
433*84e12cb7SAppaRao Puli                                  roleId);
434*84e12cb7SAppaRao Puli             return;
435*84e12cb7SAppaRao Puli         }
436*84e12cb7SAppaRao Puli         else
437*84e12cb7SAppaRao Puli         {
438*84e12cb7SAppaRao Puli             crow::connections::systemBus->async_method_call(
439*84e12cb7SAppaRao Puli                 [this, asyncResp, username, password(std::move(password)),
440*84e12cb7SAppaRao Puli                  roleId(std::move(roleId)), enabled(std::move(enabled)),
441*84e12cb7SAppaRao Puli                  newUser{std::string(*newUserName)}](
442*84e12cb7SAppaRao Puli                     const boost::system::error_code ec) {
443*84e12cb7SAppaRao Puli                     if (ec)
444*84e12cb7SAppaRao Puli                     {
445*84e12cb7SAppaRao Puli                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
446a840879dSEd Tanous                         messages::resourceNotFound(
447*84e12cb7SAppaRao Puli                             asyncResp->res,
448*84e12cb7SAppaRao Puli                             "#ManagerAccount.v1_0_3.ManagerAccount", username);
449a840879dSEd Tanous                         return;
450a840879dSEd Tanous                     }
451a840879dSEd Tanous 
452*84e12cb7SAppaRao Puli                     updateUserProperties(asyncResp, newUser, password, enabled,
453*84e12cb7SAppaRao Puli                                          roleId);
454*84e12cb7SAppaRao Puli                 },
455*84e12cb7SAppaRao Puli                 "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
456*84e12cb7SAppaRao Puli                 "xyz.openbmc_project.User.Manager", "RenameUser", username,
457*84e12cb7SAppaRao Puli                 *newUserName);
458*84e12cb7SAppaRao Puli         }
459*84e12cb7SAppaRao Puli     }
460*84e12cb7SAppaRao Puli 
461*84e12cb7SAppaRao Puli     void updateUserProperties(std::shared_ptr<AsyncResp> asyncResp,
462*84e12cb7SAppaRao Puli                               const std::string& username,
463*84e12cb7SAppaRao Puli                               boost::optional<std::string> password,
464*84e12cb7SAppaRao Puli                               boost::optional<bool> enabled,
465*84e12cb7SAppaRao Puli                               boost::optional<std::string> roleId)
466*84e12cb7SAppaRao Puli     {
4679712f8acSEd Tanous         if (password)
468a840879dSEd Tanous         {
4699712f8acSEd Tanous             if (!pamUpdatePassword(username, *password))
470a840879dSEd Tanous             {
471a840879dSEd Tanous                 BMCWEB_LOG_ERROR << "pamUpdatePassword Failed";
472f12894f8SJason M. Bills                 messages::internalError(asyncResp->res);
473a840879dSEd Tanous                 return;
474a840879dSEd Tanous             }
475a840879dSEd Tanous         }
476a840879dSEd Tanous 
4779712f8acSEd Tanous         if (enabled)
478a840879dSEd Tanous         {
479a840879dSEd Tanous             crow::connections::systemBus->async_method_call(
480a840879dSEd Tanous                 [asyncResp](const boost::system::error_code ec) {
481a840879dSEd Tanous                     if (ec)
482a840879dSEd Tanous                     {
483*84e12cb7SAppaRao Puli                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
484f12894f8SJason M. Bills                         messages::internalError(asyncResp->res);
485a840879dSEd Tanous                         return;
486a840879dSEd Tanous                     }
487*84e12cb7SAppaRao Puli                     messages::success(asyncResp->res);
488*84e12cb7SAppaRao Puli                     return;
489*84e12cb7SAppaRao Puli                 },
490*84e12cb7SAppaRao Puli                 "xyz.openbmc_project.User.Manager",
491*84e12cb7SAppaRao Puli                 "/xyz/openbmc_project/user/" + username,
492*84e12cb7SAppaRao Puli                 "org.freedesktop.DBus.Properties", "Set",
493*84e12cb7SAppaRao Puli                 "xyz.openbmc_project.User.Attributes", "UserEnabled",
494*84e12cb7SAppaRao Puli                 sdbusplus::message::variant<bool>{*enabled});
495*84e12cb7SAppaRao Puli         }
496*84e12cb7SAppaRao Puli 
497*84e12cb7SAppaRao Puli         if (roleId)
498*84e12cb7SAppaRao Puli         {
499*84e12cb7SAppaRao Puli             std::string priv = getRoleIdFromPrivilege(*roleId);
500*84e12cb7SAppaRao Puli             if (priv.empty())
501*84e12cb7SAppaRao Puli             {
502*84e12cb7SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, *roleId,
503*84e12cb7SAppaRao Puli                                                  "RoleId");
504*84e12cb7SAppaRao Puli                 return;
505*84e12cb7SAppaRao Puli             }
506*84e12cb7SAppaRao Puli 
507*84e12cb7SAppaRao Puli             crow::connections::systemBus->async_method_call(
508*84e12cb7SAppaRao Puli                 [asyncResp](const boost::system::error_code ec) {
509*84e12cb7SAppaRao Puli                     if (ec)
510*84e12cb7SAppaRao Puli                     {
511*84e12cb7SAppaRao Puli                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
512*84e12cb7SAppaRao Puli                         messages::internalError(asyncResp->res);
513*84e12cb7SAppaRao Puli                         return;
514*84e12cb7SAppaRao Puli                     }
515f12894f8SJason M. Bills                     messages::success(asyncResp->res);
516a840879dSEd Tanous                 },
517a840879dSEd Tanous                 "xyz.openbmc_project.User.Manager",
518*84e12cb7SAppaRao Puli                 "/xyz/openbmc_project/user/" + username,
519a840879dSEd Tanous                 "org.freedesktop.DBus.Properties", "Set",
520*84e12cb7SAppaRao Puli                 "xyz.openbmc_project.User.Attributes", "UserPrivilege",
521*84e12cb7SAppaRao Puli                 sdbusplus::message::variant<std::string>{priv});
522a840879dSEd Tanous         }
523a840879dSEd Tanous     }
52406e086d9SEd Tanous 
52506e086d9SEd Tanous     void doDelete(crow::Response& res, const crow::Request& req,
52606e086d9SEd Tanous                   const std::vector<std::string>& params) override
52706e086d9SEd Tanous     {
52806e086d9SEd Tanous         auto asyncResp = std::make_shared<AsyncResp>(res);
52906e086d9SEd Tanous 
53006e086d9SEd Tanous         if (params.size() != 1)
53106e086d9SEd Tanous         {
532f12894f8SJason M. Bills             messages::internalError(asyncResp->res);
53306e086d9SEd Tanous             return;
53406e086d9SEd Tanous         }
53506e086d9SEd Tanous 
53606e086d9SEd Tanous         const std::string userPath = "/xyz/openbmc_project/user/" + params[0];
53706e086d9SEd Tanous 
53806e086d9SEd Tanous         crow::connections::systemBus->async_method_call(
53906e086d9SEd Tanous             [asyncResp, username{std::move(params[0])}](
54006e086d9SEd Tanous                 const boost::system::error_code ec) {
54106e086d9SEd Tanous                 if (ec)
54206e086d9SEd Tanous                 {
54306e086d9SEd Tanous                     messages::resourceNotFound(
544f12894f8SJason M. Bills                         asyncResp->res, "#ManagerAccount.v1_0_3.ManagerAccount",
545f12894f8SJason M. Bills                         username);
54606e086d9SEd Tanous                     return;
54706e086d9SEd Tanous                 }
54806e086d9SEd Tanous 
549f12894f8SJason M. Bills                 messages::accountRemoved(asyncResp->res);
55006e086d9SEd Tanous             },
55106e086d9SEd Tanous             "xyz.openbmc_project.User.Manager", userPath,
55206e086d9SEd Tanous             "xyz.openbmc_project.Object.Delete", "Delete");
55306e086d9SEd Tanous     }
554*84e12cb7SAppaRao Puli };
55588d16c9aSLewanczyk, Dawid 
55688d16c9aSLewanczyk, Dawid } // namespace redfish
557